284 lines
7.5 KiB
Go
284 lines
7.5 KiB
Go
package subsonic
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
|
)
|
|
|
|
func init() {
|
|
register("getAlbumList", handleGetAlbumList)
|
|
register("getAlbumList2", handleGetAlbumList2)
|
|
register("getRandomSongs", handleGetRandomSongs)
|
|
register("getSongsByGenre", handleGetSongsByGenre)
|
|
register("getNowPlaying", handleGetNowPlaying)
|
|
register("getStarred", handleGetStarred)
|
|
register("getStarred2", handleGetStarred2)
|
|
}
|
|
|
|
// resolveAlbumListType fetches albums for one of the official
|
|
// getAlbumList/getAlbumList2 "type" values. Every branch is a real
|
|
// query — nothing here is a fabricated or hardcoded result.
|
|
func resolveAlbumListType(rc *Context) ([]*database.Album, *apiError) {
|
|
db := rc.Server.DB
|
|
listType, aerr := rc.Params.Required("type")
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
size := rc.Params.Int("size", 10)
|
|
if size > 500 {
|
|
size = 500
|
|
}
|
|
offset := rc.Params.Int("offset", 0)
|
|
|
|
var albums []*database.Album
|
|
var err error
|
|
switch listType {
|
|
case "random":
|
|
albums, err = database.RandomAlbums(db, size)
|
|
case "newest":
|
|
albums, err = database.RecentlyAddedAlbums(db, size, offset)
|
|
case "highest":
|
|
albums, err = database.AlbumsByHighestRating(db, size, offset)
|
|
case "frequent":
|
|
albums, err = database.AlbumsByPlayCount(db, size, offset)
|
|
case "recent":
|
|
albums, err = database.AlbumsByRecentlyPlayed(db, rc.User.ID, size, offset)
|
|
case "alphabeticalByName":
|
|
albums, err = database.AlbumsAlphabetical(db, false, size, offset)
|
|
case "alphabeticalByArtist":
|
|
albums, err = database.AlbumsAlphabetical(db, true, size, offset)
|
|
case "starred":
|
|
albums, err = starredAlbums(db, rc.User.ID, size, offset)
|
|
case "byYear":
|
|
fromYear, ferr := rc.Params.RequiredInt("fromYear")
|
|
if ferr != nil {
|
|
return nil, ferr
|
|
}
|
|
toYear, terr := rc.Params.RequiredInt("toYear")
|
|
if terr != nil {
|
|
return nil, terr
|
|
}
|
|
albums, err = database.AlbumsByYearRange(db, fromYear, toYear, size, offset)
|
|
case "byGenre":
|
|
genre, gerr := rc.Params.Required("genre")
|
|
if gerr != nil {
|
|
return nil, gerr
|
|
}
|
|
albums, err = database.AlbumsByGenre(db, genre, size, offset)
|
|
default:
|
|
return nil, newError(ErrGeneric, "Unknown album list type: "+listType)
|
|
}
|
|
if err != nil {
|
|
return nil, newError(ErrGeneric, err.Error())
|
|
}
|
|
return albums, nil
|
|
}
|
|
|
|
func starredAlbums(db *sql.DB, userID string, limit, offset int) ([]*database.Album, error) {
|
|
ids, err := database.ListStarredIDs(db, userID, "album")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if offset >= len(ids) {
|
|
return nil, nil
|
|
}
|
|
end := offset + limit
|
|
if end > len(ids) {
|
|
end = len(ids)
|
|
}
|
|
var out []*database.Album
|
|
for _, id := range ids[offset:end] {
|
|
if a, err := database.GetAlbum(db, id); err == nil {
|
|
out = append(out, a)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func handleGetAlbumList(rc *Context) *apiError {
|
|
albums, aerr := resolveAlbumListType(rc)
|
|
if aerr != nil {
|
|
return aerr
|
|
}
|
|
out := &AlbumList{}
|
|
for _, a := range albums {
|
|
out.Album = append(out.Album, childFromAlbum(rc.Server.DB, a, rc.User.ID))
|
|
}
|
|
rc.Response = newResponse()
|
|
rc.Response.AlbumList = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetAlbumList2(rc *Context) *apiError {
|
|
albums, aerr := resolveAlbumListType(rc)
|
|
if aerr != nil {
|
|
return aerr
|
|
}
|
|
out := &AlbumList2{}
|
|
for _, a := range albums {
|
|
out.Album = append(out.Album, albumToID3(rc.Server.DB, a, rc.User.ID))
|
|
}
|
|
rc.Response = newResponse()
|
|
rc.Response.AlbumList2 = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetRandomSongs(rc *Context) *apiError {
|
|
db := rc.Server.DB
|
|
size := rc.Params.Int("size", 10)
|
|
if size > 500 {
|
|
size = 500
|
|
}
|
|
genre := rc.Params.Get("genre")
|
|
fromYear := rc.Params.Int("fromYear", 0)
|
|
toYear := rc.Params.Int("toYear", 0)
|
|
|
|
ids, err := database.RandomSongIDs(db, size, genre, fromYear, toYear)
|
|
if err != nil {
|
|
return newError(ErrGeneric, err.Error())
|
|
}
|
|
out := &Songs{}
|
|
for _, id := range ids {
|
|
song, serr := database.GetSong(db, id)
|
|
if serr != nil {
|
|
continue
|
|
}
|
|
mf, merr := database.GetMediaFile(db, song.MediaFileID)
|
|
if merr != nil {
|
|
continue
|
|
}
|
|
if canSee, cerr := UserCanSeeMediaFile(db, rc.User, mf); cerr != nil || !canSee {
|
|
continue
|
|
}
|
|
out.Song = append(out.Song, childFromSong(db, song, mf, albumOfSong(db, song), rc.User.ID))
|
|
}
|
|
rc.Response = newResponse()
|
|
rc.Response.RandomSongs = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetSongsByGenre(rc *Context) *apiError {
|
|
genre, aerr := rc.Params.Required("genre")
|
|
if aerr != nil {
|
|
return aerr
|
|
}
|
|
db := rc.Server.DB
|
|
count := rc.Params.Int("count", 10)
|
|
if count > 500 {
|
|
count = 500
|
|
}
|
|
offset := rc.Params.Int("offset", 0)
|
|
|
|
songs, err := database.SongsByGenre(db, genre, count, offset)
|
|
if err != nil {
|
|
return newError(ErrGeneric, err.Error())
|
|
}
|
|
out := &Songs{}
|
|
for _, s := range songs {
|
|
mf, merr := database.GetMediaFile(db, s.MediaFileID)
|
|
if merr != nil {
|
|
continue
|
|
}
|
|
if canSee, cerr := UserCanSeeMediaFile(db, rc.User, mf); cerr != nil || !canSee {
|
|
continue
|
|
}
|
|
out.Song = append(out.Song, childFromSong(db, s, mf, albumOfSong(db, s), rc.User.ID))
|
|
}
|
|
rc.Response = newResponse()
|
|
rc.Response.SongsByGenre = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetNowPlaying(rc *Context) *apiError {
|
|
db := rc.Server.DB
|
|
entries, err := database.ListNowPlaying(db)
|
|
if err != nil {
|
|
return newError(ErrGeneric, err.Error())
|
|
}
|
|
out := &NowPlaying{}
|
|
for _, e := range entries {
|
|
song, serr := database.GetSong(db, e.SongID)
|
|
if serr != nil {
|
|
continue
|
|
}
|
|
mf, merr := database.GetMediaFile(db, song.MediaFileID)
|
|
if merr != nil {
|
|
continue
|
|
}
|
|
c := childFromSong(db, song, mf, albumOfSong(db, song), "")
|
|
minutesAgo := int(secondsSince(e.StartedAt) / 60)
|
|
out.Entry = append(out.Entry, NowPlayingEntry{
|
|
Child: c,
|
|
Username: e.Username,
|
|
MinutesAgo: minutesAgo,
|
|
PlayerID: 1,
|
|
})
|
|
}
|
|
rc.Response = newResponse()
|
|
rc.Response.NowPlaying = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetStarred(rc *Context) *apiError {
|
|
db := rc.Server.DB
|
|
userID := rc.User.ID
|
|
out := &Starred{}
|
|
|
|
artistIDs, _ := database.ListStarredIDs(db, userID, "artist")
|
|
for _, id := range artistIDs {
|
|
if a, err := database.GetArtist(db, id); err == nil {
|
|
out.Artist = append(out.Artist, Artist{ID: a.ID, Name: a.Name})
|
|
}
|
|
}
|
|
albumIDs, _ := database.ListStarredIDs(db, userID, "album")
|
|
for _, id := range albumIDs {
|
|
if a, err := database.GetAlbum(db, id); err == nil {
|
|
out.Album = append(out.Album, childFromAlbum(db, a, userID))
|
|
}
|
|
}
|
|
songIDs, _ := database.ListStarredIDs(db, userID, "song")
|
|
for _, id := range songIDs {
|
|
if s, err := database.GetSong(db, id); err == nil {
|
|
if mf, merr := database.GetMediaFile(db, s.MediaFileID); merr == nil {
|
|
out.Song = append(out.Song, childFromSong(db, s, mf, albumOfSong(db, s), userID))
|
|
}
|
|
}
|
|
}
|
|
|
|
rc.Response = newResponse()
|
|
rc.Response.Starred = out
|
|
return nil
|
|
}
|
|
|
|
func handleGetStarred2(rc *Context) *apiError {
|
|
db := rc.Server.DB
|
|
userID := rc.User.ID
|
|
out := &Starred2{}
|
|
|
|
artistIDs, _ := database.ListStarredIDs(db, userID, "artist")
|
|
for _, id := range artistIDs {
|
|
if a, err := database.GetArtist(db, id); err == nil {
|
|
out.Artist = append(out.Artist, artistToID3(db, a, userID))
|
|
}
|
|
}
|
|
albumIDs, _ := database.ListStarredIDs(db, userID, "album")
|
|
for _, id := range albumIDs {
|
|
if a, err := database.GetAlbum(db, id); err == nil {
|
|
out.Album = append(out.Album, albumToID3(db, a, userID))
|
|
}
|
|
}
|
|
songIDs, _ := database.ListStarredIDs(db, userID, "song")
|
|
for _, id := range songIDs {
|
|
if s, err := database.GetSong(db, id); err == nil {
|
|
if mf, merr := database.GetMediaFile(db, s.MediaFileID); merr == nil {
|
|
out.Song = append(out.Song, childFromSong(db, s, mf, albumOfSong(db, s), userID))
|
|
}
|
|
}
|
|
}
|
|
|
|
rc.Response = newResponse()
|
|
rc.Response.Starred2 = out
|
|
return nil
|
|
}
|