Skip to content

Fix #169: keep TV episodes contiguous when cache space is tight#170

Merged
StudioNirin merged 1 commit into
StudioNirin:mainfrom
Brandon-Haney:pr/issue-169-episode-ordering
May 29, 2026
Merged

Fix #169: keep TV episodes contiguous when cache space is tight#170
StudioNirin merged 1 commit into
StudioNirin:mainfrom
Brandon-Haney:pr/issue-169-episode-ordering

Conversation

@Brandon-Haney

@Brandon-Haney Brandon-Haney commented May 26, 2026

Copy link
Copy Markdown
Collaborator

Fixes #169.

When cache space is tight, the next OnDeck episode (e.g. S04E03) could be skipped while later episodes of the same show (E04, E05) got cached anyway — leaving a viewing gap. Two layers were contributing.

What was happening

1. Ordering was destroyed before the space-fit step. _gather_media_to_cache collected paths into a set() and then did list(modified_paths_set) to hand off to _apply_cache_limit. Python set has no defined iteration order, so OnDeck's "current + next N episodes" sequence arrived at the fitter in arbitrary hash-bucket order.

2. _apply_cache_limit was a greedy first-fit pack. If an episode didn't fit, the loop just skipped it and kept going. So a 15 GB 4K E03 with 10 GB free would be skipped, then 2 GB E04 + 2 GB E05 would both fit and get cached.

What this PR does

  1. modified_paths_set (a set) becomes modified_paths: Dict[str, None] used as an ordered set — Python dicts preserve insertion order, so OnDeck fetch order survives all the way through. Final priority order: pinned → OnDeck → OnDeck siblings → watchlist.

  2. _apply_cache_limit now tracks shows_at_capacity. Once an episode of show X doesn't fit, every later file mapped to show X via media_info_map is skipped, even if it would individually fit. Movies and other shows still pack independently into the remaining space, so one oversized 4K episode doesn't starve everything else.

  3. The space-limit warning now appends (N skipped to keep show episodes contiguous) when gap-skips happen, so the behavior is visible in logs.

Test plan

  • Configure a cache quota or min-free-space so total OnDeck size exceeds available space
  • Run the cache and confirm: either all of the in-order next episodes for that show fit, or none do — no gaps mid-sequence
  • Confirm other shows and movies still cache normally into remaining space
  • Check logs for the (N skipped to keep show episodes contiguous) note when applicable

New TestNoGapShowOrdering class in tests/test_plexcache_quota.py covers:

  • Oversized first episode → later episodes of same show skipped
  • Mid-sequence break (E03 fits, E04 oversized → E05 skipped)
  • Cross-show independence (ShowA at capacity doesn't starve ShowB or movies)
  • No-metadata fallback (movies/siblings without show keys keep first-fit behavior)
  • Happy path (all fit → all cached, no skips)

…tight

Two layers were causing the "S04E03 skipped, S04E04+E05 cached" gap pattern
when episode sizes varied within a show (e.g. 4K vs SDR mix).

1. Ordering was lost before space-fit. _gather_media_to_cache collected
   paths into a set(), so OnDeck "current + next N episodes" arrived at
   _apply_cache_limit in arbitrary hash-bucket order. Switched to a
   dict-as-ordered-set so insertion order survives: pinned, then OnDeck
   in fetch order, then siblings, then watchlist.

2. The space-fit loop in _apply_cache_limit was greedy first-fit, so a
   large episode would be skipped and smaller later episodes of the same
   show would be packed instead, creating viewing gaps. Now tracks shows
   whose sequence broke at the space boundary and skips every later file
   mapped to that show via media_info_map. Movies and other shows still
   pack independently.

Added TestNoGapShowOrdering in tests/test_plexcache_quota.py covering the
gap scenario, mid-sequence breaks, cross-show independence, the no-metadata
fallback, and the all-fit happy path.
@StudioNirin StudioNirin merged commit 7aa416d into StudioNirin:main May 29, 2026
2 checks passed
@Brandon-Haney Brandon-Haney deleted the pr/issue-169-episode-ordering branch June 7, 2026 04:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Files not cached in order when space is limited

2 participants