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:
co-authored by
Claude Opus 4.6
parent
71b3612e82
commit
e212ccc86f
@@ -0,0 +1,66 @@
|
||||
export interface DebridLinkApiKeyEntry {
|
||||
id: string;
|
||||
token: string;
|
||||
index: number;
|
||||
label: string;
|
||||
masked: string;
|
||||
}
|
||||
|
||||
const FNV64_OFFSET_BASIS = 0xcbf29ce484222325n;
|
||||
const FNV64_PRIME = 0x100000001b3n;
|
||||
const FNV64_MASK = 0xffffffffffffffffn;
|
||||
|
||||
function fnv1a64(text: string): string {
|
||||
let hash = FNV64_OFFSET_BASIS;
|
||||
for (const char of text) {
|
||||
hash ^= BigInt(char.codePointAt(0) || 0);
|
||||
hash = (hash * FNV64_PRIME) & FNV64_MASK;
|
||||
}
|
||||
return hash.toString(36);
|
||||
}
|
||||
|
||||
export function maskDebridLinkApiKey(token: string): string {
|
||||
const trimmed = token.trim();
|
||||
if (!trimmed) {
|
||||
return "Nicht hinterlegt";
|
||||
}
|
||||
if (trimmed.length <= 6) {
|
||||
return "*".repeat(trimmed.length);
|
||||
}
|
||||
return `${trimmed.slice(0, 3)}${"*".repeat(Math.max(4, trimmed.length - 6))}${trimmed.slice(-3)}`;
|
||||
}
|
||||
|
||||
export function getDebridLinkApiKeyId(token: string): string {
|
||||
return `dlk_${fnv1a64(token.trim())}`;
|
||||
}
|
||||
|
||||
export function getDebridLinkApiKeyLabel(index: number): string {
|
||||
return `Key ${index + 1}`;
|
||||
}
|
||||
|
||||
export function parseDebridLinkApiKeys(raw: string): DebridLinkApiKeyEntry[] {
|
||||
const seen = new Set<string>();
|
||||
const tokens = String(raw || "")
|
||||
.split(/[\n,]+/)
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean)
|
||||
.filter((token) => {
|
||||
if (seen.has(token)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(token);
|
||||
return true;
|
||||
});
|
||||
|
||||
return tokens.map((token, index) => ({
|
||||
id: getDebridLinkApiKeyId(token),
|
||||
token,
|
||||
index,
|
||||
label: getDebridLinkApiKeyLabel(index),
|
||||
masked: maskDebridLinkApiKey(token)
|
||||
}));
|
||||
}
|
||||
|
||||
export function getDebridLinkApiKeyIds(raw: string): string[] {
|
||||
return parseDebridLinkApiKeys(raw).map((entry) => entry.id);
|
||||
}
|
||||
Reference in New Issue
Block a user