mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
fix(jellyfin): resolve genre id as a MusicGenre item
The Jellyfin /Items/{id} endpoint resolved albums, artists, songs and
playlists by id but not genres, so a genre id returned 404. Finamp's
genre "See all" fetches the genre as the track list's parent item, and
that 404 crashed its screen to a blank page after the tracks flashed in.
Add a Genre lookup to resolveItemByID (backed by a new GenreRepository.Get)
so a genre id returns its MusicGenre BaseItemDto, matching real Jellyfin.
This commit is contained in:
parent
d080707060
commit
8e0ff1a235
@ -11,4 +11,5 @@ type Genres []Genre
|
||||
|
||||
type GenreRepository interface {
|
||||
GetAll(...QueryOptions) (Genres, error)
|
||||
Get(id string) (*Genre, error)
|
||||
}
|
||||
|
||||
@ -30,15 +30,19 @@ func (r *genreRepository) GetAll(opt ...model.QueryOptions) (model.Genres, error
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Override ResourceRepository methods to return Genre objects instead of Tag objects
|
||||
|
||||
func (r *genreRepository) Read(id string) (any, error) {
|
||||
func (r *genreRepository) Get(id string) (*model.Genre, error) {
|
||||
sel := r.selectGenre().Where(Eq{"tag.id": id})
|
||||
var res model.Genre
|
||||
err := r.queryOne(sel, &res)
|
||||
return &res, err
|
||||
}
|
||||
|
||||
// Override ResourceRepository methods to return Genre objects instead of Tag objects
|
||||
|
||||
func (r *genreRepository) Read(id string) (any, error) {
|
||||
return r.Get(id)
|
||||
}
|
||||
|
||||
func (r *genreRepository) ReadAll(options ...rest.QueryOptions) (any, error) {
|
||||
return r.GetAll(r.parseRestOptions(r.ctx, options...))
|
||||
}
|
||||
|
||||
@ -736,7 +736,7 @@ func (api *Router) listPlaylists(ctx context.Context, opts model.QueryOptions, q
|
||||
}
|
||||
|
||||
// resolveItemByID resolves a decoded navidrome id to its BaseItemDto, trying library view, album,
|
||||
// artist, song and playlist in turn. Albums and songs report not-found when the user lacks access
|
||||
// artist, song, playlist and genre in turn. Albums and songs report not-found when the user lacks access
|
||||
// to their library, so an id can't probe content outside the user's libraries.
|
||||
func (api *Router) resolveItemByID(ctx context.Context, id string, fields dto.Fields) (dto.BaseItemDto, bool) {
|
||||
// The synthetic playlists folder must resolve by the id we advertised, not 404.
|
||||
@ -778,6 +778,9 @@ func (api *Router) resolveItemByID(ctx context.Context, id string, fields dto.Fi
|
||||
if pl, err := api.playlists.Get(ctx, id); err == nil {
|
||||
return dto.PlaylistToBaseItem(*pl, fields), true
|
||||
}
|
||||
if g, err := api.ds.Genre(ctx).Get(id); err == nil {
|
||||
return dto.GenreToBaseItem(*g), true
|
||||
}
|
||||
return dto.BaseItemDto{}, false
|
||||
}
|
||||
|
||||
|
||||
@ -917,6 +917,21 @@ var _ = Describe("Items", func() {
|
||||
Expect(w.Code).To(Equal(http.StatusNotFound))
|
||||
})
|
||||
|
||||
// Finamp's genre "See all" fetches the genre by id; a 404 white-screens it (see resolveItemByID).
|
||||
It("resolves a genre id as a MusicGenre item", func() {
|
||||
Expect(ds.Genre(context.Background()).(*tests.MockedGenreRepo).Put(&model.Genre{ID: "g1", Name: "Rock"})).To(Succeed())
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/Items/"+dto.EncodeID("g1"), nil).WithContext(ctxUser())
|
||||
r = withChiURLParam(r, "itemId", dto.EncodeID("g1"))
|
||||
invoke(api.getItem, w, r)
|
||||
Expect(w.Code).To(Equal(http.StatusOK))
|
||||
var item dto.BaseItemDto
|
||||
Expect(json.Unmarshal(w.Body.Bytes(), &item)).To(Succeed())
|
||||
Expect(item.Id).To(Equal(dto.EncodeID("g1")))
|
||||
Expect(item.Name).To(Equal("Rock"))
|
||||
Expect(item.Type).To(Equal("MusicGenre"))
|
||||
})
|
||||
|
||||
It("resolves a library-view id for an admin even though their Libraries slice is empty", func() {
|
||||
ds.Library(context.Background()).(*tests.MockLibraryRepo).SetData(model.Libraries{{ID: 1, Name: "Music Library"}})
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
@ -32,6 +32,17 @@ func (r *MockedGenreRepo) GetAll(options ...model.QueryOptions) (model.Genres, e
|
||||
return all, nil
|
||||
}
|
||||
|
||||
func (r *MockedGenreRepo) Get(id string) (*model.Genre, error) {
|
||||
if r.Error != nil {
|
||||
return nil, r.Error
|
||||
}
|
||||
r.init()
|
||||
if g, ok := r.Data[id]; ok {
|
||||
return &g, nil
|
||||
}
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
|
||||
func (r *MockedGenreRepo) Put(g *model.Genre) error {
|
||||
if r.Error != nil {
|
||||
return r.Error
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user