// Shared podcast-RSS parsing, used by both the main show (episodes.js) and // any sub-show fed by its own feed URL (nuggets.js). export function extractCdata(raw) { const cdata = /^$/.exec(raw.trim()) return cdata ? cdata[1].trim() : raw.trim() } export function parseRssItems(xml, limit = Infinity) { const items = [] const itemRegex = /([\s\S]*?)<\/item>/g let match while ((match = itemRegex.exec(xml)) !== null && items.length < limit) { const block = match[1] const titleRaw = /([\s\S]*?)<\/title>/.exec(block)?.[1] ?? '' const title = extractCdata(titleRaw) if (!title) continue const pubDate = (/<pubDate>([\s\S]*?)<\/pubDate>/.exec(block)?.[1] ?? '').trim() const guidRaw = /<guid[^>]*>([\s\S]*?)<\/guid>/.exec(block)?.[1] ?? '' const guid = extractCdata(guidRaw) const enclosureUrl = /<enclosure[^>]+url="([^"]+)"/.exec(block)?.[1] ?? '' const link = guid.startsWith('http') ? guid : enclosureUrl const descRaw = /<description>([\s\S]*?)<\/description>/.exec(block)?.[1] ?? '' const descText = extractCdata(descRaw).replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim() const duration = (/<itunes:duration>([\s\S]*?)<\/itunes:duration>/.exec(block)?.[1] ?? '').trim() const episode = (/<itunes:episode>([\s\S]*?)<\/itunes:episode>/.exec(block)?.[1] ?? '').trim() const season = (/<itunes:season>([\s\S]*?)<\/itunes:season>/.exec(block)?.[1] ?? '').trim() items.push({ title, pubDate, link, audioUrl: enclosureUrl, description: descText.slice(0, 220) + (descText.length > 220 ? '…' : ''), duration, episode, season, }) } return items }