"use client"; /** * The provider-voice preference: which TTS provider and voice the listener * picked for the podcast player ("system" keeps the platform's own voices). * One blob in localStorage, read through a tiny accessor. */ import { PROVIDERS, TTS_PROFILES, ttsProfile, type ProviderInfo } from "./providers"; const STORAGE_KEY = "freezmo.podcast-natural.v1"; export type NaturalPref = { source: "system" | "natural"; provider: string; voice: string | null; model: string | null; }; const FALLBACK: NaturalPref = { source: "system", provider: "", voice: null, model: null }; export function readNaturalPref(): NaturalPref { if (typeof window === "undefined") return FALLBACK; try { const raw = window.localStorage.getItem(STORAGE_KEY); if (!raw) return FALLBACK; const parsed = JSON.parse(raw) as Partial | null; if (!parsed || typeof parsed !== "object") return FALLBACK; return { source: parsed.source === "natural" ? "natural" : "system", provider: typeof parsed.provider === "string" ? parsed.provider : "", voice: typeof parsed.voice === "string" ? parsed.voice : null, model: typeof parsed.model === "string" ? parsed.model : null, }; } catch { return FALLBACK; } } export function writeNaturalPref(next: Partial): NaturalPref { const merged = { ...readNaturalPref(), ...next }; try { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(merged)); } catch { /* private mode */ } return merged; } /** Providers with a TTS profile that the listener actually has a key for. */ export function ttsProvidersWithKeys(keys: Record): string[] { return Object.keys(TTS_PROFILES).filter((id) => Boolean(keys[id])); } /** The provider to use when the listener has not chosen one. */ export function defaultTtsProvider(keys: Record, generation?: string): string { const available = ttsProvidersWithKeys(keys); if (available.length === 0) return ""; if (generation && available.includes(generation)) return generation; /* Prefer OpenAI when both are configured: its voices are the better ones. */ if (available.includes("openai")) return "openai"; return available[0]; } export function voiceForProvider(providerId: string, wanted: string | null): string { const profile = ttsProfile(providerId); if (!profile) return ""; if (wanted && profile.voices.some((voice) => voice.id === wanted)) return wanted; return profile.voices.find((voice) => voice.male)?.id ?? profile.voices[0]?.id ?? ""; } /** Provider labels for the picker (id → label). */ export function ttsProviderLabel(id: string): string { return PROVIDERS.find((provider: ProviderInfo) => provider.id === id)?.label ?? id; } export { TTS_PROFILES };