mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-17 16:37:17 +02:00
Fix metadata consistency (Go->Flutter) and build optimization
- Backend: Return full metadata (Track, Disc, Year) from Tidal/Qobuz/Amazon download results - Flutter: Use backend metadata for tagging converted M4A and history entries - Fix: Duplicate convertTrack method in deezer.go - Fix: Better error message for Deezer fallback failure - Changed: Default service fallback to Tidal -> Qobuz -> Amazon - Build: Re-enabled resource shrinking and minification for release build
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:spotiflac_android/utils/logger.dart';
|
||||
|
||||
final _log = AppLogger('FFmpeg');
|
||||
@@ -133,22 +134,83 @@ class FFmpegService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Embed cover art to FLAC file
|
||||
/// Embed metadata and cover art to FLAC file
|
||||
/// Returns the file path on success, null on failure
|
||||
static Future<String?> embedCover(String flacPath, String coverPath) async {
|
||||
final tempOutput = '$flacPath.tmp';
|
||||
final command = '-i "$flacPath" -i "$coverPath" -map 0:a -map 1:0 -c copy -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" -disposition:v attached_pic "$tempOutput" -y';
|
||||
static Future<String?> embedMetadata({
|
||||
required String flacPath,
|
||||
String? coverPath,
|
||||
Map<String, String>? metadata,
|
||||
}) async {
|
||||
// Android Scoped Storage: Cannot write directly to Music folder with FFmpeg
|
||||
// Use app-internal cache directory for temp output
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final uniqueId = DateTime.now().millisecondsSinceEpoch;
|
||||
final tempOutput = '${tempDir.path}/temp_embed_$uniqueId.flac';
|
||||
|
||||
// Construct command
|
||||
final StringBuffer cmdBuffer = StringBuffer();
|
||||
cmdBuffer.write('-i "$flacPath" ');
|
||||
|
||||
// Add cover input if available
|
||||
if (coverPath != null) {
|
||||
cmdBuffer.write('-i "$coverPath" ');
|
||||
}
|
||||
|
||||
// Map audio stream
|
||||
cmdBuffer.write('-map 0:a ');
|
||||
|
||||
// Map cover stream if available
|
||||
if (coverPath != null) {
|
||||
cmdBuffer.write('-map 1:0 ');
|
||||
cmdBuffer.write('-c:v copy ');
|
||||
cmdBuffer.write('-disposition:v attached_pic ');
|
||||
cmdBuffer.write('-metadata:s:v title="Album cover" ');
|
||||
cmdBuffer.write('-metadata:s:v comment="Cover (front)" ');
|
||||
}
|
||||
|
||||
// Copy audio codec (don't re-encode)
|
||||
cmdBuffer.write('-c:a copy ');
|
||||
|
||||
// Add text metadata
|
||||
if (metadata != null) {
|
||||
metadata.forEach((key, value) {
|
||||
// Sanitize value: escape double quotes
|
||||
final sanitizedValue = value.replaceAll('"', '\\"');
|
||||
cmdBuffer.write('-metadata $key="$sanitizedValue" ');
|
||||
});
|
||||
}
|
||||
|
||||
cmdBuffer.write('"$tempOutput" -y');
|
||||
|
||||
final command = cmdBuffer.toString();
|
||||
_log.d('Executing FFmpeg command: $command');
|
||||
|
||||
final result = await _execute(command);
|
||||
|
||||
if (result.success) {
|
||||
try {
|
||||
// Replace original with temp
|
||||
await File(flacPath).delete();
|
||||
await File(tempOutput).rename(flacPath);
|
||||
return flacPath;
|
||||
// Copy temp output back to original location (replace)
|
||||
final tempFile = File(tempOutput);
|
||||
final originalFile = File(flacPath);
|
||||
|
||||
if (await tempFile.exists()) {
|
||||
// Delete original file
|
||||
if (await originalFile.exists()) {
|
||||
await originalFile.delete();
|
||||
}
|
||||
// Copy temp file to original location
|
||||
await tempFile.copy(flacPath);
|
||||
// Delete temp file
|
||||
await tempFile.delete();
|
||||
|
||||
return flacPath;
|
||||
} else {
|
||||
_log.e('Temp output file not found: $tempOutput');
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
_log.e('Failed to replace file after cover embed: $e');
|
||||
_log.e('Failed to replace file after metadata embed: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +223,7 @@ class FFmpegService {
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
_log.e('Cover embed failed: ${result.output}');
|
||||
_log.e('Metadata/Cover embed failed: ${result.output}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user