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 }