export type ReadingProgress = { chapter: number; page: number; ratio: number; }; export type StorageLike = Pick; export function storageKey(slug: string): string { return `sunnymh:last-read:${slug}`; } function clampRatio(n: unknown): number { const v = typeof n === "number" ? n : Number(n); if (!Number.isFinite(v)) return 0; if (v < 0) return 0; if (v > 1) return 1; return v; } export function parseProgress(raw: string | null): ReadingProgress | null { if (!raw) return null; if (raw.startsWith("{")) { try { const parsed = JSON.parse(raw) as Partial; if ( typeof parsed.chapter === "number" && typeof parsed.page === "number" && parsed.chapter > 0 && parsed.page > 0 ) { return { chapter: parsed.chapter, page: parsed.page, ratio: clampRatio(parsed.ratio), }; } } catch { return null; } return null; } const n = Number(raw); return Number.isFinite(n) && n > 0 ? { chapter: n, page: 1, ratio: 0 } : null; } export function readProgress( slug: string, storage: StorageLike | null = defaultStorage() ): ReadingProgress | null { if (!storage) return null; return parseProgress(storage.getItem(storageKey(slug))); } export function writeProgress( slug: string, progress: ReadingProgress, storage: StorageLike | null = defaultStorage() ): void { if (!storage) return; storage.setItem(storageKey(slug), JSON.stringify(progress)); } function defaultStorage(): StorageLike | null { return typeof window === "undefined" ? null : window.localStorage; }