Add daily traffic limits, auto-sort packages, Debrid-Link multi-key improvements

Daily traffic limits:
- Per-provider daily download limit (configurable in GB per provider)
- Per Debrid-Link API key daily limit (individual limits per key)
- Usage tracking with automatic daily reset at midnight
- Provider is skipped when daily limit reached, falls back to next provider
- Reset button per provider and per Debrid-Link key in account settings
- Hoster routing skips daily-limited providers gracefully

Debrid-Link multi-key improvements:
- Keys now display with labels (#1, #2...) and masked tokens in account list
- Option to show detailed per-key view with individual usage stats
- Keys that hit their daily limit are automatically skipped
- providerAccountId/providerAccountLabel stored per download item

Auto-sort packages by progress:
- Active packages automatically sorted to top during downloads
- Sorted by completion ratio, then downloaded bytes
- Toggle in settings (autoSortPackagesByProgress)

UI polish:
- Package column headers: flatter, more transparent design
- LinkSnappy mode label: "Login" renamed to "Web"
- Account list: new toggle for detailed Debrid-Link key display
- Account usage stats section with warning styling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-03-07 02:29:48 +01:00
co-authored by Claude Opus 4.6
parent 71b3612e82
commit e212ccc86f
20 changed files with 1149 additions and 54 deletions
+26 -1
View File
@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { app, BrowserWindow, clipboard, dialog, ipcMain, IpcMainInvokeEvent, Menu, shell, Tray } from "electron";
import { AddLinksPayload, AppSettings, UpdateInstallProgress } from "../shared/types";
import { AddLinksPayload, AppSettings, DebridProvider, UpdateInstallProgress } from "../shared/types";
import { AppController } from "./app-controller";
import { IPC_CHANNELS } from "../shared/ipc";
import { getLogFilePath, logger } from "./logger";
@@ -26,6 +26,17 @@ function validatePlainObject(value: unknown, name: string): Record<string, unkno
const IMPORT_QUEUE_MAX_BYTES = 10 * 1024 * 1024;
const RENAME_PACKAGE_MAX_CHARS = 240;
const RESETTABLE_PROVIDER_KEYS = new Set<DebridProvider>([
"realdebrid",
"megadebrid-api",
"megadebrid-web",
"bestdebrid",
"alldebrid",
"ddownload",
"onefichier",
"debridlink",
"linksnappy"
]);
function validateStringArray(value: unknown, name: string): string[] {
if (!Array.isArray(value) || !value.every(v => typeof v === "string")) {
throw new Error(`${name} muss ein String-Array sein`);
@@ -289,6 +300,20 @@ function registerIpcHandlers(): void {
}
return result;
});
ipcMain.handle(IPC_CHANNELS.RESET_PROVIDER_DAILY_USAGE, (_event: IpcMainInvokeEvent, provider: string) => {
const validatedProvider = validateString(provider, "provider") as DebridProvider;
if (!RESETTABLE_PROVIDER_KEYS.has(validatedProvider)) {
throw new Error("provider ist ungültig");
}
return controller.resetProviderDailyUsage(validatedProvider);
});
ipcMain.handle(IPC_CHANNELS.RESET_DEBRID_LINK_API_KEY_DAILY_USAGE, (_event: IpcMainInvokeEvent, keyId: string) => {
const validatedKeyId = validateString(keyId, "keyId").trim();
if (!validatedKeyId) {
throw new Error("keyId ist ung?ltig");
}
return controller.resetDebridLinkApiKeyDailyUsage(validatedKeyId);
});
ipcMain.handle(IPC_CHANNELS.ADD_LINKS, (_event: IpcMainInvokeEvent, payload: AddLinksPayload) => {
validatePlainObject(payload ?? {}, "payload");
validateString(payload?.rawText, "rawText");