Skip to content

Commit

Permalink
feat(subsonic): return transcoded mime and transcoded suffix in subso…
Browse files Browse the repository at this point in the history
…nic responses

fixes #106

* Added support to TranscodedContentType and TranscodedSuffix

* Make sure that we have a profile

* Fix linting

* Fixed use of NewTCTrackByFolder instead of NewTrackByTags in handlers_by_tags.go

simplify a bit
  • Loading branch information
dertasiu authored and sentriz committed Nov 2, 2022
1 parent 692ec68 commit 6e6404a
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 47 deletions.
6 changes: 3 additions & 3 deletions server/ctrlsubsonic/ctrl.go
Expand Up @@ -9,12 +9,12 @@ import (
"log"
"net/http"

"go.senan.xyz/gonic/server/ctrlbase"
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
"go.senan.xyz/gonic/jukebox"
"go.senan.xyz/gonic/podcasts"
"go.senan.xyz/gonic/scrobble"
"go.senan.xyz/gonic/server/ctrlbase"
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
"go.senan.xyz/gonic/transcode"
)

Expand Down
21 changes: 19 additions & 2 deletions server/ctrlsubsonic/handlers_by_folder.go
Expand Up @@ -95,13 +95,18 @@ func (c *Controller) ServeGetMusicDirectory(r *http.Request) *spec.Response {
Preload("TrackRating", "user_id=?", user.ID).
Order("filename").
Find(&childTracks)

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for _, ch := range childTracks {
toAppend := spec.NewTCTrackByFolder(ch, folder)
if v, _ := params.Get("c"); v == "Jamstash" {
// jamstash thinks it can't play flacs
toAppend.ContentType = "audio/mpeg"
toAppend.Suffix = "mp3"
}
toAppend.TranscodedContentType = transcodeMIME
toAppend.TranscodedSuffix = transcodeSuffix
childrenObj = append(childrenObj, toAppend)
}
// respond section
Expand Down Expand Up @@ -259,8 +264,14 @@ func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response {
if err := q.Find(&tracks).Error; err != nil {
return spec.NewError(0, "find tracks: %v", err)
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for _, t := range tracks {
results.Tracks = append(results.Tracks, spec.NewTCTrackByFolder(t, t.Album))
track := spec.NewTCTrackByFolder(t, t.Album)
track.TranscodedContentType = transcodeMIME
track.TranscodedSuffix = transcodeSuffix
results.Tracks = append(results.Tracks, track)
}

sub := spec.NewResponse()
Expand Down Expand Up @@ -335,8 +346,14 @@ func (c *Controller) ServeGetStarred(r *http.Request) *spec.Response {
if err := q.Find(&tracks).Error; err != nil {
return spec.NewError(0, "find tracks: %v", err)
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for _, t := range tracks {
results.Tracks = append(results.Tracks, spec.NewTCTrackByFolder(t, t.Album))
track := spec.NewTCTrackByFolder(t, t.Album)
track.TranscodedContentType = transcodeMIME
track.TranscodedSuffix = transcodeSuffix
results.Tracks = append(results.Tracks, track)
}

sub := spec.NewResponse()
Expand Down
46 changes: 42 additions & 4 deletions server/ctrlsubsonic/handlers_by_tags.go
Expand Up @@ -117,8 +117,13 @@ func (c *Controller) ServeGetAlbum(r *http.Request) *spec.Response {
sub := spec.NewResponse()
sub.Album = spec.NewAlbumByTags(album, album.TagArtist)
sub.Album.Tracks = make([]*spec.TrackChild, len(album.Tracks))

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, track := range album.Tracks {
sub.Album.Tracks[i] = spec.NewTrackByTags(track, album)
sub.Album.Tracks[i].TranscodedContentType = transcodeMIME
sub.Album.Tracks[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down Expand Up @@ -270,8 +275,14 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response {
if err := q.Find(&tracks).Error; err != nil {
return spec.NewError(0, "find tracks: %v", err)
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for _, t := range tracks {
results.Tracks = append(results.Tracks, spec.NewTrackByTags(t, t.Album))
track := spec.NewTrackByTags(t, t.Album)
track.TranscodedContentType = transcodeMIME
track.TranscodedSuffix = transcodeSuffix
results.Tracks = append(results.Tracks, track)
}

sub := spec.NewResponse()
Expand Down Expand Up @@ -411,9 +422,15 @@ func (c *Controller) ServeGetSongsByGenre(r *http.Request) *spec.Response {
sub.TracksByGenre = &spec.TracksByGenre{
List: make([]*spec.TrackChild, len(tracks)),
}
for i, track := range tracks {
sub.TracksByGenre.List[i] = spec.NewTrackByTags(track, track.Album)

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, t := range tracks {
sub.TracksByGenre.List[i] = spec.NewTrackByTags(t, t.Album)
sub.TracksByGenre.List[i].TranscodedContentType = transcodeMIME
sub.TracksByGenre.List[i].TranscodedSuffix = transcodeSuffix
}

return sub
}

Expand Down Expand Up @@ -475,8 +492,14 @@ func (c *Controller) ServeGetStarredTwo(r *http.Request) *spec.Response {
if err := q.Find(&tracks).Error; err != nil {
return spec.NewError(0, "find tracks: %v", err)
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for _, t := range tracks {
results.Tracks = append(results.Tracks, spec.NewTrackByTags(t, t.Album))
track := spec.NewTrackByTags(t, t.Album)
track.TranscodedContentType = transcodeMIME
track.TranscodedSuffix = transcodeSuffix
results.Tracks = append(results.Tracks, track)
}

sub := spec.NewResponse()
Expand Down Expand Up @@ -546,8 +569,13 @@ func (c *Controller) ServeGetTopSongs(r *http.Request) *spec.Response {
sub.TopSongs = &spec.TopSongs{
Tracks: make([]*spec.TrackChild, len(tracks)),
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, track := range tracks {
sub.TopSongs.Tracks[i] = spec.NewTrackByTags(track, track.Album)
sub.TopSongs.Tracks[i].TranscodedContentType = transcodeMIME
sub.TopSongs.Tracks[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down Expand Up @@ -612,8 +640,13 @@ func (c *Controller) ServeGetSimilarSongs(r *http.Request) *spec.Response {
sub.SimilarSongs = &spec.SimilarSongs{
Tracks: make([]*spec.TrackChild, len(tracks)),
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, track := range tracks {
sub.SimilarSongs.Tracks[i] = spec.NewTrackByTags(track, track.Album)
sub.SimilarSongs.Tracks[i].TranscodedContentType = transcodeMIME
sub.SimilarSongs.Tracks[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down Expand Up @@ -676,8 +709,13 @@ func (c *Controller) ServeGetSimilarSongsTwo(r *http.Request) *spec.Response {
sub.SimilarSongsTwo = &spec.SimilarSongsTwo{
Tracks: make([]*spec.TrackChild, len(tracks)),
}

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, track := range tracks {
sub.SimilarSongsTwo.Tracks[i] = spec.NewTrackByTags(track, track.Album)
sub.SimilarSongsTwo.Tracks[i].TranscodedContentType = transcodeMIME
sub.SimilarSongsTwo.Tracks[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down
12 changes: 12 additions & 0 deletions server/ctrlsubsonic/handlers_common.go
Expand Up @@ -127,6 +127,7 @@ func (c *Controller) ServeNotFound(r *http.Request) *spec.Response {
}

func (c *Controller) ServeGetPlayQueue(r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
user := r.Context().Value(CtxUser).(*db.User)
var queue db.PlayQueue
err := c.DB.
Expand All @@ -143,8 +144,12 @@ func (c *Controller) ServeGetPlayQueue(r *http.Request) *spec.Response {
sub.PlayQueue.Current = queue.CurrentSID()
sub.PlayQueue.Changed = queue.UpdatedAt
sub.PlayQueue.ChangedBy = queue.ChangedBy

trackIDs := queue.GetItems()
sub.PlayQueue.List = make([]*spec.TrackChild, len(trackIDs))

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, id := range trackIDs {
track := db.Track{}
c.DB.
Expand All @@ -154,6 +159,8 @@ func (c *Controller) ServeGetPlayQueue(r *http.Request) *spec.Response {
Preload("TrackRating", "user_id=?", user.ID).
Find(&track)
sub.PlayQueue.List[i] = spec.NewTCTrackByFolder(&track, track.Album)
sub.PlayQueue.List[i].TranscodedContentType = transcodeMIME
sub.PlayQueue.List[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down Expand Up @@ -241,8 +248,13 @@ func (c *Controller) ServeGetRandomSongs(r *http.Request) *spec.Response {
sub := spec.NewResponse()
sub.RandomTracks = &spec.RandomTracks{}
sub.RandomTracks.List = make([]*spec.TrackChild, len(tracks))

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, track := range tracks {
sub.RandomTracks.List[i] = spec.NewTrackByTags(track, track.Album)
sub.RandomTracks.List[i].TranscodedContentType = transcodeMIME
sub.RandomTracks.List[i].TranscodedSuffix = transcodeSuffix
}
return sub
}
Expand Down
14 changes: 10 additions & 4 deletions server/ctrlsubsonic/handlers_playlist.go
Expand Up @@ -13,7 +13,7 @@ import (
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
)

func playlistRender(c *Controller, playlist *db.Playlist) *spec.Playlist {
func playlistRender(c *Controller, playlist *db.Playlist, params params.Params) *spec.Playlist {
user := &db.User{}
c.DB.Where("id=?", playlist.UserID).Find(user)

Expand All @@ -29,6 +29,9 @@ func playlistRender(c *Controller, playlist *db.Playlist) *spec.Playlist {

trackIDs := playlist.GetItems()
resp.List = make([]*spec.TrackChild, len(trackIDs))

transcodeMIME, transcodeSuffix := streamGetTransPrefProfile(c.DB, user.ID, params.GetOr("c", ""))

for i, id := range trackIDs {
track := db.Track{}
err := c.DB.
Expand All @@ -44,12 +47,15 @@ func playlistRender(c *Controller, playlist *db.Playlist) *spec.Playlist {
continue
}
resp.List[i] = spec.NewTCTrackByFolder(&track, track.Album)
resp.List[i].TranscodedContentType = transcodeMIME
resp.List[i].TranscodedSuffix = transcodeSuffix
resp.Duration += track.Length
}
return resp
}

func (c *Controller) ServeGetPlaylists(r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
user := r.Context().Value(CtxUser).(*db.User)
var playlists []*db.Playlist
c.DB.Where("user_id=?", user.ID).Or("is_public=?", true).Find(&playlists)
Expand All @@ -58,7 +64,7 @@ func (c *Controller) ServeGetPlaylists(r *http.Request) *spec.Response {
List: make([]*spec.Playlist, len(playlists)),
}
for i, playlist := range playlists {
sub.Playlists.List[i] = playlistRender(c, playlist)
sub.Playlists.List[i] = playlistRender(c, playlist, params)
}
return sub
}
Expand All @@ -78,7 +84,7 @@ func (c *Controller) ServeGetPlaylist(r *http.Request) *spec.Response {
return spec.NewError(70, "playlist with id `%d` not found", playlistID)
}
sub := spec.NewResponse()
sub.Playlist = playlistRender(c, &playlist)
sub.Playlist = playlistRender(c, &playlist, params)
return sub
}

Expand Down Expand Up @@ -114,7 +120,7 @@ func (c *Controller) ServeCreatePlaylist(r *http.Request) *spec.Response {
c.DB.Save(playlist)

sub := spec.NewResponse()
sub.Playlist = playlistRender(c, &playlist)
sub.Playlist = playlistRender(c, &playlist, params)
return sub
}

Expand Down
12 changes: 12 additions & 0 deletions server/ctrlsubsonic/handlers_raw.go
Expand Up @@ -43,6 +43,18 @@ func streamGetTransPref(dbc *db.DB, userID int, client string) (*db.TranscodePre
return &pref, nil
}

func streamGetTransPrefProfile(dbc *db.DB, userID int, client string) (mime string, suffix string) {
pref, _ := streamGetTransPref(dbc, userID, client)
if pref == nil {
return "", ""
}
profile, ok := transcode.UserProfiles[pref.Profile]
if !ok {
return "", ""
}
return profile.MIME(), profile.Suffix()
}

var errUnknownMediaType = fmt.Errorf("media type is unknown")

// TODO: there is a mismatch between abs paths for podcasts and music. if they were the same, db.AudioFile
Expand Down
48 changes: 26 additions & 22 deletions server/ctrlsubsonic/spec/spec.go
Expand Up @@ -8,6 +8,8 @@ import (
"go.senan.xyz/gonic/server/ctrlsubsonic/specid"
)

// https://web.archive.org/web/20220707025402/https://www.subsonic.org/pages/api.jsp

const (
apiVersion = "1.15.0"
xmlns = "http://subsonic.org/restapi"
Expand Down Expand Up @@ -135,28 +137,30 @@ type TracksByGenre struct {
}

type TrackChild struct {
ID *specid.ID `xml:"id,attr,omitempty" json:"id,omitempty"`
Album string `xml:"album,attr,omitempty" json:"album,omitempty"`
AlbumID *specid.ID `xml:"albumId,attr,omitempty" json:"albumId,omitempty"`
Artist string `xml:"artist,attr,omitempty" json:"artist,omitempty"`
ArtistID *specid.ID `xml:"artistId,attr,omitempty" json:"artistId,omitempty"`
Bitrate int `xml:"bitRate,attr,omitempty" json:"bitRate,omitempty"`
ContentType string `xml:"contentType,attr,omitempty" json:"contentType,omitempty"`
CoverID *specid.ID `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
CreatedAt time.Time `xml:"created,attr,omitempty" json:"created,omitempty"`
Duration int `xml:"duration,attr,omitempty" json:"duration,omitempty"`
Genre string `xml:"genre,attr,omitempty" json:"genre,omitempty"`
IsDir bool `xml:"isDir,attr" json:"isDir"`
IsVideo bool `xml:"isVideo,attr" json:"isVideo"`
ParentID *specid.ID `xml:"parent,attr,omitempty" json:"parent,omitempty"`
Path string `xml:"path,attr,omitempty" json:"path,omitempty"`
Size int `xml:"size,attr,omitempty" json:"size,omitempty"`
Suffix string `xml:"suffix,attr,omitempty" json:"suffix,omitempty"`
Title string `xml:"title,attr" json:"title"`
TrackNumber int `xml:"track,attr,omitempty" json:"track,omitempty"`
DiscNumber int `xml:"discNumber,attr,omitempty" json:"discNumber,omitempty"`
Type string `xml:"type,attr,omitempty" json:"type,omitempty"`
Year int `xml:"year,attr,omitempty" json:"year,omitempty"`
ID *specid.ID `xml:"id,attr,omitempty" json:"id,omitempty"`
Album string `xml:"album,attr,omitempty" json:"album,omitempty"`
AlbumID *specid.ID `xml:"albumId,attr,omitempty" json:"albumId,omitempty"`
Artist string `xml:"artist,attr,omitempty" json:"artist,omitempty"`
ArtistID *specid.ID `xml:"artistId,attr,omitempty" json:"artistId,omitempty"`
Bitrate int `xml:"bitRate,attr,omitempty" json:"bitRate,omitempty"`
ContentType string `xml:"contentType,attr,omitempty" json:"contentType,omitempty"`
TranscodedContentType string `xml:"transcodedContentType,attr,omitempty" json:"transcodedContentType,omitempty"`
CoverID *specid.ID `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
CreatedAt time.Time `xml:"created,attr,omitempty" json:"created,omitempty"`
Duration int `xml:"duration,attr,omitempty" json:"duration,omitempty"`
Genre string `xml:"genre,attr,omitempty" json:"genre,omitempty"`
IsDir bool `xml:"isDir,attr" json:"isDir"`
IsVideo bool `xml:"isVideo,attr" json:"isVideo"`
ParentID *specid.ID `xml:"parent,attr,omitempty" json:"parent,omitempty"`
Path string `xml:"path,attr,omitempty" json:"path,omitempty"`
Size int `xml:"size,attr,omitempty" json:"size,omitempty"`
Suffix string `xml:"suffix,attr,omitempty" json:"suffix,omitempty"`
TranscodedSuffix string `xml:"transcodedSuffix,attr,omitempty" json:"transcodedSuffix,omitempty"`
Title string `xml:"title,attr" json:"title"`
TrackNumber int `xml:"track,attr,omitempty" json:"track,omitempty"`
DiscNumber int `xml:"discNumber,attr,omitempty" json:"discNumber,omitempty"`
Type string `xml:"type,attr,omitempty" json:"type,omitempty"`
Year int `xml:"year,attr,omitempty" json:"year,omitempty"`
// star / rating
Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"`
UserRating int `xml:"userRating,attr,omitempty" json:"userRating,omitempty"`
Expand Down

0 comments on commit 6e6404a

Please sign in to comment.