From 397e667af2485ea6cb5dbd2c08430a0a929124aa Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Sun, 7 Jun 2026 20:17:26 +0200 Subject: [PATCH] chore: tidy tasks/todo.md (archive completed work, keep open backlog) --- tasks/todo.md | 190 +++++++++++--------------------------------------- 1 file changed, 41 insertions(+), 149 deletions(-) diff --git a/tasks/todo.md b/tasks/todo.md index 496c7a0..73b7fd9 100644 --- a/tasks/todo.md +++ b/tasks/todo.md @@ -1,159 +1,51 @@ -# Erweitertes Logging (2026-06-07) — Goal: Tool besser kontrollieren bei Problemen/Fehlern +# Real-Debrid-Downloader — Tasks (Stand 2026-06-07) -Recon (4-Agent-Workflow) fand 40+ Lücken. Bewusste Scope-Disziplin: NICHT alle 40 -instrumentieren (die meisten leeren catches sind legitimes Cleanup → würden das Log -fluten). Fokus: strukturelle Sichtbarkeit für unbeaufsichtigten Windows-Server, wo -"Crash/Hang ohne Log" der schlimmste Fall ist. Advisor-gegengeprüft. - -## Tier 1 — Prozess-/Renderer-Crash-Sichtbarkeit (höchster Wert) -- [ ] main.ts: `render-process-gone` (+ Auto-Reload mit Circuit-Breaker max 3/5min) -- [ ] main.ts: `app.on("child-process-gone")` (GPU/Utility/Renderer-Subprozesse) -- [ ] main.ts: `webContents.on("unresponsive"/"responsive")` — NUR loggen, nie killen -- [ ] main.ts: `process.on("warning")` (Node-Warnungen, z.B. MaxListenersExceeded) -- [ ] Renderer-Fehler-Capture: window.onerror + unhandledrejection + React ErrorBoundary - → über neuen Einweg-IPC `LOG_RENDERER_ERROR` ins Main-Log (kein stilles White-Screen) -- [ ] Memory-Heartbeat: im vorhandenen runtimeStatsTimer (60s), warn bei heapUsed/heapTotal > 0.9 - -## Tier 2 — Logging-Infrastruktur -- [ ] logger.ts: DEBUG-Level, gated über `RD_DEBUG` env (no-op wenn aus → keine Format-Kosten) -- [ ] error-ring.ts (NEU, pure+getestet): letzte N WARN/ERROR im RAM, gefüttert im write()-Chokepoint -- [ ] debug-server.ts: `/errors` Endpoint -- [ ] support-bundle.ts: overview/recent-errors.json - -## Tier 3 — Gezielte High-Value-Catches -- [ ] fs-error.ts (NEU, pure+getestet): classifyDiskError(err) — ENOSPC/EACCES/EROFS/EMFILE -- [ ] download-manager.ts: ENOSPC-Klassifizierung am vorhandenen Attempt-catch (reine Log-Anreicherung) -- [ ] download-manager.ts: Integrity-Check PASS ins item-log (Symmetrie: bisher nur Fail geloggt) - -## Verifikation — ERLEDIGT 2026-06-07 -- [x] Alle Tier 1/2/3 Punkte umgesetzt (siehe unten) -- [x] tsc = 6 (Baseline unverändert — eine versehentlich eingeführte `pkg`-Referenz sofort gefixt) -- [x] 728 Tests grün (715 Baseline + 13 neu: error-ring 5, fs-error/debug-gate 8), 41 Dateien -- [x] `npm run build` grün (tsup main 1.04MB + vite renderer 33 Module) -- [x] Grep-Konsistenz LOG_RENDERER_ERROR/reportRendererError über alle 5 Dateien (Kette lückenlos: - ipc.ts → preload-api.ts → preload.ts(send) → main.ts(ipcMain.on, einweg) → main.tsx + error-boundary.tsx) -- [x] Renderer-tsc-Abdeckung BEWIESEN (nicht angenommen): absichtlicher Typfehler in error-boundary.tsx - wurde von `tsc --noEmit` geflaggt → die neuen Renderer-Dateien sind echt typgeprüft (vite build prüft NICHT) -- [x] Advisor-Feinschliff: Memory-Heartbeat misst gegen `v8.getHeapStatistics().heap_size_limit` - (echte OOM-Decke) statt heapUsed/heapTotal — sonst Fehlalarm, der die Error-Ring zumüllt - -### Geänderte/neue Dateien -NEU: error-ring.ts, fs-error.ts, renderer/error-boundary.tsx, tests/error-ring.test.ts, tests/fs-error.test.ts -GEÄNDERT: logger.ts (DEBUG-Level+Gate+Ring-Feed), main.ts (4 Crash-Handler + Renderer-IPC), -app-controller.ts (Memory-Heartbeat), debug-server.ts (/errors), support-bundle.ts (recent-errors.json), -download-manager.ts (ENOSPC-Klassifizierung + Integrity-PASS-Log), shared: ipc.ts/types.ts/preload-api.ts, preload.ts, renderer/main.tsx - -### NOCH OFFEN -- [ ] Release (Gitea + GitHub-Mirror) — wartet auf User-Go ("jo mach releasen") +**Status: nichts hängt, nichts ist halbfertig.** Alle zugesagten Tasks sind erledigt +(siehe Archiv unten). Was hier offen steht, ist freiwilliger Backlog. --- -# Real-Debrid-Downloader — Analyse & Verbesserungen (2026-05-23) +## 🟢 OFFEN — Backlog (optional, nie begonnen) -Tiefe Analyse via 3 parallele Subagents (Bugs / Features / UI) + 4 Design-Mockups. +### Features / UX (nach ROI) +App läuft headless auf Windows-Server → Nutzer sitzt nicht davor. + +1. [ ] **Push-Benachrichtigungen** (Discord/Telegram/ntfy) — S–M. Paket fertig/Fehler/Quota/Provider-down aufs Handy. Neuer `notifier.ts`, Hooks an Completion-Punkten. **Höchster ROI.** +2. [ ] **Fernsteuerung über Debug-Server** (POST-Endpunkte) — S–M. Server hat HTTP + Token-Auth, aber nur GET. POST `/control/add-links`, `/start`, `/stop`. +3. [ ] **URL-Duplikat-Erkennung beim Hinzufügen** — S. History-`urls` existiert, wird nie geprüft → versehentliche Re-Downloads. Warnen: "3 Links bereits geladen". +4. [ ] **Pre-Flight-Check + Bulk-Skip toter Links** — M. Vor Start Größe/Name/Online für ganze Queue, "alle offline überspringen". +5. [ ] **Speicherplatz-Vorabprüfung vor Start** — S. Aktuell keine Free-Space-Prüfung für Downloads → Abbruch mitten drin bei voller Platte. +6. [ ] **Konsolidierte Fehler-Ansicht** — M. Alle fehlgeschlagenen Items flach + Fehlertext + "alle erneut versuchen". (Daten dafür liegen jetzt teils in der Error-Ring aus v1.7.185.) +7. [ ] **Per-Provider-Statistik** — M. Rohdaten (`providerTotalUsageBytes`) existieren, werden nicht dargestellt. Welches Abo lohnt sich? +8. [ ] **Auto-Retry fehlgeschlagener Pakete nach Wartezeit** — S–M. Quota/Cooldown-Fails am nächsten Tag automatisch neu. +9. [ ] **Plex/Jellyfin Library-Refresh nach MKV-Move** — S. Gleicher Hook wie #1. +10. [ ] **Watch-Folder für DLC/Link-Auto-Import** — M. + +### Design-Richtung (Entscheidung steht aus) +4 Mockups in `design-mockups/` (index.html = Vergleich): **Aurora** (verfeinert dark, geringstes Risiko) · **Command** (Terminal/Ops, dicht) · **Vellum** (light editorial) · **Nebula** (neon). +→ Richtung wählen. Siehe Memory: design-taste (Anti-KI-Look) + design-direction (Ember-Wärme, flach/ehrlich). + +### Alte Audit-Items (2026-04-04, Status ggf. veraltet — VOR Fix gegen aktuellen Code verifizieren) +- [ ] Debrid-Link `maxDataHost` kühlt ganzen Key ab statt nur den Host +- [ ] Debrid-Link `fileNotAvailable` setzt Key auf "error" statt temporär +- [ ] AllDebrid: kein per-host-Cooldown für erschöpfte Quotas +- [ ] LinkSnappy: keine Auth-Dedup (parallele Requests rufen beide authenticate()) +- [ ] Extractor password-cache race (parallele Worker mutieren `packageLearnedPasswords`) +- [ ] Hybrid race: 1 Datei/Staffel evtl. beim MKV-Move nicht umbenannt (NUR per-package fixen — Post-MKV-Move-Scan ist tabu, v1.7.107 revertiert) --- -## A. BUGS / ROBUSTHEIT (verifiziert gegen Quellcode) +## ✅ ERLEDIGT — Archiv (Details in git-History + Memory) -Roter Faden: Die **Deferred-Post-Processing-Pipeline** (eingeführt um den Extract-Slot schnell freizugeben) ist nur halb ins Abbruch-/Lifecycle-Management integriert. Genau der Bereich des v1.7.156-Fixes. +- **Erweitertes Logging** → released **v1.7.185** (Crash-Handler, Renderer-Fehler-IPC, RD_DEBUG-Level, Error-Ring + `/errors`, ENOSPC-Klassifizierung, Memory-Heartbeat). → Memory: extended-logging +- **Link-Prefetch** → untersucht (6-Agent) + **bewusst verworfen** (marginal bei maxParallel 8, Mega-Web single-flight). → Memory: link-prefetch-declined +- **Backup nur Settings** → v1.7.184 (`backupIncludeDownloads`-Toggle + 4 Selektions/Flicker-Fixes). → Memory: backup-settings-only +- **Account-Rotation-Overhaul** → v1.7.164–168 (Validity/Premium-Badges, Live-Panel, "Alle prüfen"). → Memory: account-rotation +- **Mega-Debrid-Account deaktivieren (UI)** → erledigt (Toggle im Edit-Dialog, im Code verifiziert 2026-06-07) +- **Bugs/Robustheit (Deferred-Pipeline H1/H2/H3/M1/M2/N1)** → v1.7.158/159; M3 bewusst übersprungen (Generation-Guard schützt Integrität bereits) +- **Deferred-Pfad Rename-Gap** → gefixt v1.7.162+ (finaler Deferred-Pass benennt frische Dateien vor Collect um; Repro-Test grün) +- **Repo-Privacy-Audit** → GitHub gelöscht+neu (saubere History), Gitea unberührt. → Memory: repo-privacy-audit -### HOCH -- [ ] **H1 — Globaler Stop/Shutdown bricht Deferred-Post-Processing nicht ab.** `abortPostProcessing` (download-manager.ts:7053) iteriert nur über `packagePostProcessAbortControllers`, nie über `packageDeferredPostProcessAbortControllers`. Bei Stop/Shutdown/clearAll laufen MKV-Move/Archiv-Cleanup/Rename weiter, während synchron persistiert wird → FS-Zustand ≠ Session-State (halb verschobene Datei, halb gelöschtes Archiv). -- [ ] **H2 — Hybrid-Post-Extract feuert MKV-Collection/Rename als losgelöstes Promise** (download-manager.ts:11334). In keiner Tracking-Map, kein `shouldAbort`. Cancel/Reset während Hybrid-Collect → Dateien werden trotzdem verschoben/gelöscht. -- [ ] **H3 — 0-Byte-Datei wird als vollständig akzeptiert** wenn keine Größeninfo (download-completion.ts:129, source "stream-end"). Hoster antwortet HTTP 200 ohne Content-Length + schließt sofort → Item "Fertig" mit leerer Datei, kein Auto-Redownload. - -### MITTEL -- [ ] **M1 — Deferred-Post-Extraction nicht in `packagePostProcessTasks`** (download-manager.ts:11974). Scheduler-Abschluss (8154) + finishRun (12310) sehen Deferred-Tasks nicht → Run-Ende/Summary feuert während noch Dateien verschoben werden, State-Reset mitten in FS-Arbeit. -- [ ] **M2 — `blockAllPersistence` wird nach Backup-Import nie zurückgesetzt** (app-controller.ts:678). Weiterarbeiten ohne Neustart → `persistSoon` ist dauerhaft No-Op → bei hartem Crash alle Änderungen weg. -- [ ] **M3 — `cancelPendingAsyncSaves` wartet nicht auf laufenden Async-Save** (storage.ts:1064). I/O-Overlap beim Import (Datenintegrität durch Generation-Guard geschützt, nur Robustheit). - -### NIEDRIG -- [ ] **N1 — Toter Code in `findReadyArchiveSets`** (download-manager.ts:10847). Unbedingtes `ready.add+continue` macht strengeren Disk-Fallback-Block (untracked-pending-Schutz) unerreichbar. - -**Empfehlung:** H1 + H2 + M1 zusammen fixen (eine kohärente Härtung der Deferred-Pipeline). H3 ist klein & unabhängig. M2 trivial. - ---- - -## B. FEATURES / UX-GAPS (nach Mehrwert/Aufwand) - -App läuft headless auf Windows-Server → Nutzer sitzt nicht davor. Größte Lücke: keine Benachrichtigungen. - -1. [ ] **Webhook/Push-Benachrichtigungen** (Discord/Telegram/ntfy) — S–M. Bei Paket fertig/Fehler/Quota/Provider-down aufs Handy. Neuer `notifier.ts`, Hooks an Completion-Punkten. **Höchster ROI.** -2. [ ] **Fernsteuerung über bestehenden Debug-Server** (POST-Endpunkte) — S–M. Server hat schon HTTP + Token-Auth, aber nur GET. POST `/control/add-links`, `/start`, `/stop` → vom Handy steuern. -3. [ ] **URL-Duplikat-Erkennung beim Hinzufügen** — S. History-`urls` existiert, wird aber nie geprüft → versehentliche Re-Downloads verschwenden Quota. Warnen: "3 Links bereits geladen". -4. [ ] **Vereinheitlichter Pre-Flight-Check + Bulk-Skip toter Links** — M. Vor Start Größe/Name/Online für ganze Queue, "alle offline überspringen"-Button. -5. [ ] **Speicherplatz-Vorabprüfung vor Start** — S. Aktuell keine Free-Space-Prüfung → Abbruch mitten im Download bei voller Platte. -6. [ ] **Konsolidierte Fehler-Ansicht** — M. Alle fehlgeschlagenen Items flach + Fehlertext + "alle erneut versuchen". -7. [ ] **Per-Provider-Statistik** — M. Rohdaten (`providerTotalUsageBytes`) existieren, werden nur nicht dargestellt. Welches Abo lohnt sich? -8. [ ] **Auto-Retry fehlgeschlagener Pakete nach Wartezeit** — S–M. Quota/Cooldown-Fails am nächsten Tag automatisch neu versuchen. -9. [ ] **Plex/Jellyfin Library-Refresh nach MKV-Move** — S. Neue Folgen sofort sichtbar. Gleicher Hook wie #1. -10. [ ] **Watch-Folder für DLC/Link-Auto-Import** — M. Ordner überwachen → automatisch importieren+starten. - ---- - -## C. DESIGN-MOCKUPS - -4 Varianten in `design-mockups/` (index.html = Vergleich): -1. **Aurora** — verfeinerte Dark-Evolution (premium, vertraut, geringstes Risiko) -2. **Command** — Terminal/Ops-Dashboard (max. Dichte, Monospace, Status-LEDs) -3. **Vellum** — Light Editorial (warmes Papier, Serif, mutige helle Alternative) -4. **Nebula** — Neon/Synthwave (Magenta-Cyan-Glow, auffällig) - -→ Nutzer wählt Richtung (oder Mischung). - ---- - -## REVIEW / ERGEBNISSE (2026-05-23) - -**Umgesetzt (v1.7.158):** -- ✅ **H1** — `abortPostProcessing` aborted jetzt auch alle Deferred- + Hybrid-Controller (globaler Stop/Shutdown/clearAll/external). Keine FS-Race gegen Shutdown-Save mehr. -- ✅ **H2** — Hybrid-Post-Extract läuft über neue `packageHybridPostProcessControllers`-Map (Set pro Package), Controller SYNCHRON vor dem detached Promise registriert, `shouldAbort` an Rename + MKV-Collect durchgereicht. `abortPackagePostProcessing` + `clearAll` räumen die Map. Cancel/Reset stoppt jetzt laufende Hybrid-Arbeit. -- ✅ **M1** — neuer `hasAnyDeferredPostProcessPending()`; Scheduler-Abschluss + `finishRun`-Clear gaten darauf. `hasDeferredPostProcessPending` (per-Package, für package_done-Cleanup) prüft jetzt auch Hybrid. Run endet erst wenn Background-FS-Arbeit fertig. -- ✅ **H3** — `validateDownloadedFileCompletion`: 0-Byte bei `stream-end` → `ok:false` (download_underflow), routet in den bestehenden Retry-Pfad. Regressionstest in `tests/download-completion.test.ts` (8 Tests). -- ✅ **N1** — toter Disk-Fallback-Block in `findReadyArchiveSets` + verwaiste `pendingItemStatus`-Map entfernt (verhaltensneutral). - -**Bewusst NICHT umgesetzt (mit Begründung):** -- ✅ **M2** (`blockAllPersistence` nie zurückgesetzt) — GELÖST in v1.7.159 via **Auto-Relaunch**. In-Memory-Reload wäre unsicher (Task-finally-Blöcke settlen async gegen `this.session.items[id]` → Race beim Session-Swap, bräuchte async-Refactor). Stattdessen: nach erfolgreichem Import startet die App automatisch neu (main-getrieben in main.ts, nicht Renderer — robust gegen Renderer-Fehler). Der frische Prozess lädt die restored Session sauber via Standard-Startup-Pfad. `skipShutdownPersist`/`blockAllPersistence` schützen das ~1.5s-Fenster + den Quit (verifiziert: prepareForShutdown:5680 überspringt Persistenz sauber). Footgun eliminiert — User kann nicht mehr im blockierten Zustand weiterarbeiten. -- ⏭️ **M3** (`cancelPendingAsyncSaves` wartet nicht auf laufenden Save) — Report stuft selbst als reines I/O-Overlap ein; die Generation-Guard (storage.ts:1022) schützt die Datenintegrität bereits (stale Write wird verworfen). Kein Korrektheitsgewinn, daher kein Eingriff. - -**Verifikation:** 30 Test-Dateien, 621 Tests grün. Build sauber. Advisor-Review vor Implementierung (fing H2-Falle: Hybrid-Controller nicht in die Deferred-Map legen, sonst killt `runDeferredPostExtraction` sie selbst). - ---- - -## D. DEFERRED-PFAD RENAME-GAP (2026-05-28, Opus-Verifikation von 18eada9) - -**Kontext:** Eine abgestürzte Session (API 400 thinking-blocks) hinterließ ein uncommittetes Working-Tree, das **drei** releaste Commits revertierte (08372f9 Passwort + 18eada9 Hybrid-Rename + 98dc366 Support-Bundle, zurück auf v1.7.159). Kein dokumentierter Intent → als Crash-Debris bewertet, non-destruktiv **gestasht** (`git stash` — recoverable), HEAD/v1.7.162 wiederhergestellt. - -**Verifizierter Fund (Folge-Bug zu 18eada9):** -- 18eada9 schloss den "frische Datei landet unbenannt"-Bug nur für den **Hybrid-Pfad** (`deferFreshFiles=true` + Mehrfach-Pässe). -- Der **finale Deferred-Pass** (`runDeferredPostExtraction`) macht Rename (12125) → Collect (12156, `deferFreshFiles=false`). Ist eine Datei beim Deferred-Rename noch frisch (< `fileStabilizeMinAgeMs`, prod=2000ms) — v.a. eine eben per **Nested-Extraction** (12045, unmittelbar davor) geschriebene Datei — überspringt der Frische-Gate sie, und der Collect moved sie mit **Original-Scene-Namen** in die Library. `collectMkvFilesToLibrary` benennt selbst nicht um (Move-Body: `buildUniqueFlattenTargetPath`, nur Flatten). -- Pre-existierender Gap (Frische-Skip-Block älter als 18eada9); auch HEAD/v1.7.162 betroffen. - -**Gate (TDD, vor Fix):** neuer Regressionstest "deferred final pass renames fresh files before collecting them" → reproduzierte den Bug zuverlässig gegen HEAD (Datei landete unbenannt). - -**Fix (minimal, Root-Cause):** `treatFilesAsStable`-Param durch `autoRenameExtractedVideoFiles(Impl)`. Im Deferred-**Final**-Pass (kein concurrent Extractor-Write mehr, Extraktion awaited) wird der Frische-Gate umgangen → alle Dateien werden umbenannt, bevor der Collect sie sammelt. Hybrid-Pfad unangetastet (nutzt `...Impl` mit Default `false` → Frische-Skip bleibt aktiv, schützt weiter vor Rename mitten in concurrent Write). - -**Verifikation:** neuer Test grün, Hybrid-Test grün (kein Regress), **623 Tests grün** (31 Dateien), tsc unverändert (9 pre-existing). Advisor-Gate vor Fix (verlangte Repro-Test statt Timing-Argument). - -**Offen / bewusst nicht angefasst:** -- Gestashtes Crash-Debris (`stash@{0}`): enthält Revert von 08372f9/18eada9/98dc366 + log.old. Bei Bedarf inspizierbar/recoverbar; sonst irgendwann verwerfbar. -- 08372f9 (Passwort-Daemon-Reset) bewusst nicht neu aufgerollt (außerhalb dieses Goals, kein Hinweis auf Defekt). -- Untracked `*-postprocess/` + `fix-library-renames.mjs`: alte Experimente (Apr/Mai), unverändert gelassen. - ---- - -## E. Mega-Debrid Account temporär deaktivieren (UI) — 2026-05-31 - -**Goal:** Einzelne Mega-Debrid-Accounts deaktivieren (statt löschen) → Rotation überspringt sie, nutzt die anderen. - -**Befund:** Backend KOMPLETT vorhanden — `megaDebridDisabledAccountIds` (Typ/Defaults/Storage-Normalisierung) + Rotation-Skip (debrid.ts:1944) + Verfügbarkeits-Checks. Es fehlt NUR das UI-Toggle (Debrid-Link hat es bereits via keyStatsPopup). ID-Seam verifiziert: `getMegaDebridAccountId(login)` (trim+lowercase) ist auf beiden Seiten identisch → Test grün. - -**Ansatz (B-kohärent):** Toggle in die bestehende Mega-Account-Liste im Bearbeiten-Dialog falten (draft-then-Save, KEIN Live-Persist → kohärent, minimal). Schritte: -1. [x] TDD: Test „skips a manually disabled Mega-Debrid account" (acc1 disabled → acc2) — grün gegen Backend. -2. [ ] `AccountDialogState`: Feld `megaDisabledIds: string[]`. -3. [ ] Dialog-Init (createAccountDialogState): aus `settings.megaDebridDisabledAccountIds`. -4. [ ] JSX Mega-Account-Liste: Aktivieren/Deaktivieren-Button + disabled-Styling pro Account. -5. [ ] Entfernen-Handler: ID auch aus megaDisabledIds entfernen. -6. [ ] `buildSettingsFromDialog` (megadebrid-api/web): `megaDebridDisabledAccountIds` aus Draft (gefiltert auf vorhandene Accounts) übernehmen. -7. [ ] Verifizieren: tsc unverändert, volle Suite grün, Toggle-Test grün. +### Bewusst NICHT angefasst (Crash-Debris / alte Experimente) +- Gestashtes Crash-Debris `stash@{0}` (Revert von 08372f9/18eada9/98dc366 + log.old) — bei Bedarf recoverbar, sonst verwerfbar +- Untracked `*-postprocess/` + `fix-library-renames.mjs` — alte Experimente (Apr/Mai)