Documentation
¶
Overview ¶
Package spotify wraps the zmb3/spotify Web API client with the higher-level operations tuify needs: playlist and library fetches, player state polling, playback control, device selection, and transfer-on-reconnect behavior.
Client is the operational entry point; construct it with New passing an *sp.Client and *http.Client from the auth package. Both clients must share the same auth-wrapped transport so token refresh and the rate-limit gate installed by New cover SDK and raw HTTP paths alike. Client is safe for concurrent use — the underlying zmb3 client and http.Client are goroutine-safe, and the atomic DeviceOverridden flag coordinates manual-switch awareness between the UI and the librespot reconnect handler.
Errors: non-2xx responses surface as *APIError (carrying status and truncated body). When Spotify rate-limits the client, a shared cooldown is armed so subsequent calls short-circuit before hitting the network; callers polling on a timer should consult RateLimitWait to extend their interval past the deadline. Consecutive 429s escalate the cooldown exponentially (up to one hour) so a persistent throttle backs off instead of retrying at a fixed interval; the streak resets on the first non-429 response.
Index ¶
- type APIError
- type Album
- type Artist
- type Client
- func (c *Client) FetchUserID(ctx context.Context) error
- func (c *Client) FindDevice(ctx context.Context, activeOnly bool) (id string, active bool, preferred bool, err error)
- func (c *Client) GetAlbumTracks(ctx context.Context, albumID string, offset, limit int) ([]Track, bool, error)
- func (c *Client) GetArtistAlbums(ctx context.Context, artistID string, offset, limit int) ([]Album, bool, error)
- func (c *Client) GetDevices(ctx context.Context) ([]Device, error)
- func (c *Client) GetPlayerState(ctx context.Context) (*PlayerState, error)
- func (c *Client) GetPlaylistTracks(ctx context.Context, id string, offset, limit int) ([]Track, bool, error)
- func (c *Client) GetPlaylists(ctx context.Context, offset, limit int) (playlists []Playlist, rawCount int, more bool, err error)
- func (c *Client) GetSavedShows(ctx context.Context, offset, limit int) ([]Show, bool, error)
- func (c *Client) GetShowEpisodes(ctx context.Context, showID string, offset, limit int) ([]Episode, bool, error)
- func (c *Client) IsRateLimited() bool
- func (c *Client) Next(ctx context.Context, deviceID string) error
- func (c *Client) Pause(ctx context.Context, deviceID string) error
- func (c *Client) Play(ctx context.Context, itemURI, contextURI, deviceID string) error
- func (c *Client) PlayQueue(ctx context.Context, uris []string, deviceID string) error
- func (c *Client) Previous(ctx context.Context, deviceID string) error
- func (c *Client) RateLimitWait() time.Duration
- func (c *Client) Resume(ctx context.Context, deviceID string) error
- func (c *Client) SearchAlbums(ctx context.Context, query string, offset, limit int) ([]Album, bool, error)
- func (c *Client) SearchArtists(ctx context.Context, query string, offset, limit int) ([]Artist, bool, error)
- func (c *Client) SearchEpisodes(ctx context.Context, query string, offset, limit int) ([]Episode, bool, error)
- func (c *Client) SearchShows(ctx context.Context, query string, offset, limit int) ([]Show, bool, error)
- func (c *Client) SearchTracks(ctx context.Context, query string, offset, limit int) ([]Track, bool, error)
- func (c *Client) Seek(ctx context.Context, positionMs int, deviceID string) error
- func (c *Client) Shuffle(ctx context.Context, state bool, deviceID string) error
- func (c *Client) Stop(ctx context.Context, deviceID string) error
- func (c *Client) TransferPlayback(ctx context.Context, deviceID string, play bool) error
- type Device
- type Episode
- type PlayerState
- type Playlist
- type RateLimitedError
- type Show
- type Track
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIError ¶ added in v0.3.0
APIError is returned by doWithRetry for non-2xx responses. It carries the status code and (truncated) response body so callers can distinguish error shapes (e.g. StatusNoContent for "no active playback") without re-parsing.
type Album ¶
type Album struct {
ID string
URI string
Name string
Artist string // primary artist
ReleaseDate string // YYYY, YYYY-MM, or YYYY-MM-DD depending on precision
TrackCount int
}
Album is a Spotify album or single.
type Client ¶
type Client struct {
PreferredDevice string // if set, FindDevice prefers this device name
// DeviceOverridden is set when the user manually switches playback to
// another device in Spotify. Checked by the librespot OnReconnect
// callback to avoid stealing playback back.
DeviceOverridden atomic.Bool
// contains filtered or unexported fields
}
Client wraps the zmb3 Spotify SDK with the higher-level operations tuify needs (playlists, search, player control, device selection). Safe for concurrent use by multiple goroutines.
Split across files by responsibility: this file holds the Client type plus the shared HTTP/JSON plumbing; playback.go, devices.go, library.go, and search.go hold the operation methods; types.go holds the domain value types and JSON raw shapes.
func New ¶
New constructs a Client. spClient handles SDK-level calls (playback control, devices); httpClient is used for raw REST calls that the SDK doesn't expose and must be the same auth-wrapped client so both paths share token refresh.
New installs a shared rate-limit gate on httpClient.Transport so SDK and raw paths honor the same cooldown when Spotify returns 429.
func (*Client) FetchUserID ¶
FetchUserID caches the authenticated user's ID on the client so later calls (e.g. GetPlaylists) can filter by ownership without an extra round trip. Safe to skip; dependent methods degrade gracefully.
func (*Client) FindDevice ¶
func (c *Client) FindDevice(ctx context.Context, activeOnly bool) (id string, active bool, preferred bool, err error)
FindDevice returns the best device ID, whether it is currently active, and whether the returned device is the configured preferred device. When activeOnly is true, only a device currently marked active by Spotify is returned; an error is returned if no device is active.
func (*Client) GetAlbumTracks ¶
func (c *Client) GetAlbumTracks(ctx context.Context, albumID string, offset, limit int) ([]Track, bool, error)
GetAlbumTracks returns tracks from the given album in track order.
func (*Client) GetArtistAlbums ¶
func (c *Client) GetArtistAlbums(ctx context.Context, artistID string, offset, limit int) ([]Album, bool, error)
GetArtistAlbums returns albums and singles by the given artist. Compilation and appears-on releases are excluded.
func (*Client) GetDevices ¶ added in v0.2.0
GetDevices returns all available Spotify Connect devices.
func (*Client) GetPlayerState ¶
func (c *Client) GetPlayerState(ctx context.Context) (*PlayerState, error)
GetPlayerState fetches the user's current playback state. Returns (nil, nil) when nothing is playing (HTTP 204) or when the active item is not a track/episode — callers should treat a nil *PlayerState as "no playback" rather than an error.
func (*Client) GetPlaylistTracks ¶
func (c *Client) GetPlaylistTracks(ctx context.Context, id string, offset, limit int) ([]Track, bool, error)
GetPlaylistTracks returns tracks from a playlist, starting at offset. The bool indicates whether more pages are available.
func (*Client) GetPlaylists ¶
func (c *Client) GetPlaylists(ctx context.Context, offset, limit int) (playlists []Playlist, rawCount int, more bool, err error)
GetPlaylists returns the user's own playlists. The second return value (rawCount) is the unfiltered API page size, which callers must use to advance the offset (since it includes items filtered out by owner matching).
func (*Client) GetSavedShows ¶
GetSavedShows returns the user's followed podcast shows.
func (*Client) GetShowEpisodes ¶
func (c *Client) GetShowEpisodes(ctx context.Context, showID string, offset, limit int) ([]Episode, bool, error)
GetShowEpisodes returns episodes for a given podcast show.
func (*Client) IsRateLimited ¶ added in v0.5.0
IsRateLimited reports whether the client is currently in a rate-limit cooldown. Equivalent to RateLimitWait() > 0; provided for readability at call sites that don't need the duration.
func (*Client) Play ¶
Play starts playback of itemURI. If contextURI is set (playlist/album/ show), the item plays in the context of that container so Next/Previous navigate within it; otherwise only the single item is queued.
func (*Client) PlayQueue ¶
PlayQueue starts playback of an explicit list of track URIs in order. The first URI becomes the current item. Use Play when the items belong to a Spotify-side context (playlist/album) you want preserved.
func (*Client) Previous ¶
Previous skips to the previous item, or restarts the current one if playback has advanced past the start (Spotify's native behavior).
func (*Client) RateLimitWait ¶ added in v0.5.0
RateLimitWait reports the remaining cooldown imposed by Spotify, or zero when not rate limited. Callers (e.g. the now-playing poll loop) use this to skip API calls and reschedule themselves past the cooldown instead of hammering the gate.
func (*Client) SearchAlbums ¶
func (c *Client) SearchAlbums(ctx context.Context, query string, offset, limit int) ([]Album, bool, error)
SearchAlbums runs an album search against the Spotify catalog.
func (*Client) SearchArtists ¶
func (c *Client) SearchArtists(ctx context.Context, query string, offset, limit int) ([]Artist, bool, error)
SearchArtists runs an artist search against the Spotify catalog.
func (*Client) SearchEpisodes ¶
func (c *Client) SearchEpisodes(ctx context.Context, query string, offset, limit int) ([]Episode, bool, error)
SearchEpisodes runs a podcast-episode search against the Spotify catalog.
func (*Client) SearchShows ¶
func (c *Client) SearchShows(ctx context.Context, query string, offset, limit int) ([]Show, bool, error)
SearchShows runs a podcast-show search against the Spotify catalog.
func (*Client) SearchTracks ¶
func (c *Client) SearchTracks(ctx context.Context, query string, offset, limit int) ([]Track, bool, error)
SearchTracks runs a track search against the Spotify catalog.
func (*Client) Stop ¶
Stop pauses and seeks to the start of the current track. Spotify has no true "stop" — this is the closest approximation.
func (*Client) TransferPlayback ¶
TransferPlayback moves active playback to the given device. If play is true, playback resumes on the target; otherwise the target is primed but left in its current paused/playing state.
type Device ¶ added in v0.2.0
type Device struct {
ID string
Name string
Type string // "Computer", "Smartphone", "Speaker", etc.
Active bool
Volume int // 0–100
}
Device is a Spotify Connect playback target.
type PlayerState ¶
type PlayerState struct {
Playing bool
Shuffling bool
TrackName string
ArtistName string // podcast shows use the show name here
TrackURI string
ContextURI string // playlist/album/show URI the track is being played from
ImageURL string // mid-size cover image URL
ProgressMs int // playback position in milliseconds
DurationMs int // total track length in milliseconds
DeviceName string
VolumePercent int // 0–100; active device's volume (100 if device reports none)
}
PlayerState is a snapshot of the user's current playback. TrackURI is empty when no item is playing; callers typically treat a nil *PlayerState from GetPlayerState as "nothing is playing".
type RateLimitedError ¶ added in v0.5.0
RateLimitedError is returned by the http transport when a request is short-circuited because the client is in a rate-limit cooldown window. The current call returns immediately without hitting the network.
func (*RateLimitedError) Error ¶ added in v0.5.0
func (e *RateLimitedError) Error() string