go_librespot

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Nov 9, 2024 License: GPL-3.0 Imports: 12 Imported by: 1

README

go-librespot

GitHub release GitHub branch check runs Go Report Card GitHub License

Yet another open-source Spotify Connect compatible client, written in Go.

go-librespot gives you the freedom to have a Spotify Connect device wherever you want.

Getting Started

Using prebuilt binary

To get started you can download prebuilt binaries for the latest release.

Development prebuilt binaries are also available as GitHub Actions artifacts.

Building from source

To build from source the following prerequisites are necessary:

  • Go 1.22 or higher
  • Libraries: libogg, libvorbis, libasound2

To install Go, download it from the Go website.

To install the required libraries on Debian-based systems (Debian, Ubuntu, Raspbian), use:

sudo apt-get install libogg-dev libvorbis-dev libasound2-dev

Once prerequisites are installed you can clone the repository and run the daemon with:

go run ./cmd/daemon

Details about cross-compiling go-librespot are described here (thank you @felixstorm).

Configuration

The default directory for configuration files is ~/.config/go-librespot. You can change this directory with the -config_dir flag. The configuration directory contains:

  • config.yml: The main configuration (does not exist by default)
  • state.json: The player state and credentials
  • lockfile: A lockfile to prevent running multiple instances on the same configuration

The full configuration schema is available here, only the main options are detailed below.

Zeroconf mode

This is the default mode. It uses mDNS auto discovery to allow Spotify clients inside the same network to connect to go-librespot. This is also known as Spotify Connect.

An example configuration (not required) looks like this:

zeroconf_enabled: false # Whether to keep the device discoverable at all times, even if authenticated via other means
credentials:
  type: zeroconf
  zeroconf:
    persist_credentials: false # Whether to persist zeroconf user credentials even after disconnecting

If persist_credentials is true, after connecting to the device for the first time credentials will be stored locally and you can switch to interactive mode without having to authenticate manually.

Interactive mode

This mode allows you to associate your account with the device and make it discoverable even outside the network. It requires some manual steps to complete the authentication:

  1. Configure interactive mode

    zeroconf_enabled: false # Whether to keep the device discoverable at all times
    credentials:
      type: interactive
    
  2. Start the daemon to begin the authentication flow

  3. Open the authorization link in your browser and wait to be redirected

  4. If go-librespot is running on the same device as your browser, authentication should complete successfully

  5. (optional) If go-librespot is running on another device, you'll need to copy the URL from your browser and call it from the device, for example:

    curl http://127.0.0.1:36842/login?code=xxxxxxxx
    
API server

Optionally, an API server can be started to control and monitor the player. To enable this feature, add the following to your configuration:

server:
  enabled: true
  address: localhost # Which address to bind to
  port: 3678 # The server port
  allow_origin: '' # Value for the Access-Control-Allow-Origin header
  cert_file: '' # Path to certificate file for TLS
  key_file: '' # Path to key file for TLS

For detailed API documentation see here.

Volume synchronization

Various configurations for volume control are available:

  1. No external volume without mixer: Spotify volume is controlled independently of the device volume, output samples are multiplied with the volume
  2. No external volume with mixer: Spotify volume is synchronized with the device volume and vice versa, output samples are not volume dependant, Spotify volume changes are applied to the ALSA mixer and vice versa
  3. External volume without mixer: Spotify volume is not synchronized with the device volume, output samples are not volume dependant
  4. External volume with mixer: Device volume is synchronized with Spotify volume, output samples are not volume dependant, volume changes are not applied to the ALSA mixer
Additional configuration

The following options are also available:

log_level: info # Log level configuration (trace, debug, info, warn, error)
device_id: '' # Spotify device ID (auto-generated)
device_name: '' # Spotify device name
device_type: computer # Spotify device type (icon)
audio_device: default # ALSA audio device to use for playback
mixer_device: '' # ALSA mixer device for volume synchronization 
mixer_control_name: Master # ALSA mixer control name for volume synchronization
bitrate: 160 # Playback bitrate (96, 160, 320)
volume_steps: 100 # Volume steps count
initial_volume: 100 # Initial volume in steps (not applied to the mixer device)
external_volume: false # Whether volume is controlled externally 
disable_autoplay: false # Whether autoplay of more songs should be disabled

Make sure to check here for the full list of options.

Development

Protobuf definitions are managed through Buf. To recompile, execute:

buf generate

or using Go:

go generate ./...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMediaRestricted    = errors.New("media is restricted")
	ErrNoSupportedFormats = errors.New("no supported formats")
)
View Source
var ClientId = []byte{0x65, 0xb7, 0x8, 0x7, 0x3f, 0xc0, 0x48, 0xe, 0xa9, 0x2a, 0x7, 0x72, 0x33, 0xca, 0x87, 0xbd}
View Source
var ClientIdHex = hex.EncodeToString(ClientId)
View Source
var UriRegexp = regexp.MustCompile("^spotify:([a-z]+):([0-9a-zA-Z]{21,22})$")

Functions

func ContextTrackToProvidedTrack

func ContextTrackToProvidedTrack(typ SpotifyIdType, track *connectpb.ContextTrack) *connectpb.ProvidedTrack

func GetCpuFamily

func GetCpuFamily() spotifypb.CpuFamily

func GetOS

func GetOS() spotifypb.Os

func GetPlatform

func GetPlatform() spotifypb.Platform

func GetPlatformSpecificData

func GetPlatformSpecificData() *clienttokenpb.PlatformSpecificData

func GidToBase62

func GidToBase62(id []byte) string

func SpotifyLikeClientVersion

func SpotifyLikeClientVersion() string

func SystemInfoString

func SystemInfoString() string

func UserAgent

func UserAgent() string

func VersionNumberString

func VersionNumberString() string

func VersionString

func VersionString() string

Types

type AudioSource

type AudioSource interface {
	// SetPositionMs sets the new position in samples
	SetPositionMs(int64) error

	// PositionMs gets the position in samples
	PositionMs() int64

	// Read reads 32bit little endian floats from the stream
	Read([]float32) (int, error)
}

type Float32Reader

type Float32Reader interface {
	// Read reads 32bit little endian floats from the stream
	// until EOF or ErrDrainReader is returned.
	Read([]float32) (n int, err error)
}

type GetAddressFunc

type GetAddressFunc func() string

GetAddressFunc is a function that everytime it is called returns a different address for that type of endpoint.

type GetLogin5TokenFunc

type GetLogin5TokenFunc func(force bool) (string, error)

GetLogin5TokenFunc is a function that everytime it is called returns a valid login5 access token.

type Media

type Media struct {
	// contains filtered or unexported fields
}

func NewMediaFromEpisode

func NewMediaFromEpisode(episode *metadatapb.Episode) *Media

func NewMediaFromTrack

func NewMediaFromTrack(track *metadatapb.Track) *Media

func (Media) Duration

func (te Media) Duration() int32

func (Media) Episode

func (te Media) Episode() *metadatapb.Episode

func (Media) IsEpisode

func (te Media) IsEpisode() bool

func (Media) IsTrack

func (te Media) IsTrack() bool

func (Media) Name

func (te Media) Name() string

func (Media) Restriction

func (te Media) Restriction() []*metadatapb.Restriction

func (Media) Track

func (te Media) Track() *metadatapb.Track

type PageResolver

type PageResolver[T any] interface {
	Page(idx int) ([]T, error)
}

type SizedReadAtSeeker

type SizedReadAtSeeker interface {
	io.ReadSeeker
	io.ReaderAt

	Size() int64
}

type SpotifyId

type SpotifyId struct {
	// contains filtered or unexported fields
}

func SpotifyIdFromGid

func SpotifyIdFromGid(typ SpotifyIdType, id []byte) SpotifyId

func SpotifyIdFromUri

func SpotifyIdFromUri(uri string) (_ *SpotifyId, err error)

func (SpotifyId) Base62

func (id SpotifyId) Base62() string

func (SpotifyId) Hex

func (id SpotifyId) Hex() string

func (SpotifyId) Id

func (id SpotifyId) Id() []byte

func (SpotifyId) String

func (id SpotifyId) String() string

func (SpotifyId) Type

func (id SpotifyId) Type() SpotifyIdType

func (SpotifyId) Uri

func (id SpotifyId) Uri() string

type SpotifyIdType

type SpotifyIdType string
const (
	SpotifyIdTypeTrack    SpotifyIdType = "track"
	SpotifyIdTypeEpisode  SpotifyIdType = "episode"
	SpotifyIdTypePlaylist SpotifyIdType = "playlist"
)

func InferSpotifyIdTypeFromContextUri

func InferSpotifyIdTypeFromContextUri(uri string) SpotifyIdType

Jump to

Keyboard shortcuts

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