Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Podcast episodes updates. #569

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,9 @@ type PodcastEpisode struct {
Status PodcastEpisodeStatus
Error string
Podcast *Podcast
Artist string
Album string
Image string
}

func (pe *PodcastEpisode) AudioLength() int { return pe.Length }
Expand Down
7 changes: 7 additions & 0 deletions db/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (db *DB) Migrate(ctx MigrationContext) error {
construct(ctx, "202405301140", migrateAddReplayGainFields),
construct(ctx, "202501152035", migrateTrackAddIndexOnAlbumID),
construct(ctx, "202501152036", migrateAlbumAddIndexOnParentID),
construct(ctx, "202502012036", migratePodcastEpisode),
}

return gormigrate.
Expand Down Expand Up @@ -832,3 +833,9 @@ func migrateAlbumAddIndexOnParentID(tx *gorm.DB, _ MigrationContext) error {
CREATE INDEX idx_albums_parent_id ON "albums" (parent_id);
`).Error
}

func migratePodcastEpisode(tx *gorm.DB, _ MigrationContext) error {
return tx.AutoMigrate(
PodcastEpisode{},
).Error
}
22 changes: 12 additions & 10 deletions podcast/podcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (p *Podcasts) RefreshPodcast(podcast *db.Podcast, items []*gofeed.Item) err

var episodeErrs []error
for _, item := range items {
podcastEpisode, err := p.addEpisode(podcast.ID, item)
podcastEpisode, err := p.addEpisode(podcast.ID, item, podcast.Title)
if err != nil {
episodeErrs = append(episodeErrs, err)
continue
Expand All @@ -186,7 +186,7 @@ func (p *Podcasts) RefreshPodcast(podcast *db.Podcast, items []*gofeed.Item) err
return errors.Join(episodeErrs...)
}

func (p *Podcasts) addEpisode(podcastID int, item *gofeed.Item) (*db.PodcastEpisode, error) {
func (p *Podcasts) addEpisode(podcastID int, item *gofeed.Item, podcastTitle string) (*db.PodcastEpisode, error) {
var duration int
// if it has the media extension use it
for _, content := range item.Extensions["media"]["content"] {
Expand All @@ -200,14 +200,13 @@ func (p *Podcasts) addEpisode(podcastID int, item *gofeed.Item) (*db.PodcastEpis
if duration == 0 && item.ITunesExt != nil {
duration = getSecondsFromString(item.ITunesExt.Duration)
}

if episode, ok := p.findEnclosureAudio(podcastID, duration, item); ok {
if episode, ok := p.findEnclosureAudio(podcastID, duration, item, podcastTitle); ok {
if err := p.db.Save(episode).Error; err != nil {
return nil, err
}
return episode, nil
}
if episode, ok := p.findMediaAudio(podcastID, duration, item); ok {
if episode, ok := p.findMediaAudio(podcastID, duration, item, podcastTitle); ok {
if err := p.db.Save(episode).Error; err != nil {
return nil, err
}
Expand All @@ -224,7 +223,7 @@ func (p *Podcasts) isAudio(rawItemURL string) (bool, error) {
return p.tagReader.CanRead(itemURL.Path), nil
}

func itemToEpisode(podcastID, size, duration int, audio string, item *gofeed.Item) *db.PodcastEpisode {
func itemToEpisode(podcastID, size, duration int, audio string, item *gofeed.Item, podcastTitle string) *db.PodcastEpisode {
return &db.PodcastEpisode{
PodcastID: podcastID,
Description: item.Description,
Expand All @@ -234,21 +233,24 @@ func itemToEpisode(podcastID, size, duration int, audio string, item *gofeed.Ite
PublishDate: item.PublishedParsed,
AudioURL: audio,
Status: db.PodcastEpisodeStatusSkipped,
Artist: item.ITunesExt.Author,
Album: podcastTitle,
Image: item.ITunesExt.Image,
}
}

func (p *Podcasts) findEnclosureAudio(podcastID, duration int, item *gofeed.Item) (*db.PodcastEpisode, bool) {
func (p *Podcasts) findEnclosureAudio(podcastID, duration int, item *gofeed.Item, podcastTitle string) (*db.PodcastEpisode, bool) {
for _, enc := range item.Enclosures {
if t, err := p.isAudio(enc.URL); !t || err != nil {
continue
}
size, _ := strconv.Atoi(enc.Length)
return itemToEpisode(podcastID, size, duration, enc.URL, item), true
return itemToEpisode(podcastID, size, duration, enc.URL, item, podcastTitle), true
}
return nil, false
}

func (p *Podcasts) findMediaAudio(podcastID, duration int, item *gofeed.Item) (*db.PodcastEpisode, bool) {
func (p *Podcasts) findMediaAudio(podcastID, duration int, item *gofeed.Item, podcastTitle string) (*db.PodcastEpisode, bool) {
extensions, ok := item.Extensions["media"]["content"]
if !ok {
return nil, false
Expand All @@ -257,7 +259,7 @@ func (p *Podcasts) findMediaAudio(podcastID, duration int, item *gofeed.Item) (*
if t, err := p.isAudio(ext.Attrs["url"]); !t || err != nil {
continue
}
return itemToEpisode(podcastID, 0, duration, ext.Attrs["url"], item), true
return itemToEpisode(podcastID, 0, duration, ext.Attrs["url"], item, podcastTitle), true
}
return nil, false
}
Expand Down
12 changes: 12 additions & 0 deletions server/ctrlsubsonic/handlers_bookmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ func (c *Controller) ServeGetBookmarks(r *http.Request) *spec.Response {
return spec.NewError(10, "finding entry: %v", err)
}
respBookmark.Entry = spec.NewTrackByTags(&track, track.Album)
case specid.PodcastEpisode:
var podcastEpisode db.PodcastEpisode
err := c.dbc.
Preload("Podcast").
Find(&podcastEpisode, "id=?", bookmark.EntryID).
Error
if err != nil {
return spec.NewError(10, "finding entry: %v", err)
}
respBookmark.Entry = spec.NewTCPodcastEpisode(&podcastEpisode)
default:
continue
}

sub.Bookmarks.List = append(sub.Bookmarks.List, respBookmark)
Expand Down
5 changes: 4 additions & 1 deletion server/ctrlsubsonic/spec/construct_by_folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ func NewTCPodcastEpisode(pe *db.PodcastEpisode) *TrackChild {
IsDir: false,
Type: "podcastepisode",
CreatedAt: pe.CreatedAt,
Album: pe.Album,
Artist: pe.Artist,
CoverID: pe.SID(),
}
if pe.Podcast != nil {
trCh.ParentID = pe.Podcast.SID()
Expand All @@ -136,7 +139,7 @@ func NewTCPodcastEpisode(pe *db.PodcastEpisode) *TrackChild {
}

func NewArtistByFolder(f *db.Album) *Artist {
// the db is structued around "browse by tags", and where
// the db is structured around "browse by tags", and where
// an album is also a folder. so we're constructing an artist
// from an "album" where
// maybe TODO: rename the Album model to Folder
Expand Down
35 changes: 19 additions & 16 deletions server/ctrlsubsonic/spec/construct_podcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,25 @@ func NewPodcastEpisode(pe *db.PodcastEpisode) *PodcastEpisode {
return nil
}
r := &PodcastEpisode{
ID: pe.SID(),
StreamID: pe.SID(),
ContentType: pe.MIME(),
ChannelID: pe.PodcastSID(),
Title: pe.Title,
Description: CleanExternalText(pe.Description),
Status: string(pe.Status),
CoverArt: pe.PodcastSID(),
PublishDate: *pe.PublishDate,
Genre: "Podcast",
Duration: pe.Length,
Year: pe.PublishDate.Year(),
Suffix: formatExt(pe.Ext()),
BitRate: pe.Bitrate,
IsDir: false,
Size: pe.Size,
ID: pe.SID(),
StreamID: pe.SID(),
ContentType: pe.MIME(),
ChannelID: pe.PodcastSID(),
Title: pe.Title,
Description: CleanExternalText(pe.Description),
Status: string(pe.Status),
CoverArt: pe.PodcastSID(),
PublishDate: *pe.PublishDate,
Genre: "Podcast",
Duration: pe.Length,
Year: pe.PublishDate.Year(),
Suffix: formatExt(pe.Ext()),
BitRate: pe.Bitrate,
IsDir: false,
Size: pe.Size,
Album: pe.Album,
Artist: pe.Artist,
OriginalImageURL: pe.Image,
}
if pe.Podcast != nil {
r.Path = pe.AbsPath()
Expand Down
39 changes: 21 additions & 18 deletions server/ctrlsubsonic/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,24 +394,27 @@ type PodcastChannel struct {
}

type PodcastEpisode struct {
ID *specid.ID `xml:"id,attr" json:"id"`
StreamID *specid.ID `xml:"streamId,attr" json:"streamId"`
ChannelID *specid.ID `xml:"channelId,attr" json:"channelId"`
Title string `xml:"title,attr" json:"title"`
Description string `xml:"description,attr" json:"description"`
PublishDate time.Time `xml:"publishDate,attr" json:"publishDate"`
Status string `xml:"status,attr" json:"status"`
Parent string `xml:"parent,attr" json:"parent"`
IsDir bool `xml:"isDir,attr" json:"isDir"`
Year int `xml:"year,attr" json:"year"`
Genre string `xml:"genre,attr" json:"genre"`
CoverArt *specid.ID `xml:"coverArt,attr" json:"coverArt"`
Size int `xml:"size,attr" json:"size"`
ContentType string `xml:"contentType,attr" json:"contentType"`
Suffix string `xml:"suffix,attr" json:"suffix"`
Duration int `xml:"duration,attr" json:"duration"`
BitRate int `xml:"bitRate,attr" json:"bitrate"`
Path string `xml:"path,attr" json:"path"`
ID *specid.ID `xml:"id,attr" json:"id"`
StreamID *specid.ID `xml:"streamId,attr" json:"streamId"`
ChannelID *specid.ID `xml:"channelId,attr" json:"channelId"`
Title string `xml:"title,attr" json:"title"`
Description string `xml:"description,attr" json:"description"`
PublishDate time.Time `xml:"publishDate,attr" json:"publishDate"`
Status string `xml:"status,attr" json:"status"`
Parent string `xml:"parent,attr" json:"parent"`
IsDir bool `xml:"isDir,attr" json:"isDir"`
Year int `xml:"year,attr" json:"year"`
Genre string `xml:"genre,attr" json:"genre"`
CoverArt *specid.ID `xml:"coverArt,attr" json:"coverArt"`
Size int `xml:"size,attr" json:"size"`
ContentType string `xml:"contentType,attr" json:"contentType"`
Suffix string `xml:"suffix,attr" json:"suffix"`
Duration int `xml:"duration,attr" json:"duration"`
BitRate int `xml:"bitRate,attr" json:"bitrate"`
Path string `xml:"path,attr" json:"path"`
Album string `xml:"album,attr" json:"album"`
Artist string `xml:"artist,attr" json:"artist"`
OriginalImageURL string `xml:"originalImageUrl,attr" json:"originalImageUrl"`
}

type Bookmarks struct {
Expand Down
Loading