Skip to content

Add scoped library schedule modes - #3466

Open
YozoraXCII wants to merge 10 commits into
nightlyfrom
library-filters
Open

Add scoped library schedule modes#3466
YozoraXCII wants to merge 10 commits into
nightlyfrom
library-filters

Conversation

@YozoraXCII

@YozoraXCII YozoraXCII commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • Bug Fix (non-breaking change which fixes an issue)
  • Feature/Tweak (non-breaking change which adds new functionality or enhances existing functionality)
  • Breaking Change (fix or feature that would break any existing functionality for users)
  • Documentation Update
  • Chore (maintenance, dependency bumps, housekeeping - no functional change)
  • Other

Description

Adds library schedule modes using an explicit YAML list of schedule and mode mappings.

Schedule modifiers

Modifier What it does Example
.not Inverts one schedule expression. weekly.not(monday) matches every day except Monday.

Modes

Mode What it does
full Processes every top-level item in the library.
added(days) Processes items added to Plex within the specified number of days. For TV Show libraries, also includes existing shows with a recently added episode.
diff Processes top-level items whose Plex rating keys were absent from the previous cached library snapshot.
diff_episode TV Show libraries only. Processes newly seen episode rating keys and their parent shows.
index(A-F) Processes titles beginning with the inclusive A–F range.
index(A-F#) Processes A–F plus titles beginning with a number, symbol, or other non-alphabetical character.

Example configuration

libraries:
  Movies:
    schedule:
      - schedule: weekly(monday)
        mode: added(7)
      - schedule: weekly(tuesday)
        mode: index(A-F#)
      - schedule: weekly.not(monday|tuesday)
        mode: full

  TV Shows:
    schedule:
      - schedule: weekly(monday)
        mode: diff_episode
      - schedule: weekly.not(monday)
        mode: full

Related Issues [optional]

  • Related Issue #
  • Closes #

Have you updated the Documentation to reflect changes (if necessary)?

  • Yes
  • No
  • Not Applicable

Have you updated the JSON Schema files (if necessary)?

  • Yes
  • No
  • Not Applicable

Have you updated the CHANGELOG.md?

  • Yes
  • No

@YozoraXCII YozoraXCII added the docker Build Pull Request in Docker label Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Docker image pushed: kometateam/kometa:library-filters

@YozoraXCII
YozoraXCII requested a review from badja-dev August 3, 2026 13:15

@badja-dev badja-dev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things to possible settle before merge, neither causing the biggest headache:

  1. Schedule list is evaluated twice (config.py at load time, library.py at run time) with two different current_time sources. Worth consolidating to one evaluation
  2. Scope enforcement is spread across three call sites in the Plex/builder code. Would like to see this run against a real library with a list-based collection (imdb_list, trakt_list, etc) on a scoped schedule to confirm nothing outside scheduled_item_keys sneaks through

Comment thread kometa.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

library._all_items is accessed directly here to build the cache snapshot, reaching into a "private" attribute on the Plex subclass from kometa.py. Works fine since Plex is the only Library subclass, but might be worth a small accessor method on Library instead, for cleanliness

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I added Library.get_cached_items() as the public accessor for the unscoped per-run snapshot, and replaced the direct _all_items access in kometa.py.

Comment thread modules/builder.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter_and_save_items guards with getattr(self, "library", None) before checking schedule scope. Is there a real path where a builder has no library set, or was this just to satisfy a test fixture?
If it's just for the test, might be cleaner to fix the fixture instead of adding a runtime guard for a case that can't happen in a real run

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a real no-library path: playlist builders. I replaced the generic runtime guard with the explicit not self.playlist condition, and fixed the non-playlist test fixture so it supplies the required library.

Comment thread modules/config.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The schedule list gets evaluated here to decide skip_library (using current_time), then evaluated again in library._schedule_item_keys (using a fresh datetime.now()) to pick the actual mode.

Basically, can we calculate the mode once and pass it through, so there is one source of truth?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Config loading now selects the first matching schedule mode using the existing current_time, stores it in params["schedule_mode"], and Library only consumes that selected value. It no longer re-evaluates schedules with a separate clock source.

Comment thread modules/library.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scope is enforced in get_all, search, exact_search, and filter_and_save_items.
With how cumbersome builder.py is, is there a fetch path (direct rating-key lookup, list-based collection sources, etc) that could pull in an item outside scheduled_item_keys and skip these checks?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a regression test for the direct ratingKey path used after list builders resolve IDs. It fetches an item outside scheduled_item_keys and verifies filter_and_save_items excludes it. This is the shared final path for list-derived IDs, including IMDb/Trakt list results. I haven’t run it against a live Plex library from this environment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a regression test for the direct ratingKey path used after list builders resolve IDs. It fetches an item outside scheduled_item_keys and verifies filter_and_save_items excludes it. This is the shared final path for list-derived IDs, including IMDb/Trakt list results. I haven’t run it against a live Plex library from this environment.

@YozoraXCII

Copy link
Copy Markdown
Contributor Author

@badja-dev to re-review please

@badja-dev badja-dev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docker Build Pull Request in Docker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants