- Add MoviesScreen and corresponding navigation - Implement movie data aggregation in ViewingDao and repository - Enhance NetflixParser to support multiple JSON payload shapes - Apply custom app theme and update launcher icons - Add back navigation handling to ProviderSyncScreen
63 lines
No EOL
4.9 KiB
Markdown
63 lines
No EOL
4.9 KiB
Markdown
# Plan: Filme-Tab + Web-Sync-Reparatur + Navigations-Bug
|
|
|
|
Drei unabhängige Fixes, alle ohne Datenbank-Migration (Room `fallbackToDestructiveMigration` ist aktiv, Schema bleibt v1, nur neue Queries).
|
|
|
|
---
|
|
|
|
## Fix 1: Filme als eigener Tab in der Bottom-Navi
|
|
|
|
Aktuell ist das Dashboard "Filme"-Zählen kaputt (`itemCount - topShows.episodeCount` mit `LIMIT 20`) und Filme tauchen im Serien-Ranking auf.
|
|
|
|
**1a. Neue DAO-Queries** (`ViewingDao.kt`) — Room speichert `contentType` als TEXT (`'MOVIE'`/`'SERIES'`), daher String-Filter:
|
|
- `getTopMovies(limit)` → `SELECT ... WHERE contentType = 'MOVIE' GROUP BY showTitle ORDER BY totalMinutes DESC`
|
|
- `getTopShows(limit)` → ergänze `WHERE contentType != 'MOVIE'` damit Filme aus dem Serien-Ranking verschwinden
|
|
- `getMoviesCount()` → `SELECT COUNT(*) ... WHERE contentType = 'MOVIE'`
|
|
- `getSeriesEpisodesCount()` → `SELECT COUNT(*) ... WHERE contentType != 'MOVIE'`
|
|
|
|
**1b. `WatchStats` korrekt befüllen** (`StatsRepository.kt`) — `combine` von 7 Flows (Vararg-Variante wie bereits vorhanden), echte Counts statt Heuristik. `moviesCount` und `seriesEpisodesCount` direkt aus der DB.
|
|
|
|
**1c. Neue Datenmodelle** (`WatchStats.kt`) — `MovieSummary` (analog `ShowSummary`) + `topMovies: List<MovieSummary>`-Feld in `WatchStats`.
|
|
|
|
**1d. Neuer Screen `MoviesScreen.kt`** — Clone von `SeriesStatsScreen.kt` mit `MovieRankItem` (zeigt Dauer statt Folgenanzahl, Movie-Icon statt "X Folgen"). Wiederverwendet `ProviderBadge`.
|
|
|
|
**1e. Bottom-Navi erweitern** (`MainActivity.kt`) — Neuer `Screen.Movies("movies", "Filme", Icons.Default.Movie)` zwischen Series und Analytics. `NavHost` erhält die neue Route.
|
|
|
|
---
|
|
|
|
## Fix 2: Web-Sync JS-Extraktion reparieren
|
|
|
|
Root Cause: Der Button nimmt die **komplette HTML-Seite** (`document.documentElement.outerHTML`) und füttert sie dem CSV-Parser → 1 Müll-Eintrag mit `<meta>`-Tag-Text.
|
|
|
|
Recherche zeigt: DOM-Klassen sind bei Netflix gehasht (brittel). Der robuste Weg ist die **Netflix Shakti-API** aus dem WebView heraus, da die Session-Cookies (`NetflixId`) automatisch vorliegen.
|
|
|
|
**2a. Provider-spezifische JS-Extraktion** (`ProviderSyncScreen.kt` → `WebViewSyncSection`):
|
|
- **Netflix**: Injiziere JS, das `window.netflix.reactContext.models.serverDefs.data.BUILD_IDENTIFIER` + `authURL` liest, dann `fetch('/api/shakti/'+buildId+'/viewingactivity?pg='+n)` paginiert (Schleife bis `vhSize` erreicht) und ein sauberes JSON-Array von `{title, seriesTitle, episodeTitle, date, duration}` zurückgibt.
|
|
- **Prime Video**: Parse inline-JSON aus `script[type="text/template"]` (`props`→widgets→`content.content.titles[]`), fallback auf `[data-automation-id^="wh-date"]`.
|
|
- **Andere (Disney+/Apple)**: Greaceful-Degradation-Meldung "Web-Sync noch nicht unterstützt, bitte CSV verwenden".
|
|
|
|
**2b. Toast-Feedback statt HTML-String**: Der Button zeigt Fortschritt ("Lade Seite N…"). Die extrahierten JSON-Daten gehen an `viewModel.importScrapedWebHistory(json, provider)` — bereits vorhanden, leitet an `NetflixParser.parseJsonApiPayload` weiter.
|
|
|
|
**2c. `parseJsonApiPayload` robuster machen** (`NetflixParser.kt`): Akzeptiert jetzt sowohl das Netflix-`viewedItems`-Array **als auch** ein flaches Array (für den Prime-Fall). Field-Reading defensiv (`seriesTitle` für Episoden, `title` für Filme → korrekter `contentType`). Dauer aus dem `duration`-Feld (ms → Minuten) falls vorhanden, sonst Default.
|
|
|
|
---
|
|
|
|
## Fix 3: Navigations-Bug (hängt nach "Verlauf Auslesen" fest)
|
|
|
|
Symptom: Nach dem Sync-Screen kommt man nicht mehr aufs Dashboard. Ursachen: WebView wird nicht disposed, `update`-Lambda erzwingt Reloads, und das alte Parsing der kompletten HTML lief auf dem Main-Thread.
|
|
|
|
**3a. WebView sauber lifecycle-gebunden** (`WebViewSyncSection`):
|
|
- `DisposableEffect` / `remember { ...; onDispose { webView.destroy() } }` statt freischwebendem Ref — verhindert, dass der WebView den Screen blockiert.
|
|
- Reload-Schleife in `update`-Lambda entfernen (vergleicht nur noch, ob sich der Provider geändert hat, nicht jeden Frame).
|
|
|
|
**3b. Parsing off-main**: Die extrahierten JSON-Daten werden ohnehin über `viewModelScope.launch(Dispatchers.IO)` verarbeitet (bereits in `importScrapedWebHistory`), aber das JS-`evaluateJavascript`-Ergebnis wird vor dem Parsen als String geprüft — keine riesige HTML-Seite mehr, die den Main-Thread blockiert.
|
|
|
|
**3c. Navi-Zurück-Verhalten**: `BackHandler` im Sync-Screen, der bei geladenem WebView zuerst `webView.goBack()` macht (falls History vorhanden) und erst dann `navController.popBackStack()`. So kommt man sicher vom Sync-Screen weg.
|
|
|
|
---
|
|
|
|
## Validierung
|
|
- `./gradlew assembleDebug` (Java 21) baut fehlerfrei.
|
|
- `adb install -r` auf das S24 Ultra.
|
|
- Manueller Smoke-Test: Sample-Daten → Filme-Tab zeigt Filme, Serien-Tab nur Serien, Dashboard zählt korrekt. Navi nach Sync funktioniert.
|
|
|
|
Alle drei Fixes sind voneinander unabhängig und werden in einem Build-Zyklus umgesetzt. Keine DB-Schema-Änderung (nur neue Queries auf bestehenden Spalten). |