Replace Spotify embeds with branded custom audio player backed by RSS

- Add /api/episode-audio route returning MP3 URLs from Anchor RSS feed
- Replace Spotify URL text inputs in admin with RSS episode dropdowns
- New EpisodeAudioPlayer component with podcast art, show name, progress
  bar, and Spotify icon link — full and compact sizes
- Backward-compatible: legacy Spotify embed URLs still render as iframes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmert
2026-06-17 13:23:19 -04:00
parent 3d8f02d915
commit a1d5889711
6 changed files with 393 additions and 25 deletions
+11
View File
@@ -31,6 +31,7 @@ function parseRssItems(xml, limit = Infinity) {
const episode = (/<itunes:episode>([\s\S]*?)<\/itunes:episode>/.exec(block)?.[1] ?? '').trim()
items.push({
title, pubDate, link,
audioUrl: enclosureUrl,
description: descText.slice(0, 220) + (descText.length > 220 ? '…' : ''),
duration, episode,
})
@@ -174,4 +175,14 @@ export function register(app) {
res.json({ episodes: episodesCache ?? [] })
}
})
app.get('/api/episode-audio', async (_req, res) => {
try {
const episodes = await fetchAllEpisodes()
res.json({ episodes: episodes.map(e => ({ title: e.title, audioUrl: e.audioUrl, duration: e.duration, episode: e.episode })) })
} catch (err) {
console.error('[episode-audio] RSS fetch error:', err.message)
res.json({ episodes: (episodesCache ?? []).map(e => ({ title: e.title, audioUrl: e.audioUrl, duration: e.duration, episode: e.episode })) })
}
})
}