v2.53.1 — MED-2: Neue Server-Songs werden nach Download in die lokale DB eingefügt
## 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
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user