v2.52.1 — F2: YT-Links nur als Server-Fallback
## YT-Quell-URL (Server ist die Quelle) - cloud_service.ytUrlSetzen(): POST /api/v1/cloud/yt-url (per-User UPDATE user_songs.yt_url) - musik_scanner._sucheYtUrls(): durchsucht NUR Songs mit cloud_id, die auf dem Server noch keine yt_url haben; Treffer werden auf den Server hochgeladen statt lokal gespeichert - db_helper: ytUrlAktualisieren/songsOhneYtUrl entfernt, songsMitCloudId() ergänzt - download_service: yt_url wird beim Download nicht mehr lokal persistiert ## Fallback-Kette reDownload (korrupte/fehlende Datei) - 1) Server-Download via cloud_id + Magic-Byte-Check (primäre Quelle) - 2) Server-ytUrl (aus listSongs) → yt-proxy als letzte Chance - 3) Legacy: lokal gespeicherte ytUrl (Bestandsdaten vor v2.52) - song_tile: „Neu laden“ erscheint bei istKorrupt && (cloudId != null || ytUrl != null) - 3 neue Tests (ytUrlSetzen: ok/error/401) → 111 Tests grün, analyze 0 Issues
This commit is contained in:
@@ -11,6 +11,7 @@ import '../database/db_helper.dart';
|
||||
import '../utils/audio_validator.dart';
|
||||
import 'melo_logger.dart';
|
||||
import 'auth_service.dart';
|
||||
import 'cloud_service.dart';
|
||||
import '../main.dart'; // für notificationsPlugin
|
||||
import '../utils/sanitize.dart';
|
||||
|
||||
@@ -370,7 +371,8 @@ class DownloadService extends ChangeNotifier {
|
||||
istHeruntergeladen: true,
|
||||
istKorrupt: istKorrupt,
|
||||
downloadQuelle: 'youtube',
|
||||
ytUrl: url,
|
||||
// F2: yt_url wird NICHT mehr lokal persistiert — der Server ist die
|
||||
// Quelle (CloudService.ytUrlSetzen beim Scanner; Fallback via listSongs).
|
||||
);
|
||||
await _db.songEinfuegen(song);
|
||||
|
||||
@@ -479,14 +481,11 @@ class DownloadService extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Korrupten Song mit bekannter ytUrl neu herunterladen
|
||||
/// Korrupten Song neu herunterladen — Server ist die primäre Quelle (F2):
|
||||
/// 1. Server-Download (cloud_id) mit Magic-Byte-Check
|
||||
/// 2. Fallback: Server-ytUrl (aus listSongs) → yt-proxy als letzte Chance
|
||||
/// 3. Legacy-Fallback: lokal gespeicherte ytUrl (Bestandsdaten vor v2.52)
|
||||
Future<Song?> reDownload(Song song) async {
|
||||
if (song.ytUrl == null || song.ytUrl!.isEmpty) {
|
||||
_fehler = 'Keine YouTube-Quell-URL für diesen Song';
|
||||
notifyListeners();
|
||||
return null;
|
||||
}
|
||||
|
||||
_resetStatus();
|
||||
try {
|
||||
_aktuellerTitel = '🔄 Lade neu: ${song.titel}';
|
||||
@@ -505,8 +504,72 @@ class DownloadService extends ChangeNotifier {
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// Neu herunterladen mit der gespeicherten ytUrl
|
||||
return _downloadEinzeln(song.ytUrl!);
|
||||
// 1) Server-Download versuchen (primäre Quelle)
|
||||
final cloudId = song.cloudId;
|
||||
if (cloudId != null && cloudId.isNotEmpty) {
|
||||
final cloud = CloudService();
|
||||
final dir = Directory(
|
||||
'${(await getApplicationDocumentsDirectory()).path}/music');
|
||||
if (!await dir.exists()) await dir.create(recursive: true);
|
||||
final ext = song.dateiPfad.contains('.')
|
||||
? '.${song.dateiPfad.split('.').last}'
|
||||
: '.mp3';
|
||||
final dest = '${dir.path}/${sanitizeDateiname(song.titel)}$ext';
|
||||
if (await cloud.download(cloudId, dest)) {
|
||||
final file = File(dest);
|
||||
if (hatValideMagicBytes(file)) {
|
||||
final neu = Song(
|
||||
titel: song.titel,
|
||||
kuenstler: song.kuenstler,
|
||||
album: song.album,
|
||||
dauerSekunden: song.dauerSekunden,
|
||||
dateiPfad: dest,
|
||||
groesseBytes: await file.length(),
|
||||
istHeruntergeladen: true,
|
||||
istKorrupt: false,
|
||||
downloadQuelle: 'server',
|
||||
cloudId: cloudId,
|
||||
);
|
||||
await _db.songEinfuegen(neu);
|
||||
_ladt = false;
|
||||
_aktuellerTitel = '✅ ${neu.titel}';
|
||||
notifyListeners();
|
||||
return neu;
|
||||
}
|
||||
// Server-Kopie korrupt → löschen, Fallback versuchen
|
||||
try {
|
||||
await file.delete();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// 2) Server-ytUrl als letzte Chance (Server-Datei fehlt oder korrupt)
|
||||
final serverSongs = await cloud.listSongs();
|
||||
for (final s in serverSongs) {
|
||||
if ((s['id']?.toString() ?? '') == cloudId) {
|
||||
final serverYt = s['ytUrl']?.toString() ?? '';
|
||||
if (serverYt.isNotEmpty) {
|
||||
return _downloadEinzeln(serverYt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Legacy: lokal gespeicherte ytUrl (Bestandsdaten vor v2.52)
|
||||
if (song.ytUrl != null && song.ytUrl!.isNotEmpty) {
|
||||
return _downloadEinzeln(song.ytUrl!);
|
||||
}
|
||||
_fehler = 'Kein Server-Download möglich und keine YouTube-Quelle';
|
||||
notifyListeners();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Kein cloudId → nur Legacy-ytUrl
|
||||
if (song.ytUrl != null && song.ytUrl!.isNotEmpty) {
|
||||
return _downloadEinzeln(song.ytUrl!);
|
||||
}
|
||||
_fehler = 'Keine YouTube-Quell-URL für diesen Song';
|
||||
notifyListeners();
|
||||
return null;
|
||||
} finally {
|
||||
_stopBackgroundService();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user