Einseitige Playlist-Sicherung: melden, merken, bei leerer Tabelle holen
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012A2pmbnVNPiHdyf2GW8eLP
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0519c68b26
commit
faabf28abc
@@ -546,6 +546,10 @@ class MeloDb extends _$MeloDb {
|
||||
.write(SongsCompanion(cloudId: Value(cloudId)));
|
||||
}
|
||||
|
||||
Future<Song?> songByCloudId(String cloudId) =>
|
||||
(select(songs)..where((s) => s.cloudId.equals(cloudId)))
|
||||
.getSingleOrNull();
|
||||
|
||||
/// Titel, die am Server gelöscht wurden, auch auf dem Gerät als gelöscht
|
||||
/// markieren. Grabstein statt echtem Löschen — sonst legt der nächste Scan
|
||||
/// sie wieder an.
|
||||
|
||||
@@ -22,6 +22,7 @@ class PlaylistService extends ChangeNotifier {
|
||||
Future<String> createPlaylist(String name, {String? description}) async {
|
||||
final id = await db.createPlaylist(name, description: description);
|
||||
notifyListeners();
|
||||
await _sichereNeuePlaylist(id, name);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -30,24 +31,39 @@ class PlaylistService extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> addSongToPlaylist(String playlistId, String songId, int position) async {
|
||||
Future<void> addSongToPlaylist(
|
||||
String playlistId, String songId, int position) async {
|
||||
await db.addSongToPlaylist(playlistId, songId, position);
|
||||
notifyListeners();
|
||||
final cloudId = await _cloudIdDerPlaylist(playlistId);
|
||||
final songCloudId = (await db.songById(songId))?.cloudId;
|
||||
if (cloudId == null || songCloudId == null) return;
|
||||
await _still(() =>
|
||||
_cloud!.fuegePlaylistSongsHinzu(cloudId, [songCloudId]));
|
||||
}
|
||||
|
||||
Future<void> removeSongFromPlaylist(String playlistId, String songId) async {
|
||||
Future<void> removeSongFromPlaylist(
|
||||
String playlistId, String songId) async {
|
||||
final songCloudId = (await db.songById(songId))?.cloudId;
|
||||
await db.removeSongFromPlaylist(playlistId, songId);
|
||||
notifyListeners();
|
||||
final cloudId = await _cloudIdDerPlaylist(playlistId);
|
||||
if (cloudId == null || songCloudId == null) return;
|
||||
await _still(() => _cloud!.entfernePlaylistSong(cloudId, songCloudId));
|
||||
}
|
||||
|
||||
Future<void> reorderSong(String playlistId, String songId, int newPosition) async {
|
||||
Future<void> reorderSong(
|
||||
String playlistId, String songId, int newPosition) async {
|
||||
await db.reorderPlaylistSong(playlistId, songId, newPosition);
|
||||
notifyListeners();
|
||||
await _sichereReihenfolge(playlistId);
|
||||
}
|
||||
|
||||
Future<void> reorderAll(String playlistId, List<String> orderedSongIds) async {
|
||||
Future<void> reorderAll(
|
||||
String playlistId, List<String> orderedSongIds) async {
|
||||
await db.reorderAllPlaylistSongs(playlistId, orderedSongIds);
|
||||
notifyListeners();
|
||||
await _sichereReihenfolge(playlistId);
|
||||
}
|
||||
|
||||
Future<void> toggleFavorite(String songId) async {
|
||||
@@ -135,4 +151,75 @@ class PlaylistService extends ChangeNotifier {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Führt [aktion] aus und verwirft jeden Fehler.
|
||||
///
|
||||
/// Die Sicherung ist einseitig und ohne Rollback: schlägt sie fehl, bleibt
|
||||
/// der lokale Stand, wie er ist, und die nächste Änderung versucht es
|
||||
/// erneut.
|
||||
Future<void> _still(Future<void> Function() aktion) async {
|
||||
try {
|
||||
await aktion();
|
||||
} catch (e) {
|
||||
debugPrint('Playlist-Sicherung übersprungen: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> _cloudIdDerPlaylist(String playlistId) async {
|
||||
if (_cloud == null || !_cloud.istAngemeldet) return null;
|
||||
return (await db.playlistById(playlistId))?.cloudId;
|
||||
}
|
||||
|
||||
Future<void> _sichereNeuePlaylist(String id, String name) async {
|
||||
final cloud = _cloud;
|
||||
if (cloud == null || !cloud.istAngemeldet) return;
|
||||
await _still(() async {
|
||||
final cloudId = await cloud.legePlaylistAn(name);
|
||||
await db.setPlaylistCloudId(id, cloudId);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _sichereReihenfolge(String playlistId) async {
|
||||
final cloudId = await _cloudIdDerPlaylist(playlistId);
|
||||
if (cloudId == null) return;
|
||||
final songs = await db.watchPlaylistSongs(playlistId).first;
|
||||
final ids = [
|
||||
for (final s in songs)
|
||||
if (s.cloudId != null) s.cloudId!,
|
||||
];
|
||||
if (ids.isEmpty) return;
|
||||
await _still(() => _cloud!.setzePlaylistReihenfolge(cloudId, ids));
|
||||
}
|
||||
|
||||
/// Holt die Playlisten des Servers **nur** auf ein Gerät ohne eigene:
|
||||
/// Neuinstallation oder Wiederherstellung.
|
||||
///
|
||||
/// Es gibt bewusst keinen Rück-Merge — Umbenennungen und Änderungen eines
|
||||
/// zweiten Geräts erscheinen hier nicht. Der beidseitige Abgleich ist eine
|
||||
/// eigene, spätere Spec.
|
||||
Future<int> stelleWiederHer() async {
|
||||
final cloud = _cloud;
|
||||
if (cloud == null || !cloud.istAngemeldet) return 0;
|
||||
if (await db.countPlaylists() > 0) return 0;
|
||||
|
||||
var angelegt = 0;
|
||||
try {
|
||||
for (final vomServer in await cloud.playlisten()) {
|
||||
final id = await db.createPlaylist(vomServer.name);
|
||||
await db.setPlaylistCloudId(id, vomServer.id);
|
||||
final songCloudIds = await cloud.playlistSongs(vomServer.id);
|
||||
var position = 0;
|
||||
for (final songCloudId in songCloudIds) {
|
||||
final song = await db.songByCloudId(songCloudId);
|
||||
if (song == null) continue;
|
||||
await db.addSongToPlaylist(id, song.id, position++);
|
||||
}
|
||||
angelegt++;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Playlist-Wiederherstellung abgebrochen: $e');
|
||||
}
|
||||
notifyListeners();
|
||||
return angelegt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ Future<void> main() async {
|
||||
_db,
|
||||
cloud: MeloCloudService(auth: _bakaAuth),
|
||||
);
|
||||
// Nur auf einem Gerät ohne eigene Playlisten: nach Neuinstallation oder
|
||||
// Zurücksetzen holt das die gesicherten Listen zurück.
|
||||
unawaited(_playlists.stelleWiederHer());
|
||||
final navidrome = NavidromeService();
|
||||
await navidrome.ladeGespeicherteZugangsdaten();
|
||||
_downloads = DownloadService(db: _db, navidrome: navidrome);
|
||||
|
||||
Reference in New Issue
Block a user