fix anime split-cour stream matching#1022
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (4)
WalkthroughIntroduces logical vs external season/episode disambiguation for anime across the full stack: new utility functions parse logical season/episode from titles, build ambiguous query waves for split-cour anime, and propagate these fields through stream context, filterer, formatter/expression context, debrid query building, and persisted title metadata. Separately, NAB API gains ChangesAnime Logical/External Season Disambiguation
NAB Rate Limiting and Query Wave Execution
Sequence Diagram(s)sequenceDiagram
participant StreamContext
participant AnimeUtils as anime-search utils
participant ExtendedMetadata
participant StreamFilterer
participant BaseDebridAddon
participant BaseNabAddon
participant BaseNabApi
StreamContext->>AnimeUtils: extractLogicalSeasonFromTitles(titles)
AnimeUtils-->>StreamContext: logicalSeason
StreamContext->>AnimeUtils: calculateLogicalEpisode(externalEpisode, animeEntry)
AnimeUtils-->>StreamContext: logicalEpisode
StreamContext->>ExtendedMetadata: set logicalSeason, externalSeason, logicalEpisode, externalEpisode, isAmbiguousAnimeSeason
ExtendedMetadata-->>StreamFilterer: match uses logicalSeason/logicalEpisode + external fallback
BaseDebridAddon->>AnimeUtils: buildAmbiguousAnimeQueryWaves(metadata)
AnimeUtils-->>BaseDebridAddon: queryWaves[][]
BaseDebridAddon->>BaseNabAddon: performSearch with forceQuerySearch + queryWaves
loop each wave (sequential)
BaseNabAddon->>BaseNabApi: fetchQueryBatch(wave queries)
alt cooldown active
BaseNabApi-->>BaseNabAddon: NabRateLimitError
else HTTP 429
BaseNabApi-->>BaseNabAddon: NabRateLimitError(retryAfterMs)
else success
BaseNabApi-->>BaseNabAddon: results
end
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~100 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
forgot to add, I've been using this fix on my instance for the past week without any obvious issues, tested mainly with anime-type media. |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/streams/filterer.ts (1)
1005-1062:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not treat
0as “not requested” in season/episode matching.The new logical/external matching uses truthy guards, so S00 specials skip the season checks; for example, S00E01 can match S01E01 when episode
1is present. Compare againstundefinedinstead.Proposed fix
const matchesLogicalSeason = !!( - requestedSeason && + requestedSeason !== undefined && seasons && seasons.length > 0 && seasons.includes(requestedSeason) ); const matchesExternalSeason = !!( - externalSeason && + externalSeason !== undefined && seasons && seasons.length > 0 && seasons.includes(externalSeason) ); if ( - requestedSeason && + requestedSeason !== undefined && seasons && seasons.length > 0 && !matchesLogicalSeason ) { if ( matchesExternalSeason && - externalEpisode && + externalEpisode !== undefined && stream.parsedFile?.episodes?.length && stream.parsedFile.episodes.includes(externalEpisode) ) { @@ if ( - requestedEpisode && + requestedEpisode !== undefined && stream.parsedFile?.episodes?.length && !stream.parsedFile?.episodes?.includes(requestedEpisode) ) { if ( matchesExternalSeason && - externalEpisode && + externalEpisode !== undefined && stream.parsedFile.episodes.includes(externalEpisode) ) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/streams/filterer.ts` around lines 1005 - 1062, The season and episode matching logic uses truthy guards that incorrectly treat numeric zero values (like season 0 for specials) as "not requested". Replace the truthy checks on requestedSeason and requestedEpisode variables with explicit undefined comparisons. Specifically, change the conditions that use `if (requestedSeason &&` and `if (requestedEpisode &&` to instead use `if (requestedSeason !== undefined &&` and `if (requestedEpisode !== undefined &&` respectively, so that S00 specials and other zero-based values are properly evaluated against the seasons and episodes arrays.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/core/src/builtins/base/debrid.ts`:
- Around line 551-555: The querySeason and queryEpisode variables initialized
from parsedId can be strings, while externalSeason and externalEpisode are
numbers. When these are compared using strict inequality operators around line
621, string and number values that are semantically identical will be treated as
different, causing unnecessary external query fanout. Normalize the types of
querySeason and queryEpisode to numbers before they are used in comparisons with
the external season and episode values, ensuring that the strict comparison at
the point where external-tuple comparison occurs will accurately detect when
values are equal.
- Around line 682-697: The variables externalSeason and externalEpisode are
being assigned numeric conversions without validating that the parsed values are
actually numeric strings. Currently the code checks if parsedId.season and
parsedId.episode are truthy, but truthy non-numeric strings like "*" will
convert to NaN via Number(), which then propagates into logicalEpisode and
contaminates metadata. Add validation to ensure that parsedId.season and
parsedId.episode contain valid numeric content before calling Number() on them,
falling back to undefined if the values are non-numeric or malformed.
In `@packages/core/src/builtins/base/nab/addon.ts`:
- Around line 74-77: Import NabRateLimitError from ./api.js at line 16 with the
other imports. Then update the isRateLimitError function to check if the error
is an instance of NabRateLimitError directly using the instanceof operator
instead of using a regex pattern on the error message. This eliminates the
fragility of pattern matching and provides a more reliable type check for rate
limit errors.
In `@packages/core/src/formatters/base.ts`:
- Around line 197-200: The four new fields (logicalSeason, externalSeason,
logicalEpisode, externalEpisode) are defined in FormatterContext but are not
being wired into the metadata object of ParseValue. To fix this, locate the
convertStreamToParseValue function where the metadata object is constructed and
add these four fields to it, mapping their values from the FormatterContext so
that formatter templates can access them via {metadata.logicalSeason},
{metadata.externalSeason}, {metadata.logicalEpisode}, and
{metadata.externalEpisode}.
---
Outside diff comments:
In `@packages/core/src/streams/filterer.ts`:
- Around line 1005-1062: The season and episode matching logic uses truthy
guards that incorrectly treat numeric zero values (like season 0 for specials)
as "not requested". Replace the truthy checks on requestedSeason and
requestedEpisode variables with explicit undefined comparisons. Specifically,
change the conditions that use `if (requestedSeason &&` and `if
(requestedEpisode &&` to instead use `if (requestedSeason !== undefined &&` and
`if (requestedEpisode !== undefined &&` respectively, so that S00 specials and
other zero-based values are properly evaluated against the seasons and episodes
arrays.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d7ba81c1-4f6d-4266-bf1b-c5b5a14fbbe3
📒 Files selected for processing (11)
packages/core/src/builtins/base/debrid.tspackages/core/src/builtins/base/nab/addon.tspackages/core/src/builtins/base/nab/api.tspackages/core/src/debrid/base.tspackages/core/src/formatters/base.tspackages/core/src/parser/streamExpression.tspackages/core/src/streams/context.tspackages/core/src/streams/filterer.tspackages/core/src/utils/anime-search.test.tspackages/core/src/utils/anime-search.tspackages/core/src/utils/index.ts
Summary
Fix anime stream matching for split-cour / sequel entries where the Stremio request ID uses one external season number, but anime databases and release titles identify the requested content as a later logical season or cour.
The motivating case is Bungo Stray Dogs: Stremio metadata can expose three seasons, while anime trackers commonly list the same later episodes as separate 4th and 5th season entries. Requests such as
tt5679720:3:*can therefore need streams titledBungo Stray Dogs 4th Season/Bungo Stray Dogs 5th Season, not generic season 3 releases.Problem
AIOStreams currently treats
season/episodeas a single coordinate system. That works for most TV metadata, but it breaks when anime metadata has two valid coordinate systems:tt5679720:3:14.Bungo Stray Dogs 4th Season, episode 1.When those are collapsed into one value, several downstream stages can become incorrect:
Approach
This PR preserves both coordinate systems instead of replacing one with the other:
logicalSeason/logicalEpisode: anime-entry numbering inferred from anime entry titles and episode offsets.externalSeason/externalEpisode: original request coordinates from the parsed Stremio ID.For ambiguous anime seasons, the search metadata now keeps sequel-specific anime titles and marks the request for query search. Nab-based addons then use bounded query waves:
SxxExx/Sxx.The second wave only runs if the first wave returns no results. This keeps the fix targeted without spraying every possible title/episode variant at indexers.
If query search is required but the selected Nab search function does not support
q, the request now fails fast instead of issuing a broad unqualified search.Nab rate-limit handling
Torznab/Newznab APIs now track endpoint-level 429 cooldowns. During cooldown:
This is intentionally generic and applies to Nab endpoints broadly, not to one indexer-specific workaround.
Filtering and expressions
Season/episode filtering now prefers logical anime coordinates while still allowing an exact external season/episode tuple when a release is parsed that way.
Formatter and expression contexts also expose the explicit logical/external values, so advanced users can reason about either coordinate system without overloading
seasonandepisode.Validation
Added deterministic unit coverage for the pure anime search helpers:
4th Season,Season 2, and roman numeral forms;Bungo Stray Dogs S04E01andBungo Stray Dogs 4th Season 01.Validated locally with:
pnpm -F core test pnpm -F core run buildNo tests call live indexers or content endpoints.
Summary by CodeRabbit
q-based querying, including wave-based query progression.0and improved season/episode parameter derivation for searches.