Commit Graph
19 Commits
Author SHA1 Message Date
HitonabiandClaude Opus 5 35370fd552 fix(windows): Cover, Arbeitsverzeichnis und die zurueckgelassenen _MEI-Ordner
Drei Befunde des Commanders vom 28.08.2026, alle drei gemessen.

## 1. „Was ist mit dem Cover auf Windows Rippy?"

Es gab keins, weil es keinen Treffer gab. `_scan_video` verlangte woertliche
Gleichheit:

    if movie.get("title", "").lower() == kandidat.lower():

An seiner Disc gemessen:

    'Evangelion 2.22'    1 Treffer   Evangelion: 2.0 You Can (Not) Advance
    'Evangelion'        20 Treffer   irgendein Evangelion

Der EINZIGE Treffer auf den vollen Disc-Titel war der richtige Film, mit
Poster — und wurde verworfen. Jetzt zaehlt die SPEZIFITAET der Anfrage: Wer
auf den vollen Disc-Titel hoechstens drei Treffer bekommt, hat gefragt wie
jemand, der weiss was er sucht. Ergebnis an derselben Disc:

    Evangelion: 2.0 You Can (Not) Advance / 2009 / 80 % / Poster + dt. Text

## 2. „Warum heisst das hier noch container platte? … Waere es moeglich das
##     Arbeitsverzeichnis zu aendern? momentan geht das nicht."

Beide Haelften gehen auf EINE Zeile zurueck: `MEDIA_ROOT = "/app/media"` war
zugleich Vorgabe UND Pfadgrenze. Auf Windows gibt es den Ordner nicht:

* `/storage-targets` fing den OSError und gab still [] zurueck — die Auswahl
  hatte genau einen Eintrag. Das ist „momentan geht das nicht".
* Dessen Text war fest verdrahtet „(Container-Platte)".
* `/browse` antwortete auf jeden Pfad mit 422.

Die Grenze faellt nicht weg, sie wird betriebsabhaengig: Container und
Kopflos-Betrieb bedienen ein Netz, die native App den Menschen davor.
Gemessen auf seinem PC: 7 Laufwerke zur Auswahl, X/Y/Z mit je 2,2 TB frei.

## 3. „Failed to remove temporary directory: …_MEI0000b0882"

GEMESSEN: 20 zurueckgelassene _MEI-Ordner mit 1,1 GB. Ursache: `Popen` ohne
`env=` reicht PyInstallers Auspack-Zeiger an die Kinder weiter (--dienst und
--oeffnen). Beide laufen dann im Ordner des Elternprozesses, der sich zuerst
beendet und ihn loeschen will. Waere das TEILWEISE geglueckt, haetten Dienst
und Fenster mitten im Betrieb ihre Dateien verloren.

Nebenbefund: test_setup_fenster scheiterte in jeder Umgebung ohne pywebview.

794 Tests gruen, ruff sauber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 16:43:41 +02:00
HitonabiandClaude Opus 5 be3fac53af fix(prescan): makemkvcon ueber den Katalog suchen, nicht ueber shutil.which
Ampel / ampel (push) Successful in 55s
Auf die Frage des Commanders: "du hast jetzt nur mein laufwerk analysiert
oder? wenn ich rippy weitergebe wie laeuft es dort?"

Berechtigt -- und beim Nachsehen fiel derselbe Fehler auf wie heute Vormittag
im Werkzeug-Katalog:

    shutil.which("makemkvcon")   ->  None, auch bei installiertem MakeMKV

`which` sucht nur im PATH. Windows-Programme liegen in "Programme". Der
Zweig, der die Titelliste von makemkvcon holt, lief unter Windows also NIE --
unabhaengig vom Laufwerk, auf jedem Rechner. Jetzt ueber
`katalog.finden("makemkv")`, das genau dafuer da ist.

Dazu vier Tests fuer Disc-Arten, die ICH NICHT HABE, damit die Zusage nicht
an einer einzigen Disc haengt:

    Blu-ray ohne BDMV/META   -> None (sehr haeufig; Rueckfall aufs Label)
    DVD (nur VIDEO_TS)       -> None
    bdmt_deu.xml vorhanden   -> Titel wird gelesen
    deu + eng vorhanden      -> eng gewinnt (APIs suchen damit besser)

Und ein Waechter gegen shutil.which in prescan.py. Der erste Anlauf davon
fiel ueber den eigenen Erklaertext, in dem der alte Aufruf zitiert wird --
er prueft jetzt nur Code, keine Kommentare.

Ampel lokal: 774 gruen, ruff sauber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 16:05:25 +02:00
HitonabiandClaude Opus 5 878b24c43b fix: die Metadaten-Suche war seit V2-1 tot — auf Windows UND auf der VM
Ampel / ampel (push) Successful in 54s
Der Commander: "TMDB und OMDB Key sind hinterlegt, das laufwerk wird aber
auch nicht korrekt ausgelesen. Eigentlich sollte er direkt bei TMDB oder OMDB
oder JIKAN anfragen nach metadaten."

Er hat das Symptom gemeldet. Darunter lagen VIER Fehler.

## 1. Ein Phantom-Modul (der schwerste)

    clients/tmdb.py:27     from db import get_settings
    clients/omdb.py:36     from db import get_settings
    clients/thetvdb.py:16  from db import get_settings

`docker/api/db.py` gibt es seit der Zusammenlegung in V2-1 (dd1d0b7) nicht
mehr; main.py schreibt seitdem `from rippy import store as db`. Diese drei
Module haben es nie mitbekommen.

Damit starb JEDE Metadaten-Abfrage schon beim Erzeugen des Clients mit
ModuleNotFoundError -- und `_auto_prescan` verschluckte das in seinem
`except Exception`. Die Disc blieb namenlos, und niemand sah warum.

**Das betrifft die VM genauso.** Sie steht auf 05ab655, also NACH dd1d0b7 --
dort laeuft seit V2-1 dieselbe tote Metadaten-Suche.

## 2. Redis war Pflicht statt Beschleunigung

`cache/cache.py` sprach `redis:6379` an -- den Dienstnamen aus
docker-compose.yml. Auf einem Windows-PC gibt es kein Redis:

    redis.exceptions.ConnectionError: Error 11001 connecting to redis:6379

Das riss den Pre-Scan mit. Ein Zwischenspeicher ist eine Beschleunigung,
keine Voraussetzung: Jetzt faengt jeder Zugriff den Verbindungsfehler ab und
meldet "nicht vorhanden" -- was der Wahrheit entspricht. Gemeldet wird der
Ausfall EINMAL, nicht bei jeder Anfrage.

## 3. Der Klartext-Titel war unter Windows nicht erreichbar

`read_disc_title_via_mount` machte fest `mount -t udf` -- also Linux. Unter
Windows haengt Windows die Disc selbst ein. An der echten Disc gemessen:

    Volume-Label (UDF)          BD_EVG_D2      <- damit findet keine API etwas
    BDMV/META/DL/bdmt_deu.xml   Evangelion 2.22

`disc_wurzel()` liefert jetzt je Plattform einen lesbaren Einstieg, und
`titel_aus_bdmt()` ist davon getrennt (und damit ohne Disc pruefbar).

## 4. Modell und Seriennummer fehlten

Im UI stand "Modell: unbekannt, Seriennummer: -". Der Linux-Treiber liest
beides aus /sys; der Windows-Treiber lieferte leere Felder. Die Entsprechung
ist IOCTL_STORAGE_QUERY_PROPERTY. An echter Hardware gemessen:

    hersteller     'HL-DT-ST'
    modell         'BD-RE BU40N'
    fassung        '1.03'
    seriennummer   '0025114C0149'

Gemerkt statt jedes Mal abgefragt: Die Disc-Wache ruft device_info alle drei
Sekunden, und die Angaben eines Laufwerks aendern sich nicht.

## Ergebnis, an der eingelegten Disc gemessen

    title        'Neon Genesis Evangelion'
    year         1995
    disc_type    'Blu-ray'
    confidence   0.8
    fingerprint  'BD_EVG_D2|48149364736'

(Jikan antwortete waehrend der Messung mit 504 -- deren Ausfall, nicht
unserer. Der Treffer kam von TMDB.)

Zwei Waechter, beide beim Zurueckdrehen rot gesehen: Die Clients muessen sich
OHNE Datenbank und OHNE Redis bauen lassen, und ein `from db import` in
clients/ faellt mechanisch auf.

Ampel lokal: 769 gruen, ruff sauber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 15:59:47 +02:00
HitonabiandClaude Opus 5 3d7f3b1680 feat(drives): V2-4 (Teil 2) — main.py laedt unter Windows, Treiber gemessen
Ampel / ampel (push) Failing after 46s
WAS: rippy/drives/__init__.py waehlt den Treiber fuer DIESE Maschine.
main.py und prescan.py fragen ihn, statt fest den Linux-Treiber zu
importieren. Damit ist der Blocker fuer den nativen Windows-Betrieb weg.

GEMESSEN, vorher (frische Python-3.12-Umgebung unter Windows):
  >>> import main
  ModuleNotFoundError: No module named 'fcntl'

GEMESSEN, nachher:
  main.py laedt unter Windows: JA
    Treiber:   rippy.drives.windows
    Routen:    61
    Laufwerke: ['\\.\G:']

Der Import stand in rippy/drives/linux.py -> detection.py -> fcntl. Genau
dafuer gibt es den Port: Der Aufrufer sagt WAS, nicht WIE. test_treiberwahl.py
haelt ausserdem fest, dass BEIDE Treiber denselben Satz Funktionen anbieten —
sonst faellt eine fehlende erst im Betrieb als AttributeError auf, und zwar
auf der anderen Plattform.

DER TREIBER AN ECHTER HARDWARE (LG BU40N extern, Laufwerk G:, LEER):
  GetDriveTypeW("G:\\")              -> 5 (DRIVE_CDROM)
  list_optical_devices()             -> ['\\.\G:']
  CreateFileW(r"\.\G:")             -> Handle 380
  CHECK_VERIFY2 bei leerem Laufwerk  -> ERROR_NOT_READY (21)
  drive_status()                     -> 1 (CDS_NO_DISC)
  detect_disc_type()                 -> 'no_disc'
  device_info()['status']            -> 'empty'
  MEDIA_REMOVAL (entriegeln)         -> Erfolg,   0,1 ms
  EJECT_MEDIA                        -> Erfolg, 664,8 ms

Die 664,8 ms sind der Beleg, dass wirklich etwas passiert ist: Ein
abgelehnter Steuercode kommt in rund 2 ms zurueck.

BEFUND, DER EIN PLACEBO VERHINDERT HAT: IOCTL_STORAGE_LOAD_MEDIA (Schublade
einziehen) antwortet auf diesem Laufwerk mit ERROR_INVALID_FUNCTION. Bei
flachen und externen Laufwerken ist das die Regel. Deshalb gibt es bewusst
KEINE einziehen()-Funktion — ein Knopf "Schublade schliessen", der auf der
Haelfte aller Laufwerke stillschweigend nichts tut, waere genau die Sorte
Placebo, die in Etappe 19 aufgeraeumt wurde.

Dazu eine DeprecationWarning behoben: '\G' im Docstring ist keine gueltige
Escape-Sequenz und waere in einer kuenftigen Python-Version ein harter Fehler.

NOCH NICHT gemessen: das Verhalten MIT eingelegter Disc (Typ-Erkennung ueber
die Groesse, und ein Auswurf, bei dem wirklich etwas drin ist).

GEMESSEN: ruff sauber, 429 Tests gruen + 13 uebersprungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 09:55:15 +02:00
HitonabiandClaude Opus 5 b98dc5eef5 refactor(core): V2-0 — gemeinsames Paket rippy statt drei Zwillingsdateien
Ampel / ampel (push) Successful in 41s
WAS: Neues Paket src/rippy (core/drives/rip). detection.py,
makemkv_daten.py und notify.py lagen je ZWEIMAL im Repo — unter
docker/api UND docker/worker, byte-identisch. Jetzt gibt es sie einmal;
beide Container importieren dieselbe Datei. Verhalten unveraendert.

WARUM: Es gab kein geteiltes Paket zwischen den Containern, deshalb die
Kopien. docker/api/db.py sagt es im Kopfkommentar selbst: "Wer die
Struktur aendert, aendert BEIDE Dateien." Ein Waechter-Test
(test_zwillinge_sind_byteweise_identisch) hat das mechanisch
abgesichert — er war noetig, weil die Konstruktion falsch war. Erste
Etappe des v2-Plans (KONZEPT-V2.md §8.3).

IM EINZELNEN:
- src/rippy/{core/notify, drives/detection, rip/makemkv_daten}.py
- conftest.py in der Wurzel legt src/ auf den sys.path (die Ampel ruft
  pytest dort auf).
- Beide Dockerfiles kopieren src/rippy nach /app/rippy — /app ist
  Arbeitsverzeichnis und uvicorn-App-Dir, also ohne PYTHONPATH findbar.
- worker_setup_paket packt das Paket ausdruecklich mit ins Zip: die
  Schleife sah nur die oberste Ebene, ein Unterordner waere nie
  mitgekommen und der Windows-Worker beim Start gestorben.
- Die zwei Test-Dateien fuer makemkv_daten sind zu einer verschmolzen
  (die Faelle aus beiden). Damit entfaellt auch der importlib-Umweg im
  Worker-Test: der war noetig, weil bei "pytest -q" aus der Wurzel
  docker/api zuerst eingesammelt wird und jeder weitere Import nur noch
  den sys.modules-Cache trifft — die Worker-Kopie wurde also nie
  angefasst. Netto -13 doppelte Tests, +2 neue (siehe unten).

EIN FEHLER, DEN DER UMBAU FAST AUSGELIEFERT HAETTE: In tasks.py steht
der detection-Import in einem "try/except ImportError" — absichtlich,
denn der native Windows-Worker hat kein fcntl und soll trotzdem
starten. Das except verschluckt aber JEDEN ImportError, auch einen
falschen Modulpfad. Auf Linux haette der Worker ab sofort still
detect_disc_type=None gesetzt und jeden Rip verweigert, ohne dass
irgendwo ein Fehler stuende — genau die Klasse "still scheiternder
Hintergrund-Prozess" aus AGENTS.md. Gefunden ueber eine zweite Suche
mit eingerueckten Treffern.

Waechter dagegen: src/rippy/test_paket.py prueft mit
importlib.util.find_spec (fuehrt nichts aus, laeuft also auch auf
Windows ohne fcntl), dass es die drei Modulpfade wirklich gibt. Beim
Wegnehmen von detection.py gegengeprueft: Test wird rot, nach
Wiederherstellen gruen.

GEMESSEN: ruff sauber, 290 Tests gruen + 1 uebersprungen (lokal, ohne
die zwei Linux-only-Module). Kein Modul liegt noch doppelt im Repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 08:38:29 +02:00
HitonabiandClaude Opus 5 0c269a97ee fix(metadaten): exakt schlaegt unscharf - Jikan beendet die Kette nur bei Treffer
Der SAVEPOINT v3.16 vermutete, das Aehnlichkeits-Gate 0,55 sei "grosszuegig" und
Jikan stehe in der Kette zu frueh (vor OMDb). Nachgerechnet - titel_aehnlichkeit
ist eine reine Funktion - ergibt sich ein anderes Bild als vermutet:

  "Alien"           vs. "Alien 9"           -> 0,83  TRIFFT
  "Inception"        vs. "Deception"         -> 0,78  TRIFFT
  "Hero"             vs. "Heroman"           -> 0,73  TRIFFT
  "The Dark Knight"  vs. "Dark Knight Rises" -> 0,69  TRIFFT

Ein Kinofilm, den TMDB verpasst, bekam damit Anime-Metadaten mit Confidence
0,85 - und OMDb, das ihn kennt, wurde nie gefragt.

Bemerkenswert dabei, und das widerlegt die Vermutung "einfach zu niedrig": Fuer
den Fall, fuer den Jikan ueberhaupt eingebaut wurde, ist das Gate sogar zu HOCH.
"Evangelion 2.22" gegen den MAL-Titel "Evangelion: 2.0 You Can (Not) Advance"
ergibt 0,51 und faellt durch. Eine einzelne Zahl kann beides nicht leisten.

Deshalb zwei Schwellen statt Umsortieren (Reihenfolge bleibt, AGENTS Regel B):
Nur ein praktisch exakter Titel (>= 0,9) beendet die Kette. Ein unscharfer
Treffer wird GEMERKT, dann wird OMDb gefragt - und erst wenn OMDb nichts hat,
kommt er als VORSCHLAG mit Confidence 0,6 zum Zug. Damit gewinnt "exakt" immer
gegen "unscharf", egal aus welcher Quelle.

Antwort auf die Commander-Frage "JIKAN ist drin - wird das genutzt?": ja, und ab
jetzt an der richtigen Stelle.

Ehrlicher Vorbehalt: Live gegengeprueft ist das nicht - MyAnimeList war waehrend
dieser Sitzung durchweg weg (Jikan antwortete HTTP 504 auf jede Anfrage). Die
Arithmetik des Gates ist davon unberuehrt und in test_jikan_helpers.py
festgehalten, die Kettenlogik in test_prescan_helpers.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 12:59:26 +02:00
HitonabiandClaude Fable 5 8eb5653848 Restefeger: Auth komplett raus, Serien-Flow + Episoden-Matching, Jellyfin-Refresh, Duplikat-Warnung, echtes Nur-Hauptfilm
Ampel / ampel (push) Successful in 55s
AUTH ENTFERNT (Commander-Entscheid 24.07., KONZEPT §10): /token- und
/api-keys-Endpoints, auth.py, test_auth.py, passlib/bcrypt/PyJWT/
python-multipart, JWT_SECRET_KEY-Pflicht. Heimnetz-only, das UI hatte nie
einen Login — die Auth-Oberflaeche war Placebo und die passlib/bcrypt-
Falle brach die Ampel. Rate-Limit pro IP bleibt. Schnellstart laeuft
jetzt ganz ohne .env-Pflichtwerte.

Serien-Flow (Etappe-12-Kern, ARM-Wunde #395):
- Rip-Dialog: Serienname + Staffel -> Ablage <Serie>/Season NN
  (jellyfin.org/docs Naming-Schema); tvshow.nfo + poster.jpg im
  Serien-Ordner, bei Staffel 2 nicht ueberschrieben.
- Episoden-Matching per Laufzeitabgleich: HandBrakeCLI --scan
  ('+ duration:', handbrake.fr/docs) je MKV gegen TMDB-Staffel-Laufzeiten
  (GET /metadata/tv/{id}/season/{n}; tv-season-details-API).
  Ordnungserhaltend; komplette Staffel auf einer Disc klappt auch bei
  uniformen Anime-Laufzeiten (Sequenz-Stufe). Umbenannt wird NUR bei
  eindeutiger Zuordnung — sonst ehrliches Log. Mit Tests.

Weitere Punkte:
- Jellyfin/Emby-Bibliotheks-Refresh nach jedem fertigen Rip
  (POST /Library/Refresh, X-Emby-Token lt. jellyfin.org/docs) —
  URL/Key + Test-Knopf in Einstellungen -> Ripping.
- Duplikat-Warnung: Disc-Fingerabdruck (jetzt Teil des Prescan-Ergebnisses
  + der Job-Metadaten) gegen die Historie; Karte zeigt 'bereits gerippt',
  Vollautomatik ueberspringt Duplikate.
- 'Nur Hauptfilm' ECHT: makemkvcon info -> TINFO-Attr-9-Laufzeiten
  (usage.txt) -> laengster Titel -> mkv dev:X <nr>. Vorher wirkungsloses
  Setting; pro Rip im Dialog uebersteuerbar. Mit Tests.
- OMDb-Treffer eingedeutscht via TMDB /find (external_source=imdb_id,
  de-DE; find-by-id-API).
- Dashboard: Speicherplatz-Anzeige (amber < 60 GB) + CSV-Export
  (GET /jobs/export, Semikolon+BOM fuer deutsches Excel).
- Metadaten-Seite entfernt (Abnahme durch Commander-Auftrag) inkl.
  Placebo-Endpoints /metadata/lookup (scannte Dummy-Device) und
  /metadata/confirm (schrieb nie gelesenen Cache-Key).
- Doppel-Jahr-Fix: 'X (2009) (2009)' in Log und Ordnernamen.
- Remote-Worker-Blocker: redis (6379) + postgres (5432) waren NIE
  veroeffentlicht — kein Remote-Worker konnte sich je verbinden. Ports
  jetzt offen (Heimnetz-Kompromiss, kommentiert) + API_URL fuer Worker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 14:22:19 +02:00
HitonabiandClaude Fable 5 5778ac4645 Praxis-Feedback-Runde: CIFS-Cap-Fix, TMDB v3-Keys, 4K-UHD-Typ, Vollautomatik, Job-Verwaltung, Worker-Namen
Ampel / ampel (push) Successful in 29s
Zwei bewiesene Bug-Fixes:
- SMB-Mount 'Unable to apply new capability set': mount.cifs hebt
  CAP_DAC_READ_SEARCH an, die in Dockers Default-Caps fehlt (auf der VM
  reproduziert: Bounding-Set a82425fb ohne Bit 2; mit der Capability
  verschwindet der Fehler). Fix: cap_add DAC_READ_SEARCH fuer den
  api-Container.
- TMDB fiel still aus: Client konnte nur v4-Bearer-Tokens, der uebliche
  32-Hex-v3-Key bekam 401 und die Suche lieferte nur OMDb. Jetzt beide
  Key-Arten (ist_v4_token + api_key-Query-Param lt.
  developer.themoviedb.org, mit Tests) — damit kommen auch die deutschen
  Texte an (language=de-DE war ueberall schon gesetzt). Neu:
  GET /metadata/status + 'Verbindung pruefen' in Einstellungen -> APIs
  (Live-Check am Cache vorbei).

Features aus dem Commander-Feedback:
- 4K UHD als eigener Disc-Typ: classify >= 55 GiB (BD-66/BD-100; BD-50
  bleibt bluray), beide detection.py + Tests, eigene Badge-Farbe in
  Dashboard/Laufwerken, Prescan-Label '4K UHD'. UHD-Rip-Fehler 'Failed to
  open disc' (Code 11) bekommt Klartext: LibreDrive-Firmware noetig.
- Vollautomatik (Setting autoRipStart): Disc erkannt -> Rip startet ohne
  Popup in den Schnellwahl-Ordner (Serie->Serien, sonst Filme, CD->Musik).
- Job-Verwaltung: 'Neu komprimieren' nur noch mit can_retry (Rohdaten
  liegen wirklich da), DELETE /jobs/{id} + 'Erledigte aufraeumen'
  (Dateien bleiben immer), 'Alle herunterladen' im Job-Detail
  (gestaffelte Einzel-Downloads statt Server-Zip von 40-GB-Dateien).
- Worker zuordenbar: WORKER_NAME-Env als stabiler Anzeigename (fixt auch
  die Offline-Leichen nach Rebuilds), info.hostname/ip gemeldet,
  Online-Abgleich ueber hostname, DELETE /workers/{name} + Papierkorb im
  UI, Quelle-Anzeige an der Disc-Karte ('Quelle: TMDB - 99 % sicher').
- Ripping-Tab nach Medium gegliedert (Video/Audio-CD/Allgemein) +
  Untertitel-Klartext (--all-audio/--all-subtitles bleiben komplett),
  CD -> Musik-Vorauswahl im Ziel-Dialog, Ordner-Verwaltung beschriftet
  und standardmaessig eingeklappt.
- Docs: SAVEPOINT v3.3, ROADMAP Etappe 14 + Ideen (nativer
  Windows-Worker, deutsche OMDb-Texte via TMDB-Find), README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 13:29:10 +02:00
HitonabiandClaude Fable 5 6b7d391737 Korrektur-Flow + Freigaben-Auswahl + Schreibtest + Schnellwahl-Klartext
Ampel / ampel (push) Failing after 52s
Commander-Befunde (23.07. spaet):
- MANUELLE KORREKTUR (KONZEPT Schritt 5 endlich komplett): Metadaten-Seite
  hat jetzt Titelsuche ueber ALLE Quellen (GET /metadata/search) mit
  Poster-Kacheln; ein Klick uebernimmt den Treffer (POST /metadata/override)
  fuer Karte, Jobs UND merkt ihn sich 30 Tage per Disc-Fingerabdruck —
  dieselbe Disc wird beim naechsten Einlegen sofort richtig erkannt
- PC/NAS per Klick: SMB-Freigaben eines Rechners auflisten
  (GET /storage-mounts/shares via smbclient) statt //host/share raten
- Berechtigungs-PRUEFUNG beim Einhaengen: Schreibtest, Warnung bei
  nur-lesbaren Zielen (API + UI + Log)
- "Standard-Unterordner" verstaendlich gemacht: heisst jetzt "Schnellwahl
  beim Rippen" mit Erklaertext; kryptisches Basis-Feld raus
- Preview zeigt Poster; Fingerprint fuer Cache/Override vereinheitlicht
  (billiges Label+Groesse statt Mount-Titel)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:34:34 +02:00
HitonabiandClaude Fable 5 37711f87c1 Jikan-Retry bei 504 + Cache-Verfall fuer mittelgute Prescan-Treffer
Ampel / ampel (push) Failing after 39s
Jikan (Gratis-Dienst) wirft sporadisch 504 — ein Retry mit 2s Pause;
aktuell ist der Dienst ganz down, die Kette faellt sauber auf OMDb.
Prescan-Cache: 0.6-0.9 verfaellt nach 1 Tag, ab 0.9 nach 7 Tagen —
sonst wuerde ein frueher OMDb-Treffer bessere Quellen fuer immer blocken.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:25:10 +02:00
HitonabiandClaude Fable 5 07be54e62a Jikan/MAL-Quelle + Job-Titel + Abbrechen-Knopf + Dark-Hover + Ordner-Verwaltung
Ampel / ampel (push) Failing after 38s
Commander-Befunde (Screenshots 23.07. abends):
- Jikan (MyAnimeList, kostenlos OHNE Key) als Anime-Quelle vor OMDb —
  waehlt per Titel-Aehnlichkeit (SequenceMatcher, Schwelle 0.55) statt
  blind Treffer 1; damit trifft "Evangelion 2.22" den exakten Film
- Job-Titel: POST /jobs uebernimmt den erkannten Disc-Titel aus dem
  DISC_CACHE — Schluss mit "Unbekannt" in der Queue
- Kooperativer Job-Abbruch: POST /jobs/{id}/cancel setzt canceling,
  der Worker prueft das Flag bei jedem Fortschritts-Update und killt
  den Encoder-Prozess sauber (RipAbbruch); UI-Knopf "Abbrechen" fuer
  laufende, Status-Badge "Wird abgebrochen"
- Dark-Mode: Job-Zeilen-Hover war hart hell (hover:bg-slate-50)
- Speicherziele: lokaler Ordner-Browser mit "Ordner anlegen"
  (GET /browse + POST /browse/mkdir, nur unter /app/media)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:22:57 +02:00
HitonabiandClaude Fable 5 f2d5961c33 Metadaten-Feinschliff: Wort-Strip-Degradation + kein Caching von "unknown"
Ampel / ampel (push) Failing after 40s
- titel_kandidaten strippt hintere Worte iterativ bis auf eins
  ("Evangelion 2.22" wird auch als "Evangelion" gesucht — OMDb braucht das)
- Nur Treffer ab Confidence 0.6 landen im Redis-Cache: ein gecachtes
  "unknown" wurde sonst auch nach Key-Eintrag ewig wieder serviert
  (Redis ist persistent; Alt-Eintraege auf der VM geloescht)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:10:15 +02:00
HitonabiandClaude Fable 5 90eb17d407 UX-Runde: echte Disc-Titel via BD-Metadaten, Preview-Crash, Dashboard, Ziele
Ampel / ampel (push) Failing after 38s
Commander-Befunde 23.07. abends:
1. Metadaten "klappen nicht": Wurzel = kryptisches Volume-Label + kein
   TMDB-Key. Jetzt: API mountet die Disc read-only (CAP_SYS_ADMIN ist da)
   und liest den KLARTEXT-Titel aus BDMV/META/DL/bdmt_*.xml; dazu
   progressive Suchdegradation (Titel-Varianten) und OMDb-Unscharf-Suche
   (s= + imdbID-Nachladen) — mit dem vorhandenen OMDb-Key gibt es damit
   Titel/Jahr/Poster auch ohne TMDB
2. Weisses Fenster beim Pre-Scan: Lucide-Icons sind forwardRef —
   Direktaufruf getIcon(...)({size}) crashte die Seite; als JSX gerendert
3. Dashboard sortiert: System-Leiste (Encoder + aktiver Job) oben,
   Disc/Geraete -> Stats -> Jobs, Live-Log ans Ende
4. Ziel-Dialog mit ORDNER-BROWSER (GET /browse, nur unter /app/media);
   Schnellwahl nutzt die Settings-Unterordner statt Hartkodierung;
   Tab "Verzeichnisse" in "Speicherziele" aufgegangen (redundant)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:07:55 +02:00
HitonabiandClaude Fable 5 7652afe955 Deploy-Befunde gefixt: Disc-Typ-Verlust, giftiger Prescan-Cache, caps-Import
Ampel / ampel (push) Failing after 28s
- Pre-Scan verlor den erkannten Typ (BDs hiessen immer "DVD"): scan()
  reicht disc_type jetzt in die Zweige durch
- GIFTIG: Cache-Key nur aus Geraetepfad — die naechste Disc im selben
  Laufwerk haette die Metadaten der vorherigen geerbt. Key enthaelt jetzt
  einen Disc-Fingerabdruck (Label|Groesse)
- Worker-Faehigkeiten: import caps auf Modulebene — im worker_ready-Signal
  war /app nicht mehr im sys.path (ModuleNotFoundError im Deploy-Log)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 20:54:14 +02:00
HitonabiandClaude Fable 5 2474b683e2 Transcode-Stufe: HandBrake komprimiert NACH dem MakeMKV-Rip + --noscan-Fix
Ampel / ampel (push) Successful in 34s
Commander-Entscheid 23.07.: 40-GB-Rohdateien sind kein brauchbares
Endprodukt. Architektur bleibt zweistufig, weil HandBrake AACS nicht
lesen kann: MakeMKV rippt verlustfrei nach /app/temp/raw, HandBrake
macht daraus x265 auf Arbeitsgroesse in /app/media, Roh-Verzeichnis
wird erst NACH komplettem Erfolg geloescht (keepOriginal behaelt es).

- Worker: handbrake-cli im Image, run_handbrake + _komprimiere,
  Job-Status "transcoding", Settings aus Postgres (transcodeEnabled/
  Preset/keepOriginal), Fortschritt je Datei aggregiert
- makemkvcon: --noscan im Kommando verankert — der Geraete-Scan haengt
  (1.18.4) bzw. crasht (1.17.7) im Container, mit --noscan + dev:-Pfad
  laeuft es (Befund 23.07., DRV-Zeile beweist Laufwerks-Erkennung)
- UI: Settings-Tab "Verarbeitung" (Toggle/Preset/Original behalten),
  Status-Badge "Komprimieren", LiveLog erkennt transcoding als aktiv
- KONZEPT/ROADMAP entsprechend aktualisiert; Tests fuer HandBrake-Cmd
  (arbeitet auf DATEI, nie am Geraet) und Progress-Regex

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:56:37 +02:00
HitonabiandClaude Fable 5 bd6409038e UDF-Volume-Label-Leser (Blu-rays haben keine ISO-Bridge) + Etappe 12 (ARM)
Ampel / ampel (push) Successful in 35s
Praxis-Befund mit echter BD-50: reines UDF, der ISO-PVD-Leser griff nicht.
Jetzt ECMA-167-Weg (AVDP Sektor 256 -> Main VDS -> PVD Tag-ID 1 ->
Volume Identifier als d-string), mit Tests fuer das d-string-Parsing.

ROADMAP Etappe 12 aus der ARM-Vollanalyse: was wir uebernehmen
(Fingerprint-DB, bdmt_eng.xml, Suchdegradation, Manual Mode, Apprise,
Multi-Drive, Backup-Modus) und wo wir ARM schlagen (Serien-Episoden-
Matching, Main-Feature per Laufzeitabgleich).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:33:27 +02:00
HitonabiandClaude Fable 5 5528e0f652 Metadaten-Fallback OMDb + Pre-Scan repariert + Eject-Endpoint
- clients/omdb.py: OMDb als zweite Quelle (Fallback-Kette: TMDB exakt ->
  OMDb -> bester TMDB-Vorschlag mit niedriger Confidence -> unknown)
- Pre-Scan-Reparatur: Titel kam nie an — makemkvcon existiert nur im
  Worker, isosize war nirgends installiert (fiel still auf "DVD" zurueck).
  Jetzt: ISO-9660-Volume-Label direkt vom Medium + Label-Normalisierung
  (PULP_FICTION -> Pulp Fiction), Disc-Typ ueber zentrale detection.py
- POST /devices/{name}/eject (CDROMEJECT-ioctl) mit Job-Schutz (409 wenn
  auf dem Laufwerk gerade gerippt wird)
- OMDB_API_KEY in compose/.env.example; .env.example komplett ehrlich
  dokumentiert (JWT-Pflicht, MakeMKV-Beta-Key-Rhythmus)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:30:09 +02:00
Hitonabi 0ea5f10b31 Fix-Runde nach Review: alle Befunde behoben + echte Tests
Ampel / ampel (push) Failing after 12m31s
- Metadaten-Preview WIEDERHERGESTELLT (Stub ueberschattete echte
  prescan-Implementierung), tote Altmodule geloescht
- Celery update_state statt Phantom-Task/erfundener API
- abcde-Kommando korrigiert (CD-Ripping war nie funktionsfaehig)
- JWT: fester Schluessel Pflicht, echtes Logout, Cleanup nur Abgelaufene
- main.py: crashende Endpoints (Path/secrets/api_keys), year-Bug,
  Admin-Login aus .env
- Ruff gruen (29 Funde), Tests: auth/cache_keys/ripping_helpers,
  Placebo-test_health raus
- SAVEPOINT: offene MakeMKV-Entscheidung SICHTBAR gemacht (Regel B)
2026-07-22 19:31:48 +02:00
Hitonabi ba2429612a rippy-ui-modern: API UI Modernisiert & Import-Fixes
- Doppelte Arcane-Einträge behoben (rippy statt Rippy) - Import-Fixes: relative → absolute imports in main.py, cache/__init__.py, prescan/__init__.py, clients/__init__.py - Neue Dateien: cache.py, prescan.py, Settings.tsx - API-Port 8000 in docker-compose.yml gemappt - UI mit Sidebar, Dark Mode, Einstellungen-Tabs

Fixes: #2978 (doppelte Einträge), #2888 (Import-Fehler)
2026-07-21 22:08:03 +02:00