Keep only the newest 50 episodes of each podcast
A show that has published for years is unbounded: GEOlino Spezial alone is 358 episodes and 5.8 GB, and the device it syncs onto is a 30 GB SD card that also holds the rest of the library. Nothing stopped the 6-hourly poll from eventually filling it. Cap each show's folder at general.podcast_episode_limit (default 50, null to keep everything), pruning the oldest past that after each sync pass. The same limit caps what is downloaded, and it has to be one number for both. Prune to the newest N but keep fetching everything the feed offers, and every poll would re-download exactly the episodes the previous one deleted - forever, at full size, since missing_episodes() decides purely from what is on disk. There is a test for that specific loop. Pruning only touches files named the way this module names them (YYYYMMDD - Title.ext), so feed.txt, folder.jpg, the failed-download record and anything placed by hand are all left alone; a parse that fails means "not ours", not "delete it". An episode's sidecar cover goes with it. A pass that only deleted still reports a change, because the library needs the rescan just as much as it does after a download. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ from ruamel.yaml.error import YAMLError
|
||||
|
||||
from musicmouse.color import ColorRGBW, parse_color
|
||||
from musicmouse.hardware import NO_FIGURE_TAG, RFID_TAG_LENGTH
|
||||
from musicmouse.library.podcast_feeds import DEFAULT_EPISODE_LIMIT
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
@@ -288,6 +289,14 @@ class GeneralConfig(_Strict):
|
||||
|
||||
audio_extensions: tuple[str, ...] = DEFAULT_AUDIO_EXTENSIONS
|
||||
|
||||
#: How many episodes of each podcast show to keep, newest first. A show that has
|
||||
#: published for years grows without bound and will eventually fill the device's SD
|
||||
#: card. ``null`` keeps every episode, and minding the free space is then on you.
|
||||
#:
|
||||
#: Lowering this *deletes* the episodes that fall outside the window on the next
|
||||
#: poll, and an episode that has aged out of its feed cannot be fetched again.
|
||||
podcast_episode_limit: int | None = Field(default=DEFAULT_EPISODE_LIMIT, ge=1)
|
||||
|
||||
@property
|
||||
def serial_simulated(self) -> bool:
|
||||
return self.serial_port == SIMULATE
|
||||
|
||||
Reference in New Issue
Block a user