Dustin
2ce24398e4
Security-Review-Fixes (Builder): Salt-Regression behoben + Defense-in-Depth
...
- Navidrome-Salt wieder kryptographisch sicher (Random.secure, 16 Bytes)
- Regression: v2.31-Redesign (36c744d ) hatte den Security-Audit-Fix
aus 77a2042 stillschweigend auf Timestamp zurueckgesetzt
- Server-IDs (Navidrome s.id, Registry sid) vor Dateinamen defensiv sanitized
(sanitizeDateiname) — kein Path-Traversal ueber Server-Werte
- MANAGE_EXTERNAL_STORAGE entfernt: deklariert aber nie angefragt
(toter Berechtigungs-Surface, Play-Store-Policy-Risiko)
- Neuer Test: navidrome_salt_test.dart (Salt != Timestamp, 16 Bytes, eindeutig)
Verifiziert: flutter analyze 0 Issues, flutter test 156/156
2026-08-05 22:54:27 +02:00
Dustin
70a79520d0
v2.54.2 — Review-Fixes (Graph): Shuffle-Duplikat bei Einzel-Song+Repeat, Speed-Chip 1.75x, Drag-Race, Speed-Tap-Guard, Version
2026-08-05 21:04:18 +02:00
Dustin
5f7b652eb6
v2.54.1 — Queue zeigt echte Wiedergabe-Reihenfolge (inkl. Shuffle), aktuelles Lied markiert
2026-08-05 12:20:32 +02:00
Dustin
83bb86a1fa
v2.53.1 — LOW-1: Willkommen-zurück-Dialog nur bei >24h Offline (24h-Check)
2026-08-05 11:26:00 +02:00
Dustin
f14b658566
v2.53.1 — MED-3: Tests für Tombstone-Heuristik, SyncBericht, songAusServerMap + delete-deleted_at
...
## MED-3 (Review-Fix)
- test/sync_service_test.dart NEU (14 Tests): tombstoneAnwenden-Matrix
(letzterSync null → true, deletedAt null → true, älter → false, neuer →
true, Gleichstand → false, ungültiger Timestamp → true), SyncBericht
(hatAenderungen, zusammenfassung kombiniert/leer, details), songAusServerMap
(cloud_id/Titel/Künstler/Dauer/Größe/istKorrupt-Mapping, Defaults bei
fehlenden Feldern, String-Robustheit) — deckt die MED-1-Heuristik + den
MED-2-DB-Insert ab (123→140 Tests)
- test/cloud_service_test.dart +3: delete mit deletedAt sendet deleted_at im
Body, delete ohne deletedAt sendet KEIN deleted_at-Feld, delete
Netzwerkfehler → false
2026-08-05 11:24:51 +02:00
Dustin
22ce611537
v2.53 — Sprint E: Recap-Zeiträume (Woche/Monat/Jahr)
...
## Recap-Zeiträume
- recap_service.dart: RecapZeitraum-Enum (woche/monat/jahr), berechne(zeitraum:, jetzt:) mit injizierbarem Historie-Loader (Tests ohne DB), Fallback-Kette Woche → Monat → Jahr → Gesamt-Historie, Zeitraum-Getter (kopfzeile, introTitel, introUntertitel, zeitraumLabel, shareTitel, Monatsname)
- recap_screen.dart: Zeitraum-Umschalter (7 Tage / Monat / Jahr) oben im Recap, dynamische Texte („Deine Woche in Musik“, „Abspielungen in dieser Woche“, „Melo Wochen-Recap“), Seiten-Reset bei Wechsel
- home_screen.dart: Recap-Karte „Recap 2026“ + „Woche · Monat · Jahr“-Untertitel
- settings_screen.dart: Kachel „Recap (Woche/Monat/Jahr)“
- test/recap_service_test.dart: 12 neue Tests (Filter, Fallback-Kette, Aggregation, Label-Getter)
- flutter analyze 0 Issues, Tests 123/123
2026-08-05 11:10:49 +02:00
Dustin
bf0f544e4b
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
2026-08-05 10:40:37 +02:00
Dustin
3b898e238e
v2.52 — Favoriten-Sync-Fix: bidirektionaler Merge (lokal↔Server), Toggle-Push sofort, cloud_id-Verdrahtung
2026-08-05 10:33:23 +02:00
Dustin
dfa19c999b
v2.50.3 — sanitize.dart gehärtet: Windows-Namen + Traversal-Sequenzen
...
## lib/utils/sanitize.dart
- Windows-reservierte Namen (CON, NUL, PRN, AUX, COM1-9, LPT1-9) abgefangen — auch mit Endung (CON.txt) und case-insensitiv; COM10/LPT10 bleiben erlaubt
- Mehrfache ..-Sequenzen nach Sonderzeichen-Entfernung → unknown
- Trimmen VOR der Punkt-Prüfung (Regression: ' ..' ergab vorher '..' = Path-Traversal)
- Trailing Punkte/Leerzeichen entfernt (Windows-Dateisystem ignoriert sie)
- Umlaute bleiben erhalten (unicode:true + \p{L}/\p{N} statt ASCII-\w — 'Müller.mp3' wurde vorher zu 'Mller.mp3')
## test/sanitize_test.dart (18 Tests)
- Traversal: Slash/Backslash-Pfade, '..', ' ..', '..:..', versteckte Dateien
- Windows: alle reservierten Namen exakt/mit Endung/case-insensitiv, COM10-Freigabe, Prefix-Fälle (console, LPT1 - Drucker)
- Normalisierung: NULL-Bytes, Steuerzeichen, Sonderzeichen, trailing Dots, leer, 200-Limit, Umlaute
2026-08-04 20:48:31 +02:00
Dustin
5b5f72b548
v2.50.2 — Cloud/Auth-Tests (http-Mocks): LWW-Sync + Token-Ablauf-Pfade
...
## Testbarkeit (kein neues Package)
- CloudService: http.Client injizierbar (Konstruktor-Parameter, Default unverändert)
- AuthService: http.Client + TokenSpeicher injizierbar; SecureTokenSpeicher kapselt FlutterSecureStorage, @visibleForTesting AuthService.fuerTests
- Alle HTTP-Calls über _client statt Top-Level http.get/post
## test/cloud_service_test.dart (22 Tests)
- login: 200/401/Netzwerkfehler
- verbinde() ohne Benutzer → Status fehler, kein Request
- statusDaten: 200/401(Auth-Fehler)/Netzwerkfehler
- syncChanges LWW-Konflikt-Pfade: updated_at bleibt für Client-Vergleich erhalten, leere/fehlende Changes, 401 → [], Netzwerkfehler → [], since-Body
- syncAll (LWW-Schreibpfad): 200/401
- Playlists, Favoriten, History, listSongs, delete, globalList inkl. Fehlerpfade
## test/auth_service_test.dart (19 Tests)
- initialisieren: 200 → eingeloggt, 401 → Logout + Speicher gelöscht, Netzwerkfehler → Offline-Trust, 5xx → Token bleibt, ohne Token → kein Request
- tokenPruefen: 200/401/Netzwerkfehler/503
- login: ok mit Persistenz, 401, 200-ohne-Token (Fall-Through-Regression), Netzwerkfehler
- logout löscht Speicher, authHeader mit/ohne Bearer
2026-08-04 20:46:51 +02:00
Dustin
8e9d9efc64
v2.49.5 — Play-Next verschiebt statt zu duplizieren + Shuffle-Priorität
...
## Fix (Code-Review Finding 3, MED)
- spieleAlsNaechstes: Song bereits in der Queue wird an Position nach dem
aktuellen VERSCHOBEN (inkl. _aktuellerIndex-Anpassung), keine Kopie mehr
- Shuffle: keine Neu-Mischung nach Play-Next — Song wird via
_pinneInShuffleReihenfolge an die nächste Position gepinnt (Index-
Korrektur für Verschiebungen, _shufflePos-Nachführung am Reihenende)
- 3 Tests ergänzt: Verschieben statt Duplizieren, Song von vor dem
aktuellen, Shuffle-Pin (kein Duplikat + naechsterIndex == gepinnter Song)
2026-08-04 16:47:29 +02:00
Dustin
c6826db651
v2.49.3 — Shuffle-Edge-Case: Einzel-Song-Queue + Repeat-aus → Queue-Ende
...
## Fix (Code-Review Finding 1, HIGH)
- _baueShuffleReihenfolge: Index 0 nur noch bei Repeat-playlist in die
Shuffle-Reihenfolge aufnehmen (Einzel-Song-Queue)
- naechsterIndex: Sicherheitsnetz gegen stale Reihenfolge — Kandidat ==
aktueller Song bei Repeat-aus liefert null (Queue-Ende) statt denselben
Song erneut
- Test ergänzt: shuffle + repeat aus + 1-Song-Queue → null
2026-08-04 16:46:08 +02:00
Dustin
4226612065
v2.49 — Lyrics-Service (LRC + Netease)
...
## LyricsService (neu: lib/services/lyrics_service.dart)
- LyricsZeile-Modell (zeit + text)
- LRC-Parser: [mm:ss], [mm:ss.xx], [mm:ss.xxx], mehrere Zeitstempel/Zeile, [offset:±ms], Meta-Tags ignoriert, Karaoke-Tags <...> entfernt, sortiert
- Quellen: lokale .lrc neben dem Song (song.dateiPfad → .lrc) → Netease-API (Suche + Lyric, public, kein Key) → null
- Keine neuen Packages (nur http)
## Tests (test/lyrics_service_test.dart, 14 neu)
- parseLrc: Formate, Multi-Timestamps, Offset, Sortierung, Karaoke-Tags
- indexFuerPosition: Grenzfälle
- ladeLyrics: lokale .lrc-Datei (Temp-Datei), ohne Datei → null (HTTP im Test geblockt)
- flutter analyze 0 Issues, Tests 35/35
2026-08-04 16:35:19 +02:00
Dustin
b97914699e
v2.48.5 — Tests für Player-Kern (Shuffle/Repeat/Queue/Sleep-Timer)
...
## test/player_service_test.dart (neu, 17 Tests)
- Warteschlange: setWarteschlange, unveränderliche Kopie, spieleAlsNaechstes,
amEndeHinzufuegen, verschiebeInWarteschlange (Index-Anpassung)
- Repeat: aus (Ende → null), titel (immer aktuell), playlist (Wrap von vorn)
- Shuffle: alle anderen Songs genau einmal ohne Wiederholung, kein aktueller
Song; shuffle+playlist mischt nach Durchlauf neu; Einzel-Song-Queue;
Ausschluss des aktuellen Index nach Umsortieren
- Sleep-Timer: aktivieren, Restzeit, abbrechen, Ersetzen
flutter analyze 0 Issues, Tests 21/21
2026-08-04 16:27:36 +02:00
Dustin
4c987036bc
v2.45.1 — Auto-Scan ohne AudioPlayer: Byte-Parser für Dauer (MP3/M4A/FLAC/WAV), MPEG-Header-Offset fix, WAV Little-Endian fix
2026-08-03 02:47:05 +02:00
Dustin
2d4c7c8b98
v2.32 — Defekte Musik erkennen (Magic Bytes, ffprobe, DB-Flag, UI)
2026-08-01 16:40:42 +02:00
Dustin
36c744d6e3
v2.31 — Login, Einstellungen & Cloud Sync Redesign
...
- Login-Screen im Melo-Design (Schwarz+Rot) mit Baka-Auth JWT
- AuthService fuer Token-Management ueber baka-net.de/auth
- Registrierungs-Modus + 'Ohne Login fortfahren'
- Navidrome-Credentials optional im Login aufklappbar
- SettingsScreen ersetzt AlertDialog
- BottomNav navigiert statt Dialog zu triggern
- Cloud Sync, Server verbinden, Diagnosedaten, App-Info, Abmelden
- CloudEinstellungen-Dialog entfernt, alles in CloudScreen konsolidiert
- Hardcode login('Baka','') entfernt → AuthService.benutzer
- Gradient-Statuskarte, animierte Segment-Intervall-Auswahl
- JWT Authorization statt Klartext-Passwort
- AppConfig: API-Key defaultValue entfernt (kein Fallback-Leak)
- Build crasht ohne --dart-define MELO_API_KEY
Build: split APK (arm64 19.6M, armeabi 17.1M, x86_64 21.1M)
2026-08-01 15:03:22 +02:00
Dustin-Mike Jens Hähnel
94a4063070
Initial commit
2026-07-23 14:31:28 +02:00