fix(android): validate native metadata editor results

This commit is contained in:
zarzet
2026-09-17 02:59:28 +07:00
parent 39a3e680a4
commit 1a4b90db43
2 changed files with 43 additions and 6 deletions
@@ -250,6 +250,16 @@ internal fun NativeDownloadFinalizer.lyricsDurationMs(input: NativeDownloadFinal
return if (duration > 10000L) duration else duration * 1000L
}
internal fun nativeMetadataEditHandled(response: String): Boolean {
val result = JSONObject(response)
val error = if (result.isNull("error")) "" else result.optString("error", "").trim()
val method = result.optString("method", "").trim()
check(result.opt("success") == true && error.isEmpty() && method.isNotEmpty()) {
error.ifEmpty { "Native metadata editor returned no successful result" }
}
return method != "ffmpeg"
}
internal fun NativeDownloadFinalizer.embedBasicMetadata(context: Context, path: String, input: NativeDownloadFinalizer.FinalizeInput, format: String) {
if (!input.request.optBoolean("embed_metadata", false)) return
val title = resultString(input, "title").ifBlank {
@@ -318,6 +328,7 @@ internal fun NativeDownloadFinalizer.embedBasicMetadata(context: Context, path:
.put("artist", artist)
.put("album", album)
.put("album_artist", albumArtist)
.put("artist_tag_mode", input.request.optString("artist_tag_mode", ""))
.put("date", date)
.put("isrc", isrc)
.put("composer", composer)
@@ -339,12 +350,7 @@ internal fun NativeDownloadFinalizer.embedBasicMetadata(context: Context, path:
fields.put("unsyncedlyrics", lyrics)
}
val response = createCoreBackend(context).editFileMetadata(path, fields.toString())
val method = try {
JSONObject(response).optString("method", "")
} catch (_: Exception) {
""
}
method != "ffmpeg"
nativeMetadataEditHandled(response)
} catch (e: Exception) {
if (format == "flac") throw e
Log.w(TAG, "Native tag embed failed for $format: ${e.message}; falling back to ffmpeg")
@@ -0,0 +1,31 @@
package com.zarz.spotiflac
import org.junit.Assert.assertFalse
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Test
class NativeMetadataEditResultTest {
@Test
fun successfulNativeEditAndExplicitFfmpegFallbackRemainDistinct() {
for (method in listOf("native", "native_mp3", "native_ogg", "native_m4a")) {
assertTrue(nativeMetadataEditHandled("{\"success\":true,\"method\":\"$method\"}"))
}
assertFalse(nativeMetadataEditHandled("{\"success\":true,\"method\":\"ffmpeg\"}"))
}
@Test
fun unsuccessfulMissingOrContradictoryResultsCannotSkipEmbedding() {
for (response in listOf(
"{}",
"{\"method\":\"native\"}",
"{\"success\":false,\"method\":\"native\"}",
"{\"success\":true}",
"{\"success\":\"true\",\"method\":\"native\"}",
"{\"success\":true,\"method\":\"native\",\"error\":\"write failed\"}",
)) {
assertThrows(IllegalStateException::class.java) { nativeMetadataEditHandled(response) }
}
assertThrows(org.json.JSONException::class.java) { nativeMetadataEditHandled("malformed") }
}
}