diff --git a/backend/mediaprovider/model.go b/backend/mediaprovider/model.go index 2516dc1a..e83264ba 100644 --- a/backend/mediaprovider/model.go +++ b/backend/mediaprovider/model.go @@ -85,30 +85,32 @@ type Genre struct { } type Track struct { - ID string - CoverArtID string - ParentID string - Title string - Duration int - TrackNumber int - DiscNumber int - Genres []string - ArtistIDs []string - ArtistNames []string - Album string - AlbumID string - Year int - Rating int - Favorite bool - Size int64 - PlayCount int - LastPlayed time.Time - FilePath string - BitRate int - ContentType string - Comment string - BPM int - ReplayGain ReplayGainInfo + ID string + CoverArtID string + ParentID string + Title string + Duration int + TrackNumber int + DiscNumber int + Genres []string + ArtistIDs []string + ArtistNames []string + ComposerIDs []string + ComposerNames []string + Album string + AlbumID string + Year int + Rating int + Favorite bool + Size int64 + PlayCount int + LastPlayed time.Time + FilePath string + BitRate int + ContentType string + Comment string + BPM int + ReplayGain ReplayGainInfo } type ReplayGainInfo struct { diff --git a/backend/mediaprovider/subsonic/subsonicmediaprovider.go b/backend/mediaprovider/subsonic/subsonicmediaprovider.go index cd3c681a..73d74ebb 100644 --- a/backend/mediaprovider/subsonic/subsonicmediaprovider.go +++ b/backend/mediaprovider/subsonic/subsonicmediaprovider.go @@ -509,31 +509,42 @@ func toTrack(ch *subsonic.Child) *mediaprovider.Track { genres = []string{ch.Genre} } + var composerIDs []string + var composers []string + for _, ctr := range ch.Contributors { + if strings.EqualFold(ctr.Role, "composer") { + composerIDs = append(composerIDs, ctr.Artist.ID) + composers = append(composers, ctr.Artist.Name) + } + } + return &mediaprovider.Track{ - ID: ch.ID, - CoverArtID: ch.CoverArt, - ParentID: ch.Parent, - Title: ch.Title, - Duration: ch.Duration, - TrackNumber: ch.Track, - DiscNumber: ch.DiscNumber, - Genres: genres, - ArtistIDs: artistIDs, - ArtistNames: artistNames, - Album: ch.Album, - AlbumID: ch.AlbumID, - Year: ch.Year, - Rating: ch.UserRating, - Favorite: !ch.Starred.IsZero(), - PlayCount: int(ch.PlayCount), - LastPlayed: ch.Played, - FilePath: ch.Path, - Size: ch.Size, - BitRate: ch.BitRate, - ContentType: ch.ContentType, - Comment: ch.Comment, - BPM: ch.BPM, - ReplayGain: rGain, + ID: ch.ID, + CoverArtID: ch.CoverArt, + ParentID: ch.Parent, + Title: ch.Title, + Duration: ch.Duration, + TrackNumber: ch.Track, + DiscNumber: ch.DiscNumber, + Genres: genres, + ArtistIDs: artistIDs, + ArtistNames: artistNames, + ComposerIDs: composerIDs, + ComposerNames: composers, + Album: ch.Album, + AlbumID: ch.AlbumID, + Year: ch.Year, + Rating: ch.UserRating, + Favorite: !ch.Starred.IsZero(), + PlayCount: int(ch.PlayCount), + LastPlayed: ch.Played, + FilePath: ch.Path, + Size: ch.Size, + BitRate: ch.BitRate, + ContentType: ch.ContentType, + Comment: ch.Comment, + BPM: ch.BPM, + ReplayGain: rGain, } } diff --git a/go.mod b/go.mod index 7eb526a3..d0c6a0cc 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64 github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645 github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee - github.com/dweymouth/go-subsonic v0.0.0-20240716154859-c40a4519e1e0 + github.com/dweymouth/go-subsonic v0.0.0-20240721002411-f2df85be66f1 github.com/godbus/dbus/v5 v5.1.0 github.com/google/uuid v1.3.0 github.com/pelletier/go-toml/v2 v2.0.8 diff --git a/go.sum b/go.sum index dd218695..48fe1598 100644 --- a/go.sum +++ b/go.sum @@ -85,10 +85,8 @@ github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645 h1:KzqSaQwG3 github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645/go.mod h1:fcUagHBaQnt06GmBAllNE0J4O/7064zXRWdqnTTtVjI= github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee h1:ZGyJ6wp7CAfT31BugypcF/TPKEy2RrGR9JFq1JOjOpY= github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee/go.mod h1:Ov0ieN90M7i+0k3OxhA/g1dozGs+UcPHDsMKqPgRDk0= -github.com/dweymouth/go-subsonic v0.0.0-20240603150834-605046e7c78a h1:jcHDGzvpsyvEt8i0vqB92jHIfWJUt106QITrPoYjSWo= -github.com/dweymouth/go-subsonic v0.0.0-20240603150834-605046e7c78a/go.mod h1:OWtcumdQsan8uM6wmx6PqKhldaCthH10CQ+vb+94kzo= -github.com/dweymouth/go-subsonic v0.0.0-20240716154859-c40a4519e1e0 h1:Zf27NWT1N889/toYK7/x7y7ERw8iJfAHBHGiMyYxaLY= -github.com/dweymouth/go-subsonic v0.0.0-20240716154859-c40a4519e1e0/go.mod h1:OWtcumdQsan8uM6wmx6PqKhldaCthH10CQ+vb+94kzo= +github.com/dweymouth/go-subsonic v0.0.0-20240721002411-f2df85be66f1 h1:Ibjafpy6ds3DtmX43hxsnqiBR7mBcihl4IRq+jwlyJA= +github.com/dweymouth/go-subsonic v0.0.0-20240721002411-f2df85be66f1/go.mod h1:OWtcumdQsan8uM6wmx6PqKhldaCthH10CQ+vb+94kzo= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/ui/dialogs/trackinfodialog.go b/ui/dialogs/trackinfodialog.go index 7981bbbc..156165ba 100644 --- a/ui/dialogs/trackinfodialog.go +++ b/ui/dialogs/trackinfodialog.go @@ -38,7 +38,16 @@ func (t *TrackInfoDialog) CreateRenderer() fyne.WidgetRenderer { addFormRow(c, "Title", t.track.Title) - c.Add(newFormText("Artist", true)) + c.Add(newFormText("Album", true)) + album := widget.NewHyperlink(t.track.Album, nil) + album.OnTapped = func() { + if t.OnNavigateToAlbum != nil { + t.OnNavigateToAlbum(t.track.AlbumID) + } + } + c.Add(album) + + c.Add(newFormText("Artists", true)) artists := widgets.NewMultiHyperlink() artists.BuildSegments(t.track.ArtistNames, t.track.ArtistIDs) artists.OnTapped = func(id string) { @@ -48,14 +57,17 @@ func (t *TrackInfoDialog) CreateRenderer() fyne.WidgetRenderer { } c.Add(artists) - c.Add(newFormText("Album", true)) - album := widget.NewHyperlink(t.track.Album, nil) - album.OnTapped = func() { - if t.OnNavigateToAlbum != nil { - t.OnNavigateToAlbum(t.track.AlbumID) + if len(t.track.ComposerNames) > 0 { + c.Add(newFormText("Composers", true)) + composers := widgets.NewMultiHyperlink() + composers.BuildSegments(t.track.ComposerNames, t.track.ComposerIDs) + artists.OnTapped = func(id string) { + if t.OnNavigateToArtist != nil { + t.OnNavigateToArtist(id) + } } + c.Add(composers) } - c.Add(album) if len(t.track.Genres) > 0 { c.Add(newFormText("Genres", true)) diff --git a/ui/widgets/tracklistrow.go b/ui/widgets/tracklistrow.go index b9418944..fd2e86c9 100644 --- a/ui/widgets/tracklistrow.go +++ b/ui/widgets/tracklistrow.go @@ -29,6 +29,7 @@ const ( ColumnArtist = "Artist" ColumnTitleArtist = "Title/Artist" ColumnAlbum = "Album" + ColumnComposer = "Composer" ColumnTime = "Time" ColumnYear = "Year" ColumnFavorite = "Favorite" @@ -45,6 +46,7 @@ var ( {Name: ColumnNum, Col: ListColumn{Text: "#", Alignment: fyne.TextAlignTrailing, CanToggleVisible: false}}, {Name: ColumnTitleArtist, Col: ListColumn{Text: "Title / Artist", Alignment: fyne.TextAlignLeading, CanToggleVisible: false}}, {Name: ColumnAlbum, Col: ListColumn{Text: "Album", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, + {Name: ColumnComposer, Col: ListColumn{Text: "Composer", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, {Name: ColumnTime, Col: ListColumn{Text: "Time", Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnYear, Col: ListColumn{Text: "Year", Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnFavorite, Col: ListColumn{Text: " Fav.", Alignment: fyne.TextAlignCenter, CanToggleVisible: true}}, @@ -56,14 +58,15 @@ var ( {Name: ColumnPath, Col: ListColumn{Text: "File Path", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, } - // #, Title/Artist, Album, Time, Year, Favorite, Rating, Plays, Comment, Bitrate, Size, Path - ExpandedTracklistRowColumnWidths = []float32{40, -1, -1, 60, 60, 55, 100, 65, -1, 75, 75, -1} + // #, Title/Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, Comment, Bitrate, Size, Path + ExpandedTracklistRowColumnWidths = []float32{40, -1, -1, -1, 60, 60, 55, 100, 65, -1, 75, 75, -1} CompactTracklistRowColumns = []TracklistColumn{ {Name: ColumnNum, Col: ListColumn{Text: "#", Alignment: fyne.TextAlignTrailing, CanToggleVisible: false}}, {Name: ColumnTitle, Col: ListColumn{Text: "Title", Alignment: fyne.TextAlignLeading, CanToggleVisible: false}}, {Name: ColumnArtist, Col: ListColumn{Text: "Artist", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, {Name: ColumnAlbum, Col: ListColumn{Text: "Album", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, + {Name: ColumnComposer, Col: ListColumn{Text: "Composer", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, {Name: ColumnTime, Col: ListColumn{Text: "Time", Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnYear, Col: ListColumn{Text: "Year", Alignment: fyne.TextAlignTrailing, CanToggleVisible: true}}, {Name: ColumnFavorite, Col: ListColumn{Text: " Fav.", Alignment: fyne.TextAlignCenter, CanToggleVisible: true}}, @@ -75,8 +78,8 @@ var ( {Name: ColumnPath, Col: ListColumn{Text: "File Path", Alignment: fyne.TextAlignLeading, CanToggleVisible: true}}, } - // #, Title, Artist, Album, Time, Year, Favorite, Rating, Plays, Comment, Bitrate, Size, Path - CompactTracklistRowColumnWidths = []float32{40, -1, -1, -1, 60, 60, 55, 100, 65, -1, 75, 75, -1} + // #, Title, Artist, Album, Composer, Time, Year, Favorite, Rating, Plays, Comment, Bitrate, Size, Path + CompactTracklistRowColumnWidths = []float32{40, -1, -1, -1, -1, 60, 60, 55, 100, 65, -1, 75, 75, -1} ) type tracklistRowBase struct { @@ -103,6 +106,7 @@ type tracklistRowBase struct { name *widget.RichText // for bold support artist *MultiHyperlink album *MultiHyperlink // for disabled support, if albumID is "" + composer *MultiHyperlink dur *widget.Label year *widget.Label favorite *fyne.Container @@ -165,7 +169,7 @@ func NewExpandedTracklistRow(tracklist *Tracklist, im *backend.ImageManager, pla v := makeVerticallyCentered // func alias container := container.New(tracklist.colLayout, - v(t.num), titleArtistImg, v(t.album), v(t.dur), v(t.year), v(t.favorite), v(t.rating), v(t.plays), v(t.comment), v(t.bitrate), v(t.size), v(t.path)) + v(t.num), titleArtistImg, v(t.album), v(t.composer), v(t.dur), v(t.year), v(t.favorite), v(t.rating), v(t.plays), v(t.comment), v(t.bitrate), v(t.size), v(t.path)) t.Content = container t.setColVisibility = func(colNum int, vis bool) bool { c := container.Objects[colNum].(*fyne.Container) @@ -191,20 +195,21 @@ func NewCompactTracklistRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) t.playingIcon = playingIcon t.Content = container.New(tracklist.colLayout, - t.num, t.name, t.artist, t.album, t.dur, t.year, t.favorite, t.rating, t.plays, t.comment, t.bitrate, t.size, t.path) + t.num, t.name, t.artist, t.album, t.composer, t.dur, t.year, t.favorite, t.rating, t.plays, t.comment, t.bitrate, t.size, t.path) colHiddenPtrMap := map[int]*bool{ 2: &t.artist.Hidden, 3: &t.album.Hidden, - 4: &t.dur.Hidden, - 5: &t.year.Hidden, - 6: &t.favorite.Hidden, - 7: &t.rating.Hidden, - 8: &t.plays.Hidden, - 9: &t.comment.Hidden, - 10: &t.bitrate.Hidden, - 11: &t.size.Hidden, - 12: &t.path.Hidden, + 4: &t.composer.Hidden, + 5: &t.dur.Hidden, + 6: &t.year.Hidden, + 7: &t.favorite.Hidden, + 8: &t.rating.Hidden, + 9: &t.plays.Hidden, + 10: &t.comment.Hidden, + 11: &t.bitrate.Hidden, + 12: &t.size.Hidden, + 13: &t.path.Hidden, } t.setColVisibility = func(colNum int, vis bool) bool { ptr, ok := colHiddenPtrMap[colNum] @@ -226,6 +231,8 @@ func (t *tracklistRowBase) create(tracklist *Tracklist) { t.artist.OnTapped = tracklist.onArtistTapped t.album = NewMultiHyperlink() t.album.OnTapped = func(id string) { tracklist.onAlbumTapped(id) } + t.composer = NewMultiHyperlink() + t.composer.OnTapped = func(id string) { tracklist.onArtistTapped(id) } t.dur = util.NewTrailingAlignLabel() t.year = util.NewTrailingAlignLabel() favorite := NewFavoriteIcon() @@ -266,6 +273,7 @@ func (t *tracklistRowBase) Update(tm *util.TrackListModel, rowNum int) { t.name.Segments[0].(*widget.TextSegment).Text = tr.Title t.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs) t.album.BuildSegments([]string{tr.Album}, []string{tr.AlbumID}) + t.composer.BuildSegments(tr.ComposerNames, tr.ComposerIDs) t.dur.Text = util.SecondsToMMSS(float64(tr.Duration)) t.year.Text = strconv.Itoa(tr.Year) t.plays.Text = strconv.Itoa(int(tr.PlayCount))