Spaces:
Build error
Build error
| const STORE_KEY = "anicove:watch:progress"; | |
| const MAX_TITLES = 30; | |
| function read() { | |
| try { | |
| return JSON.parse(localStorage.getItem(STORE_KEY) || "{}"); | |
| } catch { | |
| return {}; | |
| } | |
| } | |
| function write(map) { | |
| try { | |
| localStorage.setItem(STORE_KEY, JSON.stringify(map)); | |
| } catch { | |
| /* storage full / blocked — fail silently */ | |
| } | |
| } | |
| /** One entry per title (anime or movie), newest episode wins. */ | |
| export const CW_KEY = { | |
| anime: (id) => `anime:${id}`, | |
| movie: (slug) => `movie:${slug}`, | |
| }; | |
| /** | |
| * entry: { | |
| * key, type ("anime"|"movie"), title, image (raw path — render via api.img), | |
| * href, label (e.g. "E3" / "S1 E2" / "Movie"), category ("sub"|"dub"|""), | |
| * position, duration (seconds), updatedAt (epoch ms), | |
| * episodeId (anime only), se/ep (movie series only) | |
| * } | |
| */ | |
| export function saveProgress(entry) { | |
| if (!entry || !entry.key) return; | |
| const map = read(); | |
| map[entry.key] = entry; | |
| const sorted = Object.values(map).sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); | |
| if (sorted.length > MAX_TITLES) { | |
| const drop = new Set(sorted.slice(MAX_TITLES).map((e) => e.key)); | |
| for (const k of Object.keys(map)) if (drop.has(k)) delete map[k]; | |
| } | |
| write(map); | |
| } | |
| export function removeProgress(key) { | |
| if (!key) return; | |
| const map = read(); | |
| delete map[key]; | |
| write(map); | |
| } | |
| export function getProgress(key) { | |
| return read()[key] || null; | |
| } | |
| /** Meaningful, unfinished entries sorted newest-first. */ | |
| export function getContinueWatching() { | |
| return Object.values(read()) | |
| .filter((e) => e && e.key && e.duration > 0 && e.position > 5 && !isFinished(e)) | |
| .sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); | |
| } | |
| /** Watched to the end (or effectively complete). */ | |
| export function isFinished(entry) { | |
| return entry?.duration > 0 && entry.position / entry.duration > 0.92; | |
| } | |