spotify

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 13 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIError added in v0.3.0

type APIError struct {
	Status int
	Body   []byte
	URL    string
}

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.

func (*APIError) Error added in v0.3.0

func (e *APIError) Error() string

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 Artist

type Artist struct {
	ID     string
	URI    string
	Name   string
	Genres []string
}

Artist is a Spotify artist entity.

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

func New(spClient *sp.Client, httpClient *http.Client) *Client

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

func (c *Client) FetchUserID(ctx context.Context) error

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

func (c *Client) GetDevices(ctx context.Context) ([]Device, error)

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

func (c *Client) GetSavedShows(ctx context.Context, offset, limit int) ([]Show, bool, error)

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

func (c *Client) IsRateLimited() bool

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) Next

func (c *Client) Next(ctx context.Context, deviceID string) error

Next skips to the next item in the current playback context.

func (*Client) Pause

func (c *Client) Pause(ctx context.Context, deviceID string) error

Pause pauses playback on the specified device.

func (*Client) Play

func (c *Client) Play(ctx context.Context, itemURI, contextURI, deviceID string) error

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

func (c *Client) PlayQueue(ctx context.Context, uris []string, deviceID string) error

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

func (c *Client) Previous(ctx context.Context, deviceID string) error

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

func (c *Client) RateLimitWait() time.Duration

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) Resume

func (c *Client) Resume(ctx context.Context, deviceID string) error

Resume resumes paused playback on the specified device.

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) Seek

func (c *Client) Seek(ctx context.Context, positionMs int, deviceID string) error

Seek jumps to positionMs within the current track.

func (*Client) Shuffle

func (c *Client) Shuffle(ctx context.Context, state bool, deviceID string) error

Shuffle enables or disables shuffle mode on the specified device.

func (*Client) Stop

func (c *Client) Stop(ctx context.Context, deviceID string) error

Stop pauses and seeks to the start of the current track. Spotify has no true "stop" — this is the closest approximation.

func (*Client) TransferPlayback

func (c *Client) TransferPlayback(ctx context.Context, deviceID string, play bool) error

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 Episode

type Episode struct {
	ID          string
	URI         string
	Name        string
	ReleaseDate string
	Duration    time.Duration
}

Episode is a single podcast episode.

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 Playlist

type Playlist struct {
	ID         string
	Name       string
	OwnerName  string
	TrackCount int
}

Playlist is a user-owned Spotify playlist.

type RateLimitedError added in v0.5.0

type RateLimitedError struct {
	Until time.Time
}

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

type Show

type Show struct {
	ID            string
	URI           string
	Name          string
	TotalEpisodes int
}

Show is a podcast show.

type Track

type Track struct {
	ID       string
	URI      string
	Name     string
	Artist   string // first artist only; collaborations use the primary artist
	Album    string
	Duration time.Duration
}

Track is a single playable audio track.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL