fix(jellyfin): honor the isFavorite query param for favorites filtering

Finamp's artist 'Favourite tracks' widget requests favorites via the
standalone isFavorite=true query param, not Filters=IsFavorite, so the
filter was ignored and non-favorited tracks were returned. Detect both
forms. (The widget's reshuffling is Finamp's explicit SortBy=Random.)
This commit is contained in:
Deluan 2026-07-06 08:57:40 -04:00
commit 4341b025ff
3 changed files with 14 additions and 2 deletions

View file

@ -70,7 +70,8 @@ authenticated user has access to; a library (or item within it) the user cannot
for scoping, an artist id when browsing into an artist's albums, or an album id when browsing into
an album's tracks); `AlbumArtistIds`/`ArtistIds`/`contributingArtistIds` (an artist's albums or
tracks — Finamp's artist screen sends these *alongside* `ParentId=<libraryId>`); `SearchTerm`;
`Filters=IsFavorite`; `SortBy`/`SortOrder`; `StartIndex`/`Limit`; and `Ids` (batch fetch by id).
favorites-only (`Filters=IsFavorite` or the standalone `isFavorite=true`); `SortBy`/`SortOrder`;
`StartIndex`/`Limit`; and `Ids` (batch fetch by id).
## Implemented endpoints

View file

@ -46,6 +46,14 @@ var _ = Describe("Annotations", func() {
Expect(q.Items[0].Name).To(Equal("Abbey Road"))
})
It("filters to favorites via the isFavorite query param (Finamp's artist widget form)", func() {
// Finamp's "Favourite tracks" widget sends isFavorite=true as a query param (not
// Filters=IsFavorite), combined with ArtistIds.
post("/Users/admin-1/FavoriteItems/"+enc(songID("Help!")), "")
q := queryResult(get("/Items?IncludeItemTypes=Audio&Recursive=true&ArtistIds=" + enc(artistID("The Beatles")) + "&isFavorite=true"))
Expect(names(q.Items)).To(ConsistOf("Help!"))
})
It("returns 404 when favoriting an unknown item", func() {
Expect(post("/Users/admin-1/FavoriteItems/"+enc("nope"), "").Code).To(Equal(http.StatusNotFound))
})

View file

@ -51,7 +51,10 @@ func (api *Router) queryItems(ctx context.Context, r *http.Request) (dto.QueryRe
}
parentId := dto.DecodeID(p.StringOr("ParentId", ""))
search := p.StringOr("SearchTerm", "")
favOnly := strings.Contains(p.StringOr("Filters", ""), "IsFavorite")
// Clients express "favorites only" two ways: Jellyfin's Filters=IsFavorite, and the standalone
// isFavorite=true query param (Finamp's artist "Favourite tracks" widget uses the latter).
favOnly := strings.Contains(p.StringOr("Filters", ""), "IsFavorite") ||
p.BoolOr("IsFavorite", false) || p.BoolOr("isFavorite", false)
sortBy := p.StringOr("SortBy", "")
sortOrder := p.StringOr("SortOrder", "")
offset := p.IntOr("StartIndex", 0)