Half a real library's episodes are never returned #47

Closed
opened 2026-08-03 22:21:49 +02:00 by Claude · 1 comment
Collaborator

Half the episodes in a real library are invisible.

Replaying a production database through both servers, /Items?Recursive=true
answers:

type upstream ours
Episode 14827 7905
Season 1113 708

Every other type agrees exactly — 4889 Audio, 329 MusicAlbum, 289 Series, 284
Movie, 102 Folder, 67 MusicArtist.

The gap is the virtual items, to the row: 6922 episodes and 405 seasons carry
IsVirtualItem=1, which is 14827−7905 and 1113−708. Both servers read copies of
one database, so nothing was scanned differently — these rows are read and
dropped.

ItemsController sets IsVirtualItem = false only when the request asks for it,
through ExcludeLocationTypes or LocationTypes (ItemsController.cs:505-513).
The user's DisplayMissingEpisodes is applied in Folder.cs:1875 and
TvShowsController.cs:231, not on this route — so upstream returns virtual
items here whatever that setting says. Measured with DisplayMissingEpisodes=0
for the user asking, and upstream still returned all 14827.

Nothing in the reference library is a virtual item, which is why no scenario
catches this.

Half the episodes in a real library are invisible. Replaying a production database through both servers, `/Items?Recursive=true` answers: | type | upstream | ours | |---|---|---| | Episode | 14827 | **7905** | | Season | 1113 | **708** | Every other type agrees exactly — 4889 Audio, 329 MusicAlbum, 289 Series, 284 Movie, 102 Folder, 67 MusicArtist. The gap is the virtual items, to the row: 6922 episodes and 405 seasons carry `IsVirtualItem=1`, which is 14827−7905 and 1113−708. Both servers read copies of one database, so nothing was scanned differently — these rows are read and dropped. `ItemsController` sets `IsVirtualItem = false` only when the request asks for it, through `ExcludeLocationTypes` or `LocationTypes` (`ItemsController.cs:505-513`). The user's `DisplayMissingEpisodes` is applied in `Folder.cs:1875` and `TvShowsController.cs:231`, not on this route — so upstream returns virtual items here whatever that setting says. Measured with `DisplayMissingEpisodes=0` for the user asking, and upstream still returned all 14827. Nothing in the reference library is a virtual item, which is why no scenario catches this.
Author
Collaborator

Virtual items are returned again, and the request decides — as upstream's does.

ItemsController.cs:505-513 sets IsVirtualItem only from what the request
asked: ExcludeLocationTypes holding Virtual excludes them, and
LocationTypes selects on whether it names Virtual — naming all four is
naming no filter. IsMissing is the fallback the SQL reads
(TranslateQuery.cs:948), IsResumable overrides both
(BaseItemRepository.cs:107), and a Series parent rewrites its own query
(Series.cs:241,282). DisplayMissingEpisodes never reaches this route.

The default in this port was Excluded. That was the bug — it is now the
request's answer, with Excluded named at the six places upstream names it.

Measured on one production database, both servers:

query before after upstream
IncludeItemTypes=Episode 7905 14827 14827
IncludeItemTypes=Season 708 1113 1113
Recursive=true (all) 14573 21900 21900
Episode LocationTypes=Virtual 7905 6922 6922
Episode ExcludeLocationTypes=Virtual 7905 7905 7905
Episode IsMissing=true 7905 6922 6922
Season LocationTypes=Virtual 708 405 405

LocationType is now derived from the stored path, matching BaseItem.cs:328,
and a series' ChildCount in a listing went from 186 of 289 wrong to 0.

One difference remains on this library and it is not this issue: five real
episodes upstream does not list. They are alternate rips of five Witcher
episodes the folder holds twice, and upstream drops a row carrying a
PrimaryVersionId (TranslateQuery.cs:794). Filed separately.

Virtual items are returned again, and the request decides — as upstream's does. `ItemsController.cs:505-513` sets `IsVirtualItem` only from what the request asked: `ExcludeLocationTypes` holding `Virtual` excludes them, and `LocationTypes` selects on whether it names `Virtual` — naming all four is naming no filter. `IsMissing` is the fallback the SQL reads (`TranslateQuery.cs:948`), `IsResumable` overrides both (`BaseItemRepository.cs:107`), and a `Series` parent rewrites its own query (`Series.cs:241,282`). `DisplayMissingEpisodes` never reaches this route. The default in this port was `Excluded`. That was the bug — it is now the request's answer, with `Excluded` named at the six places upstream names it. Measured on one production database, both servers: | query | before | after | upstream | |---|---|---|---| | `IncludeItemTypes=Episode` | 7905 | **14827** | 14827 | | `IncludeItemTypes=Season` | 708 | **1113** | 1113 | | `Recursive=true` (all) | 14573 | **21900** | 21900 | | Episode `LocationTypes=Virtual` | 7905 | **6922** | 6922 | | Episode `ExcludeLocationTypes=Virtual` | 7905 | 7905 | 7905 | | Episode `IsMissing=true` | 7905 | **6922** | 6922 | | Season `LocationTypes=Virtual` | 708 | **405** | 405 | `LocationType` is now derived from the stored path, matching `BaseItem.cs:328`, and a series' `ChildCount` in a listing went from 186 of 289 wrong to 0. One difference remains on this library and it is **not** this issue: five real episodes upstream does not list. They are alternate rips of five Witcher episodes the folder holds twice, and upstream drops a row carrying a `PrimaryVersionId` (`TranslateQuery.cs:794`). Filed separately.
Sign in to join this conversation.
No description provided.