// localStorage layer for the export "Advanced options" panel. Independent // of exportFilterStorage so filter resets / profile switches don't disturb // advanced settings (and vice versa). Strict parser — malformed value // resets storage and returns null so the UI falls back to defaults. const KEY = "ytdlp-tb:export-advanced"; const VERSION = 1; export type AdvancedSnapshot = { hitBatchValue: number; hitBatchUnlimited: boolean; fetchConcurrency: number; flushIntervalMs: number; }; type StoredAdvanced = { v: 1; s: AdvancedSnapshot; }; function clampInt( v: unknown, min: number, max: number, fallback: number, ): number { if (typeof v !== "number" || !Number.isFinite(v)) return fallback; const n = Math.floor(v); if (n < min) return min; if (n > max) return max; return n; } // Tolerates v1 records that still carry the now-removed `groupsBatch*` // fields — they're silently ignored. Only `hitBatchUnlimited` is required. function parseSnapshot(raw: unknown): AdvancedSnapshot | null { if (!raw || typeof raw !== "object") return null; const r = raw as Record; if (typeof r.hitBatchUnlimited !== "boolean") return null; return { hitBatchValue: clampInt(r.hitBatchValue, 1, 1_000_000, 500), hitBatchUnlimited: r.hitBatchUnlimited, fetchConcurrency: clampInt(r.fetchConcurrency, 1, 32, 6), flushIntervalMs: clampInt(r.flushIntervalMs, 16, 2000, 120), }; } function parseStored(raw: string): AdvancedSnapshot | null { let parsed: unknown; try { parsed = JSON.parse(raw); } catch { return null; } if (!parsed || typeof parsed !== "object") return null; const r = parsed as Record; if (r.v !== VERSION) return null; return parseSnapshot(r.s); } export function loadAdvanced(): AdvancedSnapshot | null { if (typeof window === "undefined") return null; let raw: string | null = null; try { raw = window.localStorage.getItem(KEY); } catch { return null; } if (raw === null) return null; const parsed = parseStored(raw); if (!parsed) { try { window.localStorage.removeItem(KEY); } catch { /* ignore */ } return null; } return parsed; } export function saveAdvanced(snapshot: AdvancedSnapshot): void { if (typeof window === "undefined") return; const stored: StoredAdvanced = { v: VERSION, s: snapshot }; try { window.localStorage.setItem(KEY, JSON.stringify(stored)); } catch { /* quota/serialization errors are non-fatal */ } } export function clearAdvanced(): void { if (typeof window === "undefined") return; try { window.localStorage.removeItem(KEY); } catch { /* ignore */ } }