e032a9df1c
- jobs.meta (Migration in beiden db.py): Disc-Metadaten wandern in den Job —
Quelle fuer Job-Detail-Popup (GET /jobs/{id}/detail), Ordner-Benennung, NFO.
- medien.py (Worker, mit Tests): Zielordner 'Titel (Jahr)' statt Job-UUID;
movie.nfo/tvshow.nfo (Kodi-Schema, kodi.wiki/view/NFO_files) + poster.jpg
fuer jellyfin/emby/kodi; plex nur Benennung; Kollision -> Job-ID-Suffix.
- notify.py (identisch in API+Worker, mit Tests): Webhook bei Job-Ende —
Discord ({content}, discord.com/developers), Slack ({text},
api.slack.com/messaging/webhooks), ntfy (Rohtext + ?title=, docs.ntfy.sh),
generisches JSON. Vorher war das Setting ein Placebo: nichts sendete je.
POST /notifications/test beweist die Anbindung sofort.
- mounts.py: NT_STATUS-Fehler -> handelbarer Klartext (ACCESS_DENIED ohne
Credentials = Gast-Abfrage verweigert), Timeout-Meldung, mount-Hinweis
bei error(13). Mit Tests.
- tasks.py: Platz-Check per Disc-Groesse (ioctl BLKGETSIZE64) VOR dem Rip;
Arbeitsverzeichnis workDir (unter /app/media, z.B. NAS) statt fix
/app/temp/raw — 4K-UHD-Rohdaten (bis 100 GB) sprengen sonst die VM-Platte;
MakeMKV-Key aus UI-Settings (~/.MakeMKV/settings.conf, Format wie
entrypoint.sh) gilt ab dem naechsten Rip ohne Rebuild.
- caps.py: Werkzeug-Versionen (MakeMKV aus ENV MAKEMKV_VERSION im Image,
makemkvcon hat keinen --version-Schalter lt. usage.txt; HandBrakeCLI
--version lt. handbrake.fr/docs) + Key-Quelle; workers.info-Spalte.
- /browse liefert jetzt auch DATEIEN (Name + Groesse) — der 'leere'
bluray-Ordner war voll, der Browser zeigte nur Unterordner.
- GET /system/info: Versionen, Plattenplatz, Key-/Webhook-Status.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
"""Tests für die Media-Server-Aufbereitung (Benennung + NFO)."""
|
|
|
|
import os
|
|
|
|
from medien import baue_nfo, sicherer_name, zielordner
|
|
|
|
|
|
def test_sicherer_name_entfernt_verbotene_zeichen():
|
|
assert sicherer_name('Alien: Die Wiedergeburt') == "Alien Die Wiedergeburt"
|
|
assert sicherer_name('Was/ist\\das?<>|*"') == "Wasistdas"
|
|
|
|
|
|
def test_sicherer_name_mit_jahr():
|
|
assert sicherer_name("Evangelion 2.22", 2009) == "Evangelion 2.22 (2009)"
|
|
|
|
|
|
def test_sicherer_name_kollabiert_leerraum_und_punkte():
|
|
assert sicherer_name(" Viel Raum ... ") == "Viel Raum"
|
|
|
|
|
|
def test_sicherer_name_leer_bleibt_leer():
|
|
assert sicherer_name("") == ""
|
|
assert sicherer_name("???") == ""
|
|
|
|
|
|
def test_zielordner_nutzt_titel_und_jahr(tmp_path):
|
|
pfad = zielordner(str(tmp_path), "Inception", 2010, "abc-123")
|
|
assert pfad == os.path.join(str(tmp_path), "Inception (2010)")
|
|
|
|
|
|
def test_zielordner_faellt_auf_job_id_zurueck(tmp_path):
|
|
pfad = zielordner(str(tmp_path), "", None, "abc-123")
|
|
assert pfad == os.path.join(str(tmp_path), "abc-123")
|
|
|
|
|
|
def test_zielordner_weicht_bei_kollision_aus(tmp_path):
|
|
os.makedirs(tmp_path / "Inception (2010)")
|
|
pfad = zielordner(str(tmp_path), "Inception", 2010, "abcdef12-3456")
|
|
assert pfad == os.path.join(str(tmp_path), "Inception (2010) [abcdef12]")
|
|
|
|
|
|
def test_baue_nfo_film_mit_plot_und_genres():
|
|
nfo = baue_nfo(
|
|
{"overview": "Ein Traum <im> Traum & so", "genres": ["Sci-Fi", "Action"]},
|
|
"Inception", 2010,
|
|
)
|
|
assert "<movie>" in nfo and "</movie>" in nfo
|
|
assert "<title>Inception</title>" in nfo
|
|
assert "<year>2010</year>" in nfo
|
|
# XML-Escaping: <, >, & dürfen den Parser nicht sprengen
|
|
assert "Ein Traum <im> Traum & so" in nfo
|
|
assert "<genre>Sci-Fi</genre>" in nfo
|
|
|
|
|
|
def test_baue_nfo_serie_bekommt_tvshow_wurzel():
|
|
nfo = baue_nfo({"type": "tv"}, "Neon Genesis Evangelion", 1995)
|
|
assert "<tvshow>" in nfo and "</tvshow>" in nfo
|