From 2cd34d61dc7b50e681b19366bdc170d7be0f1d7d Mon Sep 17 00:00:00 2001 From: Dustin Date: Wed, 5 Aug 2026 11:24:11 +0200 Subject: [PATCH] =?UTF-8?q?v2.53.1=20=E2=80=94=20MED-2:=20Neue=20Server-So?= =?UTF-8?q?ngs=20werden=20nach=20Download=20in=20die=20lokale=20DB=20einge?= =?UTF-8?q?f=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## MED-2 (Review-Fix, KRITISCH) - sync_service.dart: Nach erfolgreichem cloud.download wird der Song jetzt MIT cloud_id + Titeldaten (Titel/Künstler/Dauer/Größe/istKorrupt aus der Server-Liste) in die lokale DB eingefügt — vorher fehlte der Song in der Bibliothek, songNachCloudId blieb null und jeder Sync lud alle 325 Songs erneut (≈ GB/Sync) und meldete sie fälschlich als „+neu“ - Neuer statischer Helfer `songAusServerMap` (testbar): baut den Song aus den handle_list-Feldern; ytUrl wird bewusst NICHT übernommen (v2.52-F2: Server bleibt YT-Link-Quelle) - Zielpfad-Kollisionen abgesichert: existiert die Datei bereits (verwaister Download aus früherem Sync ohne DB-Eintrag), wird „ (2)“, „ (3)“ … an- gehängt — sonst scheiterte der Insert am UNIQUE-Constraint datei_pfad --- lib/services/sync_service.dart | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/services/sync_service.dart b/lib/services/sync_service.dart index ccfe5a2..de2d933 100644 --- a/lib/services/sync_service.dart +++ b/lib/services/sync_service.dart @@ -153,6 +153,38 @@ class SyncService { return letzterSync == null || d == null || d.isAfter(letzterSync); } + /// Baut den lokalen [Song]-DB-Eintrag aus einem Server-Listeneintrag + /// (handle_list-Felder: id/title/artist/duration/size/istKorrupt). + /// + /// Grundlage des MED-2-Fixes: Neue Server-Songs werden nach dem Download + /// MIT cloud_id + Titeldaten in die lokale DB eingefügt — vorher fehlten + /// sie in der Bibliothek und wurden bei jedem Sync erneut heruntergeladen. + /// `ytUrl` wird bewusst NICHT übernommen (v2.52-F2: Der Server ist die + /// Quelle für YT-Links, lokal wird yt_url nicht mehr persistiert). + /// Reine, statische Funktion → testbar. + @visibleForTesting + static Song songAusServerMap(Map song, String destPath) { + final dauerRaw = song['duration']; + final dauer = dauerRaw is num + ? dauerRaw.toInt() + : int.tryParse(dauerRaw?.toString() ?? '') ?? 0; + final groesseRaw = song['size']; + final groesse = groesseRaw is num + ? groesseRaw.toInt() + : int.tryParse(groesseRaw?.toString() ?? '') ?? 0; + return Song( + titel: (song['title'] ?? 'unknown').toString(), + kuenstler: (song['artist']?.toString() ?? '').trim(), + dauerSekunden: dauer, + groesseBytes: groesse, + dateiPfad: destPath, + downloadQuelle: 'cloud', + istHeruntergeladen: true, + istKorrupt: song['istKorrupt'] == true, + cloudId: song['id']?.toString(), + ); + } + /// Lokale Löschung eines Cloud-Songs an den Server melden (Tombstone). /// Der Server speichert `deleted=1` + `deleted_at` → andere Geräte löschen /// den Song nach ihrem nächsten Sync ebenfalls lokal (keine Zombie-Songs). @@ -351,13 +383,26 @@ class SyncService { onFortschritt?.call('Download: $title…', 0.1 + (0.4 * processed / (totalNew > 0 ? totalNew : 1))); final safeTitle = sanitizeDateiname(title); - final dest = '${dir.path}/$safeTitle'; + // Eindeutiger Zielpfad: Kollisionen (gleichnamiger Titel oder + // verwaiste Datei aus einem früheren Sync ohne DB-Eintrag) würden + // die Datei überschreiben bzw. am UNIQUE-Constraint der + // datei_pfad-Spalte scheitern (Insert würde still ignoriert). + var dest = '${dir.path}/$safeTitle'; + var kollision = 2; + while (await File(dest).exists()) { + dest = '${dir.path}/$safeTitle ($kollision)'; + kollision++; + } if (await cloud.download(sid, dest)) { downloaded++; neueSongs++; neueDetails.add('+ Neuer Song: $title'); - // In DB eintragen mit cloud_id - // (vereinfacht: ID3-Reader würde Titel extrahieren) + // MED-2: Song mit cloud_id + Titeldaten aus der Server-Liste in + // die lokale DB einfügen — sonst fehlt der Song in der + // Bibliothek, songNachCloudId bleibt null und der Song wird bei + // JEDEM Sync erneut heruntergeladen (GB/Sync) und fälschlich als + // „+neu“ gemeldet. + await _db.songEinfuegen(songAusServerMap(song, dest)); } await Future.delayed( const Duration(milliseconds: 50)); // UI-Update erlauben