mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
221 lines
7.2 KiB
Go
221 lines
7.2 KiB
Go
package spotify
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"net/url"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// SimpleAlbum contains basic data about an album.
|
||
type SimpleAlbum struct {
|
||
// The name of the album.
|
||
Name string `json:"name"`
|
||
// A slice of SimpleArtists
|
||
Artists []SimpleArtist `json:"artists"`
|
||
// The field is present when getting an artist’s
|
||
// albums. Possible values are “album”, “single”,
|
||
// “compilation”, “appears_on”. Compare to album_type
|
||
// this field represents relationship between the artist
|
||
// and the album.
|
||
AlbumGroup string `json:"album_group"`
|
||
// The type of the album: one of "album",
|
||
// "single", or "compilation".
|
||
AlbumType string `json:"album_type"`
|
||
// The SpotifyID for the album.
|
||
ID ID `json:"id"`
|
||
// The SpotifyURI for the album.
|
||
URI URI `json:"uri"`
|
||
// The markets in which the album is available,
|
||
// identified using ISO 3166-1 alpha-2 country
|
||
// codes. Note that al album is considered
|
||
// available in a market when at least 1 of its
|
||
// tracks is available in that market.
|
||
AvailableMarkets []string `json:"available_markets"`
|
||
// A link to the Web API enpoint providing full
|
||
// details of the album.
|
||
Endpoint string `json:"href"`
|
||
// The cover art for the album in various sizes,
|
||
// widest first.
|
||
Images []Image `json:"images"`
|
||
// Known external URLs for this album.
|
||
ExternalURLs map[string]string `json:"external_urls"`
|
||
// The date the album was first released. For example, "1981-12-15".
|
||
// Depending on the ReleaseDatePrecision, it might be shown as
|
||
// "1981" or "1981-12". You can use ReleaseDateTime to convert this
|
||
// to a time.Time value.
|
||
ReleaseDate string `json:"release_date"`
|
||
// The precision with which ReleaseDate value is known: "year", "month", or "day"
|
||
ReleaseDatePrecision string `json:"release_date_precision"`
|
||
}
|
||
|
||
// Copyright contains the copyright statement associated with an album.
|
||
type Copyright struct {
|
||
// The copyright text for the album.
|
||
Text string `json:"text"`
|
||
// The type of copyright.
|
||
Type string `json:"type"`
|
||
}
|
||
|
||
// FullAlbum provides extra album data in addition to the data provided by SimpleAlbum.
|
||
type FullAlbum struct {
|
||
SimpleAlbum
|
||
Artists []SimpleArtist `json:"artists"`
|
||
Copyrights []Copyright `json:"copyrights"`
|
||
Genres []string `json:"genres"`
|
||
// The popularity of the album, represented as an integer between 0 and 100,
|
||
// with 100 being the most popular. Popularity of an album is calculated
|
||
// from the popularify of the album's individual tracks.
|
||
Popularity int `json:"popularity"`
|
||
// The date the album was first released. For example, "1981-12-15".
|
||
// Depending on the ReleaseDatePrecision, it might be shown as
|
||
// "1981" or "1981-12". You can use ReleaseDateTime to convert this
|
||
// to a time.Time value.
|
||
ReleaseDate string `json:"release_date"`
|
||
// The precision with which ReleaseDate value is known: "year", "month", or "day"
|
||
ReleaseDatePrecision string `json:"release_date_precision"`
|
||
Tracks SimpleTrackPage `json:"tracks"`
|
||
ExternalIDs map[string]string `json:"external_ids"`
|
||
}
|
||
|
||
// SavedAlbum provides info about an album saved to an user's account.
|
||
type SavedAlbum struct {
|
||
// The date and time the track was saved, represented as an ISO
|
||
// 8601 UTC timestamp with a zero offset (YYYY-MM-DDTHH:MM:SSZ).
|
||
// You can use the TimestampLayout constant to convert this to
|
||
// a time.Time value.
|
||
AddedAt string `json:"added_at"`
|
||
FullAlbum `json:"album"`
|
||
}
|
||
|
||
// ReleaseDateTime converts the album's ReleaseDate to a time.TimeValue.
|
||
// All of the fields in the result may not be valid. For example, if
|
||
// f.ReleaseDatePrecision is "month", then only the month and year
|
||
// (but not the day) of the result are valid.
|
||
func (f *FullAlbum) ReleaseDateTime() time.Time {
|
||
if f.ReleaseDatePrecision == "day" {
|
||
result, _ := time.Parse(DateLayout, f.ReleaseDate)
|
||
return result
|
||
}
|
||
if f.ReleaseDatePrecision == "month" {
|
||
ym := strings.Split(f.ReleaseDate, "-")
|
||
year, _ := strconv.Atoi(ym[0])
|
||
month, _ := strconv.Atoi(ym[1])
|
||
return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
|
||
}
|
||
year, _ := strconv.Atoi(f.ReleaseDate)
|
||
return time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||
}
|
||
|
||
// GetAlbum gets Spotify catalog information for a single album, given its Spotify ID.
|
||
func (c *Client) GetAlbum(id ID) (*FullAlbum, error) {
|
||
spotifyURL := fmt.Sprintf("%salbums/%s", c.baseURL, id)
|
||
|
||
var a FullAlbum
|
||
|
||
err := c.get(spotifyURL, &a)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &a, nil
|
||
}
|
||
|
||
func toStringSlice(ids []ID) []string {
|
||
result := make([]string, len(ids))
|
||
for i, str := range ids {
|
||
result[i] = str.String()
|
||
}
|
||
return result
|
||
}
|
||
|
||
// GetAlbums gets Spotify Catalog information for multiple albums, given their
|
||
// Spotify IDs. It supports up to 20 IDs in a single call. Albums are returned
|
||
// in the order requested. If an album is not found, that position in the
|
||
// result slice will be nil.
|
||
func (c *Client) GetAlbums(ids ...ID) ([]*FullAlbum, error) {
|
||
if len(ids) > 20 {
|
||
return nil, errors.New("spotify: exceeded maximum number of albums")
|
||
}
|
||
spotifyURL := fmt.Sprintf("%salbums?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||
|
||
var a struct {
|
||
Albums []*FullAlbum `json:"albums"`
|
||
}
|
||
|
||
err := c.get(spotifyURL, &a)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return a.Albums, nil
|
||
}
|
||
|
||
// AlbumType represents the type of an album. It can be used to filter
|
||
// results when searching for albums.
|
||
type AlbumType int
|
||
|
||
// AlbumType values that can be used to filter which types of albums are
|
||
// searched for. These are flags that can be bitwise OR'd together
|
||
// to search for multiple types of albums simultaneously.
|
||
const (
|
||
AlbumTypeAlbum AlbumType = 1 << iota
|
||
AlbumTypeSingle = 1 << iota
|
||
AlbummTypeAppearsOn = 1 << iota
|
||
AlbumTypeCompilation = 1 << iota
|
||
)
|
||
|
||
func (at AlbumType) encode() string {
|
||
types := []string{}
|
||
if at&AlbumTypeAlbum != 0 {
|
||
types = append(types, "album")
|
||
}
|
||
if at&AlbumTypeSingle != 0 {
|
||
types = append(types, "single")
|
||
}
|
||
if at&AlbummTypeAppearsOn != 0 {
|
||
types = append(types, "appears_on")
|
||
}
|
||
if at&AlbumTypeCompilation != 0 {
|
||
types = append(types, "compilation")
|
||
}
|
||
return strings.Join(types, ",")
|
||
}
|
||
|
||
// GetAlbumTracks gets the tracks for a particular album.
|
||
// If you only care about the tracks, this call is more efficient
|
||
// than GetAlbum.
|
||
func (c *Client) GetAlbumTracks(id ID) (*SimpleTrackPage, error) {
|
||
return c.GetAlbumTracksOpt(id, -1, -1)
|
||
}
|
||
|
||
// GetAlbumTracksOpt behaves like GetAlbumTracks, with the exception that it
|
||
// allows you to specify extra parameters that limit the number of results returned.
|
||
// The maximum number of results to return is specified by limit.
|
||
// The offset argument can be used to specify the index of the first track to return.
|
||
// It can be used along with limit to reqeust the next set of results.
|
||
func (c *Client) GetAlbumTracksOpt(id ID, limit, offset int) (*SimpleTrackPage, error) {
|
||
spotifyURL := fmt.Sprintf("%salbums/%s/tracks", c.baseURL, id)
|
||
v := url.Values{}
|
||
if limit != -1 {
|
||
v.Set("limit", strconv.Itoa(limit))
|
||
}
|
||
if offset != -1 {
|
||
v.Set("offset", strconv.Itoa(offset))
|
||
}
|
||
optional := v.Encode()
|
||
if optional != "" {
|
||
spotifyURL = spotifyURL + "?" + optional
|
||
}
|
||
|
||
var result SimpleTrackPage
|
||
err := c.get(spotifyURL, &result)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &result, nil
|
||
}
|