From dcfb22c3f416fa0a8f9de80d874233c62e5fe168 Mon Sep 17 00:00:00 2001 From: zarzet Date: Sun, 3 May 2026 16:49:43 +0700 Subject: [PATCH] fix: persist probed audio duration --- lib/providers/download_queue_provider.dart | 15 +++++++++++++ lib/screens/track_metadata_screen.dart | 8 +++++++ lib/services/library_database.dart | 26 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/lib/providers/download_queue_provider.dart b/lib/providers/download_queue_provider.dart index bb0e936a..a81c1c19 100644 --- a/lib/providers/download_queue_provider.dart +++ b/lib/providers/download_queue_provider.dart @@ -603,11 +603,13 @@ class DownloadHistoryNotifier extends Notifier { if (hasResolvedSpecs && !isPlaceholderQualityLabel(item.quality)) { final needsComposerBackfill = normalizeOptionalString(item.composer) == null; + final needsDurationBackfill = item.duration == null || item.duration == 0; final needsTrackNumberBackfill = item.trackNumber == null; final needsTotalTracksBackfill = item.totalTracks == null; final needsDiscNumberBackfill = item.discNumber == null; final needsTotalDiscsBackfill = item.totalDiscs == null; return needsComposerBackfill || + needsDurationBackfill || needsTrackNumberBackfill || needsTotalTracksBackfill || needsDiscNumberBackfill || @@ -616,6 +618,7 @@ class DownloadHistoryNotifier extends Notifier { final needsComposerBackfill = normalizeOptionalString(item.composer) == null; + final needsDurationBackfill = item.duration == null || item.duration == 0; final needsTrackNumberBackfill = item.trackNumber == null; final needsTotalTracksBackfill = item.totalTracks == null; final needsDiscNumberBackfill = item.discNumber == null; @@ -624,6 +627,7 @@ class DownloadHistoryNotifier extends Notifier { isPlaceholderQualityLabel(item.quality) || normalizeOptionalString(item.quality) == null || needsComposerBackfill || + needsDurationBackfill || needsTrackNumberBackfill || needsTotalTracksBackfill || needsDiscNumberBackfill || @@ -652,6 +656,7 @@ class DownloadHistoryNotifier extends Notifier { storedQuality: fallbackQuality, ); final composer = normalizeOptionalString(result['composer']?.toString()); + final duration = _readPositiveInt(result['duration']); final trackNumber = _readPositiveInt(result['track_number']); final totalTracks = _readPositiveInt(result['total_tracks']); final discNumber = _readPositiveInt(result['disc_number']); @@ -661,6 +666,7 @@ class DownloadHistoryNotifier extends Notifier { bitDepth == null && sampleRate == null && composer == null && + duration == null && trackNumber == null && totalTracks == null && discNumber == null && @@ -673,6 +679,7 @@ class DownloadHistoryNotifier extends Notifier { 'bitDepth': bitDepth, 'sampleRate': sampleRate, 'composer': composer, + 'duration': duration, 'trackNumber': trackNumber, 'totalTracks': totalTracks, 'discNumber': discNumber, @@ -746,6 +753,7 @@ class DownloadHistoryNotifier extends Notifier { final resolvedComposer = normalizeOptionalString( probed['composer'] as String?, ); + final resolvedDuration = probed['duration'] as int?; final resolvedTrackNumber = probed['trackNumber'] as int?; final resolvedTotalTracks = probed['totalTracks'] as int?; final resolvedDiscNumber = probed['discNumber'] as int?; @@ -759,6 +767,8 @@ class DownloadHistoryNotifier extends Notifier { resolvedSampleRate != null && resolvedSampleRate != item.sampleRate; final composerChanged = resolvedComposer != null && resolvedComposer != item.composer; + final durationChanged = + resolvedDuration != null && resolvedDuration != item.duration; final trackNumberChanged = resolvedTrackNumber != null && resolvedTrackNumber != item.trackNumber; @@ -774,6 +784,7 @@ class DownloadHistoryNotifier extends Notifier { !bitDepthChanged && !sampleRateChanged && !composerChanged && + !durationChanged && !trackNumberChanged && !totalTracksChanged && !discNumberChanged && @@ -786,6 +797,7 @@ class DownloadHistoryNotifier extends Notifier { bitDepth: resolvedBitDepth, sampleRate: resolvedSampleRate, composer: resolvedComposer, + duration: resolvedDuration, trackNumber: resolvedTrackNumber, totalTracks: resolvedTotalTracks, discNumber: resolvedDiscNumber, @@ -915,6 +927,7 @@ class DownloadHistoryNotifier extends Notifier { int? totalTracks, int? discNumber, int? totalDiscs, + int? duration, String? composer, }) async { final index = state.items.indexWhere((item) => item.id == id); @@ -929,6 +942,7 @@ class DownloadHistoryNotifier extends Notifier { totalTracks: totalTracks, discNumber: discNumber, totalDiscs: totalDiscs, + duration: duration, composer: composer, ); @@ -939,6 +953,7 @@ class DownloadHistoryNotifier extends Notifier { updated.totalTracks == current.totalTracks && updated.discNumber == current.discNumber && updated.totalDiscs == current.totalDiscs && + updated.duration == current.duration && updated.composer == current.composer) { return; } diff --git a/lib/screens/track_metadata_screen.dart b/lib/screens/track_metadata_screen.dart index 5a1745c6..f6135ffe 100644 --- a/lib/screens/track_metadata_screen.dart +++ b/lib/screens/track_metadata_screen.dart @@ -398,6 +398,7 @@ class _TrackMetadataScreenState extends ConsumerState { needsTotalTracks || needsDiscNumber || needsTotalDiscs || + needsDuration || needsComposer || (isPlaceholderQualityLabel(_quality) && resolvedQuality != null)); @@ -446,8 +447,15 @@ class _TrackMetadataScreenState extends ConsumerState { totalTracks: needsTotalTracks ? resolvedTotalTracks : null, discNumber: needsDiscNumber ? resolvedDiscNumber : null, totalDiscs: needsTotalDiscs ? resolvedTotalDiscs : null, + duration: needsDuration ? resolvedDuration : null, composer: needsComposer ? resolvedComposer : null, ); + } else if (_isLocalItem && needsDuration) { + await LibraryDatabase.instance.updateAudioMetadata( + _localLibraryItem!.id, + duration: resolvedDuration, + ); + await ref.read(localLibraryProvider.notifier).reloadFromStorage(); } } catch (e) { _log.w('Failed to resolve audio metadata from file: $e'); diff --git a/lib/services/library_database.dart b/lib/services/library_database.dart index f6b51f4d..7bc50794 100644 --- a/lib/services/library_database.dart +++ b/lib/services/library_database.dart @@ -470,6 +470,32 @@ class LibraryDatabase { }); } + Future updateAudioMetadata( + String id, { + int? duration, + int? bitDepth, + int? sampleRate, + int? bitrate, + }) async { + final values = {}; + if (duration != null && duration > 0) { + values['duration'] = duration; + } + if (bitDepth != null && bitDepth > 0) { + values['bit_depth'] = bitDepth; + } + if (sampleRate != null && sampleRate > 0) { + values['sample_rate'] = sampleRate; + } + if (bitrate != null && bitrate > 0) { + values['bitrate'] = bitrate; + } + if (values.isEmpty) return; + + final db = await database; + await db.update('library', values, where: 'id = ?', whereArgs: [id]); + } + Future delete(String id) async { final db = await database; await db.delete('library', where: 'id = ?', whereArgs: [id]);