Implement Jellyfin MusicVideo library sync (currently silently dropped) #42
Closed
opened 2026-06-27 14:41:31 +02:00 by timothy
·
3 comments
No Branch/Tag Specified
main
901-pin-the-artifact-whole
renovate/meziantou.analyzer-3.x
release/v26.15.0-notes
renovate/lucene.net
renovate/cliwrap-3.x
issue-806-guard-populations
renovate/dotnet-monorepo
scratch/767b-poisoned
scratch/767b-control
release/v26.14.0-notes
release/v26.14.0
renovate/sqlitepclraw.bundle_e_sqlite3-3.x
docs/510-skill-logo-bug-policy
fix/510-watermark-resolution-policy
fix/629-verdict-classifier-falseopens
fix/609-decisions-edit-token-scope
issue-135-clear-to-none
release/v26.12.0-notes
fix/409b-lastscan-api-parity
fix/401-updatechannel-mirror-422
fix/327-playlist-rename-validation
fix/410-scancancel-log-level
fix/409-447-librariesscreen-neverscanned
fix/338-zap-exit-code
fix/367-plex-budget-message
fix/310-debom-legacy-cs
ci/604-lane-rebalance
feat/388-design-mirror
feat/247-test-ownership
feat/247-primary-action
feat/357-player-owned-playback
feat/357-jellyfin-plugin-poc
fix/289-mcp-hardening
issue58-mcp
feat/244-channels-extract
ci/auto-bump-prod-compose
feat/multi-rerun-collections-api
feat/collections-api
feat/quick-wins
feat/185-docs-part2
feat/140-collections-screen
feat/146-channel-edit
feat/147-classic-ui-link
issue22-renovate-dashboard
feat/91-cutover
feat/63-composite-create
feat/65-library-browse
feat/85-epg
feat/86-schedule-editor
feat/109-dashboard-data
feat/99-session-tracking
fix/dockerfile-node-tag
feat/59-spa-foundation
docs/59-ui-redesign-brief
feat/102-json-guide
feat/111-schedule-durations
feat/104-artwork-upload
feat/103-media-sources-api
feat/playouts-read-api
feat/108-health-api
feat/105-picker-list-endpoints
issue-97-channel-state-api
issue42-jellyfin-musicvideos
issue46-rest-api-error-contract
dependabot/nuget/ErsatzTV.FFmpeg.Tests/multi-d307a2e06f
qsv-improvements
hdr-vulkan-cuda-test
v26.15.0
v26.14.0
v26.13.0
v26.12.0
v26.11.0
v26.10.0
v26.9.0
v26.8.0
v26.7.0
blazor-final
v26.6.0
v26.5.0
v26.4.0
v26.3.1
v26.3.0
v26.2.0
v26.1.1
v26.1.0
v25.9.0
v25.8.0
v25.7.1
v25.7.0
v25.6.0
v25.5.0
v25.4.0
v25.3.1
v25.3.0
v25.2.0
v25.1.0
v0.8.8-beta
v0.8.7-beta
v0.8.6-beta
v0.8.5-beta
v0.8.4-beta
v0.8.3-beta
v0.8.2-beta
v0.8.1-beta
v0.8.0-beta
v0.7.9-beta
v0.7.8-beta
v0.7.7-beta
v0.7.6-beta
v0.7.5-beta
v0.7.4-beta
v0.7.3-beta
v0.7.2-beta
v0.7.1-beta
v0.7.0-beta
v0.6.9-beta
v0.6.8-beta
v0.6.7-beta
v0.6.6-beta
v0.6.5-beta
v0.6.4-beta
v0.6.3-beta
v0.6.2-beta
v0.6.1-beta
v0.6.0-beta
v0.5.8-beta
v0.5.7-beta
v0.5.6-beta
v0.5.5-beta
v0.5.4-beta
v0.5.3-beta
v0.5.2-beta
v0.5.1-beta
v0.5.0-beta
v0.4.5-alpha
v0.4.4-alpha
v0.4.3-alpha
v0.4.2-alpha
v0.4.1-alpha
v0.4.0-alpha
v0.3.8-alpha
v0.3.7-alpha
develop
v0.3.6-alpha
v0.3.5-alpha
v0.3.4-alpha
v0.3.3-alpha
v0.3.2-alpha
v0.3.1-alpha
v0.3.0-alpha
v0.2.5-alpha
v0.2.4-alpha
v0.2.3-alpha
v0.2.2-alpha
v0.2.1-alpha
v0.2.0-alpha
v0.1.5-alpha
v0.1.4-alpha
v0.1.3-alpha
v0.1.2-alpha
v0.1.1-alpha
v0.1.0-alpha
v0.0.62-alpha
v0.0.61-alpha
v0.0.60-alpha
v0.0.59-alpha
v0.0.58-alpha
v0.0.57-alpha
v0.0.56-alpha
v0.0.55-alpha
v0.0.54-alpha
v0.0.53-alpha
v0.0.52-alpha
v0.0.51-alpha
v0.0.50-alpha
v0.0.49-prealpha
v0.0.48-prealpha
v0.0.47-prealpha
v0.0.46-prealpha
v0.0.45-prealpha
v0.0.44-prealpha
v0.0.43-prealpha
v0.0.42-prealpha
v0.0.41-prealpha
v0.0.40-prealpha
v0.0.39-prealpha
v0.0.38-prealpha
v0.0.37-prealpha
v0.0.36-prealpha
v0.0.35-prealpha
v0.0.34-prealpha
v0.0.33-prealpha
v0.0.32-prealpha
v0.0.31-prealpha
v0.0.30-prealpha
v0.0.29-prealpha
v0.0.28-prealpha
v0.0.27-prealpha
v0.0.26-prealpha
v0.0.25-prealpha
v0.0.24-prealpha
v0.0.23-prealpha
v0.0.22-prealpha
v0.0.21-prealpha
v0.0.20-prealpha
v0.0.19-prealpha
v0.0.18-prealpha
v0.0.17-prealpha
v0.0.16-prealpha
v0.0.15-prealpha
v0.0.14-prealpha
v0.0.13-prealpha
v0.0.12-prealpha
v0.0.11-prealpha
v0.0.10-prealpha
v0.0.9-prealpha
v0.0.8-prealpha
v0.0.7-prealpha
v0.0.6-prealpha
v0.0.5-prealpha
v0.0.4-prealpha
v0.0.3-prealpha
v0.0.2-prealpha
v0.0.1-prealpha
Labels
Clear labels
ad-hoc
api
bug
ci-cd
content
dependencies
enhancement
frontend
in-progress
jellyfin
parked
priority: high
priority: low
priority: medium
review
security
One-off / ad-hoc work not tracked by a dedicated issue
REST API / HTTP endpoints
Something isn't working
Build, test, deploy pipeline
Channel content / schedules / playlists
Dependency updates (Renovate)
New feature or improvement
ChicoryTV React SPA frontend
Claimed by an active session — do not pick up
Jellyfin tuner / IPTV integration
Excluded from automatic queue pickup; work only when explicitly selected
Adversarial review finding
Security / vulnerability fix
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: timothy/ersatztv#42
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
ErsatzTV can't sync MusicVideo items from a Jellyfin media source — the
musicvideosJellyfin CollectionType is silently dropped, so only Movies/Shows sync. Music-video / concert content therefore has to be shoehorned into Jellyfin's Movie type (NFO<movie>+ DBType=Movie, IsLocked=1) just so ErsatzTV will ingest it. Native MusicVideo sync would remove that workaround.Known blockers (from prior analysis — server-management#174)
JellyfinApiClient.csProject()— onlytvshows/movies/boxsetsrecognized;musicvideos→None(dropped).SynchronizeJellyfinLibraryByIdHandler.cs— only routesMovies/Shows; noIJellyfinMusicVideoLibraryScanner.IJellyfinApi.cs— hardcodesincludeItemTypes=Movie.Note: local libraries already support MusicVideos (
MusicVideoFolderScanner); only the Jellyfin sync path is missing.LibraryMediaKind.MusicVideos = 3exists but is unused on the Jellyfin path. Plex/Emby sources likely have the same gap — worth checking while in here.Driver
Recurring real-world pain: server-management#489 — MTV Unplugged concerts repeatedly dropped out of Jellyfin's index and needed a per-folder restructure + Movie/IsLocked override to stay usable by ErsatzTV. Native MusicVideo sync would let such content stay typed MusicVideo and drop the Jellyfin-side hack.
Scope
Backlog stub — design/spec + implementation to be fleshed out within this project. Low priority (the workaround is effective), but a clean, possibly-upstreamable candidate now that the fork is actively maintained.
Starting implementation in isolated worktree
/private/tmp/ersatztv-issue42fromorigin/mainatf25cfdb5.Initial findings match the issue:
JellyfinApiClient.Project()dropsCollectionType=musicvideos.SynchronizeJellyfinLibraryByIdHandleronly routesMoviesandShows; unsupported kinds silently return success.MusicVideounderJellyfinLibrary, so this appears to be a sync/projection/scanner gap rather than a migration task.Plan is TDD: add failing tests for Jellyfin MusicVideo library projection and sync routing, then implement the smallest Jellyfin-only scanner path needed. I’ll keep Plex/Emby out of scope unless a shared interface change forces touching them.
Implementation is pushed and PR is open: #55
Status
What was done: Added Jellyfin MusicVideo library projection and sync routing, plus a new Jellyfin MusicVideo scanner that imports Jellyfin
MusicVideoitems into existing ErsatzTVMusicVideoentities.Root cause: Jellyfin
CollectionType=musicvideoswas not recognized inJellyfinApiClient.Project(), so the library was dropped. The scanner handler also only routed Movies and Shows; unsupported library kinds silently returned success without scanning.Files changed: Jellyfin API client/interface/model, Scanner Jellyfin sync handler, new
IJellyfinMusicVideoLibraryScanner, newJellyfinMusicVideoLibraryScanner, scanner DI registration, and focused NUnit tests.Verification:
TZ=UTC dotnet test ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj -v minimalpassed (16 tests).TZ=UTC dotnet test ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj -v minimalpassed (1467 tests).TZ=UTC dotnet test ErsatzTV.Architecture.Tests/ErsatzTV.Architecture.Tests.csproj -v minimalpassed (5 tests).git diff --checkpassed.Deferred: PR #55 is waiting for CI; issue remains open until PR CI passes and the PR is merged.
Follow-up issues: none currently.
Docs updated: n/a; no operator-facing config or workflow changed.
Done
What was done: Implemented Jellyfin MusicVideo library sync and merged PR #55. Jellyfin
CollectionType=musicvideoslibraries now project asLibraryMediaKind.MusicVideos, fetch JellyfinMusicVideoitems withincludeItemTypes=MusicVideo, and route through a new Jellyfin MusicVideo scanner that imports into existing ErsatzTVMusicVideoentities.Root cause: The Jellyfin sync path only recognized
tvshows,movies, andboxsets, somusicvideoslibraries were projected toNoneand dropped. The library sync handler also only routed Movies and Shows, so unsupported library kinds silently returned success without scanning.Files changed: Jellyfin API client/interface/model; Jellyfin sync handler; new
IJellyfinMusicVideoLibraryScanner; newJellyfinMusicVideoLibraryScanner; Scanner DI registration; focused NUnit tests for library projection and sync routing.Verification: Local TDD red tests were observed before implementation. Local verification passed:
TZ=UTC dotnet test ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj -v minimal(16 tests),TZ=UTC dotnet test ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj -v minimal(1467 tests),TZ=UTC dotnet test ErsatzTV.Architecture.Tests/ErsatzTV.Architecture.Tests.csproj -v minimal(5 tests), andgit diff --check. PR CI passed: Build & test (.NET) succeeded in 3m53s; EF migration integrity succeeded in 5m4s; PR image push job skipped as expected.Deferred: Plex/Emby MusicVideo parity was not changed; this issue scoped the Jellyfin path only.
Follow-up issues: none.
Docs updated: n/a; no operator-facing config, deployment, or workflow changed.