Skip to content

Commit

Permalink
Refactor updater
Browse files Browse the repository at this point in the history
  • Loading branch information
mxpv committed Mar 8, 2020
1 parent 62b64b6 commit e0290af
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 124 deletions.
128 changes: 5 additions & 123 deletions cmd/podsync/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@ import (
"io"
"os"
"regexp"
"strconv"
"time"

itunes "github.com/eduncan911/podcast"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/db"
"github.com/mxpv/podsync/pkg/feed"
"github.com/mxpv/podsync/pkg/fs"
"github.com/mxpv/podsync/pkg/link"
"github.com/mxpv/podsync/pkg/model"
"github.com/mxpv/podsync/pkg/ytdl"
)
Expand Down Expand Up @@ -49,6 +46,7 @@ func (u *Updater) Update(ctx context.Context, feedConfig *config.Feed) error {
"format": feedConfig.Format,
"quality": feedConfig.Quality,
}).Infof("-> updating %s", feedConfig.URL)

started := time.Now()

if err := u.updateFeed(ctx, feedConfig); err != nil {
Expand All @@ -72,7 +70,7 @@ func (u *Updater) Update(ctx context.Context, feedConfig *config.Feed) error {
// updateFeed pulls API for new episodes and saves them to database
func (u *Updater) updateFeed(ctx context.Context, feedConfig *config.Feed) error {
// Create an updater for this feed type
provider, err := u.makeBuilder(ctx, feedConfig)
provider, err := feed.New(ctx, feedConfig, u.config.Tokens)
if err != nil {
return err
}
Expand Down Expand Up @@ -142,7 +140,7 @@ func (u *Updater) downloadEpisodes(ctx context.Context, feedConfig *config.Feed)
for idx, episode := range downloadList {
var (
logger = log.WithFields(log.Fields{"index": idx, "episode_id": episode.ID})
episodeName = u.episodeName(feedConfig, episode)
episodeName = feed.EpisodeName(feedConfig, episode)
)

// Check whether episode already exists
Expand Down Expand Up @@ -220,14 +218,14 @@ func (u *Updater) downloadEpisodes(ctx context.Context, feedConfig *config.Feed)
}

func (u *Updater) buildXML(ctx context.Context, feedConfig *config.Feed) error {
feed, err := u.db.GetFeed(ctx, feedConfig.ID)
f, err := u.db.GetFeed(ctx, feedConfig.ID)
if err != nil {
return err
}

// Build iTunes XML feed with data received from builder
log.Debug("building iTunes podcast feed")
podcast, err := u.buildPodcast(ctx, feed, feedConfig)
podcast, err := feed.Build(ctx, f, feedConfig, u.fs)
if err != nil {
return err
}
Expand All @@ -243,119 +241,3 @@ func (u *Updater) buildXML(ctx context.Context, feedConfig *config.Feed) error {

return nil
}

func (u *Updater) buildPodcast(ctx context.Context, feed *model.Feed, cfg *config.Feed) (*itunes.Podcast, error) {
const (
podsyncGenerator = "Podsync generator (support us at https://github.com/mxpv/podsync)"
defaultCategory = "TV & Film"
)

now := time.Now().UTC()

p := itunes.New(feed.Title, feed.ItemURL, feed.Description, &feed.PubDate, &now)
p.Generator = podsyncGenerator
p.AddSubTitle(feed.Title)
p.AddCategory(defaultCategory, nil)
p.AddImage(feed.CoverArt)
p.IAuthor = feed.Title
p.AddSummary(feed.Description)

if feed.Explicit {
p.IExplicit = "yes"
} else {
p.IExplicit = "no"
}

if feed.Language != "" {
p.Language = feed.Language
}

for i, episode := range feed.Episodes {
if episode.Status != model.EpisodeDownloaded {
// Skip episodes that are not yet downloaded
continue
}

item := itunes.Item{
GUID: episode.ID,
Link: episode.VideoURL,
Title: episode.Title,
Description: episode.Description,
ISubtitle: episode.Title,
IOrder: strconv.Itoa(i),
}

pubDate := episode.PubDate
if pubDate.IsZero() {
pubDate = now
}

item.AddPubDate(&pubDate)

item.AddSummary(episode.Description)
item.AddImage(episode.Thumbnail)
item.AddDuration(episode.Duration)

enclosureType := itunes.MP4
if feed.Format == model.FormatAudio {
enclosureType = itunes.MP4
}

episodeName := u.episodeName(cfg, episode)
downloadURL, err := u.fs.URL(ctx, cfg.ID, episodeName)
if err != nil {
return nil, errors.Wrapf(err, "failed to obtain download URL for: %s", episodeName)
}

item.AddEnclosure(downloadURL, enclosureType, episode.Size)

// p.AddItem requires description to be not empty, use workaround
if item.Description == "" {
item.Description = " "
}

if feed.Explicit {
item.IExplicit = "yes"
} else {
item.IExplicit = "no"
}

if _, err := p.AddItem(item); err != nil {
return nil, errors.Wrapf(err, "failed to add item to podcast (id %q)", episode.ID)
}
}

return &p, nil
}

func (u *Updater) episodeName(feedConfig *config.Feed, episode *model.Episode) string {
ext := "mp4"
if feedConfig.Format == model.FormatAudio {
ext = "mp3"
}

return fmt.Sprintf("%s.%s", episode.ID, ext)
}

func (u *Updater) makeBuilder(ctx context.Context, cfg *config.Feed) (feed.Builder, error) {
var (
provider feed.Builder
err error
)

info, err := link.Parse(cfg.URL)
if err != nil {
return nil, err
}

switch info.Provider {
case link.ProviderYoutube:
provider, err = feed.NewYouTubeBuilder(u.config.Tokens.YouTube)
case link.ProviderVimeo:
provider, err = feed.NewVimeoBuilder(ctx, u.config.Tokens.Vimeo)
default:
return nil, errors.Errorf("unsupported provider %q", info.Provider)
}

return provider, err
}
111 changes: 111 additions & 0 deletions pkg/feed/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package feed

import (
"context"
"fmt"
"strconv"
"time"

itunes "github.com/eduncan911/podcast"
"github.com/pkg/errors"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/model"
)

type urlProvider interface {
URL(ctx context.Context, ns string, fileName string) (string, error)
}

func Build(ctx context.Context, feed *model.Feed, cfg *config.Feed, provider urlProvider) (*itunes.Podcast, error) {
const (
podsyncGenerator = "Podsync generator (support us at https://github.com/mxpv/podsync)"
defaultCategory = "TV & Film"
)

now := time.Now().UTC()

p := itunes.New(feed.Title, feed.ItemURL, feed.Description, &feed.PubDate, &now)
p.Generator = podsyncGenerator
p.AddSubTitle(feed.Title)
p.AddCategory(defaultCategory, nil)
p.AddImage(feed.CoverArt)
p.IAuthor = feed.Title
p.AddSummary(feed.Description)

if feed.Explicit {
p.IExplicit = "yes"
} else {
p.IExplicit = "no"
}

if feed.Language != "" {
p.Language = feed.Language
}

for i, episode := range feed.Episodes {
if episode.Status != model.EpisodeDownloaded {
// Skip episodes that are not yet downloaded
continue
}

item := itunes.Item{
GUID: episode.ID,
Link: episode.VideoURL,
Title: episode.Title,
Description: episode.Description,
ISubtitle: episode.Title,
IOrder: strconv.Itoa(i),
}

pubDate := episode.PubDate
if pubDate.IsZero() {
pubDate = now
}

item.AddPubDate(&pubDate)

item.AddSummary(episode.Description)
item.AddImage(episode.Thumbnail)
item.AddDuration(episode.Duration)

enclosureType := itunes.MP4
if feed.Format == model.FormatAudio {
enclosureType = itunes.MP4
}

episodeName := EpisodeName(cfg, episode)
downloadURL, err := provider.URL(ctx, cfg.ID, episodeName)
if err != nil {
return nil, errors.Wrapf(err, "failed to obtain download URL for: %s", episodeName)
}

item.AddEnclosure(downloadURL, enclosureType, episode.Size)

// p.AddItem requires description to be not empty, use workaround
if item.Description == "" {
item.Description = " "
}

if feed.Explicit {
item.IExplicit = "yes"
} else {
item.IExplicit = "no"
}

if _, err := p.AddItem(item); err != nil {
return nil, errors.Wrapf(err, "failed to add item to podcast (id %q)", episode.ID)
}
}

return &p, nil
}

func EpisodeName(feedConfig *config.Feed, episode *model.Episode) string {
ext := "mp4"
if feedConfig.Format == model.FormatAudio {
ext = "mp3"
}

return fmt.Sprintf("%s.%s", episode.ID, ext)
}
27 changes: 26 additions & 1 deletion pkg/feed/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package feed

import (
"context"
"errors"

"github.com/pkg/errors"

"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/link"
"github.com/mxpv/podsync/pkg/model"
)

Expand All @@ -16,3 +18,26 @@ var (
type Builder interface {
Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error)
}

func New(ctx context.Context, cfg *config.Feed, tokens config.Tokens) (Builder, error) {
var (
provider Builder
err error
)

info, err := link.Parse(cfg.URL)
if err != nil {
return nil, err
}

switch info.Provider {
case link.ProviderYoutube:
provider, err = NewYouTubeBuilder(tokens.YouTube)
case link.ProviderVimeo:
provider, err = NewVimeoBuilder(ctx, tokens.Vimeo)
default:
return nil, errors.Errorf("unsupported provider %q", info.Provider)
}

return provider, err
}

0 comments on commit e0290af

Please sign in to comment.