Skip to content

Unify missing episode definition and refresh AniDB group status periodically - #1421

Open
harshithmohan wants to merge 2 commits into
masterfrom
missing-episode-and-gs-refresh
Open

Unify missing episode definition and refresh AniDB group status periodically#1421
harshithmohan wants to merge 2 commits into
masterfrom
missing-episode-and-gs-refresh

Conversation

@harshithmohan

Copy link
Copy Markdown
Member

Summary

Addresses GitHub Discussion #1418 — the definition of "missing episode" was inconsistent across the v3 API, and AniDB_GroupStatus data went stale without the legacy v1 API.

1. Refresh AniDB_GroupStatus during periodic anime updates (e2d0e2d8d)

AniDB_GroupStatus was only refreshed by the legacy v1 API, so on a v3-only install the cached release-group progress stopped updating and "released-but-absent" missing-episode counts under-counted.

  • GetUpdatedAniDBAnimeJob now enqueues GetAniDBReleaseGroupStatusJob for each updated series, propagating ForceRefresh so scheduled runs keep the ShouldSkip() ended-anime gate intact (no unnecessary UDP traffic for ended anime).

2. Unify the missing-episode definition (6ec2e3c23)

/v3/SeriesSizes.Missing.Episodes used an aired-but-absent check while /v3/MissingEpisodes and the persisted counts used a released-but-absent check via AniDB_GroupStatus, so the same series could report different missing counts.

  • Added AnimeEpisodeExtensions.IsMissingEpisode as the single source of truth: aired, not hidden, no local file, and either no group status data or a group with CompletionState complete/finished or LastEpisodeNumber past the episode number.
  • Applied the group status gate to Sizes.Missing.Episodes in both GenerateSeriesSizes and GenerateGroupSizes so series and group counts agree. GenerateSeriesSizes now requires the per-anime status dictionary so future callers cannot fall back to the divergent aired-but-absent logic.
  • Replaced the non-collecting GetMissing raw SQL with cache-based filtering through the shared predicate; the collecting variant stays as raw SQL.
  • Added AniDB_GroupStatusRepository.GetByAnimeIDs with batched (1000-per-query) lookups.

Specials are intentionally unchanged (still bare HasAired), per the existing comment in AnimeSeriesService about there being no reliable way to check specials.

Verification

  • dotnet build Shoko.Server.sln — 0 errors, 0 warnings
  • dotnet test Shoko.Tests/Shoko.Tests.csproj — 2607 passed, 1 failed (YearlySeasonsTests.RealWorldRegression_LateSeasonPremiere_IsClassifiedOnlyUnderItsOwnSeason, pre-existing on master and unrelated to these changes — fixed separately in test: pin end date in yearly seasons regression test #1420)

⚠️ Known caveat: group-status N+1 on list endpoints

Both DTO constructors now query the (uncached) AniDB_GroupStatus repository:

  • new Series(...) runs one GetByAnimeID query per series
  • GenerateGroupSizes runs one batched query per group

On single-item endpoints (GET /v3/Series/{id} etc.) this is one extra indexed query against a small table — negligible. But list endpoints (GET /v3/Series with pageSize=100, /v3/Group, filter endpoints, dashboard, tree) now issue one extra query per constructed DTO, where previously they made zero group-status queries.

Question for maintainers: should this be fixed in this PR (batch-load statuses once per page via GetByAnimeIDs and thread them through the Series/Group constructors), or left as-is/a follow-up? A batch-loading fix has already been implemented and validated locally, so it can be added quickly if preferred — it's deliberately not part of this PR to keep the diff focused.

`AniDB_GroupStatus` was only refreshed by the legacy v1 API, so with a
v3-only install the cached release-group progress stopped updating and
"released-but-absent" missing-episode counts under-counted.

- Enqueue `GetAniDBReleaseGroupStatusJob` for each updated series in
  `GetUpdatedAniDBAnimeJob`, propagating `ForceRefresh` so scheduled
  runs keep the `ShouldSkip()` ended-anime gate intact
`/v3/Series` → `Sizes.Missing.Episodes` used an aired-but-absent check
while `/v3/MissingEpisodes` and the persisted counts used a
released-but-absent check via `AniDB_GroupStatus`, so the same series
could report different missing counts.

- Added `AnimeEpisodeExtensions.IsMissingEpisode` as the single source
  of truth: aired, not hidden, no local file, and either no group
  status data or a group with `CompletionState` complete/finished or
  `LastEpisodeNumber` past the episode number
- Applied the group status gate to `Sizes.Missing.Episodes` in both
  `GenerateSeriesSizes` and `GenerateGroupSizes` so series and group
  counts agree; `GenerateSeriesSizes` now requires the per-anime
  status dictionary so future callers cannot fall back to the
  divergent aired-but-absent logic
- Replaced the non-collecting `GetMissing` raw SQL with cache-based
  filtering through the shared predicate; the collecting variant
  stays as raw SQL
- Added `AniDB_GroupStatusRepository.GetByAnimeIDs` with batched
  (1000-per-query) lookups
@sonarqubecloud

sonarqubecloud Bot commented Sep 3, 2026

Copy link
Copy Markdown

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.

1 participant