GetOrAddFolder read libraryPath.LibraryFolders, a navigation collection only
eager-loaded on the local scan path (via GetLibrary). The Jellyfin remote sync
path takes its LibraryPath off the JellyfinLibrary entity, where LibraryFolders
is null, so .Filter(null) threw ArgumentNullException('source') on the first
item of every Jellyfin music-video scan — a feature that had therefore never
run in prod, CI, or locally.
Look the folder up from the DB by (LibraryPathId, Path) instead, removing the
implicit eager-load contract entirely (correct for all nine callers) and
documenting it on ILibraryRepository. null != empty is preserved so a re-scan
does not insert duplicate LibraryFolder rows. No new hot-path cost: local
scanners already query GetParentFolderId per folder just before this call.
Tests:
- LibraryRepositoryTests: GetOrAddFolder with a null LibraryFolders (the exact
remote-path shape) creates the folder, is idempotent on re-scan, and persists
a supplied ParentId.
- JellyfinMusicVideoLibraryScannerTests: an end-to-end scan of one synthetic
music video, wiring the REAL LibraryRepository/ArtistRepository/
MusicVideoRepository against in-memory SQLite (the existing MediaServer*
scanner tests mock every repo, which is why the bug escaped), asserts the scan
completes and creates Artist + MusicVideo rows with a real LibraryFolder.
Both proven non-vacuous against the reverted fix (each reproduces the issue's
ArgumentNullException). decisions.md entry added.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds LocalLibrariesController (L1-L7: list/get/create/update/delete/move-path/
path-exists) wrapping the existing local-library MediatR commands, mapping to
the shared S0 response DTOs. Per design #202 §A.1/§C5/§C6:
- 404 for L4/L5/L6 comes from a controller pre-check (GetLocalLibraryById is
None), not the handler -- .Apply/.ToEitherAsync both .Join() a NotFoundError
into a plain 422, so relying on the handler would be dead code. This is
check-then-act; a delete racing the pre-check falls through to the handler's
422, documented in the controller.
- L4/L5 409 via IEntityLocker.IsLibraryLocked(id); L6 resolves the source
library from the path id (new ILibraryRepository.GetLibraryIdForPath) before
its own lock check.
- MoveLocalLibraryPathHandler gains same-MediaKind and different-library
validation (finding 3) -- Blazor only filtered these client-side in the move
dialog, so an API/MCP client could bypass them.
- CreateLocalLibraryHandler/UpdateLocalLibraryHandler gain a shared
NewPathsMustExist validation (LocalLibraryHandlerBase) that Directory.Exists-
checks only new paths (Id < 1); existing rows stay exempt so an unmounted
share doesn't block a rename. L7 (path-exists) is a controller-local
IFileSystem check with no command.
Tests: controller route/mediator-arg tests incl. 404-pre-check vs
fall-through-422 and 409-lock cases; handler tests for the move-path
cross-kind/same-library 422s, new-path 422 (missing/mixed), and a lossless
round-trip proving local paths are identified by normalized path string, not
id. Full solution test suite (Scanner/Core/Architecture/Tests/Infrastructure)
green, 0 regressions.
Deviations: none from the S1 slice description. Did not touch
MediaSourceRepository.cs or any Plex/Jellyfin/Emby file (S2/S3 scope). Did not
run the OpenAPI regen scripts (separate gate after S1-S3 merge per design §E).
* improve scanner detection when developing on macos
* support ogv files in local libraries
* improve health check wording
* try to properly restore other videos that are no longer missing
* flag local movies as file not found
* show warning icon on cards
* unflag movie that is found during scan
* skip missing files when building playouts
* add state to search index
* add file not found health check
* link to search from file not found health check
* support flagging other media kinds as file not found
* continue to schedule missing items
* support episode files not found
* wip trash page
* fix trash url
* trash page is functional
* update changelog
* fix changelog merge
* use etags to optimize local movie scanner
* use etags to optimize local television scanner
* use etags to optimize local music video scanner
* code cleanup
* add letter bar with no links
* use lucene for search, add paged search results
* add search index version
* index library_name; rebuild index when folder is missing
* maintain index as local movies change
* fix tests
* maintain index as local shows change
* maintain index as plex movies change
* maintain index as plex shows change
* code cleanup
* add duplicate filter to search
* add links to letter bar
* code cleanup
* starting database redesign
* set season and episode numbers
* use datetimes in db (utc); update movie metadata
* get movie cards from new table
* copy show/episode metadata
* remove old movie metadata type
* rename new movie metadata type
* code cleanup
* start to remove old television classes
* remove old television tables from database
* fix playout building
* fix collection views
* fix show/season views
* clean up movie metadata table
* fix scanner tests
* add libraries ui
* code cleanup
* fix movie scanning/metadata
* add library scan button to ui
* delete library path from ui
* temp disable movie scanning
* remove orphan media items and prevent duplicate paths
* attach artwork to metadata
* fix split show/season display
* fix television artwork
* store year distinct from release date
* fix collections ui
* code cleanup
* add library paths from ui
* fix adding to collections from ui
* fix schedule items loading
* schedule editing works again
* remove some todos
* more cleanup
* fix unit tests
* fix episode sorting
* fix deleting show library paths
* remove unused class
* fix playout list in ui
* fix log viewer
* start to use version/file instead of statistics
* clean up old columns
* fix playout display (time zone)
* fix playback
* fix channel guide time zone
* cascade more deletes
* fix compiler warnings
* fix adding new seasons
* use artwork for channel logo
* clean cache folder on startup (move channel logos, delete everything else)
* log database migration
* update homepage docs for libraries
* fix adding new channel with logo
* fix episode numbers in epg