Commit Graph

919 Commits

Author SHA1 Message Date
Sucukdeluxe
dfd19260f6 Fix: Download-Queue läuft nach fehlgeschlagenem Update weiter (kein Stillstand bis Neustart)
Beim Klick auf "Update" stoppt das Tool zuerst die laufende Session
(stop({parkForRestart:true}) → running=false, alle Items auf "Wartet") und
startet dann die Installation. Schlug die Installation fehl — und das ist auf
realistischen Wegen möglich (git.24-music.de-Aussetzer, Netz weg über alle
Versuche, oder ein Release mit fehlendem/falschem Digest → Integritätsprüfung
schlägt fehl) — kam KEIN App-Neustart (nur bei Erfolg wird app.quit geplant) und
auch kein In-Process-Resume. Folge: die komplette Queue stand still (alle Items
"Wartet"), bis ein Mensch "Start" klickte oder das Programm neu startete — auf
einem unbeaufsichtigten Server mit ~1 TB/h ein echter Stillstand.

Fix: Der Stop-Installieren-Resume-Ablauf liegt jetzt in
runInstallWithResume(): War vorher eine Session aktiv und schlägt die
Installation fehl, wird die Session wieder gestartet (manager.start(),
idempotent — die Items sind bereits "queued", der Scheduler nimmt sie normal
auf). Der Resume greift auf BEIDEN Fehlerpfaden: started:false UND geworfene
Ausnahme (try/catch). Bei Erfolg (started:true) wird NICHT resumed (die App
beendet sich gleich), und war keine Session aktiv, passiert nichts.

Test: started:false → resume; install wirft → resume + rethrow; started:true →
kein resume; nicht-laufend → kein stop/resume. Logik in eine reine, testbare
Funktion ausgelagert (kein schwergewichtiger AppController-Konstruktor nötig).
2026-06-17 05:50:55 +02:00
Sucukdeluxe
76b3f99476 Fix: Mega-Debrid-Account sperrt sich nicht mehr dauerhaft selbst (Self-Cooldown bis Neustart)
Ein gesunder Mega-Debrid-Account konnte sich dauerhaft "bis Neustart" sperren,
ohne sich von selbst zu erholen — genau das vom Nutzer beobachtete Verhalten
("das Tool setzt sich selbst Cooldowns"). Zwei Ursachen, beide behoben:

1) Falsche Einstufung eines HOSTER-Problems als ACCOUNT-Limit:
   classifyAccountFailure hat den hoster-spezifischen Fehler "Kein Server fuer
   diesen Hoster" (MEGA_DEBRID_NO_SERVER_RE — Mega-Debrid hat fuer EINEN Hoster,
   z.B. Rapidgator, gerade keinen Server) mit limitSignal=true markiert. Dieses
   Signal speist den "bis Neustart"-Streak (3x -> Dauer-Park). Bei einer
   Warteschlange voller Links desselben (kurzzeitig nicht bedienbaren) Hosters
   kletterte der Streak hoch und parkte einen kerngesunden Account — der sich
   dann ueber die Rotation auf ALLE Accounts ausbreitete. Fix: limitSignal aus
   dem No-Server-Zweig entfernt (der 120s-Cooldown bleibt). Hoster-Verfuegbarkeit
   ist kein Account-Gesundheitssignal. Der echte Tageslimit-Pfad (leere Antwort)
   bleibt unveraendert.

2) "Bis Neustart"-Park hatte keine Ablaufzeit (until = MAX_SAFE_INTEGER) und
   konnte daher NIE von selbst aufgehen — auch nicht, nachdem Mega-Debrid wieder
   Server hatte oder das Tageslimit um Mitternacht zuruecksetzt. Nur ein Neustart
   half. Fix: Der Park laeuft jetzt zum naechsten Tagesreset (lokale Mitternacht,
   mind. 120s) ab und heilt sich damit garantiert innerhalb von <=24h selbst —
   egal welcher Zweig ihn ausgeloest hat. Texte entsprechend von "bis Neustart
   gesperrt" auf "bis zum Tagesreset gesperrt" angepasst (Main + Renderer
   konsistent).

Tests: (a) ein geparkter Account ist nach dem Tagesreset wieder frei statt
dauerhaft gesperrt (rot ohne Fix: MAX_SAFE_INTEGER laeuft nie ab); (b) ein
"no server"-Fehler liefert kein limitSignal mehr (rot ohne Fix), waehrend die
echte leere Antwort weiterhin als Limit zaehlt. 86 Debrid-Tests gruen.
2026-06-17 05:47:52 +02:00
Sucukdeluxe
68f50eaa5e Release v1.7.216 2026-06-17 05:19:18 +02:00
Sucukdeluxe
c8ea2f6765 Fix: Startup-Dedup ersetzt keine gute kanonische Datei mehr durch ein kleineres Duplikat
Beim Start gleicht das Tool Duplikat-benannte Dateien ("Name (1).ext") gegen die
kanonische Datei ("Name.ext") ab. Im Zweig "Duplikat rangiert hoeher und das
kanonische Item ist nicht 'completed'" wurde bisher bedingungslos
fs.rmSync(kanonisch) + fs.renameSync(Duplikat → kanonisch) ausgefuehrt — ohne die
echten Dateigroessen zu vergleichen. Der Rang mischt den persistierten STATUS mit
der Disk-Existenz; nach einem Absturz kann der Status von der Realitaet abweichen.
War die kanonische Datei auf der Platte tatsaechlich vollstaendig/gut, ihr Item
aber z.B. "failed"/"queued", waehrend das Duplikat-Item ein veraltetes
"completed" ueber einer kleineren/partiellen Datei trug, wurde die gute
kanonische Datei geloescht und durch das schlechtere Duplikat ersetzt —
unwiederbringlicher Verlust der besseren Datei. Zusatzrisiko: rmSync erfolgreich,
renameSync wirft EXDEV → kanonisch weg, nichts installiert.

Fix:
- Size-Guard: Ist die kanonische Datei >= dem Duplikat, wird sie behalten und das
  (kleinere/gleich grosse) Duplikat verworfen. Eine kleinere Datei kann eine
  groessere nie ueberschreiben.
- Sichere Reihenfolge fuer den echten Austausch (kanonisch kleiner): kanonisch →
  ".dedupbak" umbenennen, dann Duplikat → kanonisch; bei Fehler (EXDEV o.ae.)
  wird die kanonische Datei aus dem Backup wiederhergestellt. Kein Loss-Fenster
  mehr. Erst nach Erfolg wird ".dedupbak" entfernt.

Test: kanonisch 1024 B (gut) + Duplikat 256 B (partiell), primaeres Item "failed"
(Duplikat rangiert hoeher) → die kanonische Datei bleibt mit 1024 B erhalten.
Ohne den Size-Guard wird sie durch die 256-B-Datei ersetzt (rot bewiesen). Volle
download-manager-Suite (168) gruen, tsc unveraendert 6.
2026-06-17 05:13:40 +02:00
Sucukdeluxe
45789918b0 Fix: Falsch benannte Hash-Manifeste löschen keine korrekten Dateien mehr
readHashManifest hat den pro Zeile korrekt erkannten Algorithmus mit dem aus der
DATEIENDUNG abgeleiteten überschrieben (.sfv→crc32, .md5→md5, .sha1→sha1).
parseHashLine erkennt den Algorithmus jedoch eindeutig an der Digest-Länge
(32-hex=MD5, 40-hex=SHA1, 8-hex=CRC32) — die Länge ist die verlässliche Quelle.
Stimmte die Endung nicht mit dem Zeileninhalt überein (z.B. eine MD5-Zeile in
einer .sfv-Datei), wurde der Algorithmus auf crc32 verbogen, hashFile berechnete
einen 8-Zeichen-CRC und verglich ihn mit dem 32-Zeichen-MD5 → garantiert
Mismatch. Folge: die intakte Datei wurde gelöscht, neu geladen, scheiterte
erneut und brach hart ab ("Integritätsprüfung fehlgeschlagen").

Fix: Den von parseHashLine erkannten Algorithmus übernehmen statt ihn per
Dateiendung zu überschreiben. Bei korrekt benannten Manifesten ist das ohnehin
ein No-op; nur die fehl-etikettierten Fälle werden repariert.

Test: .sfv-Datei mit MD5-formatierter Zeile + passende Datei → Algorithmus bleibt
MD5 und die Prüfung besteht. Mit der Endungs-Überschreibung wird crc32 erzwungen
und die gute Datei fällt durch (rot bewiesen).
2026-06-17 05:07:13 +02:00
Sucukdeluxe
2b639b7267 Fix: Teildatei wird beim Entfernen eines laufenden Downloads gelöscht (kein Datei-Waise)
Wurde ein gerade herunterladendes Item entfernt (removeItem), brach der Abbruch
zwar den Stream ab, aber die angefangene Teildatei blieb für immer auf der
Platte: removeItem löscht das Item synchron aus der Session, und der danach
laufende processItem-catch stieg in der allerersten Zeile (Session-Mitglied-
schaftsprüfung `session.items[id] !== item`) per return aus — also VOR dem
Cancel-Zweig, der die geclaimte Teildatei via fs.rmSync entfernt. Folge:
verwaiste Bytes, die kein Item mehr referenziert, plus beim erneuten Hinzufügen
desselben Links eine stille Duplikat-Benennung "Name (1)".

Fix: Im catch wird vor dem frühen return — wenn das Item nicht mehr in der
Session ist und der Abbruchgrund "cancel" war — die geclaimte Teildatei
(claimedTargetPathByItem bzw. item.targetPath) gelöscht. Das passiert im catch,
also NACH dem Schließen des Streams (kein Race mit dem noch offenen Write-
Stream). releaseTargetPath/dropItemContribution laufen wie bisher (finally bzw.
removeItem). Eng auf cancel+entferntes-Item begrenzt → keine Auswirkung auf
normale/laufende Items.

Test: held-Connection hält den Download aktiv, removeItem mitten im Stream; die
Teildatei ist danach weg. Ohne den Fix bleibt sie liegen (rot bewiesen, Timeout).
2026-06-17 05:02:46 +02:00
Sucukdeluxe
1a33fc2573 Fix: Einstellungen gehen nicht mehr durch zeitgleiches Speichern verloren (Lost Update)
Der asynchrone Settings-Writer hatte — anders als der Session-Writer — keinen
Generations-Schutz. Lief eine periodische async Settings-Speicherung gerade,
während gleichzeitig synchron saveSettings() lief (z.B. Nutzer ändert eine
Option, oder ein Settings-Backup wird wiederhergestellt), konnte der async
rename die frisch synchron geschriebene Datei wieder mit dem ALTEN Stand
überschreiben. Die gerade gespeicherte Änderung war damit auf der Platte (und im
.bak) verloren — bis zur nächsten Speicherung.

Fix: Der Settings-Pfad spiegelt jetzt exakt den bereits abgesicherten
Session-Pfad:
- Eigener Generations-Zähler syncSettingsSaveGeneration; saveSettings() (sync)
  erhöht ihn.
- writeSettingsPayload bekommt die zum Zeitpunkt des Aufrufs erfasste Generation
  und bricht vor rename UND vor dem EXDEV-Copy ab, wenn inzwischen eine
  synchrone Speicherung passiert ist (generation < aktuell).
- saveSettingsAsync/saveSettingsPayloadAsync trägt die ORIGINAL-Generation auch
  durch die Warteschlange (vorher wurde beim Abarbeiten der Queue eine frische
  Generation erfasst → hätte den Schutz ausgehebelt).
- Eigener Zähler statt Wiederverwendung von syncSaveGeneration, damit eine
  synchrone Settings-Speicherung keine laufenden async SESSION-Schreibvorgänge
  fälschlich verwirft (keine Datei-übergreifende Kopplung).

Zusätzlich (verwandt): shutdown() ruft jetzt cancelPendingAsyncSaves() vor der
finalen synchronen Speicherung auf, damit eine noch laufende/eingereihte async
Settings-Schreibung den Shutdown-Save nicht mehr überholen kann.

Test: in-flight + eingereihte async Settings-Speicherung (ALT), dann synchron
NEU — nach dem Settle steht NEU auf der Platte. Ohne den Generations-Schutz
gewinnt ALT (rot bewiesen).
2026-06-17 04:57:23 +02:00
Sucukdeluxe
56bae4a384 Fix: Nicht-Archiv-".00x"-Dateien werden beim Aufräumen nicht mehr gelöscht (Datenverlust)
findArchiveCandidates behandelt jede "*.001"-Datei (nicht .zip.001/.7z.001) als
generischen Split-Kandidaten. Hatte so eine Datei KEINE Archiv-Signatur (also
gar kein Archiv — z.B. eine eigene gesplittete Datendatei, ein Media-Chunk),
wurde sie zwar korrekt als "kein Archiv" erkannt und übersprungen — aber dabei
trotzdem zu extractedArchives gezählt. Stand daneben ein echtes Archiv (das
Ausgabe erzeugt, failed===0), nahm der Cleanup ALLE candidates als Quelle und
collectArchiveCleanupTargets löschte die komplette ".00x"-Familie (.001/.002/...)
— obwohl daraus nie etwas entpackt wurde. Echter Datenverlust.

Fix: Generische Split-Dateien ohne Archiv-Signatur landen jetzt in einem eigenen
Set skippedNonArchives (per pathSetKey normalisiert) statt in extractedArchives
und werden vor dem Cleanup explizit aus den cleanupSources gefiltert. Greift in
beiden Pfaden: frischer Lauf (no-signature-Branch) und Resume (die Vorab-
Befüllung aus dem Resume-State prüft die Signatur erneut). Die Datei bleibt für
Fortschritt/Resume als erledigt markiert (resumeCompleted), zählt aber weder als
"failed" noch als Cleanup-Ziel.

Test: end-to-end über das echte extractPackageArchives — echtes movie.zip plus
mydata.001/.002/.003 (kein Archiv) mit cleanupMode=delete; nach dem Lauf ist die
ZIP-Ausgabe da und die .00x-Familie unangetastet. Ohne den Filter wird die
Familie gelöscht (rot bewiesen).
2026-06-17 04:52:54 +02:00
Sucukdeluxe
2646cba1c7 Fix: Stille Datei-Korruption auf Windows bei vorab-allozierten Downloads (Null-Bytes am Ende)
Auf Windows wird die Zieldatei vor dem Download auf die erwartete Groesse
vorab-alloziert (zero-extend via fd.truncate(item.totalBytes)) und dann ueber
einen r+/start:0-Stream beschrieben — dieser ueberschreibt ab Offset 0, kuerzt
die Datei aber nie. item.totalBytes ist dabei die Provider-Metadaten-Groesse
(knownTotal), nicht zwingend die echte content-length.

Lieferte der Server real weniger Bytes als vorab-alloziert (content-length kleiner
als die Provider-Angabe, oder Verbindungsabbruch mit sauberem EOF), blieb der
Schwanz der Datei mit Null-Bytes gefuellt. Die anschliessende stat-Korrektur hat
`written` dann FAELSCHLICH auf die On-Disk-Groesse (= Alloc-Groesse inkl.
Null-Padding) HOCHgesetzt. Dadurch wurde sowohl die Underflow-Pruefung als auch
das nachgelagerte Pre-alloc-Truncate ausgehebelt: Das Item galt als zu 100%
fertig, obwohl ein grosser Teil der Datei Nullen waren — echte Datentraeger-
Korruption, exakt auf der Plattform des Nutzers (win32).

Fix: Neue reine Funktion reconcileFinalizedSize() entscheidet die Korrektur.
Fuer vorab-allozierte Dateien wird `written` nur noch nach UNTEN korrigiert
(echter Kurz-Write), niemals nach oben auf das Null-Padding. Damit greifen die
bestehende Underflow-Validierung und das Pre-alloc-Truncate wieder wie vorgesehen:
- Voll heruntergeladen (content-length erreicht): Null-Padding wird abgeschnitten,
  Datei ist korrekt.
- Echt zu kurz: wird korrekt als Underflow erkannt und neu versucht.

Verhaltensaenderung (bewusst): Wenn die Provider-Metadaten-Groesse die echte
Dateigroesse UEBERSCHAETZT (Provider sagt 1 GB, echte Datei ist 300 MB und
vollstaendig), galt der Download bisher still als fertig (mit Null-Padding-
Korruption). Jetzt wird er als Underflow gewertet und neu versucht. Sichtbarer
Fehlschlag ist einem still korrupten "fertigen" File vorzuziehen. Die
ALLOCATION_UNIT_SIZE-Toleranz deckt kleine Abweichungen weiterhin ab. (Falls je
ein "wiederholt denselben Link" gemeldet wird, fuehrt die Spur hierher.)

Test: reconcileFinalizedSize-Matrix (Pre-alloc+Padding bleibt echte Byte-Zahl,
Pre-alloc+Kurz-Write schrumpft, Nicht-Pre-alloc beidseitig, Invalid-stat,
No-op-Gleichstand) — der Padding-Fall ist rot ohne den Fix.
2026-06-17 04:48:11 +02:00
Sucukdeluxe
21fb09b208 Fix: 1fichier/DDownload-Fehler respektiert jetzt "Auto-Fallback aus"
Wenn ein 1fichier- oder DDownload-Link beim Entsperren scheiterte, fiel das
Tool bisher trotzdem auf die Provider-Kette (z.B. Mega-Debrid) durch — auch
wenn der Nutzer den automatischen Anbieter-Fallback in den Einstellungen
ausgeschaltet hatte. Damit wurde ein anderer Anbieter (und dessen Tageslimit/
Account) ungewollt verbraucht, obwohl der Nutzer genau das unterbinden wollte.

Jetzt prüfen die catch-Blöcke beider Hoster zusätzlich autoProviderFallback:
ist er aus, wird der Fehler direkt weitergereicht statt still auf den nächsten
Anbieter umzuschalten. Die Abbruch-Behandlung (User-Cancel/echtes aborted)
bleibt unverändert davor.

Wichtig: Die Dateinamen-Auflösung (getLinkInfos) bleibt bewusst NICHT betroffen
— deren Fehlschlag muss weiterhin nicht-fatal sein.

Test: 1fichier liefert KO + Fallback aus → Linkgenerierung wird abgelehnt und
die Mega-Debrid-getLink-Route nachweislich nicht aufgerufen.
2026-06-17 04:37:42 +02:00
Sucukdeluxe
8196263ac3 Release v1.7.215 2026-06-17 04:23:16 +02:00
Sucukdeluxe
3bd6e3b23e Härtung Download/Rotation (Audit-Batch 1): Scheduler-Freeze, Cooldown-Respekt, Daily-Reset, Kategorisierung
Aus einem adversarisch verifizierten Multi-Agent-Audit (14 confirmed/11 refuted):

#1 HIGH Scheduler-Freeze: findNextQueuedItem hatte keinen activeTasks-Guard.
Wird ein Item zurueckgesetzt/ueberschrieben, waehrend sein alter Task noch in
einem nicht-abbrechbaren await parkt (z.B. Integritaets-Check), liefert
findNextQueuedItem dasselbe Item, startItem lehnt es ab ohne activeTasks zu
verkleinern → der SYNCHRONE Admission-Loop dreht endlos → Event-Loop friert
permanent ein. Fix: `if (this.activeTasks.has(itemId)) continue;`. Repro-Test
(ohne Fix haengt sogar der vitest-Timeout — Freeze bewiesen).

#2/#3 MED mega_debrid_cooldown:<ms> wurde verworfen: kein Parser (nur das
debrid_link-Analogon) → Item lief in den generischen 5s-Exponential-Backoff
und fragte cooled Accounts im Sekundentakt erneut an. Neuer
parseMegaDebridCooldownRetry (nimmt das frueheste Cooldown-Ende ueber alle
Accounts) + Handler VOR transient/generic → Item wartet die echte Cooldown-Zeit.

#7/#8 MED Mega per-Account Tages-Usage wurde am Tageswechsel nie zurueckgesetzt
(ensureProviderDailyUsageFresh ruecksetzte nur provider/debrid-link), und weil
es den Tagesschluessel zuerst weiterstellte, lief auch der Reset in
addMegaDebridAccountDailyUsageBytes ins Leere → Accounts blieben den ganzen Tag
faelschlich "am Limit" und schrumpften das (neue) Pro-Account-Umwandlungslimit.
Fix: megaDebridAccountDailyUsageBytes im Tageswechsel mit zuruecksetzen.

#14 LOW classifyAccountFailure: rate_limit-Branch vor quota (quota matchte
"limit" in "rate limit" → Fehl-Kategorisierung).

852/852 gruen, tsc unveraendert (6). #4 (empty→until-restart) bewusst deferred.
2026-06-17 04:22:20 +02:00
Sucukdeluxe
a7d989ebd2 Release v1.7.214 2026-06-17 03:30:47 +02:00
Sucukdeluxe
73004f3864 Fix: Selbst-Lahmlegung der Mega-Debrid-API beheben (1-Token-pro-Account + falscher 60-min-Cooldown)
Live aus conversion.log belegt: bei API-first + maxParallel hammerten viele
parallele Umwandlungen DENSELBEN Account → Mega-Debrids 1-Token-pro-Account-
Regel → "Token error, please log-in" (Token gegenseitig invalidiert). Ein
einzelner generischer Null-getLink wurde dann als "Login oder Unrestrict
fehlgeschlagen" geworfen → classifyAccountFailure matchte das Wort "Login" →
category=invalid → 60-MINUTEN-Cooldown auf einen NACHWEISLICH funktionierenden
Account (39x OK davor, klappt auch auf der Webseite). Folge: alle Accounts
cooled, alle Slots haengen an Fehl-Umwandlungen (conv12/dl0), nichts laedt.

Fix A (download-manager): getSerializedValidatingLimit gilt jetzt auch fuer
megadebrid-api (nicht nur -web) = Anzahl nutzbarer Accounts ohne :api-Cooldown.
Damit laeuft hoechstens EINE API-Umwandlung pro Account gleichzeitig (Rotation
verteilt 1/Account) — respektiert die 1-Token-Regel, verhindert die Token-
Kollision und gibt Download-Slots frei.

Fix B (debrid): (1) generische Wurf-Meldung "Login oder Unrestrict
fehlgeschlagen" -> "Linkgenerierung lieferte kein Ergebnis" (kein "Login"-
Trigger mehr). (2) classifyAccountFailure: "token error"/"please log-in" ->
kurzer temporary-Cooldown (15s); invalid-Branch nur noch bei ECHTEN
Credential-Fehlern (bad login/incorrect password/invalid credentials/
unauthorized/forbidden/connectUser) statt losem login|auth. Ein transienter
Fehler sperrt einen guten Account nicht mehr 60 min, sondern hoechstens Sekunden.

Tests: API-Serialisierung 2-Acct->2-parallel + 1-Acct->1-at-a-time; kein
60-min-invalid bei Null-Ergebnis; token-error<60s. 844/844 gruen, tsc=6.
2026-06-17 03:30:04 +02:00
Sucukdeluxe
21803f316b Fix: Support-Bundle-Export friert die UI nicht mehr 1-2 Minuten ein (asynchrones IO)
buildSupportBundle lief komplett synchron auf dem Electron-Main-Thread:
existsSync/readdirSync/statSync/readFileSync (via AdmZip.addLocalFile) ueber
ALLE Log-Dateien — bei Hunderten item-logs und gleichzeitig laufenden
Downloads (Platte ausgelastet) blockierte das den Event-Loop fuer 1-2 min,
die ganze Oberflaeche stand. Live belegt: ein Bundle mit Hunderten
item-logs-Dateien.

Fix: Alle Datei-Zugriffe im Bundle-Build auf fs.promises (nicht-blockierend)
umgestellt, buildSupportBundle ist jetzt async und liefert Promise<Buffer>.
Dateiinhalte werden per readFile gelesen und mit zip.addFile(buffer)
hinzugefuegt (gleiche Zip-Struktur wie vorher). Der Event-Loop bleibt
waehrend der IO-Wartezeiten frei → UI friert nicht mehr ein. Caller
angepasst (app-controller.exportSupportBundle async, main.ts await,
debug-server via .then).

Test support-bundle.test.ts: valides Zip mit Overview + echter Datei;
ein paralleler Timer feuert waehrend des Builds (Event-Loop nicht blockiert).
840/840 gruen, tsc unveraendert (6), Build ok.
2026-06-17 03:14:01 +02:00
Sucukdeluxe
738ae2e2d5 Release v1.7.213 2026-06-17 02:54:00 +02:00
Sucukdeluxe
5309f8dd69 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.
2026-06-17 02:52:44 +02:00
Sucukdeluxe
e91e66a5f3 Release v1.7.212 2026-06-17 02:18:34 +02:00
Sucukdeluxe
876483da51 Fix: R2-Web-Limit zaehlt nur Accounts ohne laufenden Web-Cooldown
getAvailableMegaDebridAccounts filtert disabled + Tageslimit, aber NICHT
Runtime-Cooldowns. Die Rotation (debrid.ts) ueberspringt einen Account
im Cooldown jedoch — ohne diesen Filter koennte der Scheduler also eine
Web-Umwandlung zu viel zulassen, die sich dann auf einen noch brauchbaren
Account stapelt und einen Download-Slot bis zum 90s-Queue-Timeout haelt.
getSerializedValidatingLimit zaehlt jetzt nur Accounts ohne aktiven
`${id}:web`-Cooldown, sodass die Admission exakt der tatsaechlichen
Rotation-Verfuegbarkeit entspricht.

Test: 2 Accounts, einer im Web-Cooldown -> nur 1 Web-Umwandlung
gleichzeitig (kein Over-Admit). afterEach setzt jetzt auch den
Mega-Runtime-State zurueck (Cooldowns/Cursor/In-Flight) als Hygiene.
2026-06-17 02:16:22 +02:00
Sucukdeluxe
6d4da02f92 Fix: Mega-Debrid-Umwandlung robust + parallel — schneller Retry, alle Accounts, sichtbarer Grund
R3 (Kern): Transiente Resolve-Fehler ("Datei beim Hoster gerade nicht
abrufbar", frz. "Fichier supprimé") werden jetzt mit kurzem Delay
(3–6–10s) neu versucht statt mit dem 5s..120s-Exponential. Ein solcher
Einzel-Fehler zählt nicht mehr zum Provider-Circuit-Breaker (der bei 20
Fehlern 30–300s Cooldown setzt und die Mega-Session invalidiert) und
löst keine Provider-Cooldown-Inflation aus — dadurch bremst er die
gesunden Links nicht mehr aus. Neuer Branch vor der generischen
Unrestrict-Retry-Logik; Detektor isMegaDebridTransientResolveFailure
matcht sowohl die rohe französische als auch die gerenderte deutsche
Meldung (am Download-Manager kommt die klassifizierte deutsche an).

R2 (parallel): getSerializedValidatingLimit für megadebrid-web ist nicht
mehr hart 1, sondern die Anzahl nutzbarer Accounts. Der harte Wert 1
stammte aus der Einzel-Account-Zeit (Commit a3e3d6f). Sicher, weil die
Web-Ebene ohnehin pro Account serialisiert (runExclusive, key=login) und
die Account-Rotation gleichzeitige Aufrufe atomar auf distinkte Accounts
verteilt (megaDebridInFlight wird synchron vor dem await erhöht). Ein
Account → Limit 1 (keine Änderung).

R4 (Sichtbarkeit): Der echte Grund steht inline im Status und als Tooltip
(item.lastError); kaputten "?"-Separator zu "(Rn)" gesäubert.

UI-Bugfixes: Account-Duplizierung beim Entfernen (React-Key-Kollision
API/Web → rowKey nach kind), Username-Spalte zeigt eingegebenen Login
statt Anbieter-Mail (Mail als Tooltip).

Tests: transientResolveRetryDelayMs, isMegaDebridTransientResolveFailure,
2 behaviorale Download-Manager-Tests (schneller Re-Try mit deutschem
Grund; 1 Web-Umwandlung pro Account parallel). 833/833 grün, tsc
unverändert.
2026-06-17 02:07:25 +02:00
Sucukdeluxe
bec119583d docs(lessons): "permanent/tot" nie ohne Transienz-Gegenprobe (supprime war transient)
Lehre aus v1.7.210->211: Mega-Debrid "Fichier supprime" als permanent annehmen
ohne zu pruefen, ob derselbe Link je danach ein OK bekam. Intersection(failed, ok)
!= leer -> transient. Plus die Account/Link-permanent/dieser-Versuch-Linse.
2026-06-17 00:51:33 +02:00
Sucukdeluxe
19650dd581 Release v1.7.211 2026-06-17 00:45:58 +02:00
Sucukdeluxe
db59b59053 Fix: Mega-Debrid "Fichier supprime" ist transient, nicht tot -- korrigiert v1.7.210
v1.7.210 hat den franzoesischen Mega-Debrid-Fehler "Fichier supprime chez
l'hebergeur" als permanent toten Link behandelt (Item sofort gescheitert, kein
Web-Fallback). Die Support-Bundle-Logs widerlegen das: von 18 Links mit diesem
Fehler haben 4 Sekunden spaeter ein OK geliefert -- 1x ueber Web, 3x ueber
API-Retry (7-66s). Der Fehler ist TRANSIENT; v1.7.210 haette diese erholbaren
Links faelschlich dauerhaft gekillt und den rettenden Web-Fallback abgeklemmt.

Korrektur:
- classifyAccountFailure: "supprime"/"introuvable" -> temporaer, cooldownMs 0,
  NICHT fatal. Der eigentliche Stall-Verursacher (30s Account-Cooldown, der bei
  nur einem Account auch alle gesunden Links via SKIP_COOLDOWN blockierte) ist
  damit weg, OHNE die erholbaren Links zu verlieren.
- isPermanentLinkError: franzoesische Phrasen wieder entfernt (nur echte
  permanente engl. Signale fuer RD/AllDebrid bleiben).
- Provider-Kette + interner Web-Fallback: Kurzschluss entfernt -> Web-Fallback
  wird wieder versucht (hat 1/4 der Links gerettet).
- Pacing kommt vom bestehenden 5s-Exponential-Backoff (unrestrictDelayMs) pro
  Item, nicht vom Account-Cooldown -> weit unter Mega-Debrid 50 req/s, kein
  IP-Ban-Risiko.
- Anzeige: deutsche, transient formulierte Meldung "Datei beim Hoster gerade
  nicht abrufbar" statt franzoesisch und statt "tot".
- shared/dead-link.ts -> shared/mega-debrid-errors.ts, Semantik korrekt benannt.

Tests: tests/mega-debrid-errors.test.ts + behavioraler Test in debrid.test.ts
(supprime -> kein Account-Cooldown, deutsche Meldung, retrybar). Volle Suite
822/822 gruen.

Behebt die Queue-Quervergiftung; macht echte tote Links bei retryLimit 0 NICHT
aufgeben (vorbestehend, unveraendert). Parallel-Umwandlung folgt separat.
2026-06-17 00:45:09 +02:00
Sucukdeluxe
ec1bdcdfe2 Release v1.7.210 2026-06-17 00:24:55 +02:00
Sucukdeluxe
938b84392d Fix: Tote Mega-Debrid-Links (frz. "Fichier supprimé") vergiften nicht mehr die ganze Queue
Mega-Debrid liefert bei geloeschten Hoster-Dateien franzoesische Fehlertexte
("Fichier supprime chez l'hebergeur"). Diese wurden weder in classifyAccountFailure
(debrid.ts) noch in isPermanentLinkError (download-manager.ts) erkannt und landeten
im generischen "temporaer"-Zweig: 30s Account-Cooldown + (bei retryLimit 0) endlose
Wiederholung. Mit nur einem Account (als API UND Web) blockierte ein einziger toter
Link ueber den Cooldown auch alle gesunden Links (SKIP_COOLDOWN) -- die Queue stand.
Beleg aus dem Support-Bundle: 479 von 983 Zeilen im Rotations-Log waren dieser Fehler.

- shared/dead-link.ts: zentrale Tot-Link-Erkennung (frz./dt./engl.), eine Quelle fuer
  beide Schichten, damit die Muster nicht auseinanderdriften.
- classifyAccountFailure: toter Link -> fatal/skip, KEIN Account-Cooldown (Account ist
  gesund, nur die Datei ist weg).
- isPermanentLinkError: toter Link -> Item sofort als gescheitert markiert, kein
  Endlos-Retry. Greift auch im aggregierten Provider-Ketten-Fehlerstring.
- Provider-Kette + interner Web-Fallback: toter Link -> kein Fallback auf weitere
  Provider/Modi (spart den 60s-Web-Timeout; saubere Meldung erreicht isPermanentLinkError
  unveraendert).
- Anzeige: deutsche Klartext-Meldung "Link tot - Datei beim Hoster geloescht" statt frz.
- Account-Liste: Hinweis, dass Mega-Debrid API + Web derselbe Account in zwei Modi sind.

Tests: tests/dead-link.test.ts (inkl. aggregierter Provider-Ketten-String + akzentfreie
Variante). Volle Suite 823/823 gruen.
2026-06-17 00:23:50 +02:00
Sucukdeluxe
e0f8b446e3 test(debrid): kaputter Account in der Mitte (1,2,4 ok, 3 nicht) wird sauber uebersprungen
Belegt das vom User gefragte Szenario fuer die parallele Mega-Umwandlung (v1.7.209):
ein ausgefallener Account (hier user3, until-restart geparkt) faellt aus der Rotation,
3 gleichzeitige Links verteilen sich parallel nur ueber die funktionierenden Accounts
(user1/2/4), alle Links loesen auf, user3 wird nie benutzt. Reine Test-Ergaenzung, kein
Verhaltens-Change (v1.7.209 macht das bereits korrekt: nicht-fataler Fehler -> Cooldown +
Failover im selben Versuch, danach Skip via Cooldown).
2026-06-16 23:43:18 +02:00
Sucukdeluxe
d296652f68 Release v1.7.209 2026-06-16 23:37:07 +02:00
Sucukdeluxe
2c596bbc8d Mega-Debrid: Link-Umwandlung parallel ueber mehrere Accounts (per-Account-Queue + Tiefen-Routing)
User-Wunsch: die Links eines Pakets parallel umwandeln statt seriell (single-flight),
damit sich die Download-Slots schneller fuellen. Gewaehlt: parallel ueber mehrere
Accounts (ein Login je Account laeuft parallel), NIE zwei gleichzeitig auf demselben
Account (Mega-Debrid-Sperr-Risiko).

- MegaWebFallback: globale Einzel-Warteschlange (this.queue) -> Warteschlange PRO Account
  (this.queues: Map<login, Promise>). Gleicher Account serialisiert (kein Doppel-Login,
  kein Hammern), verschiedene Accounts parallel. Key vor runExclusive berechnet.
- debrid.ts unrestrictWithAccounts: megaDebridInFlight zaehlt die LAUFENDE Tiefe pro
  Account (Map<`${id}:${mode}`, number>). Kandidaten werden nach aufsteigender Tiefe
  stabil sortiert (cursorOrder als Gleichstand-Tiebreak): gleichzeitige Aufloesungen
  greifen den am wenigsten belegten Account -> auch bei mehr Links als Accounts
  gleichmaessige Verteilung (4 Accounts, 8 parallel -> 2 je Account), statt sich hinter
  dem Cursor-Account zu stauen. Sequenziell (alles Tiefe 0) bleibt es klebrig beim warmen
  Account. add/inc vor dem try, dec/cleanup im finally (kein Leak).
- classifyAccountFailure: "Queue-Timeout" (lokaler Eigen-Stau) gibt jetzt cooldownMs:0 —
  der warme Account wird nicht mehr faelschlich fuer Eigen-Stau mit Cooldown bestraft.

Vor Release adversarial per Multi-Agent-Workflow geprueft (4 Lenses + Verify). Der Review
fand genau die Ueberzahl-Stau-Schwaeche (binaeres belegt/frei staute >Accounts-Links hinter
einem Account) — daraufhin auf Tiefen-Zaehlung umgestellt. Sperr-Risiko strukturell
ausgeschlossen (per-Account-Queue serialisiert unabhaengig vom Set). 4 neue Tests
(gleicher Account 1 Login, verschiedene Accounts parallel, 4 gleichzeitig->4 Accounts,
8/2-Ueberzahl->4/4 ausgewogen). 813 Tests, tsc=6, self-check + build ok.
2026-06-16 23:36:22 +02:00
Sucukdeluxe
232af28715 Release v1.7.208 2026-06-15 15:58:22 +02:00
Sucukdeluxe
6ec080489e Fix: Mega-Debrid Link-Umwandlung wieder schnell (klebrige Rotation statt Pro-Link-Wechsel)
Regress aus v1.7.197/198: Das Round-Robin wechselte bei JEDEM Link den Account,
und die Latenz-Demotion (v1.7.198) stufte einen Account direkt nach seinem
zwangslaeufig langsamen KALTEN Login als "langsam" ein und rotierte weg — Mega-Web
cacht Sessions aber pro Account (~20 Min). Ergebnis: jeder Link zahlte einen kalten
Login in die serielle Single-Flight-Queue → minutenlanger Vorlauf, bevor die 8
parallelen Downloads anliefen. Vorher (First-Wins) lief alles ueber EINEN warmen
Account → schnell.

Fix:
- Latenz-Demotion (EMA-Sortierung) komplett entfernt — sie war die Ursache des
  Kalt-Login-Teufelskreises (jeder Account galt nach seinem ersten Login als
  langsam und wurde weggedraengt).
- Rotation jetzt KLEBRIG: gestartet wird beim Cursor (zuletzt erfolgreich genutzter,
  warmer Account); der Cursor wird im Erfolgszweig nur weitergesetzt, wenn der
  Schwung MEGA_DEBRID_STICKY_LINKS (25) erreicht ist — sonst bleibt er auf dem
  Account. Aufeinanderfolgende Links laufen so auf demselben warmen Account
  (schnell). Limit/Cooldown/Fehler ueberspringen den Account weiterhin und die
  Rotation klebt dann am naechsten. Ueber die Zeit (alle 25 Links bzw. bei
  Limits) kommen weiterhin alle Accounts dran — Account 4 inklusive.

Tests: 4 alte Round-Robin-/Demotions-Tests durch 3 klebrige ersetzt (bleibt auf 1
Account ueber 5 Links; wechselt erst nach 25 Links; ueberspringt gesperrten und
klebt am naechsten). 809 Tests, tsc=6 Baseline, self-check + build ok.
2026-06-15 15:57:53 +02:00
Sucukdeluxe
1e7a3b15aa Release v1.7.207 2026-06-15 03:49:31 +02:00
Sucukdeluxe
622ed1653b Account-Liste: Status-Spalte sortiert nach Premium-Restlaufzeit (Klick)
User-Wunsch: in der Account-Liste auf "Status" klicken und nach Premium-Restlaufzeit
sortieren (laengste<->kuerzeste). Da die Accounts pro Anbieter gruppiert sind, wird
INNERHALB jeder Gruppe sortiert (dort sitzen die Premium-Tage).

- Neuer Zustand accountStatusSort (none -> desc -> asc -> none) per Klick auf den
  Status-Spaltenkopf (mit ▼/▲-Indikator).
- groupedAccountRows sortiert bei desc/asc jede Gruppe nach premiumUntilMs:
  Premium-Accounts nach Restlaufzeit (desc = laengste zuerst, asc = kuerzeste
  zuerst), Accounts ohne Premium/ohne Status bleiben am Ende.

Reine Renderer-Aenderung. tsc=6, build ok.
2026-06-15 03:49:00 +02:00
Sucukdeluxe
f5fe52bbb3 Release v1.7.206 2026-06-15 03:44:54 +02:00
Sucukdeluxe
14d1fc418b Account-Liste: Spalte "Download-Traffic" mittig zentriert
User-Wunsch: die Traffic-Werte (z.B. "Unbeschraenkt") in der Account-Liste
zentriert statt linksbuendig. text-align center fuer die Traffic-Spalte (Kopf +
Werte). Reine CSS-Aenderung. build ok.
2026-06-15 03:44:26 +02:00
Sucukdeluxe
472b604c8e Release v1.7.205 2026-06-15 03:40:44 +02:00
Sucukdeluxe
d10033f11e Update-Fenster: Changelog wird vollstaendig angezeigt (Truncation entfernt)
Der In-App-Update-Dialog kuerzte den Changelog selbst: eine "compactLines"-Logik
schnitt jede Zeile NACH dem Doppelpunkt ab, wenn dahinter mehr als 60 Zeichen
standen. Aus "- Account-Liste: <lange Beschreibung>" wurde so nur "- Account-Liste:".
Zusaetzlich wurden eingerueckte Unterpunkte und Leerzeilen verworfen.

Fix: Die Kuerzungs-Logik entfernt. Der Changelog wird jetzt vollstaendig
uebernommen (nur Markdown-Sternchen/Backticks und ATX-Ueberschriften werden
gestrippt, 3+ Leerzeilen auf eine reduziert). Die Anzeige-Box bricht ohnehin um
(white-space: pre-wrap) und scrollt (max-height) — es wird also der ganze Text
lesbar dargestellt.

Hinweis: Der Fix greift fuer Update-Fenster AB der naechsten Version; das Fenster
fuer dieses Update wird noch von der alten (kuerzenden) Version gerendert.

Reine Renderer-Aenderung. tsc=6, build ok.
2026-06-15 03:40:14 +02:00
Sucukdeluxe
0072f924c9 Release v1.7.204 2026-06-15 03:09:47 +02:00
Sucukdeluxe
cf416374e1 Account-Liste: Spalten von Kopfzeile und Zeilen fluchten wieder (Grid-Ausrichtung)
Kopfzeile und jede Datenzeile waren eigene CSS-Grids mit inhaltsabhaengigen
Spaltenbreiten (minmax(px, fr) + auto) — dadurch ergaben sich pro Zeile leicht
unterschiedliche Spaltenbreiten und die Werte (z.B. "Unbeschraenkt") standen nicht
unter ihrer Spaltenueberschrift, sondern nach links verschoben.

Fix: feste, inhaltsunabhaengige Spaltenverhaeltnisse minmax(0, Nfr) (plus fixe
Checkbox- und Aktions-Spalte). Dadurch loesen alle Grids identische Spaltenbreiten
auf und Kopf + Zeilen + Gruppen-Koepfe fluchten exakt. Zellen min-width:0 +
Ellipsis; Aktions-Spalte overflow sichtbar.

Reine CSS-Aenderung. build ok.
2026-06-15 03:08:55 +02:00
Sucukdeluxe
6d588bd27d Release v1.7.203 2026-06-15 02:02:42 +02:00
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