Files
gspt/spt/get.go
2024-06-30 20:16:26 +05:30

311 lines
6.8 KiB
Go

package spt
import (
"context"
"errors"
"github.com/zmb3/spotify/v2"
)
var (
topTracksLimit = 15
albumtypes = []spotify.AlbumType{
spotify.AlbumTypeAlbum,
spotify.AlbumTypeSingle,
spotify.AlbumTypeAppearsOn,
spotify.AlbumTypeCompilation,
}
)
type Playlist struct {
SnapshotID string
ID spotify.ID
Tracks *[]spotify.PlaylistTrack
}
type Album struct {
spotify.FullAlbum
Tracks *[]spotify.SimpleTrack
}
type SavedAlbums []spotify.SavedAlbum
type FollowedArtists []spotify.FullArtist
type UserPlaylists []spotify.SimplePlaylist
type LikedSongs []spotify.SavedTrack
type Playable interface {
Type() string
Uri()
}
var (
ctx = context.Background()
client *spotify.Client
playlistCache map[spotify.ID]*Playlist = make(map[spotify.ID]*Playlist)
albumCache map[spotify.ID]*Album = make(map[spotify.ID]*Album)
PageContinue = errors.New("CONTINUE")
)
func GetPlaylist(playlistId spotify.ID) (*Playlist, chan error) {
c := make(chan error)
if fp, err := client.GetPlaylist(ctx, playlistId); err != nil {
go func() { c <- err }()
return nil, c
} else {
if _, ok := playlistCache[fp.ID]; !ok || playlistCache[fp.ID].SnapshotID != fp.SnapshotID {
tracks := &[]spotify.PlaylistTrack{}
addTracks := func() {
*tracks = append(*tracks, fp.Tracks.Tracks...)
}
addTracks()
go func() {
for page := 1; ; page++ {
if perr := client.NextPage(ctx, &fp.Tracks); perr == spotify.ErrNoMorePages {
c <- nil
break
} else if perr != nil {
c <- perr
return
}
addTracks()
}
}()
p := &Playlist{
fp.SnapshotID,
fp.ID,
tracks,
}
playlistCache[fp.ID] = p
return p, c
}
go func() { c <- nil }()
return playlistCache[fp.ID], c
}
}
func GetAlbum(albumID spotify.ID) (*Album, chan error) {
c := make(chan error)
if _, ok := albumCache[albumID]; !ok {
fa, err := client.GetAlbum(ctx, albumID)
if err != nil {
go func() { c <- err }()
return nil, c
}
tracks := &[]spotify.SimpleTrack{}
addTracks := func() {
*tracks = append(*tracks, fa.Tracks.Tracks...)
}
addTracks()
go func() {
for page := 1; ; page++ {
if perr := client.NextPage(ctx, &fa.Tracks); perr == spotify.ErrNoMorePages {
c <- nil
break
} else if perr != nil {
c <- perr
return
}
addTracks()
}
}()
p := &Album{
*fa,
tracks,
}
albumCache[fa.ID] = p
return p, c
} else {
go func() { c <- nil }()
return albumCache[albumID], c
}
}
func CurrentUserSavedAlbums() (*SavedAlbums, chan error) {
c := make(chan error)
_a := make(SavedAlbums, 0)
albums := &_a
if sp, err := client.CurrentUsersAlbums(ctx); err != nil {
go func() { c <- err }()
return nil, c
} else {
addAlbums := func() {
_a = append(_a, sp.Albums...)
}
addAlbums()
go func() {
for page := 1; ; page++ {
if perr := client.NextPage(ctx, sp); perr == spotify.ErrNoMorePages {
c <- nil
break
} else if perr != nil {
c <- perr
return
}
addAlbums()
}
}()
return albums, c
}
}
func CurrentUserPlaylists() (*UserPlaylists, chan error) {
c := make(chan error)
_p := make(UserPlaylists, 0)
playlists := &_p
if spp, err := client.CurrentUsersPlaylists(ctx); err != nil {
go func() { c <- err }()
return nil, c
} else {
addPlaylists := func() {
_p = append(_p, spp.Playlists...)
}
addPlaylists()
go func() {
for page := 1; ; page++ {
if perr := client.NextPage(ctx, spp); perr == spotify.ErrNoMorePages {
c <- nil
break
} else if perr != nil {
c <- perr
return
}
addPlaylists()
}
}()
return playlists, c
}
}
func CurrentUserSavedTracks() (*LikedSongs, chan error) {
c := make(chan error)
_p := make(LikedSongs, 0)
playlists := &_p
if ls, err := client.CurrentUsersTracks(ctx); err != nil {
go func() { c <- err }()
return nil, c
} else {
addTracks := func() {
_p = append(_p, ls.Tracks...)
}
addTracks()
go func() {
for page := 1; ; page++ {
if perr := client.NextPage(ctx, ls); perr == spotify.ErrNoMorePages {
c <- nil
break
} else if perr != nil {
c <- perr
return
}
addTracks()
}
}()
return playlists, c
}
}
func CurrentUserFollowedArtists() (*FollowedArtists, chan error) {
c := make(chan error)
// TODO: Check if this is the proper implementation
_a := make(FollowedArtists, 0)
artists := &_a
if ar, err := client.CurrentUsersFollowedArtists(ctx); err != nil {
go func() { c <- err }()
return nil, c
} else {
ap := spotify.ID("")
addArtists := func() {
_a = append(_a, ar.Artists...)
ap = _a[len(_a)-1].ID
}
addArtists()
go func() {
for {
if len(ar.Artists) == 0 {
c <- nil
}
if ar, err = client.CurrentUsersFollowedArtists(ctx, spotify.After(string(ap))); err != nil {
if err == spotify.ErrNoMorePages {
c <- nil
break
} else {
c <- err
break
}
} else {
addArtists()
}
}
}()
return artists, c
}
}
func RecentlyPlayed() ([]spotify.RecentlyPlayedItem, error) {
return client.PlayerRecentlyPlayedOpt(ctx, &spotify.RecentlyPlayedOptions{Limit: 50})
}
func GetPlayerState() (*spotify.PlayerState, error) {
return client.PlayerState(ctx)
}
func GetTopTracks() ([]spotify.FullTrack, error) {
c, err := client.CurrentUsersTopTracks(ctx, spotify.Limit(topTracksLimit))
if c != nil {
return c.Tracks, err
} else {
return []spotify.FullTrack{}, errors.New("No Top Tracks Found!")
}
}
func GetTopArtists() ([]spotify.FullArtist, error) {
c, err := client.CurrentUsersTopArtists(ctx, spotify.Limit(topTracksLimit))
if c != nil {
return c.Artists, err
} else {
return []spotify.FullArtist{}, errors.New("No Top Artists Found!")
}
}
func GetArtistTopTracks(artistID spotify.ID) ([]spotify.FullTrack, error) {
c, err := client.CurrentUser(ctx)
if err != nil {
return []spotify.FullTrack{}, err
}
return client.GetArtistsTopTracks(ctx, artistID, c.Country)
}
func GetArtistAlbums(artistID spotify.ID) ([]spotify.SimpleAlbum, error) {
c, err := client.GetArtistAlbums(ctx, artistID, albumtypes)
if err != nil {
return []spotify.SimpleAlbum{}, err
}
return c.Albums, nil
}
func Search(s string) (*spotify.SearchResult, error) {
return client.Search(ctx, s,
spotify.SearchTypePlaylist|
spotify.SearchTypeAlbum|
spotify.SearchTypeTrack|
spotify.SearchTypeArtist)
}
func UserDevices() ([]spotify.PlayerDevice, error) {
return client.PlayerDevices(ctx)
}
func TransferPlayback(deviceId spotify.ID) error {
s, err := GetPlayerState()
if err != nil {
return errors.New("Unable to get Current Player State!")
}
err = client.PauseOpt(ctx, &spotify.PlayOptions{DeviceID: &s.Device.ID})
return client.TransferPlayback(ctx, deviceId, true)
}
func GetFullPlaylist(id spotify.ID) (*spotify.FullPlaylist, error) {
return client.GetPlaylist(ctx, id)
}