Diagnose: Vollstaendiges Conversion-Trace-Logging (conversion.log) fuer haengende/langsame Link-Umwandlung
Bewusst NUR Diagnose, KEINE Verhaltensaenderung — damit das naechste Support-Bundle das echte aktuelle Verhalten zeigt und der naechste Fix die Ursache trifft statt zu raten (live belegt: "Unrestrict Timeout nach 60s" R53/R64, API-"Token error, please log-in" kuehlt beide Accounts ab). Neues Modul conversion-trace.ts: AsyncLocalStorage-Trace, der einen unrestrict-Versuch ueber alle Schichten begleitet und EINEN strukturierten Block pro Versuch nach conversion.log schreibt (Datei-Infra wie account-rotation-log: Rotation bei 5 MB, 14 Tage Retention; im Support- Bundle). tracePhase ist no-op ohne aktiven Trace — additiv, null Risiko. Instrumentiert wird die Kern-Blindstelle der bisherigen Logs: - download-manager Boundary: runWithConversionTrace + Slot-Belegung (conv/dl/active/max) + Caller-Timeout-Attribution (was lief, als die 60s feuerten). - Provider-Kette (debrid): chain-try/ok/failed/aborted — zeigt, ob der Web->API-Failover ueberhaupt feuert oder vom globalen Abbruch gekappt wird. - Mega-Rotation: mega-account mit workMs + outcome (ok/failed/fatal/aborted) + Cooldown je Account. - API-Token-Lifecycle: token cached/pending-join/fresh-login + connectMs, getLink response_code/text — klaert die Herkunft von "Token error". - Mega-Web runExclusive: web-queue mit queueWaitMs UND workMs getrennt — klaert, ob die 60s Warten in der Queue oder echte langsame Arbeit sind. Test conversion-trace.test.ts (Formatter + ALS-Kontext-Propagation). 838/838 gruen, tsc unveraendert (6 Baseline), Build ok.
This commit is contained in:
+32
-282
@@ -1,287 +1,37 @@
|
||||
# Real-Debrid-Downloader — Tasks (Stand 2026-06-10)
|
||||
# Massives Conversion-Logging (v1.7.213) + Failover-Fix
|
||||
|
||||
**Status:** Webhook-Audit ABGESCHLOSSEN + released (v1.7.195). Davor: Bug-Audit (v1.7.189/190),
|
||||
Sichtbarkeits-Paket (v1.7.191-194). Verbleibende QoL-Kandidaten weiter unten.
|
||||
## Problem (live belegt, 2026-06-17)
|
||||
- Links haengen mit "Unrestrict Timeout nach 60s", R53/R64, halten Download-Slot → Stop-and-Go.
|
||||
- Web-first: 1 globaler 60s-Timeout um die GANZE Provider-Kette → Web frisst das Budget,
|
||||
API-Failover wird NIE versucht (debrid.ts 3801 `signal.aborted` → throw). Retry startet wieder bei Web.
|
||||
- API-first laeuft "um einiges fluessiger" (User bestaetigt: API resolved UND downloaded auf dem Server).
|
||||
- ABER: API-Token-Fehler ("Token error, please log-in") + "Login oder Unrestrict fehlgeschlagen"
|
||||
→ beide Accounts kriegen Cooldown → Doom-Loop. connectApi single-flightet Logins schon (pendingConnects),
|
||||
also ist die Token-Ursache NICHT trivial → braucht Token-Lifecycle-Logging.
|
||||
|
||||
---
|
||||
## Kern-Blindstelle
|
||||
Bestehende Logs (account-rotation.log) zeigen `elapsedMs` aber NICHT:
|
||||
- queue-wait vs aktive Arbeit (war der 60s-Timeout Warten in der Queue oder echtes Arbeiten?)
|
||||
- Token-Lifecycle (cacheHit/freshLogin/invalidation) → woher "Token error"?
|
||||
- Provider-Ketten-Entscheidung pro Item (welche Provider, welches Budget, warum Stopp)
|
||||
- Was war in-flight als der Caller-60s-Timeout feuerte (Provider/Account/Phase) + Slot-Belegung
|
||||
|
||||
## ✅ Webhook-Bug-Audit — RELEASED v1.7.195 (2026-06-10, Gitea + GitHub-Mirror 37430ba)
|
||||
## Plan (Release 213 = NUR Logging, bewusst KEINE Verhaltensaenderung — damit das naechste Bundle das ECHTE aktuelle Verhalten zeigt)
|
||||
- [x] `src/main/conversion-trace.ts`: AsyncLocalStorage-Trace + dedizierte `conversion.log`. EIN strukturierter Block pro Unrestrict-Versuch.
|
||||
- [x] Wiring: init in app-controller, shutdown, support-bundle.
|
||||
- [x] Instrumentiert (nur tracePhase-Calls, additiv, no-op ohne aktiven Trace):
|
||||
- download-manager unrestrict-Boundary: runWithConversionTrace + Caller-Timeout-Attribution + describeSlotOccupancy.
|
||||
- debrid.ts Provider-Kette: chain-try/chain-ok/chain-failed/chain-aborted (zeigt ob Failover feuert).
|
||||
- debrid.ts Mega-Rotation: mega-account workMs + outcome (ok/failed/fatal/aborted) + cooldown.
|
||||
- MegaDebridClient connectApi/doConnectApi/unrestrictViaApi: token cached/pending-join/fresh-login + connectMs + getLink response_code/text (DAS klaert "Token error").
|
||||
- mega-web-fallback runExclusive: web-queue queueWaitMs + workMs (DAS klaert ob 60s = Warten oder Arbeit).
|
||||
- [x] Test: conversion-trace.test.ts (Formatter + ALS-Kontext). tsc unveraendert 6.
|
||||
- [ ] Build + Suite gruen. Release 213 (Gitea + Mirror).
|
||||
|
||||
User-Goal: "intensiv prüfen obs Bugs gibt wodurch Webhooks nicht getriggert werden + drumrum".
|
||||
Workflow: 6 Finder → 29 adversarial bestätigte Findings (0 widerlegt, 65 Non-Findings),
|
||||
dedupliziert auf 16 Themen in 6 Fix-Commits. Volle Gate: tsc=6, 801 Tests (+9), self-check, build.
|
||||
## DEFERRED auf 214 (erst NACH Logs, kein Blind-Fix mehr)
|
||||
- 60s global → per-Provider-Budget (Failover feuert) — proven, aber erst messen: tritt der 60s ueberhaupt bei API-first auf, und ist es Queue oder Arbeit?
|
||||
- API Token-Error Doom-Loop ("Token error, please log-in") — Mechanismus per conversion.log verifizieren, DANN fixen (evtl. per-Account-Serialisierung fuer API wie bei Web).
|
||||
- Config-Realitaet an User: 2. Account (xe) lief abgelaufen/deaktiviert → 212-Parallelitaet griff nicht; API-first ist der schnelle Pfad.
|
||||
|
||||
### Gefixt (Commits f060d02, 99a2459, 8acb22d, 3fb9e85, 5f8b02e, 86d935e + Test-Commit)
|
||||
1. **notify.ts Zustellung** (N5/RATELIMIT HIGH): Send-Queue seriell + 450ms-Gap (Discord
|
||||
5/2s-Bucket), 429 mit retry_after (Sek→ms), 5xx/Netz-Backoff-Retries, Body-Konsum,
|
||||
surrogat-sichere 2000er-Kappung, Invalid-URL-Warnung. 17 notify-Tests.
|
||||
2. **Terminal-Abdeckung** (N1/DEDUP-2 HIGH, N2 HIGH, N4): refreshPackageStatus benachrichtigt
|
||||
JEDEN Failed-Übergang (success===0-Gate weg — Mixed-Paket mit letztem Fail = häufigste
|
||||
Reihenfolge verlor den ❌) + History für Mixed; 3 Early-Return-Fehlerpfade (416/toter
|
||||
Link/Debrid-Link) riefen refreshPackageStatus nie → Paket hing bis Neustart auf
|
||||
downloading; skipItems finalisiert jetzt jedes terminal gewordene Paket.
|
||||
3. **Dedup-Lifecycle** (DEDUP-1 HIGH, -3, -4): recoverRetryableItems + retryExtraction/extractNow
|
||||
geben den Notify-Marker frei (Recovery-✅ kam sonst NIE); retryExtraction tritt Run unbedingt
|
||||
bei; addTrailingPostProcessPackageIds erhält Run-Mitgliedschaft laufender Entpackungen an
|
||||
allen 5 runPackageIds-Ersetz/Clear-Stellen; Marker-Freigabe bei endgültig gescheitertem Send.
|
||||
4. **Run-Lifecycle** (RUN-1..4): stop() schickt "Durchlauf gestoppt"-Summary; Scheduler-Respawn
|
||||
in finally heilt Stop→Start-Race (führerloser Run!); finishRun sagt "Downloads beendet +
|
||||
Entpacken läuft noch" statt zu lügen; armScheduledStart beim Boot re-armt (geplanter Start
|
||||
überlebte keinen Neustart; vergangene Zeit → log+clear statt Blind-Start).
|
||||
5. **Settings/Security** (SET-2, SET-4): notifyUrl in importBackup-SENSITIVE_KEYS;
|
||||
Support-Bundle notifications-Block (konfiguriert/plausibel/Toggles, ohne URL-Leak).
|
||||
6. **Renderer** (R1, R2): Testen-Toast mahnt Speichern bei dirty Settings; Button disabled
|
||||
während Quick-Action läuft (statt Klick still zu schlucken).
|
||||
|
||||
### Bewusst NICHT gefixt (verifiziert, Begründung)
|
||||
- **SET-3** (rememberToken=false wipt notifyUrl nicht): Webhook als Credential zu wipen würde
|
||||
Benachrichtigungen für rememberToken=false-Setups brechen; Konsistenz-Trade-off akzeptiert.
|
||||
- **R3** (URL als Klartext-Feld statt password): Sichtbarkeit hilft beim Prüfen/Debuggen,
|
||||
Einzel-Operator-Setup.
|
||||
- **R4** (Boot-Window Draft-Race): generisches, vorbestehendes Settings-Hydration-Muster,
|
||||
nicht notify-spezifisch.
|
||||
- **DEDUP-5** (immediate-Cleanup schrumpft Zähler in der ✅-Meldung): kosmetisch, Policy-Kombi
|
||||
beim User nicht aktiv. **RUN-5** (Quit mid-run still): nach Prozesstod nicht zustellbar.
|
||||
**RUN-6** (Dauer-Fallback 1s): kosmetisch. **N6**: durch Marker-Freigabe + URL-Warnung subsumiert.
|
||||
|
||||
---
|
||||
|
||||
## ✅ QoL Sichtbarkeits-Paket — RELEASED v1.7.191 (2026-06-09, Gitea + GitHub-Mirror)
|
||||
1. **Push-Benachrichtigungen** (e753ea1, v1.7.192 auf Discord-Webhook-JSON umgebaut —
|
||||
{username, content}, Emoji-Titel, 2000-Zeichen-Cap): Settings notifyUrl + 3 Toggles; 3 Hooks
|
||||
(Post-Process-Ende, refreshPackageStatus all-failed-Lücke, finishRun-Summary); Dedup-Set
|
||||
Lifecycle wie historyRecordedPackages; Guard running||runPackageIds (Recovery pusht nicht).
|
||||
2. **audioStripSummary am Paket** (2a1a554): PackageEntry-Feld + Status-Spalten-Badge
|
||||
("Tonspur: 5 OK · 1 ohne DE-Tag", Tooltip mit Datei-Details); storage-Whitelist + Delta-Hash.
|
||||
3. **"Letzte Fehler anzeigen"** (be4d54a): Hilfe-Menü → Error-Ring-Snapshot im Dialog,
|
||||
Bestätigen-Knopf = in Zwischenablage kopieren.
|
||||
787 Tests, tsc=6, self-check+build grün; latest.yml-path verifiziert; Mirror f61fbc4 clean.
|
||||
|
||||
## 🟡 QoL-Backlog — code-verifiziert mit Hook-Punkten (aus Ideation 2026-06-09)
|
||||
Volle Details (exakte Zeilennummern, Verifier-Gotchas) im Ideation-Workflow-Output; Kurzform:
|
||||
1. **Mega-Web Per-Account-Timeout** (M, Score 9) — 20s eigenes Timeout pro Account via
|
||||
AbortSignal.any + Signal-IDENTITÄT (nie Error-Text!) im Rotations-catch VOR Z.~1979;
|
||||
äußeres 60s-Budget bleibt. GOTCHA: tests/debrid.test.ts:1376 asserted Signal-Objekt-Identität
|
||||
→ Test lockern. Nur mode==='web'.
|
||||
2. **ffmpeg-Pfad als Setting + Testen-Button** (M, Score 9) — ffmpegPath/ffprobePath, Setter +
|
||||
resetVideoToolingCache(); GOTCHA: auch im KONSTRUKTOR setzen (setSettings reicht nicht nach
|
||||
Neustart); IPC CHECK_VIDEO_TOOLING; UI unter keepGermanAudioOnly-Toggle.
|
||||
3. **Bibliothek-Batch Tonspur für Bestand** (M, Score 9) — Button neben Toggle; Kandidaten-Filter
|
||||
aus keepGermanAudioOnlyImpl als shared Predicate extrahieren (Overlap-Guard NICHT schwächen);
|
||||
sequenziell + Single-In-Flight + AbortController + mtime-Age-Gate.
|
||||
4. **Auto-Reset gefailter Items bei Tageswechsel** (S–M, Score 8) — Toggle, Default aus;
|
||||
GOTCHA: NICHT synchron aus ensureProviderDailyUsageFresh (Re-Entranz: läuft in getSnapshot/
|
||||
Scheduler) → über 60s-runtimeStatsTimer (app-controller ~164); resetItems löscht Teil-Downloads.
|
||||
5. **POST /control am Debug-Server** (M, Score 8) — add-links/start/stop/pause; GOTCHA: über
|
||||
AppController routen (Audit-Log), nicht manager direkt; Start-Konflikt-Guard beachten.
|
||||
6. **Mobile Statusseite GET /ui + Remote-Toggle** (M, Score 8) — handgeschriebenes flaches HTML,
|
||||
pollt /status+/errors; Toggle schreibt debug_host.txt um; GOTCHA: stop+start Race (EADDRINUSE
|
||||
→ Server tot bis Neustart) → closeAllConnections/restartDebugServer.
|
||||
7. **Mega-Cooldown-Status + aufheben** (S, Score 7) — listMegaDebridAccountCooldowns() export,
|
||||
Snapshot-Feld, Badge + Button; GOTCHA: Keys sind `${id}:api|web` getrennt; lazy expiry.
|
||||
8. **Status-Filter-Chips Downloads-Tab** (S, Score 7) — GOTCHAS: PackageCard-memo-Comparator
|
||||
braucht neue Prop; Prädikat an 2 Stellen (6615 + visibleOrderIds 3546); VOR Rendering-Limit.
|
||||
9. **Support-Bundle: Explorer zeigen + Desktop-Schnellweg** (S, Score 7) — filePath wird schon
|
||||
returned, Toast ignoriert ihn nur; shell.showItemInFolder; preload-api.ts nicht vergessen.
|
||||
Long-Tail: Low-Disk-Auto-Pause (S), Autostart/Tray (S).
|
||||
|
||||
---
|
||||
|
||||
## ✅ ERLEDIGT — Bug-Audit 2026-06-08 (Multi-Agent find→verify, 18 bestätigt)
|
||||
|
||||
Advisor-Triage: **A = einzige echte Daten-Verlust-Notlage** (zerstört echte Datei auf Platte)
|
||||
→ zuerst, ALLEINE Release. **B verifiziert demoted:** applyRetroactiveCleanupPolicy/
|
||||
removePackageFromSession löschen KEINE Platten-Dateien (nur Session/Queue-Einträge + ggf.
|
||||
History-Eintrag) → Queue-Integrität, nicht Daten-Verlust → in v1.7.190-Batch.
|
||||
Sequenz: Release 1 (v1.7.189) = **A allein**; Release 2 (v1.7.190) = B/I,C,D/E,F,G,H,J,L,M,N,O,P,Q.
|
||||
Ein Commit pro Fix, jeder einzeln verifiziert. **K übersprungen** (auto-rename-Reorder,
|
||||
schlechtestes Risiko/Nutzen, kann für diesen User gar nicht feuern).
|
||||
|
||||
### Release 1 — Daten-Verlust-Stopper (v1.7.189, A ALLEIN)
|
||||
- [x] **A** `video-processor.ts` atomic-replace zerstörte bei Windows-Lock BEIDE Kopien
|
||||
(rm(original) VOR bestätigtem Replace + outer-catch rm(temp) → 0 Kopien). **GEFIXT:**
|
||||
atomic replace-over + `renameWithRetry` (EBUSY/EACCES/EPERM/EEXIST, Backoff 200/500/1000ms),
|
||||
rm-first-Fallback entfernt, **unique** Temp-Name (`~rd<pid><rand>`, löst auch C-Kollision).
|
||||
Advisor bestätigt Ansatz besser als bak-dance (kein Missing-File-Window). 3 neue Tests
|
||||
(Recovery + Retry-Pfad), 41 video-processor-Tests grün, tsc=6 (Baseline). Commit 189af22.
|
||||
|
||||
### Release 2 — v1.7.190 (GEFIXT + verifiziert, ein Commit pro Fix)
|
||||
- [x] **L+M** video-processor.ts zu weite Deutsch-Erkennung. isGermanStream Titel-Fallback nur
|
||||
ganze Wörter (ger/deu raus → konnten falsche Spur picken + echte dt. löschen); looksLikeGerman
|
||||
Release 'dubbed' raus (ital./franz. Dub triggerte German-first). 2 Negativtests. Commit 272a41a.
|
||||
- [x] **H** logger.ts flushAsync slice-snapshot korrumpiert bei 1MB-Cap-Trim während await →
|
||||
ungeschriebene Zeilen verloren. Move-snapshot (Buffer auf [] übernehmen) + Requeue bei
|
||||
Schreibfehler. Commit 4432fa2.
|
||||
- [x] **J+Q** download-manager. J: runPackagePostProcessing finally löschte Map-Eintrag ohne
|
||||
Identity-Guard → Abort+Neustart-Race riss neuen Task raus (Waise + Doppel-Lauf); jetzt nur
|
||||
löschen wenn Map noch auf DIESEN Task/Controller zeigt (handle-Objekt wegen TS2454). Q:
|
||||
collectFilesByExtensions filtert `~rd`-Temp-Präfix (crash-verwaiste Teil-Remuxe nie ins
|
||||
Library). Commit 3c33b98.
|
||||
- [x] **P** extractor.ts nested-Resume-Keys (`nested:<name>`) bei jedem extractPackageArchives
|
||||
gepurged → verschachtelte Archive beim Resume neu entpackt; `startsWith("nested:")` im Prune
|
||||
übersprungen. Commit 61a8304.
|
||||
- [x] **B/I** app-controller.ts importBackup settings-only purgte LIVE-Queue (Dateien blieben auf
|
||||
Platte) + rollte Usage-Zähler zurück. Fix: setSettings({suppressRetroactiveCleanup}) +
|
||||
overlayLiveUsageCounters (extrahiert+wiederverwendet, inkl. Key-Filter). Commit dc05b51.
|
||||
|
||||
### Verifiziert KEINE Bugs / bewusst NICHT angefasst (Advisor-Disziplin: erst belegen, dann ändern)
|
||||
- **G** dropItemContribution "subtrahiert Session-Totals nicht" → **KEIN Bug**: Test "keeps
|
||||
cumulative session totals when completed items are removed" kodifiziert die Absicht (Session-
|
||||
Zähler kumulativ, divergieren bewusst von der Item-Map; Retry-Pfad zieht ab, weil neu geladen
|
||||
wird). Fix-Versuch ließ den Test failen → revertiert, Klarstellungs-Kommentar gesetzt.
|
||||
- **N** stripDualLangFromFileName "Kollision" → **bereits geguarded**: existsAsync-Skip verhindert
|
||||
Überschreiben; Remux machte Inhalt eh deutsch-only; collect strippt `.DL.` downstream. Residual
|
||||
= generischer Rename-TOCTOU (in JEDEM Rename-Pfad), kein spezifischer Bug hier.
|
||||
- **D/E** abort-Klassifizierung über signal.reason statt Text → **deferred (Robustheit, kein
|
||||
Live-Bug auf User-Pfad)**. BELEGT: mega-web-fallback normalisiert JEDEN Abort (Timeout UND
|
||||
Cancel) zu `new Error("aborted:mega-web")` → aktueller Guard `/aborted/i && !/timeout/i` FEUERT
|
||||
→ v1.7.187-Cooldown LÄUFT auf dem Web-Pfad (User-Pfad). Einzige Imperfektion: Cancel >8s wird
|
||||
fälschlich gecooled (minor). Empirisch bestätigt: `AbortSignal.any([ac,timeout]).reason?.name===
|
||||
'TimeoutError'` (timeout) vs string/AbortError (cancel) — falls je gebaut: signal.aborted-gaten,
|
||||
reason.name nutzen, Text-Fallback behalten, reason-Test. Hoch-Risiko (kritischer Unrestrict-Pfad
|
||||
JEDES Downloads) → nicht für Robustheit anfassen. API-Pfad-Abort-Text nicht erschöpfend geprüft.
|
||||
- **E** "API 'cancel'-Pfad umgeht" → **nicht real**: kein `'cancel'`-throw im Code gefunden.
|
||||
- **O** classifyAccountFailure abort-Branch tot → **stehen lassen**: tot NUR wegen aktueller
|
||||
Text-Interception; ein signal.aborted-gated D/E würde ihn wiederbeleben. Kein Kosmetik-Churn.
|
||||
- **F** Mega-Web empty-streak Concurrency → **N-shaped, deferred**: Streak wird bei Erfolg (1956)
|
||||
+ Nicht-Limit-Fehler (2005) gecleart; "bis Neustart gesperrt" ist bewusste Tageslimit-Logik,
|
||||
Restart-cleared; Mega-Web single-flight → Concurrency greift nicht. Keine fühlbare Schädigung
|
||||
konstruierbar → keine Park-State-Maschinerie.
|
||||
- **C** → in A subsumiert (unique Temp-Name). **K** übersprungen (auto-rename-Reorder, Risiko≫Nutzen).
|
||||
|
||||
---
|
||||
|
||||
## 🟢 OFFEN — Backlog (optional, nie begonnen)
|
||||
|
||||
### ✅ Mega-Web Account-Rotation überspringt Account 3 — GEFIXT 2026-06-08 (v1.7.187)
|
||||
**Fix:** Ein Mega-Web-Account-Abbruch (geteiltes Timeout feuert während der Account lief)
|
||||
setzt jetzt einen 2-min-Cooldown auf den Account (nur wenn er ≥8s lief, sonst = User-Cancel,
|
||||
RD_MEGA_ABORT_MIN_RUN_MS env). Dadurch überspringt der download-manager-Retry diesen Account
|
||||
und rotiert zum nächsten (debrid.ts, abort-Handling im Rotations-catch, vor classifyAccountFailure).
|
||||
Log-Event `TIMEOUT_COOLDOWN` (gelb, "Timeout/Abbruch → nächster Account beim Retry") statt
|
||||
rotem "fataler Fehler" (App.tsx:1141 Label). 2 Regressionstests (Cooldown gesetzt → Call 2
|
||||
rotiert; Quick-Abbruch → kein Cooldown). EHRLICH: fixt Korrektheit, NICHT Latenz — Account 1
|
||||
brennt weiter ~60s ins Timeout bevor der Retry auf Account 2 wechselt (instant-Failover bräuchte
|
||||
per-Account-Timeout = größerer Eingriff, bewusst verschoben). Advisor-gegengeprüft.
|
||||
|
||||
**(Ursprüngliche Analyse — Symptom & Mechanismus, zur Doku belassen)**
|
||||
**Symptom (User):** 3 Mega-Debrid-Web-Accounts aktiv, Rotation pendelt aber nur zwischen
|
||||
Account 1 ↔ 2 (bzw. nur Account 1), Account 3 (Su****xe) wird NIE probiert.
|
||||
|
||||
**Verifizierter Mechanismus (Code):**
|
||||
- Rotationsschleife `debrid.ts:1898`. Account 1 → "Mega-Web Antwort leer" → Cooldown 20s →
|
||||
weiter zu Account 2. Account 2 → `aborted:debrid`.
|
||||
- `classifyAccountFailure` (`debrid.ts:2036`) stuft JEDEN Abbruch als **fatal** ein →
|
||||
`throw` (`debrid.ts:1991`) → Schleife bricht ab → **Account 3 nie erreicht.**
|
||||
- Account 2 bekommt beim Fatal-Abbruch **keinen Cooldown** (cooldownMs:0). Beim
|
||||
download-manager-Retry wird Account 1 (Cooldown) übersprungen, aber Account 2 (kein
|
||||
Cooldown) ERNEUT vor Account 3 probiert → bricht wieder ab → ewiges 1↔2.
|
||||
- Geteiltes 60s-Unrestrict-Timeout `download-manager.ts:8590` (`AbortSignal.any([taskAbort,
|
||||
timeout(60s)])`) gilt für die GANZE Rotation, nicht pro Account. Mega-Web pollt intern bis
|
||||
180s (`mega-web-fallback.ts:235` + Poll-Loop `:371`). Sobald das geteilte 60s feuert, bleibt
|
||||
das kombinierte Signal aborted → KEIN späterer Account kriegt im selben Pass eine echte Chance.
|
||||
|
||||
**BESTÄTIGT 2026-06-08 (zweite Screenshots):** Account 1 läuft 10x rasch "erfolgreich"
|
||||
(11:51:45–11:52:26), dann zwei "abgebrochen (aborted:debrid)" um 11:53:30 UND 11:54:30 —
|
||||
**exakt 60s auseinander** = das geteilte 60s-Unrestrict-Timeout feuert (kein User-Stop, der
|
||||
wiederholt sich nicht periodisch). Hier rotiert GAR NICHTS: Account 1 bricht ab → fatal →
|
||||
Rotation stoppt sofort bei idx=0 → Account 2 und 3 werden NIE probiert. Bug eindeutig
|
||||
bestätigt, elapsedMs nicht mehr nötig. Account 1 selbst ist gesund (10x ok) — Mega-Web hängt
|
||||
nur sporadisch (no-server-Poll) bis ins 60s-Timeout.
|
||||
|
||||
**Fix-Design (wenn bestätigt):** Pro-Account-Timeout-Budget, abgekoppelt vom geteilten Cap.
|
||||
debrid.ts braucht das **cancel-only** Signal getrennt vom Timeout (kombiniertes Signal kann
|
||||
beides nicht unterscheiden). Minimal-invasiv: optionaler `opts`-Param an `unrestrictLink`
|
||||
({cancelSignal, perAttemptTimeoutMs}) — nur die Mega-Rotation liest ihn, andere Provider
|
||||
unberührt (kombiniertes Signal bleibt). Pro Account: `AbortSignal.any([cancelSignal,
|
||||
AbortSignal.timeout(perAttemptMs)])`. Abbruch-Logik: cancelSignal aborted → echter Stop;
|
||||
eigenes Account-Timer gefeuert → non-fatal, Cooldown, weiter zum nächsten Account (inkl. 3).
|
||||
**Regressionstest ZUERST** (3 Accounts, 1+2 failen/aborten → assert Account 3 kriegt TEST).
|
||||
**Advisor-Gate** vor Eingriff (kritischer Unrestrict-Pfad, betrifft jeden Download).
|
||||
Hinweis: Grundursache der leeren Antworten = Mega-Debrid Server/IP-Thema — Fix macht Rotation
|
||||
nur FAIRER (alle Accounts drankommen), bringt aber keinen busy Server zum Antworten.
|
||||
|
||||
### 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`)
|
||||
- [x] 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) → GEFIXT v1.7.196
|
||||
|
||||
---
|
||||
|
||||
## ✅ Hybrid-Race .DL.+Doppeltonspur — v1.7.196 (2026-06-10)
|
||||
|
||||
User-Goal: Desperate Housewives S03E08/E11/E17 behielten .DL. + DE+EN-Tonspur trotz keepGermanAudioOnly.
|
||||
Vermutung "langer Titel" widerlegt (gleich lange Namen). Support-Bundle: genau die 3 hatten 0× "Tonspur-Bereinigung OK".
|
||||
|
||||
Ursache: Hybrid-Extraktor laeuft SEPARAT von der per-Paket-Kette (autoRename→keepGermanAudio→collect).
|
||||
Waehrend langsamer ~3s-Remux (1,5GB) lief, entpackte er frische .DL.-MKVs in extractDir — nach dem
|
||||
keepGermanAudio-Datei-Scan, vor dem Ketten-collect. collectMkvFilesToLibrary (deferFreshFiles=true)
|
||||
verschob sie mit .DL. in die Library, bevor ihr Audio-Strip lief; raus aus extractDir fand der finale
|
||||
Deferred-keepGermanAudio sie nie. 2000ms-Frische-Gate griff nicht (Dateien ~2,3s alt).
|
||||
|
||||
Fix: collectMkvFilesToLibrary haelt bei deferFreshFiles && keepGermanAudioOnly remuxbare (.mkv/.mp4)
|
||||
Dateien mit .DL.-Marker zurueck → bleiben in extractDir, spaetere Hybrid-Runde ODER finaler Deferred-Pass
|
||||
bereinigt+sammelt. Praezise (eine .DL.avi wird nie remuxt → nicht zurueckhalten). Deferred-Pass
|
||||
(deferFreshFiles=false) unberuehrt → legitim doppeltonige Datei ohne DE-Track wird weiter gesammelt.
|
||||
Regressionstest tests/hybrid-collect-race.test.ts (3 Faelle). 804 Tests, tsc=6, self-check+build,
|
||||
Gitea+Mirror 3664e78 verifiziert (beide draft=false, 4 Assets, latest.yml path==Asset).
|
||||
|
||||
OFFEN: Altfiles in entpackt2 werden NICHT retroaktiv bereinigt — nur neue Downloads. Remediation der
|
||||
3 Episoden nur auf Admin-Account (ploet-Session sieht Administrator-Profil nicht) oder via geplantes
|
||||
"Bibliothek-Batch Tonspur"-QoL.
|
||||
|
||||
## ℹ️ Webhook "0 von 5 getriggert" (2026-06-10) — KEIN Code-Bug
|
||||
Test-Nachricht kam an (URL OK), aber alle 3 Notify-Toggles unchecked + "Einstellungen speichern" offen
|
||||
(ungespeichert). Toggle-Default=aus. User muss Toggles aktivieren UND speichern.
|
||||
|
||||
---
|
||||
|
||||
## ✅ ERLEDIGT — Archiv (Details in git-History + Memory)
|
||||
|
||||
- **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
|
||||
|
||||
### 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)
|
||||
|
||||
## ✅ Mega-Rotation Round-Robin — v1.7.197 (2026-06-11)
|
||||
|
||||
User-Goal: "4 Accounts, rotiert nur zwischen 1-3, der 4. wird nie angefasst."
|
||||
ACHTUNG: Beide Apps (Downloader + Multi-Hoster-Uploader) schreiben "account-rotation.log" —
|
||||
das Log im User-Ordner war das des Uploaders (dort eigener Befund, Fix auf User-Wunsch
|
||||
revertiert + geparkt). Downloader-Beweis kam aus rd_downloader.log im Support-Bundle:
|
||||
First-Usable-Wins ab Account 1 — Acc1/2 dauernd am Tageslimit, Acc3 trug alles (1603/1603 OK),
|
||||
Acc4 hatte null Events. Fix: Round-Robin-Cursor in unrestrictWithAccounts (Start beim Account
|
||||
nach dem zuletzt getesteten, alle Skip-Checks unverändert, Reset im Test-Hook). Nebenfix:
|
||||
Support-Bundle exportiert jetzt account-rotation.log(+.old). 2 Regressionstests, 806 grün.
|
||||
Releases Gitea + Mirror e104e72 verifiziert. Debrid-Link-Keys bewusst First-Wins gelassen:
|
||||
- [ ] Kandidat: Round-Robin auch für Debrid-Link-Keys (gleiches Muster), falls User dort
|
||||
mal mehrere Keys nutzt
|
||||
## Review
|
||||
Logging-Release: pure Diagnose, null Verhaltensrisiko. Naechster Schritt: User reproduziert, schickt Bundle, conversion.log zeigt Queue-vs-Arbeit + Token-Lifecycle eindeutig → praeziser Fix in 214.
|
||||
|
||||
Reference in New Issue
Block a user