diff --git a/CLAUDE.md b/CLAUDE.md index 360d800..b721b5f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,9 +23,10 @@ Drei Komponenten: - MutationObserver registriert neue Cards beim IntersectionObserver - `yt-navigate-finish` Event-Listener fuer SPA-Navigation - Deduplizierung ueber `sentUrls` Set, wird bei Navigation geleert - - Batch-Versand: sammelt sichtbare Videos, sendet als Array + - Batch-Versand: sammelt sichtbare Videos mit Profil-ID, sendet als Array - Selektoren ohne Klassen: nur Tags (`h3`, `img`) und Attribute (`href`, `src`) - `background.js` — empfaengt Batch vom Content Script, sendet POST an Server +- `popup.html/popup.js` — Profil-Auswahl (holt Profile vom Server, speichert in browser.storage.local) - Laden via `about:debugging#/runtime/this-firefox` → "Temporaeres Add-on laden" → `manifest.json` ### Server (`backend/`) @@ -34,24 +35,28 @@ Drei Komponenten: - Dockerisiert: `docker compose up --build -d` im `backend/` Verzeichnis - Laeuft auf `http://localhost:8000` - Download-Service speichert Videos unter `/videos/{id}.mp4` -- Streaming: heruntergeladene Videos von Datei, sonst Live-Stream via yt-dlp + ffmpeg (fragmentiertes MP4) +- Stream-Service: heruntergeladene Videos von Datei, sonst Live-Stream via yt-dlp + ffmpeg (fragmentiertes MP4) - Dedup: beim Batch-Import wird bestehender Eintrag mit gleicher Video-ID geloescht und neu eingefuegt - Sortierung: nach ID absteigend (erstes Video im Batch bekommt hoechste ID) +- Profile: fest in DB definiert, Videos ueber Many-to-Many zugeordnet ### App (`app/`) - **Kotlin, Jetpack Compose**, Android/Android TV - Gradle-Projekt, Modul `frontend` - Screens: AllVideos (Grid), Downloaded, VideoDetail, VideoPlayer - Retrofit fuer API-Calls, Coil fuer Thumbnails, ExoPlayer fuer Streaming -- Navigation mit Bottom Bar, Dark Theme +- Navigation mit TopBar (Profil-Auswahl) und Bottom Bar, Dark Theme +- Profil-Auswahl wird in SharedPreferences persistiert, filtert Videos nach Profil +- Lokaler Download: Videos werden auf dem Geraet gespeichert, lokal bevorzugt abgespielt - Server-IP konfigurierbar in `ApiClient.kt` (aktuell `192.168.178.92`) - Emulator: Android Studio → Device Manager → Pixel 6a, API 35 ## API Endpoints -- `POST /videos` — Video-Batch von Extension empfangen (Liste von Videos, Dedup + Reverse-Insert) -- `GET /videos` — alle Videos abrufen (sortiert nach ID absteigend) -- `GET /videos/downloaded` — heruntergeladene Videos abrufen +- `GET /profiles` — alle Profile abrufen +- `POST /videos` — Video-Batch von Extension empfangen (Dedup, Reverse-Insert, Profil-Zuordnung) +- `GET /videos` — alle Videos abrufen (optional `?profile_id=X`, sortiert nach ID absteigend) +- `GET /videos/downloaded` — heruntergeladene Videos abrufen (optional `?profile_id=X`) - `POST /videos/{id}/download` — Download auf Server triggern - `GET /videos/{id}/stream` — Video streamen (von Datei oder Live via yt-dlp/ffmpeg) - `GET /videos/{id}/file` — Video-Datei zum Download auf Client ausliefern @@ -60,29 +65,32 @@ Drei Komponenten: ``` backend/ - main.py — FastAPI App, CORS, Startup + main.py — FastAPI App, CORS, Startup, Seed-Profile database.py — SQLAlchemy Engine, Session, Base - models.py — Video Model (id, title, youtuber, thumbnail_url, youtube_url, file_path, created_at) - schemas.py — Pydantic Schemas (VideoCreate, VideoResponse) - routes/videos.py — Alle API-Routen + models.py — Video, Profile, video_profiles (Many-to-Many) + schemas.py — Pydantic Schemas (VideoCreate, VideoResponse, ProfileResponse) + routes/videos.py — Video- und Profil-Routen services/ - video_service.py — CRUD-Operationen, Dedup - download_service.py — yt-dlp Download + Live-Streaming + video_service.py — CRUD-Operationen, Dedup, Profil-Filter + download_service.py — yt-dlp Download + stream_service.py — Live-Streaming via yt-dlp + ffmpeg Dockerfile — Python 3.12 + ffmpeg docker-compose.yml — Service-Definition, Port 8000, Volume /videos .dockerignore — videos/, __pycache__/ .gitignore — videos/, __pycache__/ browser_extension/ - manifest.json — Manifest V2, Permissions fuer youtube.com + localhost - content.js — DOM-Extraktion + IntersectionObserver + Batch-Versand + manifest.json — Manifest V2, Permissions, browser_action + content.js — DOM-Extraktion + IntersectionObserver + Batch-Versand mit Profil background.js — Batch-POST an Server + popup.html — Profil-Auswahl UI + popup.js — Profile laden, Auswahl speichern app/ .gitignore — .gradle/, build/, .idea/, local.properties frontend/src/main/java/com/youtubeapp/ MainActivity.kt — Einstiegspunkt - data/ — Video, ApiClient, VideoApi, VideoRepository + data/ — Video, Profile, ApiClient, VideoApi, VideoRepository, LocalStorageService ui/screens/ — AllVideos, Downloaded, VideoDetail, VideoPlayer ui/components/ — VideoCard ui/viewmodel/ — VideoViewModel @@ -94,7 +102,7 @@ app/ - Kein Jellyfin — erfuellt nicht die Anforderung, Videos vor dem Download aufzulisten - Kein PostgreSQL/MySQL — SQLite reicht fuer den Prototyp -- Keine Benutzerprofile im Prototyp +- Profile fest in DB — kein UI zum Erstellen/Loeschen, werden direkt in der Datenbank verwaltet - Videos werden auf dem Server gespeichert, Client speichert nur bei explizitem Download - DOM-Extraktion statt ytInitialData-Parsing — funktioniert auch bei SPA-Navigation und Scrollen - IntersectionObserver statt blindem Scan — nur sichtbare Videos erfassen diff --git a/architecture.md b/architecture.md index 78717ef..54ca802 100644 --- a/architecture.md +++ b/architecture.md @@ -1,11 +1,13 @@ # Browser Extension - Content Script — YouTube-DOM auslesen, Videodaten extrahieren - Background Script — Daten gruppiert an Server senden (POST /videos) +- Popup — Profil vom Server laden und auswaehlen # Server ## API -- POST /videos — Video-Batch empfangen, Duplikate entfernen -- GET /videos — alle Videos abrufen -- GET /videos/downloaded — heruntergeladene Videos abrufen +- POST /videos — Video-Batch empfangen, Duplikate entfernen, Profil zuordnen +- GET /videos — alle Videos abrufen (optional nach Profil filtern) +- GET /profiles — alle Profile abrufen +- GET /videos/downloaded — heruntergeladene Videos abrufen (optional nach Profil filtern) - POST /videos/{id}/download — Download triggern - GET /videos/{id}/stream — Video streamen - GET /videos/{id}/file — Video-Datei zum Download ausliefern @@ -15,6 +17,8 @@ - StreamService — Live-Streaming via yt-dlp + ffmpeg ## Model - Video — id, title, youtuber, thumbnail_url, youtube_url, file_path +- Profile — id, name +- video_profiles — video_id, profile_id (Many-to-Many) # App ## Screens - AllVideosScreen — alle Videos als Cards @@ -26,6 +30,7 @@ ## Services - LocalStorageService — Videos lokal speichern, pruefen, loeschen ## API -- ServerApi — kommuniziert mit FastAPI (GET /videos, POST /download, GET /stream, GET /videos/{id}/file) +- ServerApi — kommuniziert mit FastAPI (GET /profiles, GET /videos, POST /download, GET /stream, GET /videos/{id}/file) ## Model -- Video — id, title, youtuber, thumbnailUrl, youtubeUrl, isDownloaded, localFilePath \ No newline at end of file +- Video — id, title, youtuber, thumbnailUrl, youtubeUrl, isDownloaded, localFilePath, profileIds +- Profile — id, name \ No newline at end of file diff --git a/commication.md b/commication.md index 1ea03cb..aa73a2b 100644 --- a/commication.md +++ b/commication.md @@ -1,7 +1,8 @@ # Browser Extension intern - Videodaten erfassen -# Browser Extension -> Server -- Videodaten gruppiert senden +# Browser Extension -> Server +- Profile abrufen +- Videodaten gruppiert mit Profil senden # Server intern - Videodaten persistieren - Video herunterladen @@ -9,7 +10,8 @@ - Video streamen - Videodatei senden # App -> Server -- Videos abrufen +- Profile abrufen +- Videos nach Profil abrufen - Video download anfragen - Video stream anfragen # App intern