8.9 KiB
8.9 KiB
Shifted Seasons Handling
This file defines the behavioral contract for mapping source season and episode numbering to target season and episode numbering through stored shifted-season rules.
Primary sources:
requirements/project.mdrequirements/architecture.md- actual tool code in
src/ffx/
Secondary source:
SCRATCHPAD.md, used only to clarify current hardening gaps and not as the primary contract source.
Scope
- Persisting shifted-season rules in SQLite.
- Allowing shifted-season rules to be attached either to a show or to a specific pattern.
- Selecting at most one active shifted-season rule for one concrete source season and episode tuple.
- Applying additive season and episode offsets to produce target numbering.
- Using shifted target numbering during
convertfor TMDB episode lookup and generated season and episode filename tokens. - Managing show-level default mappings and pattern-level override mappings from the Textual editing workflows.
Out Of Scope
- General filename parsing rules for detecting season and episode values.
- Standalone
renamecommand behavior, which currently uses explicit rename inputs rather than stored shifted-season rules. - Stream or track mapping behavior unrelated to season and episode numbering.
Terms
shifted-season rule: one persisted row describing how one source-numbering range maps to target numbering through additive offsets.show-level shifted-season rule: a rule attached directly to a show and used as the fallback mapping layer for that show.pattern-level shifted-season rule: a rule attached directly to a pattern and used as the override mapping layer for that pattern.source numbering: the season and episode values detected from the current source file or supplied as source-side conversion inputs before shifting.target numbering: the season and episode values after one active shifted-season rule has been applied.original season: the source-domain season number a shifted-season rule is eligible to match.episode range: the optional source-domain episode interval covered by one shifted-season rule.open bound: an unbounded start or end of the episode range. Current storage uses-1as the internal sentinel for an open bound.active shifted-season rule: the single rule selected for one concrete input after precedence resolution.identity mapping: the default1:1outcome where source numbering is used unchanged.
Rules
SHIFTED_SEASONS_HANDLING-0001: The domain model shall allow a shifted-season rule to be owned by exactly one of:- one show
- one pattern
SHIFTED_SEASONS_HANDLING-0002: A single shifted-season rule shall not belong to both a show and a pattern at the same time.SHIFTED_SEASONS_HANDLING-0003: A shifted-season rule shall carry these fields:original_season,first_episode,last_episode,season_offset, andepisode_offset.SHIFTED_SEASONS_HANDLING-0004:season_offsetandepisode_offsetshall be additive signed integers applied to matched source numbering to produce target numbering.SHIFTED_SEASONS_HANDLING-0005: A shifted-season rule shall match a source tuple only when:- the source season equals
original_season - the source episode is greater than or equal to
first_episodewhen the lower bound is closed - the source episode is less than or equal to
last_episodewhen the upper bound is closed
- the source season equals
SHIFTED_SEASONS_HANDLING-0006: An open lower or upper episode bound shall represent an unbounded side of the covered source episode range.SHIFTED_SEASONS_HANDLING-0007: If one shifted-season rule matches, target numbering shall be:target season = source season + season_offsettarget episode = source episode + episode_offset
SHIFTED_SEASONS_HANDLING-0008: If no shifted-season rule matches, source numbering shall pass through unchanged.SHIFTED_SEASONS_HANDLING-0009: Shifted-season handling shall operate in a source-to-target numbering model. Stored rules map detected source numbering to the target numbering used by conversion-facing metadata and output naming.SHIFTED_SEASONS_HANDLING-0010: Pattern matching identifies the owning show and optionally a more specific owning pattern. Resolution of the active shifted-season rule shall use this precedence order:- matching pattern-level rule
- matching show-level rule
- identity mapping
SHIFTED_SEASONS_HANDLING-0011: At most one shifted-season rule may be active for one concrete source season and episode tuple. Shifted-season rules shall never stack or compose.SHIFTED_SEASONS_HANDLING-0012: Within one owner scope, shifted-season rules shall not overlap in their effective episode coverage for the sameoriginal_season.SHIFTED_SEASONS_HANDLING-0013: If a shifted-season rule uses two closed episode bounds,last_episodeshall be greater than or equal tofirst_episode.SHIFTED_SEASONS_HANDLING-0014: Shifted-season rule evaluation shall be deterministic. Released behavior shall not depend on arbitrary database row order when invalid overlapping rules exist.SHIFTED_SEASONS_HANDLING-0015: A pattern-level rule is permitted to map to zero offsets. Such a rule is a valid explicit override that beats show-level fallback and produces identity mapping for its covered source range.SHIFTED_SEASONS_HANDLING-0016: Duringconvert, when show, season, and episode values are available and stored shifting is active, the shifted target numbering shall drive:- TMDB episode lookup
- season and episode filename tokens such as
S01E02 - generated episode basenames that include season and episode numbering
SHIFTED_SEASONS_HANDLING-0017: When conversion is supplied explicit target-domain season or episode values for TMDB naming, the system shall not apply stored shifting on top of those already-targeted values.SHIFTED_SEASONS_HANDLING-0018: Operator-facing editing shall expose shifted-season rule management in both of these places:- show editing for show-level default mappings
- pattern editing for pattern-level override mappings
SHIFTED_SEASONS_HANDLING-0019: User-facing shifted-season editing should present open episode bounds as a natural empty-state input rather than forcing operators to type the internal sentinel directly.
Acceptance
- A show can exist with zero or more show-level shifted-season rules.
- A pattern can exist with zero or more pattern-level shifted-season rules.
- A shifted-season rule is stored against exactly one owner scope.
- A source tuple matching a pattern-level rule yields target numbering from that rule even when a matching show-level rule also exists.
- A source tuple matching no pattern-level rule but matching a show-level rule yields target numbering from the show-level rule.
- A source tuple matching neither scope yields identity mapping.
- A pattern-level zero-offset rule can explicitly override a nonzero show-level rule for the same covered source range.
- Two shifted-season rules for the same owner scope and original season cannot both be valid if they cover overlapping episode ranges.
- During
convert, shifted numbering is what TMDB episode lookup and generated season and episode tokens see when stored shifting is active. - The TUI can display and maintain shifted-season rules from both the show and pattern editing flows.
Current Code Fit
src/ffx/model/show.pyandsrc/ffx/model/pattern.pynow both expose shifted-season relationships, andsrc/ffx/model/shifted_season.pystores each rule against exactly one owner scope throughshow_idorpattern_id.src/ffx/shifted_season_controller.pynow resolves mappings with pattern-over-show precedence and applies at most one active rule for a source tuple.src/ffx/show_details_screen.py,src/ffx/shifted_season_details_screen.py, andsrc/ffx/shifted_season_delete_screen.pyprovide reusable shifted-season editing dialogs, andsrc/ffx/pattern_details_screen.pynow exposes the pattern-level override flow.src/ffx/cli.pynow resolves shifted numbering duringconvertfrom: pattern-level match, then show-level match, then identity mapping.src/ffx/database.pynow migrates version-2 databases to version 3 by preserving existing show-level rows and extending the schema for pattern-level ownership.
Risks
- The current CLI groups
--show,--season, and--episodeunder one override bucket used for TMDB-related behavior. Source-domain versus target-domain semantics of each override must stay documented clearly so stored shifting is neither skipped nor double-applied unexpectedly. - Existing version-2 databases only contain show-owned shifted-season rows, so a version-3 migration must preserve those rows as the show-level fallback layer.
- Current modern automated test coverage for shifted-season behavior is light, so precedence, migration, and convert-time numbering behavior need focused tests.