control

package
v3.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package control exposes the OpenDeezer remote-control API: a small HTTP/JSON server that a controller (another OpenDeezer client, an MCP agent, a phone web remote) can drive, and a matching client that talks to one.

Host a control server

srv := control.NewServer(
    control.Config{
        Addr:  ":7654",      // LAN-accessible
        Token: "s3cr3t",     // bearer-token auth
    },
    func() control.State { return snapshot() },
    func() control.Account { return control.Account{UserID: uid, Name: name} },
    control.Commands{
        PlayPause: player.TogglePause,
        Next:      queue.Next,
        Prev:      queue.Prev,
        Stop:      player.Stop,
        SetVolume: player.SetVolume,
        Seek:      player.SeekMS,
    },
    dzClient, // pass nil to disable browse (/search, /playlists)
)
srv.SetVersion("1.0")
if err := srv.Start(); err != nil { log.Fatal(err) }
defer srv.Close()

Drive a remote server

client := control.NewClient("http://192.168.1.5:7654", "s3cr3t", "")
st, _ := client.Status()
fmt.Println(st.State, st.Track.Title)

Phone web remote

When [Config.WebRemote] is true, GET /remote serves a mobile-friendly SPA. Pair a phone by calling Server.EnablePairing to get a 6-digit code, then entering it in the SPA. Pairing issues a session token stored in localStorage; no cookie is used (CSRF-safe).

Auth modes

  • token — bearer token in X-OpenDeezer-Token; set [Config.Token]
  • account — controller proves it is the same Deezer account; set [Config.SameAccountOnly] = true
  • session — phone web remote; set [Config.WebRemote] = true
  • none — open (safe only on localhost)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account = internalcontrol.Account

Account is the controlled client's Deezer identity, provided to NewServer via a snapshot callback. UserID is the credential in same-account auth mode.

type Client

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

Client talks to a Server (or any compatible control endpoint) over HTTP. All mutation methods return the post-command playback snapshot. The snapshot may lag the command by one server tick; poll GET /status if you need the settled state.

Client is safe for concurrent use.

func NewClient

func NewClient(base, token, accountID string) *Client

NewClient builds a control client.

  • base — server URL, e.g. "http://192.168.1.5:7654"
  • token — X-OpenDeezer-Token value; "" to omit
  • accountID — X-OpenDeezer-Account value for same-account auth; "" to omit

func (*Client) CancelSleepTimer

func (c *Client) CancelSleepTimer() (State, error)

CancelSleepTimer disarms the server's sleep timer.

func (*Client) CycleRepeat

func (c *Client) CycleRepeat() (State, error)

CycleRepeat advances the repeat mode one step (off → all → one → off).

func (*Client) EQ

func (c *Client) EQ() (EQState, error)

EQ returns the server's equalizer snapshot (enabled, mono downmix, preamp, per-band gains, active preset and the preset/band lists). Errors when the server has no equalizer bridge (the /eq endpoints are 404).

func (*Client) Events

func (c *Client) Events(ctx context.Context) (<-chan State, error)

Events subscribes to the server's playback state stream (GET /events, Server-Sent Events). Every subscriber receives an initial State snapshot immediately, then a snapshot on each wire-visible change — no polling. The returned channel is closed when ctx is cancelled or the connection to the server drops; there is no automatic reconnect (call Events again). Snapshots are buffered and coalesced: a slow consumer may skip intermediate snapshots but always observes the newest one. Like every other method it works over LAN — point the client at a remote device's control address.

func (*Client) EventsTyped

func (c *Client) EventsTyped(ctx context.Context) (<-chan Event, error)

EventsTyped subscribes to the server's typed event stream (GET /events): both "state" snapshots and explicit "finished" events, so a controller learns a natural track end instantly instead of inferring it from a state diff. The channel closes on ctx cancel or when the stream drops (no auto-reconnect).

func (*Client) HistoryRecent

func (c *Client) HistoryRecent(n int) (json.RawMessage, error)

HistoryRecent returns the server's recent-listening history as raw JSON, most recent first (GET /history/recent). n caps the number of entries (1..500). Errors when the server exposes no history.

func (*Client) Next

func (c *Client) Next() (State, error)

Next skips to the next track.

func (*Client) PlayAlbum

func (c *Client) PlayAlbum(id string) (State, error)

PlayAlbum instructs the server to play the album with the given Deezer id from its first track (replacing the queue).

func (*Client) PlayMixArtist

func (c *Client) PlayMixArtist(id string) (State, error)

PlayMixArtist starts a Deezer mix (radio) seeded by the artist with the given id.

func (*Client) PlayMixTrack

func (c *Client) PlayMixTrack(id string) (State, error)

PlayMixTrack starts a Deezer mix (radio) seeded by the track with the given id.

func (*Client) PlayPause

func (c *Client) PlayPause() (State, error)

PlayPause toggles play/pause on the server.

func (*Client) PlayPlaylist

func (c *Client) PlayPlaylist(id string) (State, error)

PlayPlaylist instructs the server to play the playlist with the given id.

func (*Client) PlayTrack

func (c *Client) PlayTrack(id string) (State, error)

PlayTrack instructs the server to play the track with the given Deezer id.

func (*Client) Playlists

func (c *Client) Playlists() (json.RawMessage, error)

Playlists returns the server account's raw playlists JSON (GET /playlists). Errors when the server was built without a Deezer client.

func (*Client) Prev

func (c *Client) Prev() (State, error)

Prev jumps to the previous track.

func (*Client) QueueAdd

func (c *Client) QueueAdd(id string, next bool) (State, error)

QueueAdd appends the track with the given Deezer id to the server's queue, or inserts it right after the current track when next is true.

func (*Client) QueueJump

func (c *Client) QueueJump(index int) (State, error)

QueueJump jumps playback to the queue entry at index (0-based).

func (*Client) QueueMove

func (c *Client) QueueMove(from, to int) (State, error)

QueueMove moves the queue entry at position from to position to (both 0-based).

func (*Client) QueueRemove

func (c *Client) QueueRemove(index int) (State, error)

QueueRemove removes the queue entry at index (0-based).

func (*Client) Restart

func (c *Client) Restart() (State, error)

Restart seeks to position 0 in the current track.

func (*Client) Search

func (c *Client) Search(q string) (json.RawMessage, error)

Search returns the server's raw search-results JSON for query q (GET /search). Errors when the server was built without a Deezer client.

func (*Client) SeekMS

func (c *Client) SeekMS(ms int64) (State, error)

SeekMS seeks to ms milliseconds from the start of the current track.

func (*Client) SetEQ

func (c *Client) SetEQ(params url.Values) (EQState, error)

SetEQ applies a partial equalizer update. params carries any of the POST /eq query params — on=0|1, mono=0|1, preset=name, band=N&db=X, preamp=dB — and the server applies whichever are present (at least one is required).

func (*Client) SetQueue

func (c *Client) SetQueue(tracksJSON string, index int) (State, error)

SetQueue pushes a whole queue to the host (POST /queue/set): tracksJSON is the bridge.Track JSON array and index is the cursor (-1 for an empty queue). It is the groundwork for host-owned casting. Errors when the host exposes no SetQueue.

func (*Client) SetRepeat

func (c *Client) SetRepeat(mode string) (State, error)

SetRepeat sets the repeat mode: "off", "all", or "one".

func (*Client) SetShuffle

func (c *Client) SetShuffle(on bool) (State, error)

SetShuffle enables (true) or disables (false) shuffle.

func (*Client) SetSleepTimer

func (c *Client) SetSleepTimer(minutes int, endOfTrack bool) (State, error)

SetSleepTimer arms the server's sleep timer: playback fades out and pauses after minutes, or when the current track ends if endOfTrack is true (minutes is then ignored).

func (*Client) SetVolume

func (c *Client) SetVolume(v float64) (State, error)

SetVolume sets the volume (0.0 = silent, 1.0 = full).

func (*Client) Status

func (c *Client) Status() (State, error)

Status returns the current playback snapshot.

func (*Client) Stop

func (c *Client) Stop() (State, error)

Stop halts playback.

func (*Client) ToggleShuffle

func (c *Client) ToggleShuffle() (State, error)

ToggleShuffle flips shuffle on/off.

func (*Client) Whoami

func (c *Client) Whoami() (Whoami, error)

Whoami fetches the server's identity and auth mode. This endpoint is unauthenticated and is safe to call before supplying credentials.

type Commands

type Commands = internalcontrol.Commands

Commands are the playback actions a Server dispatches. Set only the functions your application implements; nil entries cause the corresponding endpoint to be a no-op.

type Config

type Config = internalcontrol.Config

Config configures a Server.

  • Addr — listen address (e.g. "127.0.0.1:7654" or ":7654")
  • Token — bearer token; set to enable token auth
  • SameAccountOnly — when Token is empty, require the controller to prove it is logged into the same Deezer account
  • WebRemote — serve the phone web-remote SPA at GET /remote and use pairing (6-digit code) as the auth mechanism

type EQ

type EQ = internalcontrol.EQ

EQ is the equalizer bridge a Server serves at /eq. Wire the functions to your audio engine (each may be nil individually) and pass it to Server.SetEQ before Start; without a bridge the /eq endpoints are 404. PlayerEQ builds one from anything satisfying EQController.

func PlayerEQ

func PlayerEQ(get func() EQController, presets []string) *EQ

PlayerEQ builds an EQ bridge from a live player getter (get may return nil while the engine is starting) and the preset-name list (see sdk/player.EQPresetNames).

type EQController

type EQController = internalcontrol.EQController

EQController is the player subset an EQ bridge built with PlayerEQ drives. sdk/player.Player satisfies it.

type EQState

type EQState = internalcontrol.EQState

EQState is the equalizer snapshot returned by GET /eq (and by all Client equalizer methods): enabled flag, mono downmix, preamp, per-band gains, the active preset and the preset/band lists.

type Event

type Event = internalcontrol.Event

Event is a typed control event (a "state" snapshot or a "finished" event).

type Server

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

Server hosts the OpenDeezer remote-control API. Construct one with NewServer; call Server.Start to bind the port; call Server.Close when done.

Server is safe for concurrent use once started.

func NewServer

func NewServer(
	cfg Config,
	status func() State,
	account func() Account,
	cmds Commands,
	dz *sdkdeezer.Client,
) *Server

NewServer builds a control server.

  • cfg — listen address and auth mode
  • status — called on each request; must return a race-free snapshot of the current playback state
  • account — called on each request; must return the logged-in identity
  • cmds — the actions the server can dispatch to your player
  • dz — Deezer client used to serve GET /search and GET /playlists; pass nil to disable browse endpoints

func (*Server) Addr

func (s *Server) Addr() string

Addr returns the actual listen address (valid after Server.Start).

func (*Server) Close

func (s *Server) Close()

Close stops the server and releases the port.

func (*Server) DisablePairing

func (s *Server) DisablePairing()

DisablePairing clears the pairing code so no new devices can pair and revokes all existing session tokens (individual sessions can be revoked via their id).

func (*Server) EnablePairing

func (s *Server) EnablePairing() string

EnablePairing mints a fresh 6-digit pairing code, activates the pairing flow, and returns the code. Display it to the user; they enter it in the phone web remote at http://<addr>/remote. Each call resets the code.

func (*Server) PairingActive

func (s *Server) PairingActive() bool

PairingActive reports whether a pairing code is currently active.

func (*Server) PairingCode

func (s *Server) PairingCode() string

PairingCode returns the current 6-digit code, or an empty string when pairing is not active.

func (*Server) RevokeSession

func (s *Server) RevokeSession(idOrToken string)

RevokeSession revokes one paired web-remote session by its public id (the "id" returned from a successful POST /pair) or by its session token. Use it for per-device revocation; Server.DisablePairing revokes all sessions.

func (*Server) SetClientInfo

func (s *Server) SetClientInfo(client, device string)

SetClientInfo records the client/platform id and human device label for GET /whoami (e.g. "myapp", "My Player v1.0").

func (*Server) SetEQ

func (s *Server) SetEQ(eq *EQ)

SetEQ wires the equalizer bridge served at GET/POST /eq. Call it before Server.Start; without a bridge the /eq endpoints are 404. Build one with PlayerEQ or fill the EQ functions yourself.

func (*Server) SetVersion

func (s *Server) SetVersion(v string)

SetVersion records the app version reported by GET /whoami.

func (*Server) Start

func (s *Server) Start() error

Start binds the port and begins serving in a background goroutine.

type State

type State = internalcontrol.State

State is the playback snapshot returned by GET /status and all mutation endpoints. It is also the return type of all Client mutation methods.

type Track

type Track = internalcontrol.Track

Track is a now-playing or queue entry in a State.

type Whoami

type Whoami = internalcontrol.Whoami

Whoami is the unauthenticated identity returned by GET /whoami. It carries the account display Name but never the UserID (which is the credential in same-account mode).

Jump to

Keyboard shortcuts

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