mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-29 07:18:49 +02:00
126 lines
4.0 KiB
Dart
126 lines
4.0 KiB
Dart
import 'package:spotiflac_android/providers/download_history_provider.dart';
|
|
import 'package:spotiflac_android/services/history_database.dart';
|
|
import 'package:spotiflac_android/services/platform_bridge.dart';
|
|
import 'package:spotiflac_android/utils/audio_conversion_utils.dart';
|
|
|
|
class ConversionLibraryService {
|
|
const ConversionLibraryService._();
|
|
|
|
static Future<T?> _retryTransientSaf<T>(
|
|
Future<T?> Function() operation,
|
|
) async {
|
|
Object? lastError;
|
|
for (var attempt = 0; attempt < 2; attempt++) {
|
|
try {
|
|
final result = await operation();
|
|
if (result != null) return result;
|
|
} catch (error) {
|
|
lastError = error;
|
|
}
|
|
if (attempt == 0) {
|
|
await Future<void>.delayed(const Duration(milliseconds: 250));
|
|
}
|
|
}
|
|
if (lastError != null) throw lastError;
|
|
return null;
|
|
}
|
|
|
|
static Future<String?> copySafSourceToTemp(String uri) {
|
|
return _retryTransientSaf(() => PlatformBridge.copyContentUriToTemp(uri));
|
|
}
|
|
|
|
static Future<({String uri, String fileName})?> publishSafConversion({
|
|
required String treeUri,
|
|
required String relativeDir,
|
|
required String originalFileName,
|
|
required String targetFormat,
|
|
required String sourcePath,
|
|
required bool keepOriginal,
|
|
}) async {
|
|
final target = convertTargetExtAndMime(targetFormat);
|
|
final requestedName = convertedOutputFileName(
|
|
originalFileName: originalFileName,
|
|
targetFormat: targetFormat,
|
|
);
|
|
|
|
final replacesSameNamedDocument =
|
|
!keepOriginal &&
|
|
requestedName.toLowerCase() == originalFileName.toLowerCase();
|
|
if (!replacesSameNamedDocument) {
|
|
final result = await _retryTransientSaf(
|
|
() => PlatformBridge.createUniqueSafFileFromPath(
|
|
treeUri: treeUri,
|
|
relativeDir: relativeDir,
|
|
fileName: requestedName,
|
|
mimeType: target.mime,
|
|
srcPath: sourcePath,
|
|
),
|
|
);
|
|
if (result == null) return null;
|
|
final uri = (result['uri'] as String? ?? '').trim();
|
|
final fileName = (result['file_name'] as String? ?? '').trim();
|
|
if (uri.isEmpty || fileName.isEmpty) return null;
|
|
return (uri: uri, fileName: fileName);
|
|
}
|
|
|
|
final uri = await _retryTransientSaf(
|
|
() => PlatformBridge.createSafFileFromPath(
|
|
treeUri: treeUri,
|
|
relativeDir: relativeDir,
|
|
fileName: requestedName,
|
|
mimeType: target.mime,
|
|
srcPath: sourcePath,
|
|
),
|
|
);
|
|
if (uri == null || uri.trim().isEmpty) return null;
|
|
return (uri: uri, fileName: requestedName);
|
|
}
|
|
|
|
static Future<void> persistHistoryConversion({
|
|
required DownloadHistoryItem source,
|
|
required String newFilePath,
|
|
required String newQuality,
|
|
required String targetFormat,
|
|
required String bitrate,
|
|
required int? bitDepth,
|
|
required int? sampleRate,
|
|
required bool keepOriginal,
|
|
String? newSafFileName,
|
|
}) async {
|
|
final convertedBitrate = convertedAudioBitrateKbps(
|
|
targetFormat: targetFormat,
|
|
bitrate: bitrate,
|
|
);
|
|
final isLossless = isLosslessConversionTarget(targetFormat);
|
|
|
|
if (!keepOriginal) {
|
|
await HistoryDatabase.instance.updateFilePath(
|
|
source.id,
|
|
newFilePath,
|
|
newSafFileName: newSafFileName,
|
|
newQuality: newQuality,
|
|
newFormat: normalizedConvertedAudioFormat(targetFormat),
|
|
newBitrate: convertedBitrate,
|
|
newBitDepth: bitDepth,
|
|
newSampleRate: sampleRate,
|
|
clearAudioSpecs: !isLossless,
|
|
);
|
|
return;
|
|
}
|
|
|
|
final converted = source.toJson()
|
|
..['id'] = convertedLibraryItemId(source.id, newFilePath)
|
|
..['filePath'] = newFilePath
|
|
..['downloadedAt'] = DateTime.now().toIso8601String()
|
|
..['quality'] = newQuality
|
|
..['format'] = normalizedConvertedAudioFormat(targetFormat)
|
|
..['bitrate'] = convertedBitrate
|
|
..['bitDepth'] = isLossless ? bitDepth : null
|
|
..['sampleRate'] = isLossless ? sampleRate : null;
|
|
if (newSafFileName != null) {
|
|
converted['safFileName'] = newSafFileName;
|
|
}
|
|
await HistoryDatabase.instance.upsert(converted);
|
|
}
|
|
}
|