Skip to content

Commit d8e7ae7

Browse files
committed
Add global cleanup policy configuration
- Add global cleanup policy to main Config struct - Change per-feed cleanup policy to pointer for optional inheritance - Implement fallback logic to use global policy when feed doesn't specify its own - Add comprehensive tests for cleanup policy inheritance scenarios - Update configuration documentation with examples - Add nil check in cleanup function to handle feeds without cleanup policies Fixes #214
1 parent e8bd603 commit d8e7ae7

File tree

5 files changed

+131
-3
lines changed

5 files changed

+131
-3
lines changed

cmd/podsync/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type Config struct {
3535
Tokens map[model.Provider]StringSlice `toml:"tokens"`
3636
// Downloader (youtube-dl) configuration
3737
Downloader ytdl.Config `toml:"downloader"`
38+
// Global cleanup policy applied to feeds that don't specify their own cleanup policy
39+
Cleanup *feed.Cleanup `toml:"cleanup"`
3840
}
3941

4042
type Log struct {
@@ -179,6 +181,11 @@ func (c *Config) applyDefaults(configPath string) {
179181
if _feed.PlaylistSort == "" {
180182
_feed.PlaylistSort = model.SortingAsc
181183
}
184+
185+
// Apply global cleanup policy if feed doesn't have its own
186+
if _feed.Clean == nil && c.Cleanup != nil {
187+
_feed.Clean = c.Cleanup
188+
}
182189
}
183190
}
184191

cmd/podsync/config_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ timeout = 15
8484
assert.EqualValues(t, 86400, feed.Filters.MaxDuration)
8585
assert.EqualValues(t, 365, feed.Filters.MaxAge)
8686
assert.EqualValues(t, 1, feed.Filters.MinAge)
87+
require.NotNil(t, feed.Clean)
8788
assert.EqualValues(t, 10, feed.Clean.KeepLast)
8889
assert.EqualValues(t, model.SortingDesc, feed.PlaylistSort)
8990

@@ -233,6 +234,114 @@ data_dir = "/data"
233234
assert.True(t, config.Database.Badger.FileIO)
234235
}
235236

237+
func TestGlobalCleanupPolicy(t *testing.T) {
238+
t.Run("global cleanup policy applied to feeds without cleanup", func(t *testing.T) {
239+
const file = `
240+
[cleanup]
241+
keep_last = 25
242+
243+
[server]
244+
data_dir = "/data"
245+
246+
[feeds]
247+
[feeds.FEED1]
248+
url = "https://youtube.com/channel/test1"
249+
250+
[feeds.FEED2]
251+
url = "https://youtube.com/channel/test2"
252+
clean = { keep_last = 5 }
253+
`
254+
path := setup(t, file)
255+
defer os.Remove(path)
256+
257+
config, err := LoadConfig(path)
258+
assert.NoError(t, err)
259+
require.NotNil(t, config)
260+
261+
// Global cleanup policy should be set
262+
require.NotNil(t, config.Cleanup)
263+
assert.EqualValues(t, 25, config.Cleanup.KeepLast)
264+
265+
// FEED1 should inherit global cleanup policy
266+
feed1, ok := config.Feeds["FEED1"]
267+
assert.True(t, ok)
268+
require.NotNil(t, feed1.Clean)
269+
assert.EqualValues(t, 25, feed1.Clean.KeepLast)
270+
271+
// FEED2 should keep its own cleanup policy
272+
feed2, ok := config.Feeds["FEED2"]
273+
assert.True(t, ok)
274+
require.NotNil(t, feed2.Clean)
275+
assert.EqualValues(t, 5, feed2.Clean.KeepLast)
276+
})
277+
278+
t.Run("no global cleanup policy", func(t *testing.T) {
279+
const file = `
280+
[server]
281+
data_dir = "/data"
282+
283+
[feeds]
284+
[feeds.FEED1]
285+
url = "https://youtube.com/channel/test1"
286+
287+
[feeds.FEED2]
288+
url = "https://youtube.com/channel/test2"
289+
clean = { keep_last = 5 }
290+
`
291+
path := setup(t, file)
292+
defer os.Remove(path)
293+
294+
config, err := LoadConfig(path)
295+
assert.NoError(t, err)
296+
require.NotNil(t, config)
297+
298+
// Global cleanup policy should not be set
299+
assert.Nil(t, config.Cleanup)
300+
301+
// FEED1 should have no cleanup policy
302+
feed1, ok := config.Feeds["FEED1"]
303+
assert.True(t, ok)
304+
assert.Nil(t, feed1.Clean)
305+
306+
// FEED2 should keep its own cleanup policy
307+
feed2, ok := config.Feeds["FEED2"]
308+
assert.True(t, ok)
309+
require.NotNil(t, feed2.Clean)
310+
assert.EqualValues(t, 5, feed2.Clean.KeepLast)
311+
})
312+
313+
t.Run("feed cleanup overrides global cleanup", func(t *testing.T) {
314+
const file = `
315+
[cleanup]
316+
keep_last = 100
317+
318+
[server]
319+
data_dir = "/data"
320+
321+
[feeds]
322+
[feeds.FEED1]
323+
url = "https://youtube.com/channel/test1"
324+
clean = { keep_last = 10 }
325+
`
326+
path := setup(t, file)
327+
defer os.Remove(path)
328+
329+
config, err := LoadConfig(path)
330+
assert.NoError(t, err)
331+
require.NotNil(t, config)
332+
333+
// Global cleanup policy should be set
334+
require.NotNil(t, config.Cleanup)
335+
assert.EqualValues(t, 100, config.Cleanup.KeepLast)
336+
337+
// FEED1 should use its own cleanup policy, not the global one
338+
feed1, ok := config.Feeds["FEED1"]
339+
assert.True(t, ok)
340+
require.NotNil(t, feed1.Clean)
341+
assert.EqualValues(t, 10, feed1.Clean.KeepLast)
342+
})
343+
}
344+
236345
func setup(t *testing.T, file string) string {
237346
t.Helper()
238347

config.toml.example

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# This is an example of TOML configuration file for Podsync.
22

3+
# Global cleanup policy applied to feeds that don't specify their own cleanup policy.
4+
# When set, this policy is used as a fallback for all feeds.
5+
# Comment out or remove this section if you don't want a global cleanup policy.
6+
[cleanup]
7+
keep_last = 50 # Keep last 50 episodes globally (unless overridden per feed)
8+
39
# Web server related configuration.
410
[server]
511
# HTTP server port.
@@ -75,8 +81,9 @@ vimeo = [ # Multiple keys will be rotated.
7581
# If set then overwrite 'update_period'.
7682
cron_schedule = "@every 12h"
7783

78-
# Whether to cleanup old episodes.
84+
# Whether to cleanup old episodes for this specific feed.
7985
# Keep last 10 episodes (order desc by PubDate)
86+
# This overrides the global cleanup policy if one is set.
8087
clean = { keep_last = 10 }
8188

8289
# Optional Golang regexp format.

pkg/feed/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type Config struct {
3333
// Only download episodes that match the filters (defaults to matching anything)
3434
Filters Filters `toml:"filters"`
3535
// Clean is a cleanup policy to use for this feed
36-
Clean Cleanup `toml:"clean"`
36+
Clean *Cleanup `toml:"clean"`
3737
// Custom is a list of feed customizations
3838
Custom Custom `toml:"custom"`
3939
// List of additional youtube-dl arguments passed at download time

services/update/updater.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,16 @@ func (u *Manager) cleanup(ctx context.Context, feedConfig *feed.Config) error {
327327
var (
328328
feedID = feedConfig.ID
329329
logger = log.WithField("feed_id", feedID)
330-
count = feedConfig.Clean.KeepLast
331330
list []*model.Episode
332331
result *multierror.Error
333332
)
334333

334+
if feedConfig.Clean == nil {
335+
logger.Debug("no cleanup policy configured")
336+
return nil
337+
}
338+
339+
count := feedConfig.Clean.KeepLast
335340
if count < 1 {
336341
logger.Info("nothing to clean")
337342
return nil

0 commit comments

Comments
 (0)