fix(download): preserve finalization metadata and library labels

This commit is contained in:
zarzet
2026-08-29 00:31:25 +07:00
parent c3b2214e2a
commit 5dac33dfa4
11 changed files with 264 additions and 26 deletions
@@ -18,8 +18,6 @@ import com.zarz.spotiflac.SafDownloadHandler.normalizeExt
import com.zarz.spotiflac.NativeFinalizationPolicy.applyQualityVariantFilenameLabel
import com.zarz.spotiflac.NativeFinalizationPolicy.displayAudioQuality
import com.zarz.spotiflac.NativeFinalizationPolicy.formatIndexTag
import com.zarz.spotiflac.NativeFinalizationPolicy.isLosslessAudioCodec
import com.zarz.spotiflac.NativeFinalizationPolicy.isLossyAudioCodec
import com.zarz.spotiflac.NativeFinalizationPolicy.normalizeAudioCodec
import com.zarz.spotiflac.NativeFinalizationPolicy.resolvePreferredDecryptionExtension
import gobackend.Gobackend
@@ -808,7 +806,11 @@ object NativeDownloadFinalizer {
try {
val codec = probePrimaryAudioCodec(localInput, shouldCancel)
val isAlreadyNativeFlac = codec == "flac" && isNativeFlacFile(localInput)
if (!isLosslessAudioCodec(codec)) {
if (!NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceContainerConversion,
codec,
)
) {
Log.d(TAG, "Preserving native container; audio codec is ${codec.ifBlank { "unknown" }}")
// The preserved stream is not FLAC but still carries the
// requested .flac name. Rename to the real container so the
@@ -158,6 +158,22 @@ internal object NativeFinalizationPolicy {
)
}
/**
* Decides whether a stream should enter the lossless container conversion
* path. A missing or generic M4A/MP4 codec is inconclusive rather than
* proof of lossy audio; an extension capability may explicitly request
* that FFmpeg attempt the conversion. Known lossy codecs remain native.
*/
fun shouldAttemptLosslessContainerConversion(
forceConversion: Boolean,
probedCodec: String?,
): Boolean {
if (isLosslessAudioCodec(probedCodec)) return true
val normalized = normalizeAudioCodec(probedCodec)
val inconclusive = normalized == null || normalized == "m4a"
return forceConversion && inconclusive
}
fun displayAudioQuality(
filePath: String,
fileName: String,
@@ -101,6 +101,40 @@ class NativeFinalizationPolicyTest {
assertFalse(NativeFinalizationPolicy.isLosslessAudioCodec("aac"))
}
@Test
fun forcedContainerConversionAttemptsInconclusiveCodecButPreservesLossy() {
assertTrue(
NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceConversion = true,
probedCodec = null,
),
)
assertTrue(
NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceConversion = true,
probedCodec = "m4a",
),
)
assertTrue(
NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceConversion = false,
probedCodec = "flac",
),
)
assertFalse(
NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceConversion = true,
probedCodec = "aac",
),
)
assertFalse(
NativeFinalizationPolicy.shouldAttemptLosslessContainerConversion(
forceConversion = false,
probedCodec = null,
),
)
}
@Test
fun isoBmffAudioUsesM4aExceptForAc4Passthrough() {
assertEquals(