Jellyfin does not support 5-star ratings - make it disableable

This commit is contained in:
Drew Weymouth
2023-11-14 09:05:02 -08:00
parent f25e748be5
commit e261eab4f3
12 changed files with 72 additions and 24 deletions
@@ -312,10 +312,6 @@ func (j *jellyfinMediaProvider) SetFavorite(params mediaprovider.RatingFavoriteP
return err return err
} }
func (j *jellyfinMediaProvider) SetRating(params mediaprovider.RatingFavoriteParameters, rating int) error {
return errors.New("unimplemented")
}
func (j *jellyfinMediaProvider) GetStreamURL(trackID string, forceRaw bool) (string, error) { func (j *jellyfinMediaProvider) GetStreamURL(trackID string, forceRaw bool) (string, error) {
return j.client.GetStreamURL(trackID) return j.client.GetStreamURL(trackID)
} }
+4 -2
View File
@@ -109,8 +109,6 @@ type MediaProvider interface {
SetFavorite(params RatingFavoriteParameters, favorite bool) error SetFavorite(params RatingFavoriteParameters, favorite bool) error
SetRating(params RatingFavoriteParameters, rating int) error
GetPlaylists() ([]*Playlist, error) GetPlaylists() ([]*Playlist, error)
CreatePlaylist(name string, trackIDs []string) error CreatePlaylist(name string, trackIDs []string) error
@@ -130,6 +128,10 @@ type MediaProvider interface {
RescanLibrary() error RescanLibrary() error
} }
type SupportsRating interface {
SetRating(params RatingFavoriteParameters, rating int) error
}
func genresMatch(filterGenres, albumGenres []string) bool { func genresMatch(filterGenres, albumGenres []string) bool {
for _, g1 := range filterGenres { for _, g1 := range filterGenres {
for _, g2 := range albumGenres { for _, g2 := range albumGenres {
+3 -3
View File
@@ -93,6 +93,8 @@ func newAlbumPage(
} }
a.tracklist.SetVisibleColumns(a.cfg.TracklistColumns) a.tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
a.tracklist.SetSorting(sort) a.tracklist.SetSorting(sort)
_, canRate := a.mp.(mediaprovider.SupportsRating)
a.tracklist.Options.DisableRating = !canRate
a.tracklist.OnVisibleColumnsChanged = func(cols []string) { a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
a.cfg.TracklistColumns = cols a.cfg.TracklistColumns = cols
} }
@@ -154,9 +156,7 @@ func (a *AlbumPage) load() {
return return
} }
a.header.Update(album, a.im) a.header.Update(album, a.im)
a.tracklist.Options = widgets.TracklistOptions{ a.tracklist.Options.ShowDiscNumber = len(album.Tracks) > 0 && album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber
ShowDiscNumber: len(album.Tracks) > 0 && album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber,
}
a.tracks = album.Tracks a.tracks = album.Tracks
a.tracklist.SetTracks(album.Tracks) a.tracklist.SetTracks(album.Tracks)
a.tracklist.SetNowPlaying(a.nowPlayingID) a.tracklist.SetNowPlaying(a.nowPlayingID)
+2
View File
@@ -229,6 +229,8 @@ func (a *ArtistPage) showTopTracks() {
tl = widgets.NewTracklist(ts) tl = widgets.NewTracklist(ts)
} }
tl.Options = widgets.TracklistOptions{AutoNumber: true} tl.Options = widgets.TracklistOptions{AutoNumber: true}
_, canRate := a.mp.(mediaprovider.SupportsRating)
tl.Options.DisableRating = !canRate
tl.SetVisibleColumns(a.cfg.TracklistColumns) tl.SetVisibleColumns(a.cfg.TracklistColumns)
tl.SetSorting(a.trackSort) tl.SetSorting(a.trackSort)
tl.OnVisibleColumnsChanged = func(cols []string) { tl.OnVisibleColumnsChanged = func(cols []string) {
+2
View File
@@ -370,6 +370,8 @@ func (a *FavoritesPage) onShowFavoriteSongs() {
tracklist = widgets.NewTracklist(fav.Tracks) tracklist = widgets.NewTracklist(fav.Tracks)
} }
tracklist.Options = widgets.TracklistOptions{AutoNumber: true} tracklist.Options = widgets.TracklistOptions{AutoNumber: true}
_, canRate := a.mp.(mediaprovider.SupportsRating)
tracklist.Options.DisableRating = !canRate
tracklist.SetVisibleColumns(a.cfg.TracklistColumns) tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
tracklist.SetSorting(a.trackSort) tracklist.SetSorting(a.trackSort)
tracklist.OnVisibleColumnsChanged = func(cols []string) { tracklist.OnVisibleColumnsChanged = func(cols []string) {
+10 -7
View File
@@ -37,11 +37,12 @@ type NowPlayingPage struct {
} }
type nowPlayingPageState struct { type nowPlayingPageState struct {
contr *controller.Controller contr *controller.Controller
pool *util.WidgetPool pool *util.WidgetPool
conf *backend.NowPlayingPageConfig conf *backend.NowPlayingPageConfig
pm *backend.PlaybackManager pm *backend.PlaybackManager
p *player.Player p *player.Player
canRate bool
} }
func NewNowPlayingPage( func NewNowPlayingPage(
@@ -51,9 +52,10 @@ func NewNowPlayingPage(
conf *backend.NowPlayingPageConfig, conf *backend.NowPlayingPageConfig,
pm *backend.PlaybackManager, pm *backend.PlaybackManager,
p *player.Player, // TODO: once other player backends are supported (eg uPnP), refactor p *player.Player, // TODO: once other player backends are supported (eg uPnP), refactor
canRate bool,
) *NowPlayingPage { ) *NowPlayingPage {
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{ a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{
contr: contr, pool: pool, conf: conf, pm: pm, p: p, contr: contr, pool: pool, conf: conf, pm: pm, p: p, canRate: canRate,
}} }}
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
@@ -74,6 +76,7 @@ func NewNowPlayingPage(
a.tracklist.Options = widgets.TracklistOptions{ a.tracklist.Options = widgets.TracklistOptions{
AutoNumber: true, AutoNumber: true,
DisablePlaybackMenu: true, DisablePlaybackMenu: true,
DisableRating: !canRate,
AuxiliaryMenuItems: []*fyne.MenuItem{ AuxiliaryMenuItems: []*fyne.MenuItem{
fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue), fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue),
}, },
@@ -213,5 +216,5 @@ func (a *NowPlayingPage) load(highlightedTrackID string) {
} }
func (s *nowPlayingPageState) Restore() Page { func (s *nowPlayingPageState) Restore() Page {
return NewNowPlayingPage("", s.contr, s.pool, s.conf, s.pm, s.p) return NewNowPlayingPage("", s.contr, s.pool, s.conf, s.pm, s.p, s.canRate)
} }
+2
View File
@@ -93,7 +93,9 @@ func newPlaylistPage(
fyne.NewMenuItem("Move down", a.onMoveSelectedDown), fyne.NewMenuItem("Move down", a.onMoveSelectedDown),
fyne.NewMenuItem("Move to bottom", a.onMoveSelectedToBottom), fyne.NewMenuItem("Move to bottom", a.onMoveSelectedToBottom),
}...) }...)
_, canRate := a.sm.Server.(mediaprovider.SupportsRating)
a.tracklist.Options = widgets.TracklistOptions{ a.tracklist.Options = widgets.TracklistOptions{
DisableRating: !canRate,
AuxiliaryMenuItems: []*fyne.MenuItem{reorderMenu, AuxiliaryMenuItems: []*fyne.MenuItem{reorderMenu,
fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist)}, fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist)},
} }
+3 -1
View File
@@ -2,6 +2,7 @@ package browsing
import ( import (
"github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/ui/controller" "github.com/dweymouth/supersonic/ui/controller"
"github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/util"
) )
@@ -45,7 +46,8 @@ func (r Router) CreatePage(rte controller.Route) Page {
case controller.Genres: case controller.Genres:
return NewGenresPage(r.Controller, r.App.ServerManager.Server) return NewGenresPage(r.Controller, r.App.ServerManager.Server)
case controller.NowPlaying: case controller.NowPlaying:
return NewNowPlayingPage(rte.Arg, r.Controller, r.widgetPool, &r.App.Config.NowPlayingPage, r.App.PlaybackManager, r.App.Player) _, canRate := r.App.ServerManager.Server.(mediaprovider.SupportsRating)
return NewNowPlayingPage(rte.Arg, r.Controller, r.widgetPool, &r.App.Config.NowPlayingPage, r.App.PlaybackManager, r.App.Player, canRate)
case controller.Playlist: case controller.Playlist:
return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager) return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
case controller.Playlists: case controller.Playlists:
+2
View File
@@ -51,8 +51,10 @@ func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig,
} else { } else {
t.tracklist = widgets.NewTracklist(nil) t.tracklist = widgets.NewTracklist(nil)
} }
_, canRate := mp.(mediaprovider.SupportsRating)
t.tracklist.Options = widgets.TracklistOptions{ t.tracklist.Options = widgets.TracklistOptions{
DisableSorting: true, DisableSorting: true,
DisableRating: !canRate,
AutoNumber: true, AutoNumber: true,
} }
t.tracklist.SetVisibleColumns(conf.TracklistColumns) t.tracklist.SetVisibleColumns(conf.TracklistColumns)
+5 -1
View File
@@ -577,7 +577,11 @@ func (c *Controller) SetTrackFavorites(trackIDs []string, favorite bool) {
} }
func (c *Controller) SetTrackRatings(trackIDs []string, rating int) { func (c *Controller) SetTrackRatings(trackIDs []string, rating int) {
go c.App.ServerManager.Server.SetRating(mediaprovider.RatingFavoriteParameters{ r, ok := c.App.ServerManager.Server.(mediaprovider.SupportsRating)
if !ok {
return
}
go r.SetRating(mediaprovider.RatingFavoriteParameters{
TrackIDs: trackIDs, TrackIDs: trackIDs,
}, rating) }, rating)
+34 -6
View File
@@ -15,15 +15,19 @@ import (
) )
var ( var (
themedResStarFilled = theme.NewThemedResource(res.ResStarFilledSvg) themedResStarFilled = theme.NewThemedResource(res.ResStarFilledSvg)
themedResStarOutline = theme.NewThemedResource(res.ResStarOutlineSvg) themedResStarOutline = theme.NewThemedResource(res.ResStarOutlineSvg)
themedDisabledStarOutline = theme.NewDisabledResource(res.ResStarOutlineSvg)
) )
var _ fyne.Disableable = (*StarRating)(nil)
type StarRating struct { type StarRating struct {
widget.BaseWidget widget.BaseWidget
Rating int IsDisabled bool
StarSize float32 Rating int
StarSize float32
OnRatingChanged func(int) OnRatingChanged func(int)
@@ -44,7 +48,9 @@ func (s *StarRating) createContainer() {
}) })
var im *canvas.Image var im *canvas.Image
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
if s.Rating > i { if s.IsDisabled {
im = canvas.NewImageFromResource(themedDisabledStarOutline)
} else if s.Rating > i {
im = canvas.NewImageFromResource(themedResStarFilled) im = canvas.NewImageFromResource(themedResStarFilled)
} else { } else {
im = canvas.NewImageFromResource(themedResStarOutline) im = canvas.NewImageFromResource(themedResStarOutline)
@@ -61,6 +67,9 @@ func (s *StarRating) MouseIn(e *desktop.MouseEvent) {
} }
func (s *StarRating) MouseMoved(e *desktop.MouseEvent) { func (s *StarRating) MouseMoved(e *desktop.MouseEvent) {
if s.IsDisabled {
return
}
hoverRating := int(math.Ceil(5 * float64(e.Position.X/s.Size().Width))) hoverRating := int(math.Ceil(5 * float64(e.Position.X/s.Size().Width)))
if s.mouseHoverRating != hoverRating { if s.mouseHoverRating != hoverRating {
s.holdRating = false s.holdRating = false
@@ -69,7 +78,24 @@ func (s *StarRating) MouseMoved(e *desktop.MouseEvent) {
} }
} }
func (s *StarRating) Disable() {
s.IsDisabled = true
s.Refresh()
}
func (s *StarRating) Enable() {
s.IsDisabled = false
s.Refresh()
}
func (s *StarRating) Disabled() bool {
return s.IsDisabled
}
func (s *StarRating) MouseOut() { func (s *StarRating) MouseOut() {
if s.IsDisabled {
return
}
s.mouseHoverRating = 0 s.mouseHoverRating = 0
s.holdRating = false s.holdRating = false
s.Refresh() s.Refresh()
@@ -105,7 +131,9 @@ func (s *StarRating) Refresh() {
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
im := s.container.Objects[i].(*canvas.Image) im := s.container.Objects[i].(*canvas.Image)
im.SetMinSize(fyne.NewSize(s.StarSize, s.StarSize)) im.SetMinSize(fyne.NewSize(s.StarSize, s.StarSize))
if rating > i { if s.IsDisabled {
im.Resource = themedDisabledStarOutline
} else if rating > i {
im.Resource = themedResStarFilled im.Resource = themedResStarFilled
} else { } else {
im.Resource = themedResStarOutline im.Resource = themedResStarOutline
+5
View File
@@ -66,6 +66,9 @@ type TracklistOptions struct {
// Disables sorting the tracklist by clicking individual columns. // Disables sorting the tracklist by clicking individual columns.
DisableSorting bool DisableSorting bool
// Disables the five star rating widget.
DisableRating bool
} }
type Tracklist struct { type Tracklist struct {
@@ -732,6 +735,7 @@ func NewTrackRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) *TrackRow
favorite.OnTapped = t.toggleFavorited favorite.OnTapped = t.toggleFavorited
t.favorite = container.NewCenter(favorite) t.favorite = container.NewCenter(favorite)
t.rating = NewStarRating() t.rating = NewStarRating()
t.rating.IsDisabled = t.tracklist.Options.DisableRating
t.rating.StarSize = 16 t.rating.StarSize = 16
t.rating.OnRatingChanged = t.setTrackRating t.rating.OnRatingChanged = t.setTrackRating
t.plays = newTrailingAlignLabel() t.plays = newTrailingAlignLabel()
@@ -842,6 +846,7 @@ func (t *TrackRow) Update(tm *trackModel, rowNum int) {
t.dur.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnTime)] t.dur.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnTime)]
t.year.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnYear)] t.year.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnYear)]
t.favorite.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnFavorite)] t.favorite.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnFavorite)]
t.rating.IsDisabled = t.tracklist.Options.DisableRating
t.rating.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnRating)] t.rating.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnRating)]
t.plays.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnPlays)] t.plays.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnPlays)]
t.bitrate.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnBitrate)] t.bitrate.Hidden = !t.tracklist.visibleColumns[ColNumber(ColumnBitrate)]