export type YoutubeProChannel = { id: string; name: string; /** 备忘尾码(旧版) */ streamKeySuffix?: string; /** 完整串流密钥或 rtmp(s) URL */ streamKey?: string; /** 本线路 URL_config 草稿(多路本地编排) */ urlLines?: string; /** 建议 PM2 名,如 youtube2__xxx */ pm2Name?: string; notes?: string; }; const STORAGE_KEY = "live-hub-youtube-pro-v2"; function migrateRow(x: Record): YoutubeProChannel | null { if (!x || typeof x !== "object") return null; const id = String(x.id || "").trim(); const name = String(x.name || "").trim(); if (!id || !name) return null; return { id, name, streamKeySuffix: typeof x.streamKeySuffix === "string" ? x.streamKeySuffix : undefined, streamKey: typeof x.streamKey === "string" ? x.streamKey : undefined, urlLines: typeof x.urlLines === "string" ? x.urlLines : undefined, pm2Name: typeof x.pm2Name === "string" ? x.pm2Name : undefined, notes: typeof x.notes === "string" ? x.notes : undefined, }; } function safeParse(raw: string | null): YoutubeProChannel[] { if (!raw) return []; try { const v = JSON.parse(raw) as unknown; if (!Array.isArray(v)) return []; return v.map((x) => migrateRow(x as Record)).filter((c): c is YoutubeProChannel => c !== null); } catch { return []; } } export function loadYoutubeProChannels(): YoutubeProChannel[] { if (typeof window === "undefined") return []; let raw = window.localStorage.getItem(STORAGE_KEY); if (!raw) { raw = window.localStorage.getItem("live-hub-youtube-pro-v1"); if (raw) { const legacy = safeParse(raw); if (legacy.length) { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(legacy)); return legacy; } } } return safeParse(raw); } export function saveYoutubeProChannels(channels: YoutubeProChannel[]): void { if (typeof window === "undefined") return; window.localStorage.setItem(STORAGE_KEY, JSON.stringify(channels)); } export function newChannelId(): string { return `ch_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`; } export function defaultPm2NameForChannel(channelId: string): string { return `youtube2__${channelId}`; }