From 35dc6043bc455a5adca4900c4d97af7026779aa2 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Sat, 7 Mar 2020 18:01:00 -0800 Subject: [PATCH] Support episodes cleanup #44 --- README.md | 1 + cmd/podsync/updater.go | 61 +++++++++++++++++++++++++++++++++++++++ pkg/config/config.go | 7 +++++ pkg/config/config_test.go | 4 +++ 4 files changed, 73 insertions(+) diff --git a/README.md b/README.md index 4647aa4..1d68d3e 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ vimeo = "{VIMEO_API_TOKEN}" # max_height = "720" # Optional maximal height of video, example: 720, 1080, 1440, 2160, ... # cron_schedule = "@every 12h" # Optional cron expression format. If set then overwrite 'update_period'. See details below # filters = { title = "regex for title here" } # Optional Golang regexp format. If set, then only download episodes with matching titles. + # clean = { keep_last = 10 } # Keep last 10 episodes (order desc by PubDate) ``` Episodes files will be kept at: `/path/to/data/directory/ID1`, feed will be accessible from: `http://localhost/ID1.xml` diff --git a/cmd/podsync/updater.go b/cmd/podsync/updater.go index 44d0fe7..3660275 100644 --- a/cmd/podsync/updater.go +++ b/cmd/podsync/updater.go @@ -7,8 +7,10 @@ import ( "io" "os" "regexp" + "sort" "time" + "github.com/hashicorp/go-multierror" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -61,6 +63,10 @@ func (u *Updater) Update(ctx context.Context, feedConfig *config.Feed) error { return err } + if err := u.cleanup(ctx, feedConfig); err != nil { + log.WithError(err).Error("cleanup failed") + } + elapsed := time.Since(started) nextUpdate := time.Now().Add(feedConfig.UpdatePeriod.Duration) log.Infof("successfully updated feed in %s, next update at %s", elapsed, nextUpdate.Format(time.Kitchen)) @@ -241,3 +247,58 @@ func (u *Updater) buildXML(ctx context.Context, feedConfig *config.Feed) error { return nil } + +func (u *Updater) cleanup(ctx context.Context, feedConfig *config.Feed) error { + var ( + feedID = feedConfig.ID + logger = log.WithField("feed_id", feedID) + count = feedConfig.Clean.KeepLast + list []*model.Episode + result *multierror.Error + ) + + if count < 1 { + logger.Info("nothing to clean") + return nil + } + + logger.WithField("count", count).Info("running cleaner") + if err := u.db.WalkEpisodes(ctx, feedConfig.ID, func(episode *model.Episode) error { + switch episode.Status { + case model.EpisodeError, model.EpisodeCleaned: + // Skip + default: + list = append(list, episode) + } + return nil + }); err != nil { + return err + } + + if count > len(list) { + return nil + } + + sort.Slice(list, func(i, j int) bool { + return list[i].PubDate.After(list[j].PubDate) + }) + + for _, episode := range list[count:] { + logger.WithField("episode_id", episode.ID).Infof("deleting %q", episode.Title) + + if err := u.fs.Delete(ctx, feedConfig.ID, feed.EpisodeName(feedConfig, episode)); err != nil { + result = multierror.Append(result, errors.Wrapf(err, "failed to delete episode: %s", episode.ID)) + continue + } + + if err := u.db.UpdateEpisode(feedID, episode.ID, func(episode *model.Episode) error { + episode.Status = model.EpisodeCleaned + return nil + }); err != nil { + result = multierror.Append(result, errors.Wrapf(err, "failed to set state for cleaned episode: %s", episode.ID)) + continue + } + } + + return result.ErrorOrNil() +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 7cdecd0..bbb57c4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -38,6 +38,8 @@ type Feed struct { CoverArt string `toml:"cover_art"` // Only download episodes that match this regexp (defaults to matching anything) Filters Filters `toml:"filters"` + // Clean is a cleanup policy to use for this feed + Clean Cleanup `toml:"clean"` } type Tokens struct { @@ -64,6 +66,11 @@ type Database struct { Dir string `toml:"dir"` } +type Cleanup struct { + // KeepLast defines how many episodes to keep + KeepLast int `toml:"keep_last"` +} + type Config struct { // Server is the web server configuration Server Server `toml:"server"` diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index c29ce61..4cdb8ab 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -32,6 +32,8 @@ dir = "/home/user/db/" update_period = "5h" format = "audio" quality = "low" + filters = { title = "regex for title here" } + clean = { keep_last = 10 } ` f, err := ioutil.TempFile("", "") @@ -62,6 +64,8 @@ dir = "/home/user/db/" assert.EqualValues(t, Duration{5 * time.Hour}, feed.UpdatePeriod) assert.EqualValues(t, "audio", feed.Format) assert.EqualValues(t, "low", feed.Quality) + assert.EqualValues(t, "regex for title here", feed.Filters.Title) + assert.EqualValues(t, 10, feed.Clean.KeepLast) } func TestApplyDefaults(t *testing.T) {