58 lines
1.5 KiB
Go
58 lines
1.5 KiB
Go
package podcasts
|
|
|
|
import "encoding/xml"
|
|
|
|
// rssFeed is a pragmatic subset of RSS 2.0 (with the de facto iTunes
|
|
// podcast extensions most feeds use) — enough to get channel metadata
|
|
// and each episode's title, description, publish date, and audio
|
|
// enclosure. Real podcast feeds vary a lot in which optional fields they
|
|
// include, so every field here is best-effort.
|
|
type rssFeed struct {
|
|
Channel rssChannel `xml:"channel"`
|
|
}
|
|
|
|
type rssChannel struct {
|
|
Title string `xml:"title"`
|
|
Description string `xml:"description"`
|
|
Image rssImage `xml:"image"`
|
|
Items []rssItem `xml:"item"`
|
|
}
|
|
|
|
type rssImage struct {
|
|
URL string `xml:"url"`
|
|
}
|
|
|
|
type rssItem struct {
|
|
GUID rssGUID `xml:"guid"`
|
|
Title string `xml:"title"`
|
|
Description string `xml:"description"`
|
|
PubDate string `xml:"pubDate"`
|
|
Enclosure rssEnclosure `xml:"enclosure"`
|
|
Duration string `xml:"http://www.itunes.com/dtds/podcast-1.0.dtd duration"`
|
|
}
|
|
|
|
type rssGUID struct {
|
|
Value string `xml:",chardata"`
|
|
}
|
|
|
|
type rssEnclosure struct {
|
|
URL string `xml:"url,attr"`
|
|
}
|
|
|
|
func parseRSS(data []byte) (*rssFeed, error) {
|
|
var feed rssFeed
|
|
if err := xml.Unmarshal(data, &feed); err != nil {
|
|
return nil, err
|
|
}
|
|
return &feed, nil
|
|
}
|
|
|
|
// episodeGUID returns the item's GUID if present, falling back to its
|
|
// enclosure URL — some minimal feeds omit <guid> entirely.
|
|
func (i rssItem) episodeGUID() string {
|
|
if i.GUID.Value != "" {
|
|
return i.GUID.Value
|
|
}
|
|
return i.Enclosure.URL
|
|
}
|