# VideoKonverter Web-basierter Video-Konverter mit GPU-Beschleunigung (Intel VAAPI), Video-Bibliotheksverwaltung und TVDB-Integration. Laeuft als Docker-Container auf Unraid oder lokal. ## Features ### Video-Konvertierung - **GPU-Encoding**: Intel VAAPI (AV1, AV1 10-Bit, HEVC, H.264) ueber Intel A380 - **CPU-Encoding**: SVT-AV1, x265, x264 als Fallback - **AV1 10-Bit Standard**: Bessere Qualitaet bei gleichem Speed (p010 Pixel-Format) - **Konfigurierbare Presets**: 7 Presets (4x GPU + 3x CPU) - **Parallele Jobs**: Mehrere Videos gleichzeitig konvertieren - **Audio-Handling**: Alle Spuren behalten (DE+EN), kein Downmix, Opus-Transcoding - **Live-Fortschritt**: WebSocket-basierte Echtzeit-Updates im Dashboard - **Queue-Management**: Drag-and-Drop, Pause, Abbruch, Prioritaeten ### Video-Player - **Browser-Streaming**: Direktes Abspielen mit ffmpeg-Transcoding (EAC3/DTS/AC3 -> AAC) - **Play-Buttons**: In Serien-, Film- und Ordner-Ansichten - **Delete-Buttons**: Einzelne Videos loeschen (DB + Datei) ### Video-Bibliothek - **Ordner-Scan**: Konfigurierbare Scan-Pfade fuer Serien und Filme - **Serien-Erkennung**: Automatisch via Ordnerstruktur (`S01E01`, `1x02`, `Staffel/Season XX`) - **Doppel-Episoden**: Erkennung von Multi-Episoden-Dateien (`S01E01E02`, `S01E01-E02`, `1x01-02`) - **Episoden-Titel**: Automatische Extraktion aus Dateinamen (ohne Qualitaets-Tags) - **Film-Erkennung**: Ein Video pro Ordner = Film, Ordnername als Filmtitel - **ffprobe-Analyse**: Codec, Aufloesung, Bitrate, Audio-Spuren, Untertitel, HDR/10-Bit - **TVDB-Integration**: Serien + Filme, Poster, Episoden-Titel, fehlende Episoden - **TVDB Review-Modal**: Vorschlaege pruefen statt blindem Auto-Match, manuelle Suche - **TVDB-Sprachkonfiguration**: Metadaten in Deutsch, Englisch oder anderen Sprachen - **Schnellfilter**: Vordefinierte Filter (Nicht konvertiert, Alte Formate, Fehlende Episoden) - **Filter-Presets**: Eigene Filter speichern und als Standard setzen - **Fehlende Episoden**: Uebersicht aller fehlenden Episoden ueber alle Serien - **Filter**: Video-Codec, Aufloesung, Container, Audio-Sprache, Kanaele, 10-Bit - **Duplikat-Finder**: Gleiche Episode in verschiedenen Formaten erkennen - **Import-Service**: Videos einsortieren mit Serien-Erkennung und TVDB-Lookup - **Clean-Service**: Nicht-Video-Dateien (NFO, JPG, SRT etc.) finden und entfernen - **Direkt-Konvertierung**: Videos aus der Bibliothek direkt in die Queue senden ### Administration - **Web-UI**: Responsive Dashboard, Bibliothek, Einstellungen, Statistik - **Settings**: Encoding-Modus, Ziel-Container, Audio-/Untertitel-Sprachen, Cleanup - **TVDB-Verwaltung**: API-Key/PIN konfigurieren, Sprache waehlen, Serien + Filme zuordnen - **Scan-Pfad-Management**: Pfade hinzufuegen/loeschen/scannen ueber Admin-UI - **Statistik**: Konvertierungs-Historie mit Groessen-Ersparnis, Dauer, Codec-Verteilung ## Architektur ``` ┌────────────────────────────────────────────────────┐ │ Browser (Dashboard / Bibliothek / Admin / Stats) │ ├──────────────┬──────────────┬──────────────────────┤ │ HTMX/JS │ WebSocket │ REST API │ ├──────────────┴──────────────┴──────────────────────┤ │ aiohttp Server │ │ ┌──────────┐ ┌────────────┐ ┌──────────────────┐ │ │ │ Queue │ │ Encoder │ │ LibraryService │ │ │ │ Service │ │ Service │ │ (Scan, Filter, │ │ │ │ │ │ (ffmpeg) │ │ Serien + Filme) │ │ │ ├──────────┤ ├────────────┤ ├──────────────────┤ │ │ │ Scanner │ │ Probe │ │ TVDBService │ │ │ │ Service │ │ Service │ │ (API v4, i18n) │ │ │ ├──────────┤ │ (ffprobe) │ ├──────────────────┤ │ │ │ Importer │ └────────────┘ │ CleanerService │ │ │ │ Service │ │ (Junk-Scan) │ │ │ └──────────┘ └──────────────────┘ │ ├─────────────────────────────────────────────────────┤ │ MariaDB (statistics, library_*, tvdb_episode_cache)│ └─────────────────────────────────────────────────────┘ ``` ### Technologie-Stack | Komponente | Technologie | |------------|-------------| | Backend | Python 3.12, aiohttp (async) | | Templates | Jinja2 + HTMX | | Datenbank | MariaDB (aiomysql) | | Video | FFmpeg + FFprobe | | GPU | Intel VAAPI (iHD-Treiber) | | Metadaten | TVDB API v4 (tvdb-v4-official) | | Container | Docker (Ubuntu 24.04) | | Echtzeit | WebSocket | ## Projektstruktur ``` video-konverter/ ├── __main__.py # Einstiegspunkt ├── Dockerfile # Ubuntu 24.04 + ffmpeg + Intel GPU ├── entrypoint.sh # Default-Configs in Volumes kopieren ├── docker-compose.yml # GPU + CPU Profile ├── requirements.txt # Python-Abhaengigkeiten ├── unraid/ │ └── my-VideoKonverter.xml # Unraid Docker-Template ├── app/ │ ├── server.py # Haupt-Server (aiohttp Application) │ ├── config.py # Settings + Presets laden │ ├── cfg/ │ │ ├── settings.yaml # Laufzeit-Einstellungen │ │ └── presets.yaml # Encoding-Presets (7 Stueck) │ ├── models/ │ │ ├── media.py # MediaFile, VideoStream, AudioStream │ │ └── job.py # ConvertJob, JobStatus │ ├── services/ │ │ ├── library.py # Bibliothek: Scan, Filter, Duplikate (1747 Z.) │ │ ├── tvdb.py # TVDB: Auth, Suche, Episoden, Sprache (1005 Z.) │ │ ├── importer.py # Import: Erkennung, TVDB-Lookup, Kopieren (734 Z.) │ │ ├── cleaner.py # Clean: Junk-Scan, Nicht-Video-Dateien (155 Z.) │ │ ├── queue.py # Job-Queue mit MariaDB-Persistierung (541 Z.) │ │ ├── encoder.py # FFmpeg-Wrapper (GPU + CPU) │ │ ├── probe.py # FFprobe-Analyse │ │ ├── scanner.py # Dateisystem-Scanner │ │ └── progress.py # Encoding-Fortschritt parsen │ ├── routes/ │ │ ├── api.py # REST API (Queue, Jobs, Convert) │ │ ├── library_api.py # REST API (Bibliothek, TVDB, Scan) (998 Z.) │ │ ├── pages.py # HTML-Seiten (Dashboard, Admin, etc.) │ │ └── ws.py # WebSocket-Manager │ ├── templates/ │ │ ├── base.html # Basis-Layout mit Navigation │ │ ├── dashboard.html # Queue + aktive Jobs │ │ ├── library.html # Bibliothek mit Filtern │ │ ├── admin.html # Einstellungen + TVDB + Scan-Pfade │ │ ├── statistics.html # Konvertierungs-Statistik │ │ └── partials/ │ │ └── stats_table.html │ └── static/ │ ├── css/style.css # Komplettes Styling (1554 Z.) │ └── js/ │ ├── library.js # Bibliothek-UI (1912 Z.) │ ├── websocket.js # WebSocket-Client │ └── filebrowser.js # Datei-Browser ├── data/ # Queue-Persistierung ├── logs/ # Server-Logs └── testmedia/ # Test-Dateien ``` ## Installation ### Voraussetzungen - Docker + Docker Compose - MariaDB-Server (extern, z.B. auf Unraid) - Optional: Intel GPU fuer Hardware-Encoding (Intel A380 empfohlen) ### MariaDB einrichten ```sql CREATE DATABASE video_converter CHARACTER SET utf8mb4; CREATE USER 'video'@'%' IDENTIFIED BY 'dein_passwort'; GRANT ALL PRIVILEGES ON video_converter.* TO 'video'@'%'; FLUSH PRIVILEGES; ``` Die Tabellen werden automatisch beim ersten Start erstellt. ### Unraid-Installation 1. Docker-Image laden (Unraid Web-Terminal): ```bash docker load -i /mnt/user/downloads/videokonverter-cpu.tar ``` 2. XML-Template kopieren: ```bash cp /mnt/user/downloads/my-VideoKonverter.xml /boot/config/plugins/dockerMan/templates-user/ ``` 3. In der Unraid Docker-WebGUI: "Container hinzufuegen" → Template waehlen → Werte anpassen → Starten Das Template enthält alle Variablen mit korrekten Defaults. ### Konfiguration Alle Einstellungen sind per **Umgebungsvariablen** (VK_*) konfigurierbar. ENV-Variablen ueberschreiben immer die `settings.yaml`. | Variable | Default | Beschreibung | |----------|---------|-------------| | `VK_DB_HOST` | `192.168.155.11` | MariaDB Host | | `VK_DB_PORT` | `3306` | MariaDB Port | | `VK_DB_USER` | `video` | MariaDB Benutzer | | `VK_DB_PASSWORD` | - | MariaDB Passwort | | `VK_DB_NAME` | `video_converter` | Datenbank-Name | | `VK_MODE` | `cpu` | Encoding-Modus: `gpu`, `cpu`, `auto` | | `VK_GPU_DEVICE` | `/dev/dri/renderD129` | GPU Render-Device | | `VK_DEFAULT_PRESET` | `gpu_av1_10bit` | Standard Encoding-Preset | | `VK_MAX_JOBS` | `1` | Max. parallele Jobs | | `VK_TVDB_API_KEY` | - | TVDB API Key | | `VK_TVDB_LANGUAGE` | `deu` | TVDB Sprache | | `VK_LOG_LEVEL` | `INFO` | Log-Level | Alternativ kann `app/cfg/settings.yaml` direkt bearbeitet werden. Bei Erstinstallation werden Default-Konfigdateien automatisch ins cfg-Volume kopiert. ### GPU-Device ermitteln Auf dem Host pruefen welches renderD* die Intel GPU ist: ```bash cat /sys/class/drm/renderD*/device/uevent | grep -B1 DRIVER ``` Beispiel: `renderD128` = AMD, `renderD129` = Intel → `VK_GPU_DEVICE=/dev/dri/renderD129` ### Starten **GPU-Modus** (Produktion auf Unraid): ```bash docker compose --profile gpu up --build -d ``` **CPU-Modus** (lokal testen): ```bash PUID=1000 PGID=1000 docker compose --profile cpu up --build -d ``` Web-UI: http://localhost:8080 ## Encoding-Presets | Preset | Codec | Container | Qualitaet | Modus | |--------|-------|-----------|-----------|-------| | GPU AV1 | av1_vaapi | WebM | QP 30 | GPU | | GPU AV1 10-Bit | av1_vaapi | WebM | QP 30 | GPU | | GPU HEVC | hevc_vaapi | MKV | QP 28 | GPU | | GPU H.264 | h264_vaapi | MP4 | QP 23 | GPU | | CPU AV1/SVT | libsvtav1 | WebM | CRF 30 | CPU | | CPU HEVC/x265 | libx265 | MKV | CRF 28 | CPU | | CPU H.264/x264 | libx264 | MP4 | CRF 23 | CPU | ## API Referenz ### Konvertierung | Methode | Pfad | Beschreibung | |---------|------|-------------| | POST | `/api/convert` | Dateien/Ordner zur Queue hinzufuegen | | GET | `/api/queue` | Queue-Status abrufen | | DELETE | `/api/jobs/{id}` | Job entfernen/abbrechen | ### Bibliothek | Methode | Pfad | Beschreibung | |---------|------|-------------| | GET | `/api/library/paths` | Scan-Pfade auflisten | | POST | `/api/library/paths` | Scan-Pfad hinzufuegen | | DELETE | `/api/library/paths/{id}` | Scan-Pfad loeschen | | POST | `/api/library/scan` | Alle Pfade scannen | | POST | `/api/library/scan/{id}` | Einzelnen Pfad scannen | | GET | `/api/library/scan-status` | Scan-Fortschritt | | GET | `/api/library/videos` | Videos filtern (siehe Filter-Params) | | GET | `/api/library/series` | Alle Serien | | GET | `/api/library/series/{id}` | Serie mit Episoden | | GET | `/api/library/series/{id}/missing` | Fehlende Episoden einer Serie | | GET | `/api/library/missing-episodes` | Alle fehlenden Episoden (paginated) | | GET | `/api/library/filter-presets` | Filter-Presets laden | | POST | `/api/library/filter-presets` | Neues Preset speichern | | PUT | `/api/library/filter-presets` | Presets aktualisieren | | DELETE | `/api/library/filter-presets/{id}` | Preset loeschen | | PUT | `/api/library/default-view` | Standard-Ansicht setzen | | POST | `/api/library/series/{id}/tvdb-match` | TVDB-ID zuordnen | | POST | `/api/library/series/{id}/convert` | Alle Episoden konvertieren | | GET | `/api/library/series/{id}/convert-status` | Codec-Status der Serie | | POST | `/api/library/series/{id}/cleanup` | Alte Dateien loeschen | | GET | `/api/library/duplicates` | Duplikate finden | | POST | `/api/library/videos/{id}/convert` | Direkt konvertieren | | POST | `/api/library/delete-folder` | Ordner komplett loeschen | | GET | `/api/library/stats` | Bibliotheks-Statistiken | | GET | `/api/library/movies` | Filme auflisten | | POST | `/api/library/movies/{id}/tvdb-match` | Film-TVDB-Zuordnung | | POST | `/api/library/tvdb-auto-match` | Review-Vorschlaege sammeln | | POST | `/api/library/tvdb-confirm` | TVDB-Match bestaetigen | | POST | `/api/library/tvdb-refresh-episodes` | Episoden-Cache aktualisieren | | GET | `/api/tvdb/search?q=` | TVDB-Suche | | GET | `/api/tvdb/language` | TVDB-Sprache lesen | | PUT | `/api/tvdb/language` | TVDB-Sprache aendern | ### Streaming | Methode | Pfad | Beschreibung | |---------|------|-------------| | GET | `/api/library/videos/{id}/stream` | Video-Transcoding-Stream (ffmpeg pipe) | | DELETE | `/api/library/videos/{id}` | Video loeschen (DB + Datei) | ### Import | Methode | Pfad | Beschreibung | |---------|------|-------------| | GET | `/api/library/import` | Alle Import-Jobs auflisten | | POST | `/api/library/import` | Neuen Import-Job erstellen | | GET | `/api/library/import/{id}` | Import-Job Status mit Items | | POST | `/api/library/import/{id}/analyze` | Import analysieren | | POST | `/api/library/import/{id}/execute` | Import ausfuehren | | POST | `/api/library/import/{id}/assign` | Item manuell zuordnen | | POST | `/api/library/import/{id}/skip` | Item ueberspringen | ### System | Methode | Pfad | Beschreibung | |---------|------|-------------| | GET | `/api/logs` | Server-Logs abrufen | | GET | `/api/system` | System-Info (GPU, Jobs) | ### Video-Filter (`/api/library/videos`) ``` ?video_codec=hevc # h264, hevc, av1, mpeg4 &min_width=1920 # Mindest-Aufloesung &container=mkv # mkv, mp4, avi, webm &audio_lang=ger # Audio-Sprache &audio_channels=6 # Kanal-Anzahl (2=Stereo, 6=5.1) &is_10bit=1 # Nur 10-Bit ¬_converted=1 # Nicht im Zielformat (Container + Codec) &exclude_codec=av1 # Codec ausschliessen &exclude_container=webm # Container ausschliessen &search=breaking # Dateiname-Suche &sort=file_size # Sortierung &order=desc # asc | desc &page=1&limit=50 # Pagination ``` ## Datenbank-Schema ### library_paths Konfigurierte Scan-Pfade fuer Serien- und Film-Ordner. ### library_series Erkannte Serien mit optionaler TVDB-Verknuepfung (Poster, Beschreibung, Episoden-Zaehler). ### library_movies Erkannte Filme mit optionaler TVDB-Verknuepfung (Poster, Beschreibung, Jahr). ### library_videos Jedes Video mit vollstaendigen ffprobe-Metadaten: - Video: Codec, Aufloesung, Framerate, Bitrate, 10-Bit, HDR - Audio: JSON-Array mit Spuren (`[{"codec":"eac3","lang":"ger","channels":6,"bitrate":256000}]`) - Untertitel: JSON-Array (`[{"codec":"subrip","lang":"ger"}]`) - Serien: Staffel/Episode-Nummer, episode_end (fuer Doppel-Episoden), Episoden-Titel ### tvdb_episode_cache Zwischenspeicher fuer TVDB-Episodendaten (Serie, Staffel, Episode, Name, Ausstrahlung). ## Docker Volumes | Volume (Host) | Container-Pfad | Beschreibung | |----------------|---------------|-------------| | `./app/cfg` (lokal) / `/mnt/user/appdata/videokonverter/cfg` (Unraid) | `/opt/video-konverter/app/cfg` | Konfiguration (persistent, Defaults werden automatisch kopiert) | | `./data` (lokal) / `/mnt/user/appdata/videokonverter/data` (Unraid) | `/opt/video-konverter/data` | Queue-Persistierung | | `./logs` (lokal) / `/mnt/user/appdata/videokonverter/logs` (Unraid) | `/opt/video-konverter/logs` | Server-Logs | | `/mnt` (lokal) / `/mnt/user` (Unraid) | `/mnt` | Medien-Pfade | | `/dev/dri` | `/dev/dri` | GPU-Devices (fuer VAAPI) | ## Lizenz Privates Projekt von Eddy (Eduard Wisch).