Skip to content

Add optional Jellyfin star ratings - #1736

Open
martin-77 wants to merge 1 commit into
finamp-app:redesignfrom
martin-77:feature/star-ratings
Open

martin-77 wants to merge 1 commit into
finamp-app:redesignfrom
martin-77:feature/star-ratings

Conversation

@martin-77

Copy link
Copy Markdown
Contributor

Summary

This adds optional personal Jellyfin star ratings to Finamp using Jellyfin's existing UserData.Rating field.

The feature is disabled by default and is intentionally separate from Jellyfin's existing favorite/heart state.

Why?

Finamp already exposes Jellyfin favorites well, but a favorite is inherently binary: a track is either a favorite or it is not.

Jellyfin also stores a personal numeric rating for each item (UserData.Rating, 0–10). That represents a different piece of user data:

  • Favorite / heart: "I want this in my favorites."
  • Rating: "How much do I like this track?"

Using only the favorite flag loses that distinction. A binary heart cannot express preference strength without creating additional playlists or tags.

For larger music libraries, numeric ratings are useful for gradually curating a collection and distinguishing between tracks that are merely worth keeping, tracks a user actively likes, favorites, and exceptional tracks they may want to surface more often.

Jellyfin already has a dedicated per-user numeric rating field for this purpose, so this PR exposes existing server functionality rather than introducing a separate Finamp-only rating model or overloading IsFavorite.

First-class personal numeric ratings also appear to be relatively uncommon among current Jellyfin-focused mobile music clients. Rating systems exist elsewhere in the Jellyfin ecosystem, but exposing Jellyfin's own per-user numeric rating directly in a dedicated mobile music player is still unusual.

This also makes ratings useful beyond the immediate player UI: they provide structured personal library metadata that can later be used for filtering, recommendations, or rule-based/smart playlists.

The broader value of preserving personal listening metadata as input for future smart-playlist rules has already come up in Finamp discussion:
#194

This PR does not replace favorites. IsFavorite and UserData.Rating remain independent and useful for different purposes.

User experience

When enabled in Player Settings:

  • a five-star control is shown in the existing player action area
  • the same control is available in the portrait lyrics view through TrackNameContent
  • tapping a star sets the personal rating
  • tapping the currently selected star clears the rating
  • an optional setting enables half-star ratings
  • half-star values can be selected by swiping across the control
  • favorites continue to work exactly as before

The setting is off by default, so the existing player layout and behavior remain unchanged unless the user explicitly enables ratings.

Jellyfin mapping

Jellyfin stores personal ratings on a 0–10 scale. Finamp maps this to the UI as:

  • 0.5 stars → 1
  • 1 star → 2
  • 2 stars → 4
  • 3 stars → 6
  • 4 stars → 8
  • 5 stars → 10

Ratings are written using Jellyfin's user-data endpoint:

POST /UserItems/{itemId}/UserData

Clearing a rating uses:

DELETE /UserItems/{itemId}/Rating

This deliberately does not use Jellyfin's like/dislike endpoint and does not modify IsFavorite.

Implementation

The implementation follows the existing Finamp architecture:

  • settings are part of FinampSettings and persisted through Hive
  • generated settings providers/setters are used
  • Jellyfin endpoints are defined in jellyfin_api.dart
  • calls go through JellyfinApiHelper
  • UI state uses Riverpod
  • updates are optimistic and roll back on API failure
  • writes are disabled in offline mode
  • all new user-facing strings use Finamp's localization system
  • interactive star targets are 44×44 with accessibility labels/tooltips
  • conversion behavior has unit tests
  • existing system-heart behavior is preserved when star ratings are disabled

System media controls

The PR also exposes the existing MediaAction.setRating abstraction when ratings are enabled.

For iOS, the intended lock-screen representation is a single heart-style feedback control:

  • inactive → set the personal rating to 5 stars / Jellyfin rating 10
  • active → clear the personal rating

This is only the system-control representation; it does not turn the Jellyfin favorite state into a rating.

When star ratings are disabled, the existing heart/favorite behavior remains unchanged.

The Finamp implementation contains no custom iOS command-channel workaround. Full iOS lock-screen support depends on the corresponding Darwin implementation in audio_service.

Validation

Validated with:

  • build_runner
  • flutter gen-l10n
  • flutter analyze
  • rating conversion unit tests
  • debug build on a physical iPhone
  • release build on a physical iPhone

The feature was tested with existing Jellyfin numeric ratings as well as setting, changing and clearing ratings from Finamp.

The branch is based on the current redesign branch and squashed to one feature commit.

This PR remains a draft until the audio_service dependency is ready for upstream review.

Development note

This feature was developed with assistance from AI tools for code review, implementation support and iteration. The resulting code was manually reviewed and tested, including validation on a physical device.

@Chaphasilor

Copy link
Copy Markdown
Member

@martin-77 are numeric ratings actually supported by Jellyfin in any meaningful capacity? It seems like even Jellyfin Web doesn't support anything other than favoriting. If the API supports it we could add it, but I'm not sure if that would really offer a benefit, for example if the server doesn't actually support filtering or sorting based on rating (which I don't think it does, especially since no official client needs it?).

@martin-77

Copy link
Copy Markdown
Contributor Author

You're right that Jellyfin Web currently doesn't expose personal star ratings in its normal UI.

However, Jellyfin itself already has a native per-user UserData.Rating field, and this PR deliberately uses that instead of introducing a Finamp-specific rating system.

This isn't just theoretical either: Jellyfin plugins can consume that native field. We recently added support for it to the SmartLists plugin as well:
jyourstone/jellyfin-smartlists-plugin#502

So I'd distinguish between “Jellyfin Web has no rating UI” and “Jellyfin doesn't support ratings at all” — the former is currently true, the latter isn't.

There have also been long-standing Jellyfin feature requests for exactly this kind of functionality:

Music Star Rating:
https://features.jellyfin.org/posts/9/music-star-rating

Personal ratings:
https://features.jellyfin.org/posts/1134/personal-ratings

Importantly, this PR doesn't change the default Finamp experience either. Favorites remain the default, and star ratings are entirely optional.

There is, however, a group of users who specifically want a more granular rating system than a binary favorite/not-favorite state. I think this also fits Finamp quite well: Finamp already offers a fairly extensive set of optional settings that let users adapt the player to their preferred way of managing and listening to their music, without imposing those choices on everyone else.

For users who don't care about ratings, nothing changes. For users who do, Finamp can expose a capability that is already present in Jellyfin's user data instead of maintaining a separate rating system.

The missing pieces in Jellyfin itself — especially broader server-side support and a proper Web UI — are something we'd like to address upstream separately in Jellyfin afterwards.

@martin-77

Copy link
Copy Markdown
Contributor Author

Just curious - anything I can do or optimize in order to implement this feature?

@github-actions
github-actions Bot force-pushed the feature/star-ratings branch from fef2f72 to 289f2ce Compare September 1, 2026 10:37
@Chaphasilor

Copy link
Copy Markdown
Member

@martin-77 I get that, but my concern is that the Jellyfin devs consider this to be "legacy" and are not interested in supporting this in the future. So it could happen that this API surface will vanish in a future release, which would break the functionality in Finamp again. Did you have any direct contact with members of the Jellyfin team, or public statements from them saying that this API is safe to be used?

Also, why id github-actions committing and force-pushing this branch? 👀

@Rusty-Weasel

Copy link
Copy Markdown

@Chaphasilor

my concern is that the Jellyfin devs consider this to be "legacy" and are not interested in supporting this in the future. So it could happen that this API surface will vanish in a future release

This risk exists with any dependency, so it makes no difference whether it is an API or a library; the result is the same—if it suddenly disappears or changes, something perhaps breaks.

From what I’ve gathered, the feature is disabled by default, so it doesn't affect ordinary users at all; only those who specifically want to use it need to enable it.

Consequently, an ordinary user will never notice if the feature breaks; only those who choose to use it will let you know.

If the API supports it we could add it,

it does -> https://api.jellyfin.org/#tag/UserData/operation/UpdateUserItemRating

@martin-77

Copy link
Copy Markdown
Contributor Author

Thanks @Rusty-Weasel — I had another look into this as well.

I haven’t had a direct confirmation from a Jellyfin maintainer that personal ratings are guaranteed to stay, so I don’t want to overstate that.

However, looking at the history, I’m less concerned that this is simply an abandoned legacy feature. The numeric personal UserData.Rating field has been part of Jellyfin for many years — it was already present in the 10.5 era — and is still part of the current UserData model.

What I find more relevant is that it has survived some pretty substantial changes to Jellyfin’s backend. In 10.11 Jellyfin completed the major migration of the library database to EF Core, replacing much of the old database implementation and migrating the existing data into the new unified database:

https://jellyfin.org/posts/jellyfin-release-10.11.0/

Personal Rating was retained through that migration and the surrounding UserData refactoring. Recent Jellyfin 12 work still explicitly carries Rating through the current UserData/database mappings as well:

jellyfin/jellyfin#16969

So while that obviously isn’t a promise that the field can never disappear, we’re talking about a personal rating field that has existed for roughly six years, was retained through the major 10.11 database/UserData rewrite, and is still being accounted for in current Jellyfin development.

That seems quite different to me from depending on an old API that is simply being kept around for backwards compatibility.

There are also clients/plugins starting to make practical use of the existing field. I recently submitted a PR adding support for Jellyfin’s native personal rating to SmartLists:

jyourstone/jellyfin-smartlists-plugin#502

And I think both @Rusty-Weasel and @Chaphasilor make a fair point about the risk on the Finamp side. This feature is entirely opt-in and Favorites remain the default, so Finamp doesn’t become dependent on personal ratings for its normal functionality.

Regarding the force-push: that came from the automated workflow I used to update/rebase the branch against the current redesign base.

Upstream changes had taken Hive field IDs that this PR was using, so the branch needed a small compatibility update. The workflow rebuilt the feature as a single commit on top of the current base and replaced the branch history, which is why the commit shows up as being made by github-actions[bot].

That was more disruptive than necessary for an already open PR. I’ll avoid rewriting the branch history like that for future updates unless it’s actually necessary.

@martin-77

Copy link
Copy Markdown
Contributor Author

Quick follow-up: I re-tested the existing rating commit against current redesign without changing the feature code. All 8 tests pass and the iOS release build succeeds. I’d still very much like to get this into Finamp, so if there’s anything blocking review or merge, I’m happy to address it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants