mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-05-15 05:10:28 +02:00
fix(native-worker): preserve requested output container in finalizer
When the native worker result advertises a requested non-FLAC output extension (for example '.m4a'), skip the m4a-to-flac container conversion in both the Dart and Kotlin finalizers so the native output container is preserved end-to-end. - ffmpeg_service: propagate the top-level 'output_extension' hint into the download-result descriptor for both the map-backed and legacy paths; expose a normalized getter for consistent comparisons. - download_queue_provider: short-circuit the native-worker container-conversion step when the descriptor's requested extension is not '.flac', with a debug log describing the skip. - NativeDownloadFinalizer: mirror the guard on the Kotlin side so the finalizer does not force a container conversion that would clobber the requested native output.
This commit is contained in:
@@ -501,6 +501,8 @@ object NativeDownloadFinalizer {
|
||||
shouldCancel: () -> Boolean,
|
||||
) {
|
||||
if (requestQuality(input) == "HIGH" || outputExt(input) != ".flac") return
|
||||
val requestedDecryptionExt = requestedDecryptionOutputExt(input)
|
||||
if (requestedDecryptionExt.isNotBlank() && requestedDecryptionExt != ".flac") return
|
||||
if (!looksLikeM4a(state.filePath, state.fileName) && !shouldForceContainerConversion(input, state)) return
|
||||
|
||||
val localInput = materializeForFFmpeg(context, input, state)
|
||||
@@ -1330,6 +1332,14 @@ object NativeDownloadFinalizer {
|
||||
return container == "m4a" || container == "mp4" || container == "mov" || container == "aac"
|
||||
}
|
||||
|
||||
private fun requestedDecryptionOutputExt(input: FinalizeInput): String {
|
||||
val descriptor = input.result.optJSONObject("decryption")
|
||||
return normalizeExt(
|
||||
descriptor?.optString("output_extension", "")
|
||||
?.ifBlank { input.result.optString("output_extension", "") }
|
||||
)
|
||||
}
|
||||
|
||||
private fun validateRequestContract(request: JSONObject) {
|
||||
val version = request.optInt("contract_version", -1)
|
||||
if (version != NATIVE_WORKER_CONTRACT_VERSION) {
|
||||
|
||||
@@ -6049,6 +6049,16 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
if (context.quality == 'HIGH' || context.outputExt != '.flac') {
|
||||
return filePath;
|
||||
}
|
||||
final requestedDecryptionExt =
|
||||
DownloadDecryptionDescriptor.fromDownloadResult(
|
||||
result,
|
||||
)?.normalizedOutputExtension;
|
||||
if (requestedDecryptionExt != null && requestedDecryptionExt != '.flac') {
|
||||
_log.d(
|
||||
'Native-worker decrypted output requested $requestedDecryptionExt; preserving native container.',
|
||||
);
|
||||
return filePath;
|
||||
}
|
||||
final lowerPath = filePath.toLowerCase();
|
||||
final resultFileName = (result['file_name'] as String?)?.toLowerCase();
|
||||
final looksLikeM4a =
|
||||
|
||||
@@ -66,9 +66,9 @@ class DownloadDecryptionDescriptor {
|
||||
) {
|
||||
final rawDecryption = result['decryption'];
|
||||
if (rawDecryption is Map) {
|
||||
final descriptor = DownloadDecryptionDescriptor.fromJson(
|
||||
Map<String, dynamic>.from(rawDecryption),
|
||||
);
|
||||
final descriptorJson = Map<String, dynamic>.from(rawDecryption);
|
||||
descriptorJson['output_extension'] ??= result['output_extension'];
|
||||
final descriptor = DownloadDecryptionDescriptor.fromJson(descriptorJson);
|
||||
if (descriptor.normalizedStrategy == 'ffmpeg.mov_key' &&
|
||||
descriptor.key.isNotEmpty) {
|
||||
return descriptor;
|
||||
@@ -84,6 +84,7 @@ class DownloadDecryptionDescriptor {
|
||||
strategy: 'ffmpeg.mov_key',
|
||||
key: legacyKey,
|
||||
inputFormat: 'mov',
|
||||
outputExtension: (result['output_extension'] as String?)?.trim(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,6 +101,12 @@ class DownloadDecryptionDescriptor {
|
||||
return strategy.trim();
|
||||
}
|
||||
}
|
||||
|
||||
String? get normalizedOutputExtension {
|
||||
final trimmed = (outputExtension ?? '').trim().toLowerCase();
|
||||
if (trimmed.isEmpty) return null;
|
||||
return trimmed.startsWith('.') ? trimmed : '.$trimmed';
|
||||
}
|
||||
}
|
||||
|
||||
class FFmpegService {
|
||||
|
||||
Reference in New Issue
Block a user