Replace Spotify iframe with custom centered player (layout A); v1.1.5
- EpisodeAudioPlayer full variant: centered title, large gold play button, skip-back 15s / skip-forward 30s flanking controls, full-width scrubber - Compact variant (study sections) unchanged - Episode detail page fetches direct Anchor MP3 URL from /api/episodes by title match; falls back to resolvedEmbedUrl while loading - Plays stream from Anchor CDN so stats still count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+20
-15
@@ -1282,6 +1282,21 @@ function EpisodeDetailPage({ content }: { content: SiteContent }) {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const episode = (content.podcastFeaturedLinks ?? []).find(e => e.id === id)
|
||||
const [resolvedEmbedUrl, setResolvedEmbedUrl] = useState('')
|
||||
const [audioUrl, setAudioUrl] = useState('')
|
||||
|
||||
// Fetch the direct MP3 URL from the RSS-backed episodes list, matching by title
|
||||
useEffect(() => {
|
||||
if (!episode) return
|
||||
fetch('/api/episodes')
|
||||
.then(r => r.ok ? r.json() : Promise.reject())
|
||||
.then((data: { episodes?: { title: string; audioUrl: string }[] }) => {
|
||||
const match = (data.episodes ?? []).find(e =>
|
||||
e.title?.trim().toLowerCase() === episode.title?.trim().toLowerCase()
|
||||
)
|
||||
if (match?.audioUrl) setAudioUrl(match.audioUrl)
|
||||
})
|
||||
.catch(() => {})
|
||||
}, [episode])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
@@ -1383,22 +1398,12 @@ function EpisodeDetailPage({ content }: { content: SiteContent }) {
|
||||
<h1 className="episode-detail-title">{episode.title}</h1>
|
||||
{episode.summary && <p className="episode-detail-summary">{episode.summary}</p>}
|
||||
|
||||
{(episode.embedUrl || episode.url) && (
|
||||
{(episode.embedUrl || episode.url || audioUrl) && (
|
||||
<div className="episode-detail-embed">
|
||||
{resolvedEmbedUrl ? (
|
||||
resolvedEmbedUrl.includes('spotify.com') ? (
|
||||
<iframe
|
||||
src={resolvedEmbedUrl}
|
||||
title={episode.title}
|
||||
width="100%"
|
||||
height="152"
|
||||
frameBorder="0"
|
||||
allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
|
||||
loading="lazy"
|
||||
/>
|
||||
) : (
|
||||
<EpisodeAudioPlayer src={resolvedEmbedUrl} title={episode.title} size="full" spotifyUrl={episode.url || content.platformSpotifyUrl} />
|
||||
)
|
||||
{audioUrl ? (
|
||||
<EpisodeAudioPlayer src={audioUrl} title={episode.title} size="full" spotifyUrl={episode.url || content.platformSpotifyUrl} />
|
||||
) : resolvedEmbedUrl ? (
|
||||
<EpisodeAudioPlayer src={resolvedEmbedUrl} title={episode.title} size="full" spotifyUrl={episode.url || content.platformSpotifyUrl} />
|
||||
) : (
|
||||
<div className="episode-embed-skeleton" aria-label="Loading player…" />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user