This commit is contained in:
Marek
2026-04-05 23:26:55 +02:00
parent b3b4410ee0
commit b6635a107d
21 changed files with 229 additions and 75 deletions

View File

@@ -31,41 +31,48 @@ Drei Komponenten:
### Server (`backend/`)
- **Python, FastAPI, SQLAlchemy, SQLite** (`videos/youtubeapp.db`)
- **yt-dlp + ffmpeg** fuer Video-Download und Live-Streaming
- **yt-dlp + ffmpeg** fuer Video-Download und Streaming
- **WebSocket** (`/ws`) — benachrichtigt verbundene Clients bei neuen Videos
- Dockerisiert: `docker compose up --build -d` im `backend/` Verzeichnis
- Laeuft auf `http://localhost:8000`
- Download-Service speichert Videos unter `/videos/{id}.mp4`
- Stream-Service: heruntergeladene Videos von Datei, sonst Live-Stream via yt-dlp + ffmpeg (fragmentiertes MP4)
- Stream-Service: heruntergeladene Videos von Datei, sonst progressiver Download via yt-dlp mit gleichzeitigem Streaming
- 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
- Nach lokalem Download wird die Server-Datei geloescht (file_path auf null)
### App (`app/`)
- **Kotlin, Jetpack Compose**, Android/Android TV
- Gradle-Projekt, Modul `frontend`
- Screens: AllVideos (Grid), Downloaded, VideoDetail, VideoPlayer
- Screens: AllVideos (Grid), Downloaded (lokal verfuegbare Videos), VideoDetail, VideoPlayer
- Retrofit fuer API-Calls, Coil fuer Thumbnails, ExoPlayer fuer Streaming
- Navigation mit TopBar (Profil-Auswahl) und Bottom Bar, Dark Theme
- OkHttp WebSocket-Client — automatisches Neuladen bei neuen Videos
- Navigation mit TopBar (Profil-Auswahl, Aufraeumen-Icon) 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
- Aufraeumen: loescht alle nicht lokal gespeicherten Videos des Profils (sendet lokale IDs als Ausnahme)
- Server-IP konfigurierbar in `ApiClient.kt` (aktuell `192.168.178.92`)
- Emulator: Android Studio → Device Manager → Pixel 6a, API 35
## API Endpoints
- `GET /profiles` — alle Profile abrufen
- `POST /videos` — Video-Batch von Extension empfangen (Dedup, Reverse-Insert, Profil-Zuordnung)
- `POST /videos` — Video-Batch von Extension empfangen (Dedup, Reverse-Insert, Profil-Zuordnung, WebSocket-Benachrichtigung)
- `GET /videos` — alle Videos abrufen (optional `?profile_id=X`, sortiert nach ID absteigend)
- `GET /videos/downloaded` — heruntergeladene Videos abrufen (optional `?profile_id=X`)
- `DELETE /videos?profile_id=X&exclude_ids=` — Videos des Profils loeschen (ausser lokal gespeicherte)
- `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}/stream` — Video streamen (von Datei oder progressiver Download via yt-dlp)
- `GET /videos/{id}/file` — Video-Datei zum Download auf Client ausliefern
- `DELETE /videos/{id}/file` — Server-Datei loeschen (nach lokalem Download)
- `WS /ws` — WebSocket, sendet Profile-IDs bei neuen Videos
## Projektstruktur
```
backend/
main.py — FastAPI App, CORS, Startup, Seed-Profile
main.py — FastAPI App, CORS, Startup, Seed-Profile, WebSocket
database.py — SQLAlchemy Engine, Session, Base
models.py — Video, Profile, video_profiles (Many-to-Many)
schemas.py — Pydantic Schemas (VideoCreate, VideoResponse, ProfileResponse)
@@ -73,14 +80,14 @@ backend/
services/
video_service.py — CRUD-Operationen, Dedup, Profil-Filter
download_service.py — yt-dlp Download
stream_service.py — Live-Streaming via yt-dlp + ffmpeg
stream_service.py — Progressiver Download + Streaming via yt-dlp
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, browser_action
manifest.json — Manifest V2, Permissions, browser_action, storage
content.js — DOM-Extraktion + IntersectionObserver + Batch-Versand mit Profil
background.js — Batch-POST an Server
popup.html — Profil-Auswahl UI
@@ -93,9 +100,12 @@ app/
data/ — Video, Profile, ApiClient, VideoApi, VideoRepository, LocalStorageService
ui/screens/ — AllVideos, Downloaded, VideoDetail, VideoPlayer
ui/components/ — VideoCard
ui/viewmodel/ — VideoViewModel
ui/viewmodel/ — VideoViewModel (inkl. WebSocket-Client)
ui/navigation/ — AppNavigation, Routes
ui/theme/ — Theme (Dark)
frontend/src/main/res/
layout/player_view.xml — PlayerView mit TextureView fuer TV-Kompatibilitaet
drawable/tv_banner.png — Android TV Launcher-Banner
```
## Entscheidungen
@@ -103,8 +113,9 @@ app/
- Kein Jellyfin — erfuellt nicht die Anforderung, Videos vor dem Download aufzulisten
- Kein PostgreSQL/MySQL — SQLite reicht fuer den 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
- Server-Datei wird nach lokalem Download geloescht — spart Speicherplatz auf dem Server
- DOM-Extraktion statt ytInitialData-Parsing — funktioniert auch bei SPA-Navigation und Scrollen
- IntersectionObserver statt blindem Scan — nur sichtbare Videos erfassen
- Live-Streaming via yt-dlp/ffmpeg statt synchronem Download vor dem Streamen
- Progressiver Download via yt-dlp mit gleichzeitigem Streaming statt komplettem Download vor dem Abspielen
- WebSocket statt Polling — effiziente Echtzeit-Aktualisierung der Videoliste
- Sprache der Dokumentation: Deutsch