Skip to content

feat-recs - Moonbase + Jellyfin 12 Super Search - #278

Merged
RadicalMuffinMan merged 3 commits into
Moonfin-Client:masterfrom
mattsigal:feature/jf12-similar-items-provider
Sep 8, 2026
Merged

feat-recs - Moonbase + Jellyfin 12 Super Search#278
RadicalMuffinMan merged 3 commits into
Moonfin-Client:masterfrom
mattsigal:feature/jf12-similar-items-provider

Conversation

@mattsigal

Copy link
Copy Markdown
Collaborator

Pull Request

Summary

Implements native support for Jellyfin 12's new extensible recommendation provider backend (ILocalSimilarItemsProvider) in Moonbase. This enables Jellyfin 12 servers running Moonbase to register "Moonfin Recommends" directly into Jellyfin's similarity pipeline with built-in server-side 24-hour disk/memory caching (SimilarItemsManager.TryReadSimilarItemsCacheAsync).
Additionally, this PR provides:

  1. Full library scoring on the server side (removing artificial candidate caps) for comprehensive recommendations across thousands of titles.
  2. Support for bypass=moonfin query parameters, allowing Moonfin clients to selectively invoke Jellyfin's stock recommendation engine with a boosted candidate pool (5,000 items) so stock similarity does not starve from played/permission filtering.
  3. A dedicated GET /Moonfin/Items/{itemId}/Similar endpoint and recommendationsSupported capability flag in /Moonfin/Ping for clean client auto-detection.

Related Issues

Link related issues or tickets separated by commas.

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Performance improvement
  • API / endpoint change
  • Settings schema change
  • Documentation update
  • Build/CI change
  • Other (describe):

Area

  • Settings sync / profiles
  • Admin defaults / config page
  • Ratings (MDBList / TMDB)
  • Notifications / Push (FCM / relay)
  • Seerr integration
  • Games / Emulators
  • Custom home rows
  • Web Client (Go to Moonfin-Core repo)
  • Other / shared

Changes Made

List the key changes included in this PR.

  • Dynamic ILocalSimilarItemsProvider Registration: Implemented MoonfinSimilarItemsProviderManager.cs using runtime reflection and lightweight IL emitting (TypeBuilder). This dynamically defines and registers an ILocalSimilarItemsProvider implementation if running on Jellyfin 12 without hard compile-time dependencies that would break backwards compatibility on Jellyfin 10.x.
  • Server-Side 9-Factor Similarity Engine: Implemented MoonfinSimilarItemsService.cs providing high-accuracy similarity scoring based on 9 weighted factors:
    • Shared genres (up to 35 pts)
    • Shared tags (up to 20 pts)
    • Shared actors (up to 18 pts)
    • Shared directors (up to 15 pts)
    • Shared writers (up to 8 pts)
    • Shared studios (up to 8 pts)
    • Production year proximity (decay formula within 5-15 years, up to 10 pts)
    • Community rating alignment (up to 5 pts)
    • Premiere date / recency fallback when candidate pool is sparse
  • Full Library Scoring: Removed arbitrary candidate query limits (Limit = 50) on the server. Because Moonbase runs in-process with direct access to SQLite and Entity Framework Core indexes, candidate gathering across the entire library executes in milliseconds. The resulting scored list is cached by Jellyfin 12's SimilarItemsManager for 24 hours, making repeat queries instant (< 5 ms).
  • Stock Provider Delegation with Candidate Scaling: Captured registered stock similarity providers at startup in MoonfinSimilarItemsProviderManager.cs. When a client requests bypass=moonfin, Moonbase directly delegates to stock Jellyfin providers while boosting the internal candidate query limit to 5,000, preventing Jellyfin's stock Take(limit) from prematurely starving candidate pools in libraries where users have already watched many matching titles.
  • Dedicated Endpoint and Capability Announcement: Added GET /Moonfin/Items/{itemId}/Similar in MoonfinController.cs and announced recommendationsSupported = true in /Moonfin/Ping via PluginServiceRegistrator.cs.

Client Impact

Does this need matching changes in a client repo (Core, Smart-TV, Roku)?

Compatibility

  • Change to the settings profile is additive only, no renamed or removed properties
  • New properties use the same type the client sends (a client bool maps to bool?, an int to int?)
  • Migration added for any renamed or removed settings
  • Older clients still work, unknown fields are ignored and no keys were removed

Testing

Describe how this change was tested.

  • Built the plugin and deployed to a Jellyfin server
  • Verified against a live client (which one:) Windows Desktop, Android TV
  • Manual testing completed
  • Not tested (explain why):

Test Steps

  1. Built Moonfin.Server.dll and deployed to Jellyfin 12.0.0 container on Synology NAS.
  2. Verified Jellyfin startup logs confirm registration of "Moonfin Recommends" as ILocalSimilarItemsProvider.
  3. Tested GET /Moonfin/Items/{id}/Similar directly to verify 9-factor scored output for movies and series.
  4. Tested GET /Items/{id}/Similar?bypass=moonfin to verify clean delegation to stock Jellyfin similarity.
  5. Tested candidate limits from 30 to 5,000 on large library items to ensure candidate pools do not starve.
  6. Ran Moonfin-Core client (mfdbW -q) and verified all recommendation sources ("Moonfin Recommends", "Jellyfin Recommends", "TMDb Similarity") render distinct, full lists on both Home screen rows and Details pages.

Screenshots (if applicable)

Include config page screenshots or request/response samples where relevant.

Moonfin Recommends as Vanilla Search Provider!

2026-09-08_11-11-24_brave 2026-09-08_11-11-04_brave

Checklist

  • Code builds successfully
  • Code follows project style and conventions
  • No unnecessary commented-out code
  • No new warnings introduced
  • Any new setting keys match the client-side keys exactly

…th full library scoring and stock bypass

- Implement MoonfinSimilarItemsProviderManager using dynamic Reflection.Emit
  to implement Jellyfin 12's ILocalSimilarItemsProvider interface at runtime.
  This allows Moonfin Recommends to compile cleanly against net8.0 without
  breaking on older Jellyfin versions.
- Implement MoonfinSimilarItemsService with 9-factor scoring (genres, tags,
  actors, directors, writers, studios, release year, community rating, premiere date).
- Support full library scoring on the server side without artificial candidate
  caps, leveraging in-process SQLite indexes and Jellyfin 12's 24-hour disk/memory
  cache (SimilarItemsManager.TryReadSimilarItemsCacheAsync).
- Add support for bypass=moonfin query parameter, enabling direct invocation
  of stock Jellyfin providers with boosted candidate limits (5,000) so stock
  recommendations do not starve after played/permission filtering.
- Add GET /Moonfin/Items/{itemId}/Similar endpoint and announce
  recommendationsSupported capability flag in /Moonfin/Ping.
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

Build Successful

Both plugins compiled against .NET 8, and both test suites passed.

Property Value
Commit 030d7c9
Jellyfin ABI 10.10.0.0
Emby version 2.2.0.0
Workflow Build #377

…n with IsAssignableFrom

Ensure stock provider invocation checks whether the provider type implements ILocalSimilarItemsProvider before attempting to invoke interface methods, preventing TargetException when iterating third-party or non-local similarity providers.
…access, preserve the stock providers when registering Moonfin ahead of them, cache the reflection lookups at emit time, use GetPeopleByItems on Jellyfin 12 with per-item reads as the fallback, and add the RecommendationsProviderEnabled toggle plus scoring tests.
@RadicalMuffinMan
RadicalMuffinMan merged commit aba1b8d into Moonfin-Client:master Sep 8, 2026
1 check passed
@mattsigal
mattsigal deleted the feature/jf12-similar-items-provider branch September 8, 2026 22:05
RadicalMuffinMan added a commit that referenced this pull request Sep 9, 2026
…Ping, and send UserData on Moonfin cards
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants