// Podcast Selection Page — Layer 1 const COLOR_PALETTE = ['#6366f1', '#22d3ee', '#f59e0b', '#22c55e', '#ec4899']; const deriveColor = (id) => { if (!id) return COLOR_PALETTE[0]; let hash = 2166136261; for (let i = 0; i < id.length; i++) { hash ^= id.charCodeAt(i); hash = Math.imul(hash, 16777619); } return COLOR_PALETTE[Math.abs(hash) % COLOR_PALETTE.length]; }; const PodcastSelect = ({ lang, onSelect }) => { const t = lang === 'zh'; const [search, setSearch] = React.useState(''); const [hovered, setHovered] = React.useState(null); const [shows, setShows] = React.useState(null); const [error, setError] = React.useState(null); React.useEffect(() => { let cancelled = false; setShows(null); setError(null); (async () => { try { const res = await fetch(`${API_BASE}/shows`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); if (!cancelled) setShows(data); } catch (err) { if (!cancelled) setError(err.message); } })(); return () => { cancelled = true; }; }, []); const filtered = (shows || []).filter(s => { const q = search.toLowerCase(); return ( (s.title || '') + (s.description || '') + (s.rss_url || '') ).toLowerCase().includes(q); }); const totalTranscribed = (shows || []).reduce((a, s) => a + (s.transcribed_count || 0), 0); return (
{t ? '節目庫' : 'Show Library'}
{shows ? (t ? `共 ${shows.length} 個節目,${totalTranscribed} 集已轉錄完成` : `${shows.length} shows, ${totalTranscribed} episodes transcribed`) : (t ? '載入中...' : 'Loading...')}
{t ? `載入節目失敗:${error}` : `Failed to load shows: ${error}`}
{t ? '尚未新增節目,請透過 POST /shows 加入第一個 RSS feed' : 'No shows yet — add one via POST /shows with an RSS URL'}
{t ? '找不到符合的節目' : 'No matching shows found'}
{show.description}
)} {/* Stats */}