import 'dart:io'; import 'package:just_audio/just_audio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import '../models/song.dart'; import '../database/db_helper.dart'; class MusikScanner { static final MusikScanner _instanz = MusikScanner._(); factory MusikScanner() => _instanz; MusikScanner._(); final DbHelper _db = DbHelper(); int _neueSongs = 0; int get anzahlNeueSongs => _neueSongs; Future frageSpeicherZugriff() async { final status = await Permission.audio.request(); return status.isGranted; } Future> scanneMusikOrdner() async { _neueSongs = 0; final gefunden = []; final pfade = await _sammleMusikPfade(); for (final pfad in pfade) { try { final file = File(pfad); if (!await file.exists()) continue; final stat = await file.stat(); gefunden.add(Song( titel: _dateiNameOhneEndung(pfad), kuenstler: 'Unbekannt', album: '', dauerSekunden: await _ermittleDauer(pfad), dateiPfad: pfad, coverPfad: null, groesseBytes: stat.size, istHeruntergeladen: true, downloadQuelle: 'local', )); } catch (_) { // Datei nicht lesbar → überspringen } } // In DB speichern final vorhandene = await _db.alleSongs(); final vorhandenePfade = vorhandene.map((s) => s.dateiPfad).toSet(); final neue = gefunden.where((s) => !vorhandenePfade.contains(s.dateiPfad)).toList(); if (neue.isNotEmpty) { await _db.songsEinfuegen(neue); _neueSongs = neue.length; } return gefunden; } Future> _sammleMusikPfade() async { final pfade = {}; // Typische Musik-Ordner auf Android final ordner = [ '/storage/emulated/0/Music', '/storage/emulated/0/Download', '/storage/emulated/0/Musik', '/storage/emulated/0/Downloads', '/sdcard/Music', '/sdcard/Download', '/sdcard/Musik', ]; // Externe SD-Karte (falls vorhanden) try { final extern = await getExternalStorageDirectory(); if (extern != null) { ordner.add(extern.path); } } catch (_) {} // Android Media Store (bessere Methode) try { final pfadeVonMediaStore = await _scanneViaMediaStore(); pfade.addAll(pfadeVonMediaStore); } catch (_) {} // Fallback: Dateisystem durchsuchen for (final ord in ordner) { try { final dir = Directory(ord); if (await dir.exists()) { await _durchsucheOrdner(dir, pfade); } } catch (_) {} } return pfade.toList(); } Future> _scanneViaMediaStore() async { // Nutzt Android's MediaStore Query // Wird über Method Channel in native Android implementiert // Für v1: Fallback auf Dateisystem-Suche return []; } Future _durchsucheOrdner(Directory dir, Set pfade, {int tiefe = 0}) async { if (tiefe > 4) return; try { await for (final entity in dir.list(followLinks: false)) { if (entity is File) { final ext = entity.path.toLowerCase(); if (ext.endsWith('.mp3') || ext.endsWith('.m4a') || ext.endsWith('.flac') || ext.endsWith('.wav') || ext.endsWith('.aac') || ext.endsWith('.ogg')) { pfade.add(entity.path); } } else if (entity is Directory) { await _durchsucheOrdner(entity, pfade, tiefe: tiefe + 1); } } } catch (_) {} } Future _ermittleDauer(String pfad) async { try { final player = AudioPlayer(); await player.setFilePath(pfad); final dauer = player.duration; await player.dispose(); return dauer?.inSeconds ?? 0; } catch (_) { return 0; } } String _dateiNameOhneEndung(String pfad) { final name = pfad.split('/').last; final dot = name.lastIndexOf('.'); return dot > 0 ? name.substring(0, dot) : name; } }