A library that is not movies, tvshows or music is configured, listed and never scanned #194
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every milestone is closed and the scanner still reads three kinds of library.
scan::Collectionis the whole of what it knows:A library of any other kind is configured, listed, kept — and never scanned.
Two call sites decide it:
scan::configured(crates/ephyra-app/src/scan/run/mod.rs:661) pushes thekind onto
refusedwhereCollection::namedanswersNone, so the librarycontributes no
Libraryto the pass.libraries::reconcile(crates/ephyra-server/src/libraries.rs:291) passesCollection::EVERYas the set of kinds a sweep may forget rows for, which iswhat keeps an unscanned library's rows rather than deleting them.
The browse side is already ahead of the scanner and says so:
item::kind::browsed_as(crates/ephyra-core/src/item/kind.rs:126) mapsbooks,photos,homevideos,musicvideos,boxsetsandfoldersto thetypes each lists, under a doc comment reading the kind on a row may be one
this server never scanned. A database handed those rows renders them; a
directory of the files produces nothing.
What upstream resolves that we do not
One resolver each, under
upstream/Emby.Server.Implementations/Library/Resolvers/:booksBooks/BookResolver.csphotos,homevideosPhotoResolver.cs,PhotoAlbumResolver.cs, andupstream/Emby.Photos/PhotoProvider.cs(175 lines) for what a photo's metadata ismusicvideosGenericVideoResolver.csoverMusicVideofolders, mixed contentGenericFolderResolver.cs, andMovies/MovieResolver.cs's mixed-content branchEmby.Photos/PhotoProvider.csis the one that is not just a resolver: a photo'swidth, height, orientation and EXIF date come off the file, which is work
ephyra-imagesmay already be close to.Where to start
crates/ephyra-app/src/scan/is the scanner:mod.rsholdsCollection,tree/resolves a directory intoNodes,ingest.rswrites the rows, andrun/drives a pass. Adding a kind means aCollectionvariant, the namingrules in
ephyra-namingfor it, a resolver intree/, and the row shape iningest.rs.Open, and worth settling before anything is written
file extension and a naming rule rather than a hierarchy, and are the cheap
pair; mixed content is the expensive one because it changes how a library's
root is walked rather than what a leaf resolves to.
short films and has no book, photo or music video in it, and
crates/ephyra-harness/README.mdis where a diff gets its meaning. Ascanner for a kind no fixture holds cannot be compared to upstream at all,
and a test that cannot fail on the fixture it runs against is worse than
none. So this needs either the reference library to grow a directory per kind
(which redraws the snapshot — see
MILESTONES.mdand the rebuild note) or afixture of its own.
Books and home videos are done in
d818759c. Music videos and mixed contentare not, so this stays open.
The fixture question the issue flagged
It has an answer that does not touch the reference. Registering a library is
a write, and the rule for a write is already written down — its own container
from the pinned image over a
cp -acopy of a snapshot, on its own ports. Socargo xtask reference gen-library-kindslays a deterministic tree underreference/var/library-kinds, stands a second container up over a copy ofsnapshots/default, registers abooksand ahomevideoslibrary with everyfetcher off, scans, and writes upstream's rows and the listing they were
resolved from into
crates/ephyra-app/corpus/library-kinds.json.crates/ephyra-app/tests/library_kinds.rsreplayslibrary_treeover thatlisting and compares. So it is a real differential against upstream that needs
neither docker nor a disk to run, and the shared reference, its ids and its
snapshots never move.
One finding that changed the scope
photosis not a registerable collection type.CollectionTypeOptionsoffers
homevideos— "Home Videos (and Photos)" — and nothing else; aphotoslibrary is a legacy stored value. So the home-video library is the photo
library. Both are resolved here, and they part only over a disc rip, which
homevideosresolves andphotosdoes not.Left, and named rather than hidden
GenericVideoResolverover aMusicVideotype thisserver does not model at all; only the type name exists.
folders— changes how a library's root is walkedrather than what a leaf resolves to.
provider: rows carry width and height and no EXIF.
PhotoAlbumfolder image upstream copies from the first picture inside.RunTimeTickson an.epub, which upstream fills with exactly one second.One test that could not fail
The sixth mutation — removing the rule that a picture is its own
Primary—passed. The fixture could not tell that code from the generic artwork
rules. Going back to the container established what upstream actually does:
17x16.jpgand17x16.pngin one folder each get themselves, a.dnggetsitself despite not being an artwork extension, and a
poster.jpgbeside themillustrates the album. The fixture was widened to those cases and the mutation
then failed. Six of the seven failed first time; this is the one that did not.
For the sweep
forget_librariesgains two tests: a books library the configuration stillnames keeps its folder and its rows, and one nothing names goes with everything
under it while the film library survives.
scanned_kind— the guard onPOST /Library/VirtualFolders— is derived fromCollection::EVERYnow ratherthan a literal, so a new kind follows automatically.
Music videos are done, on
mainas89dcdca3anda441bc3d. Mixed content andfoldersare not, for reasons that turned out to change what is left on this issue — see the bottom.Music videos
Kind::MusicVideoend to end: type name,from_type_name, not a folder, media type Video, unrated type Music (upstream/MediaBrowser.Controller/Entities/MusicVideo.cs:25,GetBlockUnratedType() => UnratedItem.Music),held_as_video;Collection::MusicVideosinEVERYandREGISTERABLE.Upstream resolves one with the same walk as a film —
MovieResolver.cs:200ResolveVideos<MusicVideo>(parent, files, true, ct, false)against:227ResolveVideos<Movie>(parent, files, true, ct, true), differing only inparseName— soscan/tree/movies.rsnow takes aLeaves { kind, parse_name, named_by_its_folder }and serves both, one function where upstream has one class instantiated twice. (The hint in this issue's description pointed atGenericVideoResolver, which is wrong: that class is only ever instantiated byExtraResolver.cs:35, for trailers.)Everything that follows from a new kind went with it:
providers::from_path, the artwork name lists, a music genre's collage, the library-options dialog row, and the sweep's scanned-kinds list.Three film bugs the new fixture found
The generated answer key (
cargo xtask reference gen-library-kinds) now registers four libraries — books, homevideos, musicvideos and movies. The film library is there because three changes touched the film path and nothing else could check them. It immediately disagreed with upstream three times:FindMoviereturns null whenresult.Items.Count != 1). Films in a folder that keeps a row now hang from it.Extras Beside (2011)/Feature.mp4was not named after its folder.MovieResolver.cs:427steps over extras first.Movie.BeforeMetadataRefresh/MusicVideo.BeforeMetadataRefresh): upstream filesYearless Folder (2014)/Untitled.mp4withProductionYear2014 and we filed none.A fourth came out of the review: a multi-disc rip read no year at all, because
Video.ContainingFolderPathfor a stacked video is the release folder, not the disc (Video.cs:201-218). Upstream filesRelease (1999)/Feature - cd 1|2/VIDEO_TS/asFeature, year 1999; the answer key now says so.What the review caught
Three of its findings were rules with no test — the shape that cost this issue a round already:
Collection::MusicVideosinREGISTERABLEwas unasserted. Deleting it left all 3241 tests green, and it is the only thingPOST /Library/VirtualFolders?collectionType=musicvideosconsults — the switch that turns the whole feature on from the dashboard. Now pinned by a test that posts all six registerable kinds and reads the configuration back.reads_a_year(Kind::Movie)was unasserted, because the generated tree's film half contained no disc rip at all. It does now.disc_namesomittedBoxSetwhereLocalImageProvider.cs:221hasitem is Video || item is BoxSet— a wrong row left in a table transcribed from upstream.Each was mutated and watched to fail.
3260tests, clippy silent, fmt clean. The regenerated corpus is insertions only: 807 added lines across both commits, nothing moved or removed, so every row the port and upstream already agreed on still agrees.Filed rather than buried
Video.cs:691)VideoInfo::alternate_versionsis read nowhereAlso worth knowing:
from_type_namenow answering forMusicVideochanges two call sites for rows seeded from a real Jellyfin database —ephyra-db/src/items/writes.rs:37(the sort-name rule) androutes/library/remote_images.rs:225(which providers a music-video row is offered). Both look benign; neither has a test.What is left on this issue, and a correction to its scope
foldersis not a library kind and never was.CollectionTypeOptions— whatLibraryStructureController.cs:87binds — has nofoldersmember, so no.collectionfile can name one.CollectionType.foldersexists only forGetNamedView("folders"), the Folders user view. There is nothing to scan, and our read-sidebrowsed_as("folders")is already right. This part of the issue can be struck.Mixed content is a resolver chain, not a resolver. A
mixedlibrary writesmixed.collection,Enum.TryParse<CollectionType>fails on it, andCollectionTypeis null — at which point every resolver'scollectionType is nullbranch comes into play:SeriesResolverpromotes a directory holdingtvshow.nfoor a season folder,MovieResolver.ResolveMultipleaborts when it seestvshow.nfo/season.nfobeside the files, andResolvePathstries multi-item resolvers first and falls back per file, ordered byResolverPriority. Ourtree/picks one function per collection kind up front, so this is a different shape for the module rather than another arm — it deserves its own issue rather than a fourth round here.So: with
foldersstruck and mixed content split out, music videos and box sets were the remainder. Box sets are still open.Closing this. Every kind in its table is scanned, with one struck and the rest split out:
Emby.Photos/PhotoProvider.csfills, thePhotoAlbumfolder image andLibraryOptions.EnablePhotosare #20989dcdca3,a441bc3d)folders— struck. It is not a library kind:CollectionTypeOptions, whichLibraryStructureController.cs:87binds, has no such member, so no.collectionfile can name one.CollectionType.foldersexists only forGetNamedView("folders"), the Folders user view. Our read-sidebrowsed_as("folders")is already right and there is nothing to scan.mixedlibrary leavesCollectionTypenull, and null is the case every resolver has its own branch for, tried inResolverPriorityorder. That is a change to how a root is walked, not another arm on a match.Also filed from the two review rounds on this issue: #205, #206, #207.