// Package model 提供播客和剧集的数据模型 package model import ( "errors" "fmt" "github.com/mmcdole/gofeed" ) // Podcast 表示一个播客及其剧集 type Podcast struct { // 播客的唯一标识符 GUID string `json:"guid,omitempty"` // 播客的URL URL string `json:"url,omitempty"` // 播客的链接 Link string `json:"link,omitempty"` // 播客的标题 Title string `json:"title,omitempty"` // 播客的描述 Description string `json:"description,omitempty"` // 播客的图片URL Image string `json:"image,omitempty"` // 版权信息 Copyright string `json:"copyright,omitempty"` // 是否锁定,表示此订阅是否可以被导入到其他平台 Locked *Locked `json:"locked,omitempty"` // 资金支持信息 Funding []Funding `json:"funding,omitempty"` // 人员信息 Persons []Person `json:"persons,omitempty"` // 价值交换信息 Value []Value `json:"value,omitempty"` // 阻止标签 Block []Block `json:"block,omitempty"` // 剧集列表 Episodes []Episode `json:"episodes,omitempty"` // 远程项目 RemoteItems []RemoteItem `json:"remote_items,omitempty"` // 媒体类型 Medium Medium `json:"medium,omitempty"` } // LoadFeed 从URL加载播客RSS订阅 func LoadFeed(url string) (*Podcast, error) { fp := gofeed.NewParser() feed, err := fp.ParseURL(url) if err != nil { return nil, fmt.Errorf("解析播客订阅失败: %w", err) } if feed == nil { return nil, errors.New("解析播客订阅失败: 空订阅") } podcast := &Podcast{ Title: feed.Title, Description: feed.Description, Link: feed.Link, Image: feed.Image.URL, Copyright: feed.Copyright, Episodes: make([]Episode, 0), Funding: make([]Funding, 0), Persons: make([]Person, 0), Value: make([]Value, 0), Block: make([]Block, 0), Medium: MediumPodcast, } // 解析剧集 for _, item := range feed.Items { episode := Episode{ GUID: item.GUID, Title: item.Title, Description: item.Description, Link: item.Link, PublicationDate: item.PublishedParsed, Author: item.Author.Name, } // 解析媒体URL if len(item.Enclosures) > 0 { episode.ContentURL = item.Enclosures[0].URL } // 解析剧集图片 if item.Image != nil && item.Image.URL != "" { episode.ImageURL = item.Image.URL } // 解析时长 if item.ITunesExt != nil && item.ITunesExt.Duration != "" { // 简单处理,实际应该解析时间格式 durationSec := 0 fmt.Sscanf(item.ITunesExt.Duration, "%d", &durationSec) episode.Duration = durationSec } podcast.Episodes = append(podcast.Episodes, episode) } return podcast, nil }