refactor(player): move restorePlaybackSession to playback_session_restore.dart

The function only needed the file-level logger, which the new file declares
with the same tag. It is re-exported from music_player_service.dart.
This commit is contained in:
zarzet committed 2026-10-18 23:53:44 +07:00
1 parent 548567eff3
commit 92d655fd1c
2 files changed
+112 -102

No files matched your search

+1 -102
View File
@@ -14,7 +14,6 @@ import 'package:audio_session/audio_session.dart'
AudioSessionConfiguration,
AudioInterruptionType;
import 'package:audioplayers/audioplayers.dart';
import 'package:path_provider/path_provider.dart';
import 'package:spotiflac_android/services/listening_statistics.dart'
show ListeningTrack;
import 'package:spotiflac_android/services/library_database.dart';
@@ -43,6 +42,7 @@ import 'package:spotiflac_android/services/playable_media.dart';
export 'music_player_runtime.dart';
export 'playable_media.dart';
export 'playback_metadata.dart';
export 'playback_session_restore.dart';
part 'music_player_automix.dart';
part 'music_player_autoplay.dart';
@@ -2094,104 +2094,3 @@ Future<MusicPlayerHandler> initMusicPlayer() => musicPlayerRuntime.initialize();
/// exist are dropped; content URIs are kept and fail gracefully at play time.
Future<void> restorePersistedPlaybackSession() =>
musicPlayerRuntime.restoreSession();
Future<void> restorePlaybackSession(MusicPlayerRuntime runtime) async {
try {
final database = runtime.dependencies.sessionDatabase;
final session = await database.getPlaybackSession();
if (session == null) return;
final rawMedia = session['media'];
if (rawMedia is! List) {
await database.clearPlaybackSession();
return;
}
final items = <PlayableMedia>[];
final keptOriginalIndices = <int>[];
final iosDocumentsPath = runtime.dependencies.isIOS
? (await getApplicationDocumentsDirectory()).path
: null;
var artworkRelocated = false;
for (var i = 0; i < rawMedia.length; i++) {
final entry = rawMedia[i];
if (entry is! Map) continue;
final media = PlayableMedia.fromJson(
Map<String, dynamic>.from(entry),
iosDocumentsPath: iosDocumentsPath,
);
if (media == null) continue;
if (!media.isContentUri &&
!media.isNetwork &&
!await File(media.source).exists()) {
continue;
}
final artwork = await resolveRestoredArtworkUri(
media.artUri,
loadLibraryCoverPath: () async {
final database = runtime.dependencies.libraryDatabase;
final row = await database.getById(media.id);
if (row != null) return row['coverPath'] as String?;
final matches = await database.findByTrackAndArtist(
media.title,
media.artist,
);
for (final row in matches) {
if (row['filePath'] == media.source) {
return row['coverPath'] as String?;
}
}
return null;
},
);
items.add(
artwork == media.artUri
? media
: PlayableMedia.fromJson({...media.toJson(), 'artUri': artwork})!,
);
artworkRelocated |= artwork != entry['artUri'];
keptOriginalIndices.add(i);
}
if (items.isEmpty) {
await database.clearPlaybackSession();
return;
}
// Remap the saved index onto the surviving list; if the current track
// itself was dropped, land on the nearest earlier survivor at 0:00.
final savedIndex = (session['index'] as num?)?.toInt() ?? 0;
var index = 0;
for (var i = 0; i < keptOriginalIndices.length; i++) {
if (keptOriginalIndices[i] <= savedIndex) index = i;
}
var position = Duration(
milliseconds: (session['positionMs'] as num?)?.toInt() ?? 0,
);
if (keptOriginalIndices[index] != savedIndex) {
position = Duration.zero;
}
final handler = await runtime.initialize();
await handler.restoreSession(
items: items,
index: index,
position: position,
shuffle: session['shuffle'] == true,
originalOrder: [
for (final i in keptOriginalIndices)
((rawMedia[i] as Map)['queueOriginalIndex'] as num?)?.toInt() ?? i,
],
queueNeedsRewrite: items.length != rawMedia.length || artworkRelocated,
repeatMode: AudioServiceRepeatMode.values.firstWhere(
(mode) => mode.name == session['repeat'],
orElse: () => AudioServiceRepeatMode.none,
),
);
_log.i(
'Restored playback session: ${items.length} track(s), paused at '
'${position.inSeconds}s',
);
} catch (e) {
_log.w('Failed to restore playback session: $e');
}
}
+111
View File
@@ -0,0 +1,111 @@
import 'dart:io';
import 'package:audio_service/audio_service.dart' show AudioServiceRepeatMode;
import 'package:path_provider/path_provider.dart';
import 'package:spotiflac_android/services/music_player_runtime.dart';
import 'package:spotiflac_android/services/playable_media.dart';
import 'package:spotiflac_android/utils/logger.dart';
import 'package:spotiflac_android/utils/playback_artwork.dart';
final _log = AppLogger('MusicPlayer');
Future<void> restorePlaybackSession(MusicPlayerRuntime runtime) async {
try {
final database = runtime.dependencies.sessionDatabase;
final session = await database.getPlaybackSession();
if (session == null) return;
final rawMedia = session['media'];
if (rawMedia is! List) {
await database.clearPlaybackSession();
return;
}
final items = <PlayableMedia>[];
final keptOriginalIndices = <int>[];
final iosDocumentsPath = runtime.dependencies.isIOS
? (await getApplicationDocumentsDirectory()).path
: null;
var artworkRelocated = false;
for (var i = 0; i < rawMedia.length; i++) {
final entry = rawMedia[i];
if (entry is! Map) continue;
final media = PlayableMedia.fromJson(
Map<String, dynamic>.from(entry),
iosDocumentsPath: iosDocumentsPath,
);
if (media == null) continue;
if (!media.isContentUri &&
!media.isNetwork &&
!await File(media.source).exists()) {
continue;
}
final artwork = await resolveRestoredArtworkUri(
media.artUri,
loadLibraryCoverPath: () async {
final database = runtime.dependencies.libraryDatabase;
final row = await database.getById(media.id);
if (row != null) return row['coverPath'] as String?;
final matches = await database.findByTrackAndArtist(
media.title,
media.artist,
);
for (final row in matches) {
if (row['filePath'] == media.source) {
return row['coverPath'] as String?;
}
}
return null;
},
);
items.add(
artwork == media.artUri
? media
: PlayableMedia.fromJson({...media.toJson(), 'artUri': artwork})!,
);
artworkRelocated |= artwork != entry['artUri'];
keptOriginalIndices.add(i);
}
if (items.isEmpty) {
await database.clearPlaybackSession();
return;
}
// Remap the saved index onto the surviving list; if the current track
// itself was dropped, land on the nearest earlier survivor at 0:00.
final savedIndex = (session['index'] as num?)?.toInt() ?? 0;
var index = 0;
for (var i = 0; i < keptOriginalIndices.length; i++) {
if (keptOriginalIndices[i] <= savedIndex) index = i;
}
var position = Duration(
milliseconds: (session['positionMs'] as num?)?.toInt() ?? 0,
);
if (keptOriginalIndices[index] != savedIndex) {
position = Duration.zero;
}
final handler = await runtime.initialize();
await handler.restoreSession(
items: items,
index: index,
position: position,
shuffle: session['shuffle'] == true,
originalOrder: [
for (final i in keptOriginalIndices)
((rawMedia[i] as Map)['queueOriginalIndex'] as num?)?.toInt() ?? i,
],
queueNeedsRewrite: items.length != rawMedia.length || artworkRelocated,
repeatMode: AudioServiceRepeatMode.values.firstWhere(
(mode) => mode.name == session['repeat'],
orElse: () => AudioServiceRepeatMode.none,
),
);
_log.i(
'Restored playback session: ${items.length} track(s), paused at '
'${position.inSeconds}s',
);
} catch (e) {
_log.w('Failed to restore playback session: $e');
}
}