A scan files one row where upstream files a row per alternate version #207

Closed
opened 2026-09-12 17:18:06 +02:00 by Claude · 1 comment
Collaborator

VideoInfo::alternate_versions is never read. grep alternate_versions crates/ephyra-app returns nothing — movie_node resolves a group and then keeps only the primary, so where upstream files a row per version, we file one.

Upstream

upstream/MediaBrowser.Controller/Entities/Video.cs:583 — RefreshMetadataForVersions walks LocalAlternateVersions, calling ResolveAlternateVersion → CreateItem, so each version is its own row linked to the primary. The grouping itself is VideoListResolver.IsEligibleForMultiVersion.

The fixture says it is covered and is not

xtask/src/reference/kinds.rs lays down Versions/Anthem.mp4 and Versions/Anthem - 1080p.mp4 with the comment "Two cuts of one title, which this kind groups and the photo kinds do not."

Upstream filed two separate rows, both in_mixed_folder: true. No grouping happened at all: VideoListResolver.IsEligibleForMultiVersion (:180) requires the filename to start with the folder name, and "Anthem" does not start with "Versions". So the case in the answer key cannot exercise what its comment claims, and the port agrees with upstream on it for the wrong reason.

Renaming the folder to Anthem/ turns it into a real case — and would then fail, which is the point.

Reach

crates/ephyra-http/tests/versions.rs covers serving versions that already exist as rows; this is about the scan producing them. crates/ephyra-http/src/map/media.rs:51,160 gives each source its own runtime, which is also what #203 needs.

Found reviewing #194.

`VideoInfo::alternate_versions` is never read. `grep alternate_versions crates/ephyra-app` returns nothing — `movie_node` resolves a group and then keeps only the primary, so where upstream files a row per version, we file one. ## Upstream `upstream/MediaBrowser.Controller/Entities/Video.cs:583` — `RefreshMetadataForVersions` walks `LocalAlternateVersions`, calling `ResolveAlternateVersion` → `CreateItem`, so each version is its own row linked to the primary. The grouping itself is `VideoListResolver.IsEligibleForMultiVersion`. ## The fixture says it is covered and is not `xtask/src/reference/kinds.rs` lays down `Versions/Anthem.mp4` and `Versions/Anthem - 1080p.mp4` with the comment *"Two cuts of one title, which this kind groups and the photo kinds do not."* Upstream filed **two separate rows**, both `in_mixed_folder: true`. No grouping happened at all: `VideoListResolver.IsEligibleForMultiVersion` (`:180`) requires the filename to start with the **folder** name, and `"Anthem"` does not start with `"Versions"`. So the case in the answer key cannot exercise what its comment claims, and the port agrees with upstream on it for the wrong reason. Renaming the folder to `Anthem/` turns it into a real case — and would then fail, which is the point. ## Reach `crates/ephyra-http/tests/versions.rs` covers serving versions that already exist as rows; this is about the scan producing them. `crates/ephyra-http/src/map/media.rs:51,160` gives each source its own runtime, which is also what #203 needs. Found reviewing #194.
Author
Collaborator

Landed on main: 2a5a91ec, 5a2ff728, 085fdd2a, f06fbc21, f66e2ab8.

What changed

Each entry of VideoInfo::alternate_versions is now a row (version_nodes, crates/ephyra-app/src/scan/tree/movies.rs): filed under the type the title took, named by its own file, owned by the title, carrying its mixed-folder flag — and held by the title's own parent. Upstream's key settled that last part: Anthem - 1080p.mp4 has parent: /kinds/musicvideos, where a stack's later part has none.

Two defects a real scan found that no tree test could

  1. Insert order. OwnerId is an immediate foreign key and rows were filed in path order. That is safe for a parent, which is a prefix of its child's path, but an owner is not above what it owns: Anthem - 1080p.mkv sorts before Anthem.mkv, so a real scan failed the whole task with FOREIGN KEY constraint failed. Stack parts had only worked by luck (cd1 < cd2). filed_in_order (scan/library.rs) now files owners first.
  2. The parent was discarded at write time. Every owned row was written with both parent columns empty, so the version's parent never reached the database.

Both are pinned in crates/ephyra-app/tests/scan_write.rs against an in-memory database, and each goes red with its half reverted.

Verified

  • Regenerated answer key from a live upstream container; every library_kinds test agrees.
  • Review round: no defects remaining.
  • In the web client the films library shows one Anthem, not two — the owned cut is hidden on the same predicate upstream uses.

Not done here — filed

  • #214 — a version is filed but never joined to its title (PrimaryVersionId, LocalAlternateVersion), so it is not yet served as a second media source.
  • #215 — episodes are never grouped by version; the resolver that does it is unreachable from a scan.
  • #216 — an owned row outlives its file.
Landed on `main`: `2a5a91ec`, `5a2ff728`, `085fdd2a`, `f06fbc21`, `f66e2ab8`. ## What changed Each entry of `VideoInfo::alternate_versions` is now a row (`version_nodes`, `crates/ephyra-app/src/scan/tree/movies.rs`): filed under the type the title took, named by its own file, owned by the title, carrying its mixed-folder flag — and **held by the title's own parent**. Upstream's key settled that last part: `Anthem - 1080p.mp4` has `parent: /kinds/musicvideos`, where a stack's later part has none. ## Two defects a real scan found that no tree test could 1. **Insert order.** `OwnerId` is an immediate foreign key and rows were filed in path order. That is safe for a parent, which is a prefix of its child's path, but an owner is not above what it owns: `Anthem - 1080p.mkv` sorts *before* `Anthem.mkv`, so a real scan failed the whole task with `FOREIGN KEY constraint failed`. Stack parts had only worked by luck (`cd1` < `cd2`). `filed_in_order` (`scan/library.rs`) now files owners first. 2. **The parent was discarded at write time.** Every owned row was written with both parent columns empty, so the version's parent never reached the database. Both are pinned in `crates/ephyra-app/tests/scan_write.rs` against an in-memory database, and each goes red with its half reverted. ## Verified - Regenerated answer key from a live upstream container; every `library_kinds` test agrees. - Review round: no defects remaining. - In the web client the films library shows one `Anthem`, not two — the owned cut is hidden on the same predicate upstream uses. ## Not done here — filed - #214 — a version is filed but never joined to its title (`PrimaryVersionId`, `LocalAlternateVersion`), so it is not yet *served* as a second media source. - #215 — episodes are never grouped by version; the resolver that does it is unreachable from a scan. - #216 — an owned row outlives its file.
Sign in to join this conversation.
No description provided.