From b684ab790bc7b16974a16b1b749f8a2afcdfb55a Mon Sep 17 00:00:00 2001 From: Yuri Tatishchev Date: Tue, 24 Mar 2026 21:18:11 -0700 Subject: [PATCH] refactor player state persist to zod schema --- src/lib/player/persist.ts | 42 +++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lib/player/persist.ts b/src/lib/player/persist.ts index 59a6348..7b8c770 100644 --- a/src/lib/player/persist.ts +++ b/src/lib/player/persist.ts @@ -1,22 +1,48 @@ +import { z } from "zod"; import { browser } from "$app/environment"; import type { Track } from "./types"; const STORAGE_KEY = "amqtrain:player:v2"; -export type PersistedState = { - queue: Track[]; - currentId: number | null; - volume: number; - isMuted: boolean; - minimized: boolean; -}; +export const trackSchema: z.ZodType = z.object({ + id: z.number(), + src: z.string(), + title: z.string(), + artist: z.string(), + album: z.string(), + animeName: z.string().optional(), + type: z.number(), + number: z.number(), + fileName: z.string().nullable().optional(), + dub: z.boolean(), + rebroadcast: z.boolean(), + globalPercent: z.number(), +}); + +export const persistedStateSchema = z.object({ + queue: z.array(trackSchema), + currentId: z.number().nullable(), + volume: z.number(), + isMuted: z.boolean(), + minimized: z.boolean(), +}); + +export type PersistedState = z.infer; export function loadState(): PersistedState | null { if (!browser) return null; try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return null; - return JSON.parse(raw); + + const parsed = JSON.parse(raw); + const result = persistedStateSchema.safeParse(parsed); + if (result.success) { + return result.data; + } + + console.error("Failed to parse player state", result.error); + return null; } catch (e) { console.error("Failed to load player state", e); return null;