Commit Graph

930 Commits

Author SHA1 Message Date
Sucukdeluxe
ce3d7bb728 Account-Liste: kein irrefuehrendes gruenes "Konfiguriert" mehr bei nicht-pruefbaren Anbietern
Single-Token-Anbieter (Real-Debrid, AllDebrid, 1Fichier, DDownload, LinkSnappy,
BestDebrid) haben keine Status-Pruefung. Bisher stand bei ihnen ein gruenes
"Konfiguriert"-Badge in der Status-Spalte, das wie "geprueft & ok" aussah, obwohl
nichts geprueft wurde. Jetzt zeigen sie dort ein dezentes graues "—" (Tooltip:
"Fuer diesen Anbieter gibt es keine Status-Pruefung"). Gruen/gelb/rot bleibt den
tatsaechlich geprueften Mega-Debrid-/Debrid-Link-Accounts vorbehalten.

Reine Renderer-Aenderung. tsc=6, build ok.
2026-06-15 02:02:07 +02:00
Sucukdeluxe
9c75e1676c Release v1.7.202 2026-06-15 01:46:59 +02:00
Sucukdeluxe
32e43d1a62 Account-Liste: einklappbare Anbieter-Gruppen (z.B. "Mega-Debrid · 4 Accounts")
User-Idee: Anbieter mit mehreren Accounts zusammenfassbar machen, platzsparend.

- Anbieter mit >= 2 Accounts (Mega-Debrid, Debrid-Link) bekommen einen klickbaren
  Gruppen-Kopf "<Anbieter> · N Accounts" mit Chevron zum Ein-/Ausklappen; Einzel-
  account-Anbieter bleiben normale flache Zeilen.
- Gruppen-Kopf zeigt eine Mini-Status-Zusammenfassung als Badges: "X OK" (gruen),
  "Y Problem" (rot, ungueltige Logins), "Z aus" (deaktiviert).
- Standard ausgeklappt (Status bleibt auf einen Blick sichtbar); Klapp-Zustand wird
  pro Anbieter in localStorage gemerkt (rd-account-collapsed-groups-v1).
- Mitglied-Zeilen leicht eingerueckt mit Akzent-Leiste. Zebra-Streifen entfernt
  (mit Gruppen-Koepfen unruhig).
- Zeilen-Rendering in renderAccountRow ausgelagert (fuer flache + Gruppen-Mitglieder
  wiederverwendet); neues groupedAccountRows-useMemo gruppiert accountRows nach Service.

Reine Renderer-Aenderung. 810 Tests gruen, tsc=6, build ok.
2026-06-15 01:46:23 +02:00
Sucukdeluxe
04b8ba1dc4 Release v1.7.201 2026-06-15 01:12:46 +02:00
Sucukdeluxe
d594afe93a UI Phase 3: Account-Verwaltung als JDownloader-artige Liste (eine Zeile pro Account, Status inline) + Pruefung beim Hinzufuegen
Account-Rework (User-Wunsch nach JDownloader-Vorlage-Screenshot):

- Tabelle zeigt jetzt EINE ZEILE PRO EINZELNEM ACCOUNT statt eine Zeile pro
  Anbieter. Mega-Debrid mit 4 Accounts = 4 Zeilen, Debrid-Link je Key eine Zeile,
  Single-Token-Anbieter je eine Zeile. Neues geflachtes Modell accountRows
  (useMemo) aus configuredAccounts: Mega ueber parseMegaDebridAccounts, DL ueber
  entry.debridLinkKeys, Rest 1:1.
- Spalten wie JDownloader: aktiviert-Checkbox | Hoster (+Modus) | Download-Traffic
  (Rest von Limit "X von Y uebrig" bzw. "Unbeschraenkt") | Status (farbig) |
  Benutzername | Verfallsdatum | Aktion (Bearbeiten/Entfernen).
- STATUS INLINE + farbig (gruen Premium / gelb Free / rot ungueltig / grau nicht
  geprueft / Deaktiviert) direkt in der Zeile, ohne erst "Bearbeiten" zu oeffnen.
  Quelle: settings.debridAccountStatuses[accountId] (Mega/DL werden geprueft),
  Benutzername aus status.email, Verfallsdatum aus premiumUntilMs. Single-Token-
  Anbieter (Real-Debrid, AllDebrid, 1Fichier, ...) werden nicht geprueft -> "Konfiguriert".
- Problemzeilen (Login ungueltig) rot hinterlegt, deaktivierte Zeilen ausgegraut.
- aktiviert-Checkbox schaltet den EINZELNEN Account: Mega via neuem
  onToggleMegaAccountEnabled (megaDebridDisabledAccountIds), DL via bestehendem
  onToggleDebridLinkApiKeyEnabled, Single via onToggleAccountEnabled. Entfernen je
  Account: Mega/DL ueber neue Handler (Zeile aus megaCredentials/debridLinkApiKeys
  raus), Single ueber onRemoveAccount.
- PRUEFUNG BEIM HINZUFUEGEN: onSaveAccountDialog stoesst nach dem Speichern
  checkAllAccounts() an -> Status erscheint sofort in der Liste + Toast meldet
  "X/Y Login gueltig, Z Premium" (Speichern bleibt erlaubt, wie gewuenscht).
- Hoster-Reihenfolge- und Rotations-Verlauf-Panel unveraendert darunter. Alte
  resizable Spalten + "Zugang einzeln"-Toggle entfernt (durch Zeilen ersetzt).
  Web-Login-/AllDebrid-Status-Aktion bleibt als Knopf in der Single-Zeile.
- account-validity-badge.ok von Neon-Verlauf auf flaches Gruen, .disabled ergaenzt.

Reine Renderer-Aenderung. 810 Tests gruen, tsc=6 Baseline, build ok.
Erste Version nach Screenshot — Feinschliff der Optik nach User-Feedback.
2026-06-15 01:11:56 +02:00
Sucukdeluxe
1ea9c42d04 Release v1.7.200 2026-06-15 00:49:59 +02:00
Sucukdeluxe
de154ab783 UI Phase 2: Einstellungen-Tab neu strukturiert (Untergruppen + Erklaertexte) + konfigurierbarer Verlauf (Obergrenze + Zeitlimit)
Settings-Rework (User-Wunsch, mit Multi-Agent-Design-Runde fuer die Taxonomie:
3 Lenses -> Synthese, gegen das echte settingsDraft-Inventar auf Vollstaendigkeit
geprueft, 51 Einstellungen je genau einmal platziert).

UI (App.tsx + styles.css):
- 5 der 6 Bereiche (Allgemein/Entpacken/Geschwindigkeit/Bereinigung/Updates) in
  klare Untergruppen mit Unter-Ueberschriften (.settings-subhead) gegliedert, je
  Bereich ein Intro, und unter JEDER Einstellung ein knapper Erklaertext
  (.setting-hint, <= ~90 Zeichen, echte Umlaute). Reihenfolge nach Aufgaben-Logik
  (z.B. Allgemein: Speicherort / Download-Verhalten / Verlauf / Oberflaeche /
  Discord; Entpacken: Ziel & Ablauf / Deutsche Tonspur / Ablageform / Leistung /
  Passwoerter). Einige Labels praezisiert (z.B. "Codeberg Repo" -> "Update-Quelle",
  "Light Mode" -> "Heller Modus"). Account-Bereich bleibt fuer Phase 3 unangetastet.

Verlauf-Retention konfigurierbar (vorher: hart 500, kein Zeitlimit):
- Neue Settings historyMaxEntries (Standard 500) + historyMaxAgeDays (Standard 0=aus)
  in types/constants/normalizeSettings (geclamped 50..100000 bzw. 0..3650) + App-
  Default-Snapshot. Zwei neue Zahlenfelder im Bereich Allgemein -> Verlauf, direkt
  unter "Verlauf speichern"; ausgegraut wenn nicht "Dauerhaft".
- storage.ts: pruneHistoryEntries(entries, limits) wendet Alters- (completedAt <
  jetzt - Tage) und Anzahl-Grenze an; load/save/addHistoryEntry + die *ForRetention-
  Wrapper nehmen optionale Limits. app-controller reicht die Limits aus den Settings
  durch (historyLimits()) und schneidet den Verlauf bei Aenderung der Grenzen aktiv
  neu (damit "aelter als X Tage" wirklich von der Platte fliegt).

2 neue storage-Tests (Anzahl-Cap, Alters-Pruning). 810 Tests gruen, tsc=6 Baseline,
self-check + build ok.
2026-06-15 00:49:19 +02:00
Sucukdeluxe
3a37c5a537 Release v1.7.199 2026-06-15 00:18:58 +02:00
Sucukdeluxe
4c09c9a2f3 UI Phase 1: Statistik 50/50, Footer rechts, Linksammler bis Footer, Bandbreiten-Graph oben rechts, Stat-Karten + Hilfe-Untermenues
Sichtbarkeits-/Layout-Politur (User-Wunsch, Quick-Wins-Paket vor den groesseren
Reworks von Einstellungen-Tab und Account-Verwaltung):

- Statistik: Bandbreitenverlauf und Hoster-Statistik jetzt 50/50 statt 40/60
  (grid-template-columns 1fr 1fr).
- Footer: die Zaehler (Pakete/Links/Session/Gesamt/Hoster/Speed/ETA) wandern
  nach unten-RECHTS, die Aktions-Buttons (Ein-/Ausklappen, Leeren, Clipboard)
  nach links.
- Linksammler: das Textfeld fuellt jetzt die volle Hoehe bis zum Footer
  (collector-view: grid-row 1fr, textarea flex:1) statt bei 220px zu enden.
- Downloads-Tab: neuer Bandbreiten-Graph oben rechts (DownloadSpeedSparkline)
  neben der Suche. Eigener 250ms-Timer mit geglaettetem Verlauf: bei kurzem
  Einbruch auf 0 faellt die Kurve nicht hart ab, sondern gleitet weich runter
  (asymmetrisches Easing: schnell hoch 0.45, langsam runter 0.12) und
  korrigiert sich wieder; die angezeigte Zahl bleibt der echte aktuelle Wert.
  Erste Version - Optik wird nach JDownloader-Screenshot nachgezogen.
- Stat-Karten professioneller: Wert in Zahl + Einheit getrennt (Einheit
  dezent), ruhige Leerzustaende (idle '0'/'—' gedaempft statt nacktem grossen
  '0'), kompaktere Karten, dezentere Eyebrow-Labels.
- Hoster-Balken: flacher Akzent statt Neon-Verlauf (kein Gradient).
- Hilfe-Menue umstrukturiert mit Hover-Untermenues: 'Logs oeffnen' (Haupt-,
  Audit-, Rename-, Session-, Trace-Log), 'Remote-Support' (Support-Bundle +
  Support-Trace), 'Diagnose' (Debug-Setup + Debug-Token); 'Letzte Fehler
  anzeigen' und 'Suche Aktualisierungen' bleiben direkt.

Reine Renderer-Aenderung (App.tsx + styles.css). 808 Tests gruen, tsc=6
Baseline, Build ok.
2026-06-15 00:18:14 +02:00
Sucukdeluxe
73f871bfcb Release v1.7.198 2026-06-11 14:33:52 +02:00
Sucukdeluxe
d77dfbedec Fix: Langsame Mega-Accounts bremsen nicht mehr die ganze Umwandlungs-Queue (Latenz-Demotion)
Folge-Fix zu v1.7.197 (Round-Robin): User meldete direkt nach dem Update
deutlich langsamere Link-Umwandlung. Ursache: MegaWebFallback.runExclusive
ist eine GLOBALE Single-Flight-Queue — alle Umwandlungen laufen seriell.
Vor v1.7.197 liefen praktisch alle Links ueber denselben warmen, schnellen
Account (~800ms); das Round-Robin mischte nun auch die zuvor nie genutzten
Accounts in die Reihe. Ist einer davon langsam (kalte Session, traegere
Server, abgelaufenes Premium), blockiert seine Umwandlung in der seriellen
Queue ALLE nachfolgenden Links — gefuehlt wird alles langsam.

Fix: Pro Account+Modus wird ein EMA (0.7/0.3) der erfolgreichen
Unrestrict-Dauer gefuehrt. Bei jeder Aufloesung wird die Round-Robin-
Reihenfolge partitioniert: Accounts, deren EMA ueber
max(6s, 3x bestes verfuegbares EMA) liegt, wandern ans Ende der Reihe —
sie bleiben Failover-Reserve (werden weiter genutzt, wenn die schnellen
am Limit/Cooldown sind), laufen aber nicht mehr in der gleichmaessigen
Verteilung mit. Ungemessene Accounts gelten als gesund (bekommen ihre
Chance und damit ein EMA). Erholt sich ein Account (relativer Threshold),
rotiert er automatisch wieder mit. Schon nach EINEM langsamen Erfolg ist
ein Bremser-Account aus der Verteilung draussen. Fehlschlaege werden wie
bisher ueber die bestehenden Cooldowns behandelt.

Diagnose-Sichtbarkeit: das TEST-Event im account-rotation.log traegt jetzt
emaMs und slow=true, damit ein gebremster Account sofort erkennbar ist.

2 neue Regressionstests (langsamer Account wird depriorisiert; bleibt
Failover-Reserve wenn die schnellen gesperrt sind). Suite 808 gruen,
tsc=6 Baseline, self-check + build ok.
2026-06-11 14:33:20 +02:00
Sucukdeluxe
b60b2b00f3 docs(tasks): Mega-Rotation Round-Robin v1.7.197 dokumentiert (Acc4-nie-genutzt, Log-Namenskollision, Bundle-Nebenfix) 2026-06-11 14:19:49 +02:00
Sucukdeluxe
6c5927dbc5 Release v1.7.197 2026-06-11 14:17:04 +02:00
Sucukdeluxe
cf5c498ee9 Fix: Mega-Debrid-Rotation verteilt jetzt ueber ALLE Accounts (Round-Robin statt First-Wins)
Symptom (User): 4 Accounts hinterlegt, aber die Rotation nutzte nur die
Accounts 1-3 — der 4. wurde nie angefasst, ausser man deaktivierte die
anderen manuell.

Ursache (im Live-Log des Servers belegt, rd_downloader.log): Die
Account-Schleife in unrestrictWithAccounts startete bei JEDER
Link-Aufloesung bei Account 1 und nahm den ersten brauchbaren
(First-Usable-Wins-Failover). Ein spaeterer Account kam nur dran, wenn
ALLE davor am Tageslimit/Cooldown/deaktiviert waren. Live-Verteilung:
Account 1 = 749 OK + 1314x "Tageslimit — bis Neustart gesperrt",
Account 2 = 1733 OK + 448x Tageslimit-Sperre, Account 3 = 1603 OK ohne
ein einziges Limit — die Kette endete deshalb IMMER spaetestens bei
Account 3, und Account 4 tauchte im gesamten Log mit keinem einzigen
Event auf (nicht getestet, nicht geskippt). Accounts 1-2 liefen also
staendig ins Tageslimit, waehrend die Kapazitaet von Account 4 jeden
Tag verfiel.

Fix: Round-Robin-Cursor in unrestrictWithAccounts. Jede Aufloesung
startet beim Account NACH dem zuletzt getesteten (Modulo ueber die
Liste), alle bestehenden Checks (deaktiviert, lokales Tageslimit,
Cooldown, Park-bis-Neustart) bleiben unveraendert und werden in der
neuen Reihenfolge durchlaufen. Damit verteilen sich Links gleichmaessig
ueber alle Accounts, kein Account wird mehr stumpf bis ans Limit
gehaemmert, und Account 4 nimmt automatisch teil. Der Cursor ist
Modul-State (bei App-Neustart wieder Account 1), die "naechster
Account"-Vorschau im Fehlerpfad folgt der Modulo-Reihenfolge, und
resetMegaDebridRuntimeStateForTests setzt ihn fuer deterministische
Tests zurueck. Die Debrid-Link-Key-Rotation (separate Schleife) bleibt
unveraendert First-Wins — dort ist kein Account konfiguriert; bei
Bedarf gleiches Muster nachziehen.

Nebenfix: Das Support-Bundle exportiert jetzt auch
logs/account-rotation.log (+ .old) — genau dieses Log fehlte im Bundle
und haette die Diagnose sofort geliefert (die Datei kollidiert
namentlich mit dem gleichnamigen Log des Multi-Hoster-Uploaders, daher
war zunaechst das falsche Log in der Analyse).

Tests: 2 neue Regressionstests (5 Links auf 4 Accounts -> 1,2,3,4,1;
Cooldown-Account wird in der Reihe uebersprungen), Suite 806 gruen,
tsc=6 Baseline, self-check + build ok.
2026-06-11 14:16:17 +02:00
Sucukdeluxe
18f29a6a2c docs(tasks): Hybrid-Race .DL.-Doppeltonspur-Fix dokumentiert (v1.7.196) + Webhook-0/5-Diagnose
Markiert das offene Audit-Item "Hybrid race: 1 Datei/Staffel beim MKV-Move nicht
umbenannt" als erledigt und haelt Ursache, Fix, Verifikation und die offene
Altfile-Remediation fest. Zusaetzlich die Webhook-"0 von 5"-Diagnose (kein
Code-Bug: Notify-Toggles unchecked + ungespeichert).
2026-06-10 16:06:53 +02:00
Sucukdeluxe
aac11e8b8a Release v1.7.196 2026-06-10 15:54:58 +02:00
Sucukdeluxe
cbb3fce7ef Fix: Hybrid-Race liess .DL.+Doppeltonspur auf einzelnen Episoden zurueck
Symptom: Bei manchen Episoden (z.B. Desperate Housewives S03E08/E11/E17)
blieb der .DL.-Marker stehen UND beide Tonspuren (DE+EN) erhalten — obwohl
keepGermanAudioOnly aktiv war und alle anderen Episoden des Pakets sauber
verarbeitet wurden. Die Vermutung "langer Titel" war falsch; die betroffenen
Episoden hatten gleich lange Namen wie die sauberen.

Ursache (im Support-Bundle bewiesen): genau die 3 Episoden hatten null
"Tonspur-Bereinigung OK"-Zeilen. Im Hybrid-Modus laeuft der Entpacker
SEPARAT von der per-Paket-Kette (autoRename -> keepGermanAudio -> collect).
Waehrend ein langsamer Remux einer anderen Episode (1,5 GB, ~3 s) lief,
entpackte der Extraktor frische .DL.-MKVs in denselben extractDir — also
NACH dem Datei-Scan von keepGermanAudio, aber bevor der Ketten-Abschluss-
collect lief. collectMkvFilesToLibrary griff sie dann mit .DL. ab und
verschob sie in die MKV-Bibliothek, bevor ihre eigene Tonspur-Bereinigung
je lief. Einmal aus extractDir heraus, fand der finale Deferred-
keepGermanAudio sie nicht mehr. Das 2000-ms-Frische-Gate schuetzte nicht,
weil die Dateien beim collect schon ~2,3 s alt waren.

Fix: collectMkvFilesToLibrary haelt im Hybrid-Lauf (deferFreshFiles=true)
bei aktivem keepGermanAudioOnly jede remuxbare Datei (.mkv/.mp4) zurueck,
die noch den .DL.-Marker traegt — sie hat die Tonspur-Bereinigung sicher
noch nicht durchlaufen. Sie bleibt in extractDir und wird von einer
spaeteren Hybrid-Runde ODER dem finalen Deferred-Pass (erst keepGermanAudio,
dann collect mit deferFreshFiles=false) bereinigt + gesammelt. Praezise auf
remuxbare Dateien begrenzt: eine .DL.avi ruehrt keepGermanAudio nie an, also
darf sie nicht haengen bleiben. Der Deferred-Pass (deferFreshFiles=false)
ist NICHT betroffen — dort darf eine legitim doppeltonige Datei (kein
DE-Track) weiterhin mit .DL. gesammelt werden, statt fuer immer liegen zu
bleiben.

Regressionstest tests/hybrid-collect-race.test.ts (3 Faelle): Hybrid haelt
remuxbare .DL.-Datei zurueck (sammelt bereinigte mkv + nicht-remuxbare
.DL.avi trotzdem), Deferred sammelt sie, keepGermanAudioOnly aus haelt
nichts zurueck.
2026-06-10 15:53:47 +02:00
Sucukdeluxe
2f2646c68a docs(tasks): Webhook-Audit abgeschlossen — 29 Findings, 16 Themen gefixt (v1.7.195), 6 begruendete Nicht-Fixes 2026-06-10 00:43:45 +02:00
Sucukdeluxe
2f13035725 Release v1.7.195 2026-06-10 00:40:36 +02:00
Sucukdeluxe
c2ba225047 Test: Regressionstests fuer die Failed-Transition-Benachrichtigung (Mixed-Paket, Dedup, Run-Guard, Marker-Freigabe) 2026-06-10 00:37:40 +02:00
Sucukdeluxe
86d935e449 Fix: Testen-Button — Speichern-Hinweis + kein stilles Verschlucken
Audit-Befunde R1, R2:
- Nach erfolgreichem Test mit ungespeicherten Einstellungen sagt der Toast
  jetzt "Einstellungen jetzt noch speichern!" — vorher konnte man testen
  (klappt!), nie speichern, und nach dem naechsten App-Neustart/Auto-Update
  feuerte kein einziger Webhook, weil notifyUrl nie persistiert war.
- Button ist waehrend einer laufenden Quick-Action deaktiviert statt den
  Klick still zu verschlucken (performQuickAction returnt sonst kommentarlos).
2026-06-10 00:36:39 +02:00
Sucukdeluxe
5f8b02e970 Fix: Webhook-Settings — Backup-Maskierung + Support-Bundle-Diagnose
Audit-Befunde SET-2, SET-4:
- notifyUrl in die SENSITIVE_KEYS des Backup-Imports aufgenommen: ein mit
  "***" maskierter Wert (haendisch redigierte Backup-Datei) wird wieder durch
  den aktuellen ersetzt statt als kaputte URL persistiert zu werden — die
  Webhook-URL ist ein Capability-Secret wie die Tokens.
- Support-Bundle enthaelt jetzt einen notifications-Block (konfiguriert?,
  URL-Format plausibel?, welche Toggles an) — "warum kam kein Webhook" ist
  damit aus einem Bundle diagnostizierbar, ohne die URL selbst zu leaken.
2026-06-10 00:35:54 +02:00
Sucukdeluxe
3fb9e85ba2 Fix: Run-Lebenszyklus — Stop-Summary, Scheduler-Race, ehrliche Run-Ende-Meldung, Boot-Re-Arm
Audit-Befunde RUN-1 bis RUN-4:

- RUN-1: Manueller Stop beendete den Durchlauf, ohne dass je eine Run-Summary
  kam (der Scheduler bricht an der while-Bedingung ab, finishRun wird nie
  erreicht). stop() schickt jetzt "Durchlauf gestoppt" mit den bis dahin
  gesammelten Zahlen (nur wenn der Run lief; beim Restart/Shutdown-Pfad
  unterdrueckt — der Prozess stirbt gleich).
- RUN-2: Stop->Start innerhalb des Scheduler-Sleeps (~120-220ms) liess den
  neuen Run fuehrerlos zurueck: ensureScheduler returnte (scheduleRunning noch
  true), die alte Schleife exitete auf Generation-Mismatch — danach lief KEIN
  Scheduler mehr, obwohl running=true: keine Downloads, kein finishRun, kein
  Webhook, und erneutes Start() heilte nichts (early-return wegen running).
  Die finally respawnt jetzt den Scheduler, wenn der Run aktiv ist und die
  Generation weitergezogen wurde.
- RUN-3: Geplanter Start ueberlebte keinen App-Neustart (Timer lebte nur im
  Prozess, Setting blieb stehen) — Auto-Update/Reboot verschluckte den
  geplanten Run still. armScheduledStart extrahiert, beim Boot re-armt;
  vergangene Zeit beim Boot wird geloggt+geleert statt blind zu starten
  (Konflikt mit autoResumeOnStart-Gate).
- RUN-4: "Durchlauf beendet" feuerte in der Default-Konfiguration
  (autoExtractWhenStopped) waehrend das Entpacken noch lief. Titel sagt jetzt
  "Downloads beendet" + Hinweis "Entpacken laeuft noch — Paket-Meldungen
  folgen", wenn Post-Processing aussteht.
2026-06-10 00:34:31 +02:00
Sucukdeluxe
8acb22d3af Fix: Dedup-Lifecycle der Benachrichtigungen — Recovery/Retry/Trailing-Pakete
Audit-Befunde DEDUP-1 (HIGH), DEDUP-3, DEDUP-4, NOTIFY-DEDUP-BEFORE-CONFIRM:

- DEDUP-1: recoverRetryableItems (Auto-Requeue gefailter Items beim Start)
  loescht jetzt den notifiedPackages-Eintrag der betroffenen Pakete. Vorher
  blieb der Failed-Marker aus Run 1 kleben — die Erfolgs-Benachrichtigung nach
  geglueckter Recovery in Run 2 (genau die Nachricht, auf die man wartet) kam
  nie; in Discord blieb das Paket fuer immer .
- DEDUP-3: retryExtraction/extractNow loeschen den Dedup-Marker und treten dem
  Run UNBEDINGT bei (runPackageIds.add) — der korrigierende  nach manuell
  wiederholtem Entpacken kam sonst nie an, v.a. wenn der Run schon vorbei war.
  History-Dedup bewusst unangetastet (sonst doppelte History-Eintraege).
- DEDUP-4: start()/startPackages()/startItems() ersetzen runPackageIds; Pakete
  mit noch LAUFENDEM Post-Processing (Task, Deferred, Hybrid) flogen aus dem
  Set und ihre Abschluss-Benachrichtigung wurde nach dem naechsten finishRun
  verworfen (autoExtractWhenStopped beendet den Run ~sofort). Neuer Helper
  addTrailingPostProcessPackageIds ergaenzt das neue Set an allen 5 Stellen —
  inkl. der Start-ohne-Queue-Pfade, die sogar die GERADE angestossenen
  Entpackungen aus dem Set warfen.
- Dedup-Marker wird wieder freigegeben, wenn der Versand (nach den Sender-
  Retries) endgueltig scheiterte — ein transienter Ausfall verbraucht den
  Einmal-Slot nicht mehr dauerhaft.
2026-06-10 00:28:50 +02:00
Sucukdeluxe
99a24592c5 Fix: Paket-Endstatus + Webhook gingen verloren, wenn das letzte Item fehlschlug
Audit-Befunde N1/DEDUP-2 (HIGH), N2 (HIGH), N4 (MEDIUM):

N2: Drei terminale Fehler-Pfade (HTTP-416 erschoepft, permanent toter Link,
Debrid-Link-Terminalfehler) returnten VOR dem gemeinsamen Schwanz mit
refreshPackageStatus. Schlug das LETZTE offene Item eines Pakets ueber einen
dieser Pfade fehl, blieb das Paket bis zum Neustart auf "downloading"/"queued"
haengen und die Fehler-Benachrichtigung kam nie — bei Paketen voller toter
Links (haeufigster Fehlerfall) deterministisch. Jetzt rufen alle drei Pfade
refreshPackageStatus auf (defensiv eingefuegt statt fall-through, damit kein
nachfolgender Retry-Branch ein endgueltig gefailtes Item wieder einreiht).

N1: refreshPackageStatus benachrichtigte beim Failed-Uebergang nur bei
success===0. Gemischte Pakete (teils OK, teils Fehler), deren letztes Item
FEHLSCHLAEGT, erreichen das Post-Processing aber nie (Trigger haengt nur an
Completion-Pfaden) — die Fehler-Benachrichtigung war weg, und zwar genau in
der haeufigen Reihenfolge (Fehl-Items brennen ihre Retries nach den
Geschwistern ab). Gate entfernt; das Dedup-Set verhindert Doppel-Sends, falls
Post-Processing doch laeuft. Zusaetzlich wird fuer den gemischten Fall jetzt
der History-Eintrag geschrieben (fehlte komplett; dedup-sicher via
historyRecordedPackages).

N4: skipItems triggert Post-Processing jetzt fuer JEDES durch den Skip
terminal gewordene Paket (vorher nur autoExtract&&!hasFailed&&unextracted) —
sonst fehlten Completed-/Failed-Benachrichtigung, History-Eintrag und
package_done-Bereinigung, z.B. mit autoExtract aus oder wenn hybrid schon
alles entpackt hatte. Label-Reset bleibt auf den Entpack-Fall begrenzt.
2026-06-10 00:22:49 +02:00
Sucukdeluxe
f060d0238e Fix: Webhook-Zustellung haertbar — Discord-Rate-Limit, Retries, Kappung, Logging
Audit-Befunde N5/RATELIMIT (HIGH), DEDUP-BEFORE-CONFIRM, SLICE-SURROGATE,
BODY-UNCONSUMED, SET-1(a):
- Alle Sends laufen jetzt seriell durch eine Queue mit 450ms Mindestabstand —
  Burst-Completions (viele Pakete gleichzeitig fertig) liefen sonst in Discords
  5-pro-2s-Limit und die ueberzaehligen Benachrichtigungen waren weg.
- 429 wird mit Discords retry_after (Sekunden -> ms, Header oder JSON-Body)
  wiederholt, 5xx/Netzwerkfehler mit Backoff (2 Retries); 4xx bleibt endgueltig.
- Response-Body wird immer konsumiert (undici-Verbindung nicht bis zum GC halten).
- 2000-Zeichen-Kappung surrogat-sicher (kein zerrissenes Emoji -> Discord 400).
- Ungueltige (nicht-leere) Webhook-URL loggt jetzt eine Warnung statt still zu
  verwerfen.
- Tests: 17 (Retry-Pfade 429/5xx/Netz, 4xx ohne Retry, Serialisierung, Kappung).
2026-06-10 00:17:57 +02:00
Sucukdeluxe
d8134ce74d Release v1.7.194 2026-06-09 23:42:46 +02:00
Sucukdeluxe
25f226db43 Feature: Testen-Button neben der Webhook-URL
Schickt sofort eine Test-Nachricht (inkl. Discord-Ping falls gesetzt) an die
EINGETRAGENEN Entwurfs-Werte — funktioniert also schon vor dem Speichern der
Einstellungen. Toast meldet Erfolg bzw. verweist bei Fehlschlag auf
Hilfe -> Letzte Fehler (dort steht der HTTP-Status/Fehlertext aus notify.ts).
Neuer IPC TEST_NOTIFY (main.ts ruft sendNotification direkt), Button im
input-row-Muster, deaktiviert solange die URL leer ist.
2026-06-09 23:42:15 +02:00
Sucukdeluxe
b92808a637 Release v1.7.193 2026-06-09 21:53:20 +02:00
Sucukdeluxe
8ab87bda51 Feature: Discord-Ping in Benachrichtigungen (optionale Erwaehnung)
Neues Settings-Feld "Discord-Ping" unter der Webhook-URL: User-ID, @everyone
oder @here. Wird jeder Webhook-Nachricht vorangestellt, damit Discord wirklich
pingt statt nur still in den Kanal zu schreiben. Eine nackte Zahl wird als
<@id> verpackt (nur so pingt eine User-Erwaehnung); @everyone/@here und fertige
<@...>-Mentions gehen unveraendert durch. Default leer = Verhalten wie bisher.
5 neue Tests (Normalisierung + Content-Prefix).
2026-06-09 21:52:47 +02:00
Sucukdeluxe
f08db49f0b docs(tasks): v1.7.192 Discord-Webhook-Umbau dokumentiert 2026-06-09 21:44:17 +02:00
Sucukdeluxe
0229c77abd Release v1.7.192 2026-06-09 21:41:13 +02:00
Sucukdeluxe
41cf36890b Benachrichtigungen: ntfy ersetzt durch Discord-Webhooks
User-Wunsch: Discord statt ntfy. notify.ts sendet jetzt einen JSON-Webhook-POST
({username, content} mit fettem Titel + Nachricht, auf Discords 2000-Zeichen-
Limit gekappt) statt ntfy-Headern. Emoji-Status im Titel (OK/Fehler/Ziel-
flagge) ersetzt Priority/Tags. Settings-UI: Label/Placeholder/Hinweis auf
Discord-Webhook umgestellt (Servereinstellungen -> Integrationen -> Webhooks).
Hooks, Dedup und Guards unveraendert. Tests auf das JSON-Format angepasst
(inkl. Discord-204-Antwort und 2000-Zeichen-Cap).
2026-06-09 21:40:39 +02:00
Sucukdeluxe
4684144093 docs(tasks): QoL Sichtbarkeits-Paket released (v1.7.191) + 9 verifizierte QoL-Kandidaten mit Gotchas dokumentiert 2026-06-09 20:59:29 +02:00
Sucukdeluxe
380fd0d77e Release v1.7.191 2026-06-09 20:54:11 +02:00
Sucukdeluxe
e753ea1296 Feature: Push-Benachrichtigungen (ntfy/Webhook) bei Paket fertig/fehlgeschlagen + Run-Ende
Headless-Server: Paket-Ausgaenge waren bisher nur per RDP+Log sichtbar. Neues
Modul notify.ts schickt einen fire-and-forget POST (ntfy-kompatibel: Title/
Priority/Tags als Header, Nachricht als Body) an eine konfigurierbare URL —
mit der kostenlosen ntfy-App aufs Handy, ohne Account/Port/Firewall (outbound).

- Settings: notifyUrl + 3 Ereignis-Toggles (Default aus) in Allgemein.
- Hook 1: Post-Processing-Ende (Paket completed/failed nach Entpacken).
- Hook 2: refreshPackageStatus fuer den Alle-Items-fehlgeschlagen-Fall (Link
  tot -> Paket erreicht das Post-Processing nie; ohne diesen Hook schwiege
  ausgerechnet der haeufigste Fehlerfall).
- Hook 3: finishRun mit Run-Summary (X/Y erfolgreich, Dauer, Schnitt).
- Dedup-Set pro Paket+Run, Lifecycle gespiegelt an historyRecordedPackages
  (Run-Start-Clear, Retry-Deletes, removePackageFromSession). Guard
  session.running || runPackageIds.has(id): nachlaufendes Entpacken nach
  Run-Ende benachrichtigt noch, Startup-Recovery nach App-Neustart nicht
  (sonst Doppel-Push fuer laengst fertige Pakete).
- 5s-Timeout, Fehler nur als logger.warn — blockiert nie den Download-Pfad.
- 9 Unit-Tests fuer notify.ts.
2026-06-09 20:50:58 +02:00
Sucukdeluxe
be4d54a6b5 Feature: "Letzte Fehler anzeigen" im Hilfe-Menue (Error-Ring ins UI)
Der Error-Ring aus v1.7.185 war bisher nur ueber die Debug-Server-URL mit
Token erreichbar — per RDP ist ein Menueklick drastisch schneller als curl.
Neuer Menuepunkt im Hilfe-Dropdown zeigt die letzten 200 WARN/ERROR-Eintraege
(Kopf: "X Fehler, Y Warnungen") im bestehenden Bestaetigungs-Dialog mit
aufklappbaren Details; der Bestaetigen-Knopf kopiert die komplette Liste in
die Zwischenablage — direkt verwertbar fuer Bug-Reports.

IPC-Kette nach dem GET_DEBUG_SETUP_CHECK-Muster (ipc.ts, main.ts mit direktem
error-ring-Import wie debug-server/support-bundle, preload, preload-api).
Read-only auf den In-Memory-Snapshot, kein neues CSS.
2026-06-09 20:45:21 +02:00
Sucukdeluxe
2a1a55401e Feature: Tonspur-Ergebnis sichtbar am Paket (audioStripSummary)
Die Antwort auf "warum hat Paket X noch .DL.?" steht bisher nur in den
Rename-/Item-Logs — "kein Deutsch-Tag" ist INFO-Level und taucht nirgends im
UI auf. Jetzt speichert keepGermanAudioOnlyImpl pro Paket eine Zusammenfassung
(remuxed/kept-single/ohne-DE-Tag/ffmpeg-fehlt/Fehler + bis zu 100 Datei-Details
mit Aktion, Grund und erkannten Sprachen) direkt am PackageEntry:

- Status-Spalte zeigt "Tonspur: 5 OK / 1 ohne DE-Tag / ffmpeg fehlt" (rot bei
  Auffaelligkeiten, flacher Stil), Datei-Details als Tooltip.
- Auch der ffmpeg-nicht-gefunden-Fruehausstieg schreibt die Summary.
- pkg.updatedAt wird gesetzt + Feld im Paket-Delta-Hash, damit der Snapshot
  die Aenderung pusht; normalizeLoadedSession whitelistet das Feld mit
  Shape-Validierung, sonst waere es nach jedem App-Neustart weg.
- 2 neue Integrationstests (Summary-Zaehler + ffmpeg-fehlt-Pfad).
2026-06-09 20:42:22 +02:00
Sucukdeluxe
77c937888a Release v1.7.190 2026-06-08 23:05:25 +02:00
Sucukdeluxe
fbbc960d9d docs(tasks): Bug-Audit Batch 2 abgeschlossen — 5 Fixes (L/M,H,J/Q,P,B/I) + verifizierte Nicht-Bugs (G,N,D/E,E,O,F) 2026-06-08 23:04:28 +02:00
Sucukdeluxe
dc05b51083 Fix: Settings-only-Backup-Import wischte Live-Queue + Zaehler (B/I)
importBackup wendete die Settings fuer beide Pfade ueber setSettings an, das bei
nicht-"never"-CleanupPolicy applyRetroactiveCleanupPolicy ausloest. Beim reinen
Settings-Restore purgte das die LIVE-Queue (fertige Items), obwohl der Vertrag
"running queue stays untouched" lautet (Dateien blieben auf Platte). Zudem rollte
der Import die laufenden Usage-/Status-Zaehler auf den (aelteren) Backup-Stand
zurueck (anders als updateSettings).

- setSettings bekommt optionales { suppressRetroactiveCleanup }; der Settings-only
  Import setzt es. Die importierte Policy gilt weiter fuer KUENFTIGE Completions
  ueber den normalen Vorwaertspfad (immediate/package_done) — nur der retroaktive
  Sweep wird hier unterdrueckt.
- overlayLiveUsageCounters aus updateSettings extrahiert und im Settings-only Import
  wiederverwendet (inkl. Key-Filter der Debrid-Link-Per-Key-Usage auf existierende
  Keys). Nicht ueber updateSettings geroutet (vermeidet dessen resetHistoryForRetention).
2026-06-08 22:51:16 +02:00
Sucukdeluxe
61a830475b Fix: verschachtelte Entpack-Fortschritte wurden bei jedem Lauf verworfen
Der Resume-Prune validiert Eintraege gegen die Top-Level-Archiv-Kandidaten auf
der Platte. Nested-Archiv-Schluessel (nested:<name>) haben dort kein Gegenstueck,
also wurden sie bei JEDEM extractPackageArchives-Aufruf geloescht — verschachtelte
Archive wurden beim Resume erneut entpackt. nested:-Schluessel werden im Prune
jetzt uebersprungen (sie werden mit dem Rest geleert, wenn das Paket fertig ist).
2026-06-08 22:47:34 +02:00
Sucukdeluxe
3c33b988c3 Fix: Post-Process-Identity-Guard (J) + Remux-Temp nie ins Library sammeln (Q)
J: runPackagePostProcessing loescht im finally die Map-Eintraege fuer das Paket.
Hatte ein Abort den Handle schon entfernt und ein neuer Lauf einen frischen
Task+Controller gesetzt, riss das spaete finall des alten Tasks diesen neuen
Eintrag mit raus -> nicht abbrechbarer Waisen-Task + doppeltes paralleles
Post-Processing. Jetzt nur loeschen wenn Map noch auf DIESEN Task/Controller zeigt.

Q: collectFilesByExtensions filtert jetzt ~rd-Praefix (unsere Remux-Temp/Orphan-
Sidecars) aus, damit eine bei einem Crash mitten im Remux liegengebliebene
Teil-Datei nie in die MKV-Library gesammelt wird.

(dropItemContribution: Kommentar ergaenzt, dass das Nicht-Abziehen der
Session-Totals Absicht ist — kumulative Session-Zaehler, per Test abgesichert.)
2026-06-08 22:46:14 +02:00
Sucukdeluxe
4432fa25e8 Fix: Logger-Flush konnte ungeschriebene Zeilen verlieren (Race mit 1MB-Cap)
flushAsync nahm eine Kopie der pending-Zeilen und entfernte sie nach dem await
per Index-Zaehlung (slice(snapshot.length)). Feuerte waehrend des awaits ein
write() den 1MB-Buffer-Cap, der vorne Zeilen wegshiftet, war die Zaehlung
desynchron und verwarf neu hinzugekommene, noch nicht geschriebene Zeilen.
Jetzt: pending-Zeilen per Move uebernehmen (Buffer auf [] zuruecksetzen) statt
kopieren; await-Zeit-writes laufen in einen frischen Buffer. Bei Schreibfehler
werden die Zeilen wieder vorn eingereiht und der Cap erneut angewandt.
2026-06-08 22:33:11 +02:00
Sucukdeluxe
272a41a4a7 Fix: zu weite Deutsch-Erkennung konnte falsche Tonspur behalten
- isGermanStream: Titel-Fallback nur noch ganze Woerter (german/deutsch); die
  2-3-Buchstaben-Codes ger/deu sind im freien Titel-Text mehrdeutig und konnten
  die falsche Spur als "deutsch" picken (und damit die echte deutsche loeschen).
  Der Sprach-Tag-Check (ger/deu/de) bleibt unveraendert.
- looksLikeGermanRelease: 'dubbed' entfernt — ein nacktes "Dubbed" kann ein
  italienischer/franzoesischer Dub sein und darf den German-first-Fallback nicht
  ausloesen. Explizite german/deutsch-Tokens reichen.
- 2 Negativtests (3-Letter-Titel-Code, nicht-deutscher Dub).
2026-06-08 22:31:34 +02:00
Sucukdeluxe
b71866c3dc Release v1.7.189 2026-06-08 22:23:07 +02:00
Sucukdeluxe
b200b4e5b1 docs(tasks): Bug-Audit Sequenz — B verifiziert demoted (keine Platten-Loeschung), A allein v1.7.189 2026-06-08 22:19:07 +02:00
Sucukdeluxe
189af2242f Fix: Tonspur-Remux konnte bei Windows-Datei-Lock Original UND Remux verlieren
Der atomare Ersetzen-Schritt loeschte das Original bevor der Ersatz bestaetigt
war; schlug das anschliessende Rename fehl (z.B. AV/Indexer-Lock), raeumte der
aeussere catch zusaetzlich die Temp-Datei weg -> null Kopien auf der Platte.

- Atomares Replace-over (MoveFileEx REPLACE_EXISTING / rename(2)) statt
  rm-dann-rename: filePath haelt zu jedem Zeitpunkt entweder das volle Original
  oder den vollen Remux.
- renameWithRetry: transiente Locks (EBUSY/EACCES/EPERM/EEXIST) mit Backoff
  (200/500/1000ms) statt sofort abzubrechen.
- Eindeutiger Temp-Name (~rd<pid><rand>) statt fixem ~rdtmp -> keine Kollision
  zwischen parallelen Paketen/Retries.
- 3 neue Tests (Recovery bei Replace-Fehler, Retry-Pfad EBUSY/EXDEV).
2026-06-08 22:14:13 +02:00
Sucukdeluxe
92890f9649 Release v1.7.188 2026-06-08 14:51:22 +02:00
Sucukdeluxe
2b93f47d3a German-audio step: mislabeled-tag fallback, full logging, shorter temp
- tag mode: when no German-tagged audio track is found but the release name
  says German/Dubbed, fall back to the first track (the dub is mislabeled, e.g.
  German tagged "eng") instead of skipping; non-German names still skip safely
- comprehensive logging: per-package ffmpeg/ffprobe availability, plus per-file
  detected audio languages, decision + reason, remux/rename result and the exact
  error text when a file can't be processed
- shorter same-dir temp name so a long scene path + temp suffix cannot exceed
  Windows MAX_PATH and silently fail the remux
2026-06-08 14:50:34 +02:00