import 'dart:io'; import 'package:crypto/crypto.dart'; import 'package:flutter/foundation.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; /// Ablage für bewusst heruntergeladene Titel. /// /// Bewusst **nicht** im Cache-Ordner: den darf Android bei Speichernot ohne /// Vorwarnung leeren — das ist sein Zweck. Einem Album, das jemand für die /// Zugfahrt mitgenommen hat, darf genau das nicht passieren. Deshalb liegt /// es neben der Datenbank im Support-Ordner, den das System in Ruhe lässt. /// /// Die Trennung ist auch die Grundlage der Speicher-Rechnung: die Grenze für /// den Zwischenspeicher gilt nur dort, Downloads sind unbegrenzt. class DownloadSpeicher { static const ordnerName = 'melo_downloads'; Directory? _ordner; Future _ordnerHolen() async { final vorhanden = _ordner; if (vorhanden != null) return vorhanden; final basis = await getApplicationSupportDirectory(); final ordner = Directory(p.join(basis.path, ordnerName)); if (!await ordner.exists()) await ordner.create(recursive: true); _ordner = ordner; return ordner; } /// Dateiname eines Titels. Wie im Zwischenspeicher über die Server-ID und /// nicht über die Stream-Adresse: die trägt bei jedem App-Start ein neues /// Token und wäre als Schlüssel wertlos. static String dateiName(String navidromeId) => '${md5.convert('navidrome:$navidromeId'.codeUnits)}.mp3'; /// Wohin der Titel geschrieben wird — die Datei muss es noch nicht geben. Future ziel(String navidromeId) async => File(p.join((await _ordnerHolen()).path, dateiName(navidromeId))); /// Die fertige Datei, oder `null`, wenn der Titel nicht heruntergeladen ist. Future treffer(String navidromeId) async { final datei = await ziel(navidromeId); return await datei.exists() ? datei : null; } Future loesche(String navidromeId) async { try { final datei = await ziel(navidromeId); if (await datei.exists()) await datei.delete(); } catch (e) { debugPrint('Download nicht löschbar: $e'); } } Future loescheAlle() async { try { final ordner = await _ordnerHolen(); if (await ordner.exists()) await ordner.delete(recursive: true); _ordner = null; await _ordnerHolen(); } catch (e) { debugPrint('Downloads nicht löschbar: $e'); } } }