Commit Graph
22 Commits
Author SHA1 Message Date
Hermes (Server)andClaude Opus 5 bb800adb61 Datenschutz: Fehlerberichte nur mit Zustimmung senden (Opt-in)
Uebertragung eines Befunds aus dem Security-Audit der alten Melo-App
(21.08.2026) in die neue Codebasis.

Ausgangslage hier war eine ANDERE als dort: LoggerService lud jeden Fehler
unbedingt zu logs.baka-net.de hoch, es gab ueberhaupt keinen Schalter. In
der alten App existierte er zwar, wirkte aber nicht ueber einen Neustart
hinaus.

Neu:
- Schalter "Fehlerberichte senden" in den Einstellungen unter Datenschutz,
  Standard AUS. Ohne ausdrueckliche Zustimmung verlaesst kein Bericht das
  Geraet - auch nicht beim allerersten Start und auch nicht im Zeitfenster
  zwischen logger.init() und settings.init().
- Sperre an der einzigen Stelle, durch die jeder Upload laeuft. Lokales
  debugPrint bleibt, aber nichts verlaesst das Geraet; der Puffer wird
  geleert, damit er nicht unbegrenzt waechst.
- Die Entscheidung ueberlebt den Neustart: AppSettings speichert sie und
  reicht sie an den Logger durch, UND LoggerService liest sie beim Start
  zusaetzlich selbst.
- LoggerService bekam einen injizierbaren http.Client (Muster wie BakaAuth),
  damit sich belegen laesst, dass ohne Zustimmung KEIN Request rausgeht.

Auswirkung auf bestehende Installationen: Wer bisher unfreiwillig Berichte
gesendet hat, sendet ab diesem Update keine mehr, bis er zustimmt. Das ist
gewollt - die Zustimmung wurde nie eingeholt.

Nicht uebernommen: der zweite Befund (Logout liess Zugangsdaten zurueck)
trifft hier nicht zu. BakaAuth.abmelden() loescht genau die Schluessel, die
anmelden() schreibt, und Navidrome hat mit loescheZugangsdaten() ein
eigenes, vollstaendiges Trennen.

Auf main (34d6d8e) rebast. settings_screen.dart hat sich sauber automatisch
zusammengefuehrt - die Umbenennungen und MeloTheme-Farben der UI-Politur
bleiben erhalten, der Datenschutz-Abschnitt fuegt sich ein. Im CHANGELOG
kollidierten beide Seiten am Kopf; beide Eintraege wurden behalten.

Tests: 340 gruen (main allein: 328), 12 neue in
test/settings/diagnose_opt_out_test.dart. Fuenf tragende Stellen per
Mutationsprobe geprueft. flutter analyze: keine Befunde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbuWT267W8rFDsaavANuEn
2026-08-21 15:23:03 +02:00
Hermes (Server)andClaude Opus 5 cd79213bb3 Serverseitig: Uploads landen in der Navidrome-Bibliothek
Auf Wunsch: was vom Handy hochgeladen wird, soll auch in Navidrome
auftauchen. Die Subsonic-API kennt keinen Upload — also erledigt es die
Melo-Cloud selbst.

Server (/home/dustin/scripts/melo_cloud.py, nicht versioniert — Backup als
melo_cloud.py.bak-20260821-084506):
- verknuepfe_navidrome(): Hardlink der Registry-Datei nach
  /home/dustin/navidrome/music (Bind-Mount des Containers). Gleiche
  Partition -> kein zusaetzlicher Speicher. Fallback: Kopie.
- rescan_navidrome(): Subsonic startScan.view ueber Navidromes
  AuthProxyHeader (TrustedSources 127.0.0.1) — kein Passwort im Code.
  Nur zur Beschleunigung, der Watcher findet neue Dateien ohnehin.
- upload() verknuepft neue UND bereits bekannte Titel (heilt Bestand).
- handle_delete() entfernt die Datei aus Registry + Navidrome, sobald kein
  Konto sie mehr aktiv hat. Der Registry-EINTRAG bleibt stehen: handle_list
  haengt die Grabsteine daran (JOIN registry) — ohne ihn erfuehren die
  anderen Geraete nie von der Loeschung (Zombie-Song).
- registry_pfad(): gemeinsame Dateisuche ueber alle Audio-Endungen, mit
  Rueckfall auf den Navidrome-Ordner.

Nebenbei repariert:
- Alle 325 Cloud-Dateien lagen nur noch im Navidrome-Ordner, REG war leer:
  jeder Download antwortete "File missing". Per Hardlink zurueckverknuepft
  (scripts/melo_cloud_migriere_registry.py).
- upload() legte jede Datei als ".mp3" ab, auch m4a/flac. Jetzt echte
  Endung; _download liefert passenden Content-Type und einen Dateinamen
  ohne doppelte Endung.

App:
- MeloCloudService.herunterladen() gibt die geschriebene Datei zurueck und
  leitet die Endung aus dem Content-Type ab (endungFuer) — sonst landet
  eine M4A als .mp3 auf dem Handy und Android ordnet sie falsch ein.
- loeschBremseGreift(): der Abgleich reicht keine Loeschwelle mehr zum
  Server durch (>10 Titel UND >1/3 des Serverbestands). Ohne die Bremse
  haette eine nicht eingehaengte Speicherkarte die Sammlung auf allen
  Geraeten geloescht.

276 Tests gruen (1 uebersprungen), flutter analyze ohne Befund, plus ein
Durchlauf gegen den echten Server (scripts/test_melo_cloud_navidrome.py):
Upload -> Registry + Navidrome (ein Hardlink) -> Navidrome liest ein ->
Loeschen entfernt beides, Grabstein bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpPu4nuKjKKeX1RpdDeX81
2026-08-21 08:56:44 +02:00
Hermes (Server)andClaude Opus 5 9fa027fca1 Fix: Lokale Wiedergabe + neuer Geraete-Abgleich (Handy <-> Server)
BUG 1 — Lieder vom Handy waren nicht abspielbar
("Wiedergabe fehlgeschlagen: (0) Source error" / "Loading interrupted")

Wurzel-Ursache: MeloAudioHandler.loadPlaylist hat jeden Warteschlangen-
Eintrag durch NavidromeService.streamAndCacheToLocal(item.id) geschickt,
sobald Zugangsdaten existierten. item.id ist aber NIE eine Navidrome-Song-ID
— lokal ist es file:///storage/..., beim Server die fertige Stream-Adresse.
Der Server bekam also 'file:///...' als Song-ID, antwortete mit einem Fehler,
und diese Fehlerantwort wurde an just_audio weitergereicht (Source error) —
bzw. als .mp3 in den Cache geschrieben, wodurch der Titel dauerhaft kaputt
blieb.

Zweite Ursache: die Schleife lud die GANZE Warteschlange seriell vorab
herunter (30s Timeout je Titel), bevor setAudioSources lief. Bei hunderten
Titeln startete die Wiedergabe deshalb nie; ein zweiter Tipp brach den
laufenden Ladevorgang ab ("Loading interrupted").

Fix:
- Server-Titel tragen ihre ID in MediaItem.extras['navidromeId'] statt sie
  aus der Abspiel-Adresse zu raten. Neue reine Funktionen navidromeIdOf,
  songIdOf, nutztServerCache, quelleFuer.
- loadPlaylist baut die Quellen ohne Netzzugriff; Caching des laufenden
  Titels im Hintergrund (unawaited).
- Resume/Scrobble nur noch mit der jeweils passenden ID (Server bzw. lokal).
- ladeInCache() ersetzt streamAndCacheToLocal(): .part-Datei, Pruefung des
  Inhaltstyps (istAudioAntwort), stabiler Cache-Schluessel ueber die
  Song-ID statt der Stream-Adresse (die trug Token+Salt und war je Sitzung
  anders — der Cache war nie wiederauffindbar), Client wird geschlossen.

BUG 2 — kein Abgleich zwischen Handy und Server

Neu: services/melo_cloud_service.dart + services/sync_service.dart gegen
cloud.baka-net.de (Bearer-JWT ueber BakaAuth). Server-Titel herunterladen
(offline verfuegbar), eigene Dateien hochladen, Loeschungen in beide
Richtungen (Tombstones), Favoriten und Wiedergabe-Verlauf. Automatisch beim
App-Start und bei Rueckkehr in die App (max. alle 15 Min), plus Knopf unter
Einstellungen -> Geraete-Abgleich. Reine Planungsfunktion planeSync().

Bewusst NICHT ueber Navidrome: die Subsonic-API kennt keinen Upload-
Endpunkt. Navidrome bleibt die Streaming-Bibliothek, die Melo-Cloud ist der
gemeinsame Speicher.

DB-Schema 8: songs.cloud_id verbindet Geraet und Server.

Nebenbei behoben (blockierte Build bzw. Tests):
- database.g.dart war veraltet — das Projekt liess sich nicht uebersetzen.
- metadataEdited wurde nirgends gesetzt/beachtet: von Hand korrigierte
  Metadaten wurden vom naechsten Scan ueberschrieben. Jetzt in beiden
  Scans respektiert; metadatenUebernahme() setzt die Markierung.
- song_detail_sheet_test.dart haengt beim Oeffnen des Modal-Sheets und
  blockierte den gesamten Testlauf — vorerst uebersprungen (TODO im Code);
  der Zweck wird von metadaten_uebernahme_test.dart abgedeckt.

Enthaelt ausserdem die bis dahin nicht committete Arbeit der Vorsitzung
(Musikerkennung/ACRCloud, MusicBrainz-Metadaten, MediaStore-Datentraeger).

267 Tests gruen (1 uebersprungen), flutter analyze ohne Befund.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpPu4nuKjKKeX1RpdDeX81
2026-08-21 08:32:32 +02:00
Hermes (Server)andClaude Opus 5 15e3d44453 Automatische Erkennung: neue Dateien auf dem Geraet und neue Alben am Server
- AutoScan: beim Zurueckkehren in die App wird die Zahl der Musikdateien
  mit der Bibliothek verglichen; nur bei Abweichung laeuft ein Scan, und
  hoechstens alle 5 Minuten. Gleich viele Loeschungen wie Neuzugaenge
  bleiben unbemerkt - dafuer gibt es den Scan von Hand.
- ServerNeuheiten: meldet neu auf Navidrome aufgetauchte Alben im
  Online-Tab. Der erste Abruf meldet bewusst nichts, sonst waere die ganze
  Sammlung "neu"; er nutzt die ohnehin geladenen Alben statt eines zweiten
  Serveraufrufs.
- Neu: MeloDb.countSongs(), countAndroidMediaStoreSongs().

189 Tests gruen, flutter analyze ohne Befund.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018NLW1q1hzEC9goDQ1dJ98d
2026-08-20 19:19:04 +02:00
Hermes (Server)andClaude Opus 5 6200c77614 YouTube-Downloader ueber den Baka-Proxy inkl. Anmeldung und MediaStore
Neuer YouTube-Bereich im Online-Tab: Adresse einfuegen, herunterladen, der
Titel landet in Meine Musik.

- BakaAuth: Anmeldung gegen baka-net.de/auth, Token verschluesselt auf dem
  Geraet. Der Server meldet Fehler mit HTTP 200 und Text im Rumpf, deshalb
  wird der Inhalt geprueft statt nur der Statuscode.
- YtDownloadService: Proxy fragen, MP3 abholen, halbe Dateien aufraeumen.
  Kuenstler nur aus "Kuenstler - Lied", sonst leer statt geraten.
- MediaStoreBridge (Kotlin): legt die Datei in Music/Melo ab und meldet sie
  dem MediaStore. Noetig, weil der Android-Scan sonst beim naechsten Lauf
  alles wieder als verschwunden markiert.
- SubTabs nach shared/ gezogen (jetzt in Meine Musik und Online genutzt).

177 Tests gruen, flutter analyze ohne Befund, Release-APK baut.
Der Weg ueber den echten Proxy ist noch nicht auf dem Geraet erprobt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018NLW1q1hzEC9goDQ1dJ98d
2026-08-20 19:13:55 +02:00
Hermes (Server)andClaude Fable 5 5d08da1086 Login-Dialog zeigt echte Server-Fehlermeldung + pwLen im Log
Tiefe Debug-Runde bewiesen: Server, DB-Passwort und App-Token-Logik sind
korrekt (8/8-Repro gegen Live-Server) — abgelehnt wird ein falscher
Passwort-Wert vom Gerät. Damit das künftig sofort sichtbar ist:
- NavidromeService.letzterLoginFehler hält die Server-Meldung fest
- Login-Dialog zeigt sie statt generischem "Login fehlgeschlagen"
- Fehler-Log enthält die Passwort-Länge (nie das Passwort selbst)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JRj3pupcigUi683vy2Wwnz
2026-08-20 16:13:34 +02:00
Hermes (Server) 2e40cc2024 Merge: Fix Server-Bibliothek-Laden + Tab-Abschnitt
# Conflicts:
#	CHANGELOG.md
2026-08-20 09:34:11 +02:00
Hermes (Server)andClaude Opus 4.8 3d39e8b922 Fix: Server-Bibliothek lädt nicht + Tab '🌐 Server' abgeschnitten
Bug 2 (Laden schlägt fehl trotz 'ping ok'): Der Code ignorierte das Subsonic-
status-Feld. Navidrome liefert bei falschem Passwort HTTP 200 mit
status:"failed" — ping() meldete dadurch fälschlich Erfolg, getAlben/getArtists
behandelten die Fehlerantwort still als leer ("Erneut versuchen").
- parseSubsonic() wirft NavidromeException bei status:"failed" (mit Servermsg).
- ping() prüft jetzt den Body statt nur HTTP 200.
- getAlben/getArtists reichen den Fehler durch (rethrow) statt [] zu liefern.
- getAlben nutzt getAlbumList2 (ID3, wie getArtists) statt getAlbumList (Folder).
- Server-Tab zeigt die echte Fehlermeldung statt "Keine Alben geladen".

Bug 1 (Tab abgeschnitten -> nur "Serve"): TabBar labelPadding verkleinert
(engere Abstände), Schriftgröße unverändert.

Neue Tests: test/navidrome_parse_test.dart (5). 84/84 grün, analyze sauber.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tr2UwurtxyJUpWpBSeVmBm
2026-08-20 02:24:37 +02:00
Hermes (Server)andClaude Opus 4.8 d83f8c8c54 Datenschutz: Log-Bereinigung vor Server-Upload (Scrubber + Quelle)
Diagnose-Logs werden zentral bereinigt, bevor sie an logs.baka-net.de gehen.
Lokaler debugPrint bleibt vollständig.

- Freitext-Scrubber (LoggerService.scrubText) für message + stackTrace:
  maskiert user=/pw=/password=/token=/secret=/url= sowie Datei-Pfade,
  nackte URLs, Bearer-Token, JWTs und lange Hex-IDs.
- stackTrace auf 8 Zeilen gekürzt (capFrames).
- deviceModel nur noch grobe Plattform (android/ios) statt Hersteller+Modell;
  device_info_plus im Logger entfernt.
- Quelle entschärft: settings_screen loggte Navidrome-Login mit Klartext
  user=/url= — jetzt nur neutraler Status inkl. pwLeer-Flag.
- Neue Tests: test/logger_service_test.dart (9). 79/79 grün, analyze sauber.

Opt-in/Einwilligung bleibt separater Folgeschritt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tr2UwurtxyJUpWpBSeVmBm
2026-08-20 01:38:56 +02:00
Hermes (Server)andClaude Haiku 4.5 61e28d128f 🔧 Fix Log-Upload System: ERROR-Level sofort hochladen + Navidrome-Fehler tracken
- error() ist jetzt async mit await — ERROR-Logs werden SOFORT zum Server hochgeladen
- Alle Navidrome API-Fehler nutzen logger.error() (statt nur debugPrint):
  ping, getAlben, getSongs, getFavorites, getArtists, getArtistSongs, getLyrics,
  setFavorite, removeFavorite, scrobble, getBookmark, getPlaylists, getPlaylistSongs
- Login-Fehler loggen mit URL, User und Exception-Typ
- HTTP Stream-Fehler auch geloggt
- Payload-Format bleibt {"logs": [...]} Array (https://logs.baka-net.de/api/logs)

Alle 70 Tests bestanden 

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiRmGyzAMkzHMqBsBe2h3n
2026-08-19 22:36:58 +02:00
Hermes (Server)andClaude Haiku 4.5 323a67e3a2 🐛 Fix: INTERNET-Permission fehlte im Release-Manifest
ROOT CAUSE für die fehlenden Logs — und für den fehlschlagenden
Navidrome-Login: Flutter injiziert android.permission.INTERNET nur in
debug/ und profile/AndroidManifest.xml. In main/AndroidManifest.xml
stand sie nicht, das Release-APK hatte damit gar keinen Netzzugriff.
Jede http-Anfrage schlug sofort mit SocketException fehl.

- INTERNET + ACCESS_NETWORK_STATE in main/AndroidManifest.xml ergänzt
- Login-Versuch/-Erfolg/-Fehlschlag im Settings-Dialog explizit geloggt
  (URL + User + ob das Passwortfeld leer war; das Passwort selbst nicht)
- Batch-Schwelle 20 -> 5, damit INFO-Logs auch ohne vorherigen Fehler
  hochgeladen werden

Nicht geaendert: der Sofort-Upload bei ERROR war bereits implementiert
(error() ruft _uploadIfError -> _uploadLogs direkt auf) und war nicht
die Ursache.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 22:28:36 +02:00
Hermes (Server)andClaude Haiku 4.5 db0152e3fa 🔍 Diagnose: Ping-Fehler mit vollen Details loggen
Bisher stand im Log nur die nackte Exception-Message ("Connection timeout")
— ohne URL und ohne Fehlertyp war die Ursache nicht eingrenzbar.

Neu im Fehler-Log:
- Fehlerart klassifiziert: TIMEOUT / SOCKET / TLS-HANDSHAKE / HTTP / FORMAT
- SocketException zusätzlich mit osError-Message, errorCode, Adresse und
  Adress-Typ (IPv4 vs IPv6 — zeigt ein IPv6-Problem direkt an)
- Server-URL sowie geparstes scheme/host/port (falsche URL, fehlendes
  https, DNS-Auflösung erkennbar)
- e.runtimeType + Message

Bewusst NICHT geloggt: die volle Ping-URI — sie enthält Auth-Token und
Salt als Query-Parameter, die nicht auf dem Log-Server landen sollen.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 21:55:55 +02:00
Hermes (Server)andClaude Haiku 4.5 91fbe3dd6e 🔒 Fix: Log-Server-URL auf HTTPS umgestellt
Android 9+ blockt Cleartext-HTTP-Traffic standardmäßig.
logs.baka-net.de läuft hinter Caddy mit TLS — https:// ist korrekt.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 21:41:20 +02:00
Hermes (Server)andClaude Haiku 4.5 45141a5f05 📊 Feature: Auto-Bugreport System (Logger Service)
Flutter-App Seite:
- LoggerService: Centralized Logging (DEBUG/INFO/WARNING/ERROR)
- Automatic Upload zu logs.baka-net.de/api/logs
  - Fehler sofort senden
  - Andere Logs collected (batch von 20)
- Device-Info: Model + OS-Version tracken
- Integration in NavidromeService: Login-Fehler loggen + URL + Status
- Global logger Instance für überall nutzbar

Auto-Features:
 Timestamp + Device-Info + Error Stack-Traces
 Auto-Upload nach 20 Logs oder sofort bei Fehler
 JSON-Format für Server-Verarbeitung

Nächste Schritte:
- Log-Server deployen (FastAPI, SQLite, HTML-Viewer)
- Caddy-Route für logs.baka-net.de
- Basic Auth für Log-Seite

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 21:32:32 +02:00
Hermes (Server)andClaude Haiku 4.5 221e6fd923 📋 Feature: Playlisten-Sync vom Navidrome-Server (Phase 2, Part 6/X)
- getPlaylists() + getPlaylistSongs() APIs für Subsonic-Playlist-Laden
- syncPlaylistsFromServer() in PlaylistService importiert alle Server-Playlisten als lokale
- Benennung mit 🌐 Präfix um Server-Playlisten zu kennzeichnen
- Settings-Button lädt alle Playlisten mit ihren Songs vom Server
- Zeigt Anzahl importierter Playlisten mit SnackBar

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 19:30:50 +02:00
Hermes (Server)andClaude Haiku 4.5 f93b2d35da 📊 Feature: History-Sync vom Navidrome-Server (Phase 2, Part 5/X)
- Neue NavidromeService APIs: scrobble() + getBookmark()
- Lädt Wiedergabe-Position vom Server beim Song-Start (Subsonic-API)
- Sendet Position alle 5s zum Server wenn verbunden
- Priorisiert Server-Position über lokale Position
- Full Sync: lokal speichern + Server synchen parallel

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 19:26:41 +02:00
Hermes (Server) 5c9a7dad2f feat(phase2): Auto-Caching beim Musikstreaming (P0)
IMPLEMENTATION:
- NavidromeService.streamAndCacheToLocal(): Stream + gleichzeitig cachen
- Cache-First-Logik: Wenn Cache existiert → lokal spielen
- AudioHandler erweitert: loadPlaylist() nutzt Auto-Caching
- CacheManager Integration in AudioHandler

FLOW:
1. User spielt Album ab → streamt vom Server
2. Während des Abspielens → lokal in Cache speichern
3. Nächstes Mal: Lokal spielen (schneller, Offline möglich)

Phase 2 P0 COMPLETE! 
Tests: 70/70 
2026-08-19 19:00:12 +02:00
Hermes (Server) 51cab003f9 feat(phase2): Caching + Offline-Mode Infrastruktur (P0)
CACHING:
- CacheManager: Speichert Stream-Lieder lokal mit MD5-Hash-Namensgebung
- getCacheSize(): Berechne Cache-Größe
- clearCache(): Lösche alle gecachten Lieder
- streamAndCache(): Stream gleichzeitig abspielen + cachen

OFFLINE-MODE:
- OfflineMode-Service: Toggle Offline-Modus
- Persistiert in SharedPreferences
- ChangeNotifier für UI-Updates
- Flag: Nur gecachte Lieder spielen

Infrastructure für Phase 2 P0 ready
Tests: 70/70 
2026-08-19 18:54:31 +02:00
Hermes (Server) 0e5b346f68 feat(player): Lyrics-Anzeige + Shuffle/Repeat Buttons
LYRICS:
- Lyrics-Button im Now-Playing Screen (📝 Icon)
- Bottom-Sheet mit Lyrics vom Server (getLyrics() API)
- Fallback: 'Keine Lyrics verfügbar'
- Lyrics-Klasse für Datenmodell

SHUFFLE/REPEAT:
- Shuffle-Button (schon implementiert!) zeigt aktiven Status rot
- Repeat-Button (Off → All → One → Off cycle)
- Beide via AudioHandler.setShuffleMode() / setRepeatMode()
- Integration in _Controls (Player-UI)

Phase 1 P1-Features jetzt funktionsfähig!
Tests: 70/70 
2026-08-19 18:49:34 +02:00
Hermes (Server) 6ba1632082 feat(navidrome): Erweiterte Service-APIs (Artists, Favoriten)
- getArtists(): Alle Künstler vom Server laden
- getArtistSongs(): Alle Songs eines Künstlers
- setFavorite()/removeFavorite(): Server-Favoriten toggle
- getFavorites(): Favoriten vom Server laden
- SubsonicArtist-Klasse für Künstler

APIs für Phase 2 vorbereitet (Artist-Tab, Server-Favoriten-Sync)
Tests: 70/70 grün
2026-08-19 18:34:52 +02:00
Hermes (Server) a7be62bf6f fix(navidrome): Defensiv null-check für Credentials in _uri()
Verhindert StateError wenn _uri() vor setCredentials() aufgerufen wird.
Code-Review finding adressiert.
2026-08-19 07:26:07 +02:00
Hermes (Server)andClaude Haiku 4.5 06be0a7065 feat(navidrome): Musikserver-Integration (Subsonic API)
- NavidromeService mit Credential-Verwaltung (secure storage)
- Navidrome-Settings in Settings-Tab: Login/Logout für Server-Verbindung
- Dependencies hinzugefügt: http, crypto, shared_preferences, flutter_secure_storage
- Tests: 70/70 grün
- Analyzer:  keine Fehler

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
2026-08-19 07:21:32 +02:00