Files
youtube-app/CLAUDE.md
2026-04-05 21:44:43 +02:00

5.6 KiB

YouTube App

Selbst-gehostete Anwendung: YouTube-Videos per Browser Extension erfassen, auf einem Server speichern und per Kotlin-App auf Android/Android TV streamen und herunterladen.

Dokumentation

  • systems.md — Technologie-Stack pro Komponente
  • commication.md — Kommunikationsflüsse zwischen den Systemen
  • features.md — Konkrete Features und Benutzerinteraktionen
  • architecture.md — Detaillierter Systemaufbau (Endpoints, Services, Models, Screens)
  • szenarios.md — Benutzer-Szenarien

Architektur

Drei Komponenten:

Browser Extension (browser_extension/)

  • Manifest V2, Firefox-kompatibel (browser.* API)
  • content.js — extrahiert Videodaten direkt aus dem YouTube-DOM:
    • ytd-rich-item-renderer (Homepage, Abos, Kanalseiten)
    • ytd-video-renderer (Suchergebnisse)
    • IntersectionObserver (threshold 50%) — nur sichtbare Cards erfassen
    • 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 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/)

  • Python, FastAPI, SQLAlchemy, SQLite (videos/youtubeapp.db)
  • yt-dlp + ffmpeg fuer Video-Download und Live-Streaming
  • 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)
  • 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 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

  • 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

Projektstruktur

backend/
  main.py              — FastAPI App, CORS, Startup, Seed-Profile
  database.py          — SQLAlchemy Engine, Session, Base
  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, 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, 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, Profile, ApiClient, VideoApi, VideoRepository, LocalStorageService
    ui/screens/        — AllVideos, Downloaded, VideoDetail, VideoPlayer
    ui/components/     — VideoCard
    ui/viewmodel/      — VideoViewModel
    ui/navigation/     — AppNavigation, Routes
    ui/theme/          — Theme (Dark)

Entscheidungen

  • 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
  • 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
  • Sprache der Dokumentation: Deutsch