Flask-basierte Web-App zum Scannen, Queueing und Transkodieren von Videodateien mit HandBrakeCLI. Enthält UI für Dashboard/Queue/History/Settings, persistente Logs und konfigurierbare Post-Checks.
- Dashboard: Scan mit Cache, Filter/Suche/Status, Mehrfachauswahl, Profilpflicht, Mediainfo-Modal (Raw + kompakt), Lokalisierung der Zeitstempel.
- Queue: Manuelles Start/Pause/Stop, Status-Badges, ETA aus HandBrake-Logs, Log-Modal, Multi-Remove, Logs mit Timestamp+UUID, harter Stop killt Prozessgruppe, Retry-Logik, sofortige Status-Anzeige (Pause/Start/Stop).
- History: Abgeschlossene Jobs mit Start/Fertig/Dauer/Size/Ratio/Profil/Log-Link, Log-Modal wie in der Queue.
- Output: Strategien rename_original/replace/archive (+ Retention), Metadatei pro Output inkl. aktiven Checks und Größen/Ratio.
- Post-Checks: ffprobe (Video-Stream + Dauer > 0, Pflicht), ffmpeg Null-Decode (optional), mkvmerge (MKV, optional), Mediainfo (optional), konfigurierbare Retries.
- Benachrichtigung: Pushover (Token/User/Trigger, optional Title/Priority, Test-Push).
- Konfig: Live-Reload nach Settings-Save (ohne Server-Neustart), Profile-Editor im UI, log_dir konfigurierbar.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python main.py- Aufruf im Browser:
http://localhost:5000(läuft auf 0.0.0.0). - Tests:
pytest
- Hauptdatei:
config/config.yaml(für das Repo sindconfig/config.example.yaml/config/profiles.example.yamlbeigelegt). - Wichtige Felder:
input_paths,include_extensions,path_exclusions(Glob, case-sensitiv, ignoriert Pfade),title_exclusions(Substring, case-insensitiv; getaggt als exclusion)- Tools:
handbrake,ffprobe,ffmpeg,mkvmerge,mediainfo - Output:
output_strategy(rename_original|replace|archive),archive_path,archive_retention_days - Temp:
temp_mode(in-place|temp_dir),temp_dir - Verifikation/Retry:
max_retries,check_ffmpeg_null,check_mkvmerge,check_mediainfo(ffprobe ist immer aktiv) - Pushover:
token,user,triggers, optionaltitle,priority profiles_path,log_dir
- Logs:
logs/YYYYMMDDTHHMMSSZ_job_<uuid>.log(mit Start/End-Markern, Retry-Hinweis, Check-Fehlern). - History:
logs/history.json(persistente Historie, inkl. Log-Pfad, Zeiten, Größen, Ratio). - Output-Metadatei:
.meta.jsonneben dem Output, enthält Profil, Container, Quelle, Checks, Command-Args, Größen/Ratio, UUID.
- Sensitive/variable Dateien sind in
.gitignore:config/config.yaml,config/profiles.yaml,support_docs/,test_dir/,logs/,.venv/usw. - Verwende die
config/config.example.yamlundconfig/profiles.example.yamlals Vorlage.
- Dev-Server:
flask run --host 0.0.0.0 --port 5000(Debug off empfohlen). - Für Produktion: hinter einen WSGI-Server (gunicorn/uwsgi) und Reverse-Proxy stellen, eigene Pfade/Logs/Permissions beachten.
- Build:
docker build -f docker/Dockerfile -t transcode-deck . - Run (Beispiel):
docker run -p 5000:5000 \
-v $PWD/config/config.yaml:/app/config/config.yaml:ro \
-v $PWD/config/profiles.yaml:/app/config/profiles.yaml:ro \
-v $PWD/logs:/app/logs \
-v /srv/media/videos:/srv/media/videos:ro \
-e PORT=5000 \
transcode-deck - Image enthält HandBrakeCLI, ffmpeg/ffprobe, mkvmerge und mediainfo.
- Falls keine
config.yaml/profiles.yamlgemountet sind, kopiert der EntryPoint die Beispiel-Dateien (liegen im Image unter/app/config.examples) ins Laufzeit-Volume. - Details/Compose-Beispiel:
docker/README.md(Container läuft mit einem Gunicorn-Worker, weil Queue/Scan-Cache im Prozess gehalten werden)
docker-compose.yml im Repo-Root:
services:
transcode-deck:
image: transcode-deck
build:
context: .
dockerfile: docker/Dockerfile
ports:
- "5000:5000"
volumes:
- ./config:/app/config
- ./logs:/app/logs
- /home/marcel/Videos:/srv/media/videos
environment:
- PORT=5000Start: docker compose up --build
pytestMIT License (siehe LICENSE).