A stack's later parts do not inherit the owner's mixed-folder flag #205

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

A stack's later parts are filed with in_mixed_folder: false regardless of where the stack sits. Upstream copies the owner's flag.

Both sides

Ours: crates/ephyra-app/src/scan/tree/movies.rs:286 hardcodes it.

Upstream, upstream/MediaBrowser.Controller/Entities/Video.cs:691:

video.IsInMixedFolder = IsInMixedFolder;

— the owner's flag, which LibraryManager set from isInMixedFolder = resolverResult.Count > 1 || parent.IsTopParent.

What it costs

/m/Concert - cd1.mp4 and /m/Concert - cd2.mp4 at a library root: the owner is mixed=true (the root is a top parent), and upstream gives the part true as well. We give the part false.

IsInMixedFolder is what BeforeMetadataRefresh consults before reading a year off the folder above (BaseItem.cs), so a wrong flag on a part is a wrong name or year on it.

Pre-existing rather than introduced by #194, but 7e3804f5 rewrote part_nodes and added a stack to the answer key one directory deep (Stacked/). Putting that case at the library root instead would have caught it, which is the cheap way to pin the fix.

Found reviewing #194.

A stack's later parts are filed with `in_mixed_folder: false` regardless of where the stack sits. Upstream copies the owner's flag. ## Both sides Ours: `crates/ephyra-app/src/scan/tree/movies.rs:286` hardcodes it. Upstream, `upstream/MediaBrowser.Controller/Entities/Video.cs:691`: ```csharp video.IsInMixedFolder = IsInMixedFolder; ``` — the **owner's** flag, which `LibraryManager` set from `isInMixedFolder = resolverResult.Count > 1 || parent.IsTopParent`. ## What it costs `/m/Concert - cd1.mp4` and `/m/Concert - cd2.mp4` at a library root: the owner is `mixed=true` (the root is a top parent), and upstream gives the part `true` as well. We give the part `false`. `IsInMixedFolder` is what `BeforeMetadataRefresh` consults before reading a year off the folder above (`BaseItem.cs`), so a wrong flag on a part is a wrong name or year on it. Pre-existing rather than introduced by #194, but `7e3804f5` rewrote `part_nodes` and added a stack to the answer key one directory deep (`Stacked/`). Putting that case at the library root instead would have caught it, which is the cheap way to pin the fix. Found reviewing #194.
Author
Collaborator

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

A stack's later part now takes its owner's in_mixed_folder (crates/ephyra-app/src/scan/tree/movies.rs, part_nodes), as Video.cs:691 does. Upstream's answer for a stack at the library root, from the regenerated key: Recital - cd2.mp4 is a Video, parentless, in_mixed_folder: true. tests/scan.rs pins both the root case and the one-directory-down contrast.

Verified

  • Against a real upstream scan. The fixture tree gained the cases these issues asked for — a stack at a library root (movies/Recital - cd1/cd2), a film alone in a disc folder (movies/I, Robot (2004)/CD 01/…), and musicvideos/Versions/ renamed to Anthem/ so its files really start with the folder name. gen-library-kinds was regenerated from a live upstream container and every library_kinds test agrees with it.
  • Review round: no defects in the new write path; filed_in_order was probed against two levels of ownership, a diamond, a cycle and an owner outside the batch. Mutation-checked: each change reverted alone turns its own tests red.
  • In the web client, over a tree carrying all three shapes: the films library lists exactly Anthem, CD 01 · 2004, Concert and Loose Film · 1999 — no second Anthem from the owned cut and no stack part — which is the same predicate upstream hides them on (BaseItemRepository.TranslateQuery.cs:810-814).

On an existing install, an incremental scan decides a row is unchanged from its file (path, mtime, size), so rows filed before this change keep their old value until the file is touched or a full refresh runs. New rows are right immediately.

Landed on `main`: `2a5a91ec`, `e0653be6`, `085fdd2a`, `f06fbc21`, `f66e2ab8`. A stack's later part now takes its owner's `in_mixed_folder` (`crates/ephyra-app/src/scan/tree/movies.rs`, `part_nodes`), as `Video.cs:691` does. Upstream's answer for a stack at the library root, from the regenerated key: `Recital - cd2.mp4` is a `Video`, parentless, `in_mixed_folder: true`. `tests/scan.rs` pins both the root case and the one-directory-down contrast. ## Verified - **Against a real upstream scan.** The fixture tree gained the cases these issues asked for — a stack at a library root (`movies/Recital - cd1/cd2`), a film alone in a disc folder (`movies/I, Robot (2004)/CD 01/…`), and `musicvideos/Versions/` renamed to `Anthem/` so its files really start with the folder name. `gen-library-kinds` was regenerated from a live upstream container and every `library_kinds` test agrees with it. - **Review round**: no defects in the new write path; `filed_in_order` was probed against two levels of ownership, a diamond, a cycle and an owner outside the batch. Mutation-checked: each change reverted alone turns its own tests red. - **In the web client**, over a tree carrying all three shapes: the films library lists exactly `Anthem`, `CD 01 · 2004`, `Concert` and `Loose Film · 1999` — no second `Anthem` from the owned cut and no stack part — which is the same predicate upstream hides them on (`BaseItemRepository.TranslateQuery.cs:810-814`). **On an existing install**, an incremental scan decides a row is unchanged from its file (path, mtime, size), so rows filed before this change keep their old value until the file is touched or a full refresh runs. New rows are right immediately.
Sign in to join this conversation.
No description provided.