sdk

package
v3.0.0 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: 0 Imported by: 0

README

OpenDeezer SDK

The OpenDeezer SDK is a public Go library that lets third-party developers build on the OpenDeezer engine: the Deezer API client, track decode/decrypt and streaming, LAN device discovery (OpenDeezer Connect), and the remote control API.

go get github.com/Cycl0o0/OpenDeezer/v3

Import paths:

Package Purpose
github.com/Cycl0o0/OpenDeezer/v3/sdk/deezer Deezer API client + decode
github.com/Cycl0o0/OpenDeezer/v3/sdk/connect OpenDeezer Connect (LAN discovery + remote)
github.com/Cycl0o0/OpenDeezer/v3/sdk/control Control server + client (HTTP/JSON API)
github.com/Cycl0o0/OpenDeezer/v3/sdk/player In-process audio playback (cgo)

Go docs: https://pkg.go.dev/github.com/Cycl0o0/OpenDeezer/v3/sdk

Control works both ways (in + out)

Everything that controls a client is available in both directions — you can drive another device (out) and be driven by one (in):

Capability Out (control another) In (be controlled)
Remote control API control.Client control.Server
OpenDeezer Connect connect.Discover + connect.RemoteClient connect.Host (+ connect.Advertise)

Both sides cover the full control-API command set. control.Client and connect.RemoteClient expose identical methods; the "in" column is the control.Commands hook (or server wiring) that receives each command:

Command Out (Client / RemoteClient method) In (server side)
Status snapshot Status status callback (NewServer/NewHost)
Identity / auth mode Whoami account callback + SetVersion/SetClientInfo
Play/pause, next, prev, stop, restart PlayPause, Next, Prev, Stop, Restart Commands.PlayPauseCommands.Restart
Seek, volume SeekMS, SetVolume Commands.Seek, Commands.SetVolume
Repeat (set / cycle) SetRepeat, CycleRepeat Commands.SetRepeat, Commands.CycleRepeat
Shuffle (set / toggle) SetShuffle, ToggleShuffle Commands.SetShuffle, Commands.ToggleShuffle
Play track / playlist PlayTrack, PlayPlaylist Commands.PlayTrack, Commands.PlayPlaylist
Play album PlayAlbum Commands.PlayAlbum
Play mix (track / artist seed) PlayMixTrack, PlayMixArtist Commands.PlayMixTrack, Commands.PlayMixArtist
Queue (add / jump / remove / move) QueueAdd, QueueJump, QueueRemove, QueueMove Commands.QueueAdd, Commands.QueueJump, Commands.QueueRemove, Commands.QueueMove
Listening history HistoryRecent Commands.HistoryRecent
State events (SSE) Events built into Server/Host (GET /events)
Sleep timer (arm / cancel) SetSleepTimer, CancelSleepTimer Commands.SetSleepTimer, Commands.CancelSleepTimer
Equalizer (read / write) EQ, SetEQ Server.SetEQ bridge (build with control.PlayerEQ)
Browse (search / playlists) Search, Playlists the Deezer client passed to NewServer/NewHost
Web-remote pairing — (phone SPA) EnablePairing, DisablePairing, RevokeSession

Authentication (ARL)

Deezer uses a long-lived cookie called the ARL (Audio Reference Link) for authentication. Get yours from a browser session: open deezer.com, press F12, go to Application → Cookies → arl.

The ARL never leaves your machine beyond the HTTPS requests made to deezer.com and media.deezer.com.

import dz "github.com/Cycl0o0/OpenDeezer/v3/sdk/deezer"

client := dz.New(os.Getenv("DEEZER_ARL"))
if err := client.Login(); err != nil {
    // errors.Is(err, dz.ErrARLExpired) → ARL needs refreshing
    log.Fatal(err)
}
acc := client.Account()
fmt.Printf("Hello %s (%s)\n", acc.Name, acc.Offer)

Browse

// Search
results, _ := client.Search("Radiohead")
for _, t := range results.Tracks {
    fmt.Println(t.Name, "—", t.ArtistLine())
}

// Charts (global top 50)
charts, _ := client.Charts("0")

// Favorites / playlists (requires login)
tracks, _ := client.Favorites()
playlists, _ := client.Playlists()

// Artist profile
page, _ := client.ArtistProfile("27")   // Radiohead
fmt.Println(page.Artist.Name, page.Artist.NbFans, "fans")

// Lyrics
lyr, _ := client.Lyrics(trackID)
if lyr.IsSynced() {
    for _, line := range lyr.Synced {
        fmt.Printf("%d ms  %s\n", line.TimeMS, line.Text)
    }
}

Download and decrypt a track

PrepareStream resolves the CDN URL and decryption key. DownloadTrack then fetches, decrypts (BF_CBC_STRIPE), and writes the audio bytes to any io.Writer:

import (
    "os"
    dz "github.com/Cycl0o0/OpenDeezer/v3/sdk/deezer"
)

client.SetQuality(dz.QualityHigh) // prefer MP3 320; falls back if not entitled

plan, err := client.PrepareStream(trackID)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Format:", dz.FormatLabel(plan.Format)) // "MP3 · 320 kbps"

f, _ := os.Create("track.mp3")
defer f.Close()
if err := dz.DownloadTrack(plan, f); err != nil {
    log.Fatal(err)
}

Quality levels:

Constant Format Requires
dz.QualityNormal MP3 128 kbps Any account
dz.QualityHigh MP3 320 kbps Premium
dz.QualityLossless FLAC HiFi

Deezer falls back to the highest quality the account is entitled to automatically.

Decrypt an in-memory buffer
plain, err := dz.DecryptBytes(trackID, encryptedBytes)

OpenDeezer Connect (LAN discovery + remote)

OpenDeezer Connect is symmetric — the SDK exposes both directions:

Direction What API
out discover + control other devices connect.Discover, connect.RemoteClient
in be discoverable + controllable connect.Host (or connect.Advertise for the discovery half alone)
Out — discover and drive a device
import "github.com/Cycl0o0/OpenDeezer/v3/sdk/connect"

// Find devices (2-second probe window).
devices, _ := connect.Discover(2*time.Second, 0)
for _, d := range devices {
    fmt.Printf("%s at %s\n", d.Name, d.Addr)
}

// Drive the first device (same-account auth — no token needed).
rc := connect.NewRemoteClient(devices[0].Addr, "", myUserID)
st, _ := rc.PlayPause()
fmt.Println("state:", st.State)
In — be a controllable device

connect.Host ties a control endpoint together with LAN advertising. The device accepts the exact command set a RemoteClient sends:

host := connect.NewHost(
    connect.HostConfig{
        Control: connect.Config{Addr: ":7654", SameAccountOnly: true},
        Name:    "My Player", Client: "myapp", Version: "1.0",
    },
    func() connect.State { return currentState() },
    func() connect.Account {
        a := client.Account()
        return connect.Account{UserID: a.UserID, Name: a.Name, Offer: a.Offer}
    },
    connect.Commands{
        PlayPause: player.TogglePause,
        Stop:      player.Stop,
        SetVolume: player.SetVolume,
        PlayTrack: playByID,
    },
    client, // browse routes; nil to disable
)
host.Start()
defer host.Close()
// host.Server().EnablePairing() to also accept the phone web remote.

If you already run your own control server, advertise the discovery half alone:

resp, _ := connect.Advertise(func() connect.AdvertiseInfo {
    return connect.AdvertiseInfo{Name: "My Player", Client: "myapp", Version: "1.0"}
}, controlPort)
defer resp.Close()
Auth modes for RemoteClient

Check Whoami.Auth on the target device to know which credential to supply:

Auth What to pass
"token" token="<bearer-token>"
"account" accountID="<your Deezer user id>"
"session" Not controllable from RemoteClient/control.Client; driveable only from the device's embedded browser remote, which sends a paired session token in the X-OpenDeezer-Session header (stored in localStorage, not a cookie)
"none" Empty strings

Remote control (server = in, client = out)

The control API is also symmetric: control.Server hosts a controllable endpoint (in), control.Client drives one (out).

Control server (in)

Host a controllable endpoint that phones, AI agents, or other OpenDeezer clients can drive.

import "github.com/Cycl0o0/OpenDeezer/v3/sdk/control"

srv := control.NewServer(
    control.Config{
        Addr:  ":7654",
        Token: "my-secret-token",
    },
    func() control.State { return currentState() },
    func() control.Account {
        a := client.Account()
        return control.Account{UserID: a.UserID, Name: a.Name, Offer: a.Offer}
    },
    control.Commands{
        PlayPause: player.TogglePause,
        Next:      queue.Next,
        Stop:      player.Stop,
        Seek:      player.SeekMS,
        SetVolume: player.SetVolume,
    },
    client, // for GET /search and GET /playlists; nil to disable
)
srv.SetVersion("1.0")
srv.Start()
defer srv.Close()

To also serve the equalizer endpoints (GET/POST /eq), wire the EQ bridge before Startcontrol.PlayerEQ builds one from an sdk/player.Player:

srv.SetEQ(control.PlayerEQ(
    func() control.EQController { return p }, // *player.Player satisfies EQController
    player.EQPresetNames(),
))
Phone web remote

Enable pairing to let a phone control playback via a browser:

srv := control.NewServer(
    control.Config{Addr: ":7654", WebRemote: true},
    ...
)
srv.Start()
code := srv.EnablePairing() // display this 6-digit code to the user
fmt.Printf("Open http://192.168.1.X:7654/remote — code: %s\n", code)
Control client (out)
c := control.NewClient("http://192.168.1.5:7654", "my-secret-token", "")
st, _ := c.Status()
fmt.Println(st.State, st.Track.Title)
c.SetVolume(0.8)
c.SeekMS(30000)
c.PlayTrack("3135556")
c.PlayAlbum("302127")     // whole album from the top
c.PlayMixTrack("3135556") // Deezer mix seeded by a track (PlayMixArtist for an artist seed)
c.SetRepeat("all")
c.SetShuffle(true)
c.SetSleepTimer(30, false) // pause after 30 minutes (fade-out)
c.SetEQ(url.Values{"preset": {"rock"}, "on": {"1"}})
results, _ := c.Search("daft punk") // raw JSON from the server's account
history, _ := c.HistoryRecent(20)   // raw JSON, most recent first

The queue endpoints (POST /queue/add, /queue/jump, /queue/remove, /queue/move) are covered by the matching client methods — indexes are 0-based positions in State.Queue:

c.QueueAdd("3135556", true) // insert right after the current track (false = append)
c.QueueJump(2)              // play queue entry 2 now
c.QueueMove(4, 0)           // reorder: entry 4 to the front
c.QueueRemove(3)            // drop entry 3
Events (SSE)

Instead of polling Status, subscribe to the server's GET /events stream (Server-Sent Events) with Events. The first State snapshot arrives immediately, then one on every wire-visible change. The returned channel is closed when the context is cancelled or the connection drops (no automatic reconnect — call Events again). Snapshots are coalesced for slow consumers: you may skip intermediate states but always see the newest one. It works over LAN like every other method, and connect.RemoteClient exposes the identical Events for driving discovered devices:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

states, err := c.Events(ctx)
if err != nil {
    log.Fatal(err)
}
for st := range states { // channel closes on cancel / disconnect
    fmt.Printf("%s %s (%d ms)\n", st.State, st.Track.Title, st.PositionMS)
}

In-process playback (cgo)

The sdk/player package wraps the audio engine (miniaudio/malgo or oto, selected by build tag). It requires cgo. Omit this import if you only need API access, search, or download/decrypt.

import (
    "github.com/Cycl0o0/OpenDeezer/v3/sdk/player"
    dz "github.com/Cycl0o0/OpenDeezer/v3/sdk/deezer"
)

p, _ := player.NewPlayer()
defer p.Close()

p.SetReplayGain(true)
p.SetVolume(0.9)

// Play a track.
plan, _ := client.PrepareStream(trackID)
p.Play(plan, track.DurationMS)

// Advance queue when track ends.
p.SetOnFinish(func() { /* load next */ })

// Gapless: preload the next track before this one ends.
nextPlan, _ := client.PrepareStream(nextTrackID)
p.Preload(nextPlan, nextTrack.DurationMS)

Examples

Runnable examples are in examples/:

Directory Direction What it shows
examples/search Login + search + print results
examples/download Login → PrepareStream → DownloadTrack → file
examples/player Login → PrepareStream → gapless in-process playback of a queue (cgo)
examples/connect out Discover LAN devices + send PlayPause
examples/host in Be a discoverable, controllable Connect device
examples/remote-server in Host a control server + poll it via the client

Run any example with:

DEEZER_ARL=<your_arl> go run ./examples/search "Daft Punk"
DEEZER_ARL=<your_arl> go run ./examples/download 3135556
DEEZER_ARL=<your_arl> go run ./examples/player 3135556 3135554
DEEZER_ARL=<your_arl> go run ./examples/connect
DEEZER_ARL=<your_arl> go run ./examples/host
DEEZER_ARL=<your_arl> go run ./examples/remote-server

Stability

The SDK follows an additive-only policy across minor versions: within a major version, exported identifiers in sdk/... are never removed or given incompatible signatures by a minor or patch release — changes are limited to adding new functions, methods, fields and packages. Behavior-preserving fixes are allowed anywhere. Anything under internal/ carries no compatibility promise; depend only on the sdk/... import paths.

Documentation

Overview

Package sdk is the OpenDeezer public SDK — a curated Go API for third-party developers who want to build on the OpenDeezer engine without forking the application itself.

Sub-packages

  • sdk/deezer — Deezer API client (login, browse, stream resolution, decrypt)
  • sdk/connect — OpenDeezer Connect (LAN device discovery, remote playback)
  • sdk/control — control server + client (HTTP/JSON remote-control API)
  • sdk/player — in-process audio playback (cgo required: miniaudio or oto)

Install

go get github.com/Cycl0o0/OpenDeezer/v3

Quick start

import (
    dz "github.com/Cycl0o0/OpenDeezer/v3/sdk/deezer"
)

client := dz.New(os.Getenv("DEEZER_ARL"))
if err := client.Login(); err != nil {
    log.Fatal(err)
}
results, _ := client.Search("Daft Punk")
for _, t := range results.Tracks {
    fmt.Println(t.Name, "-", t.ArtistLine())
}

ARL authentication

Deezer uses a long-lived cookie called the ARL (Audio Reference Link) for authentication. Obtain yours from a browser session (Application > Cookies > arl on deezer.com) and pass it to sdk/deezer.New. The ARL never leaves your machine beyond the HTTPS requests made to Deezer.

Directories

Path Synopsis
Package connect implements OpenDeezer Connect: LAN discovery and remote control of OpenDeezer devices, in both directions.
Package connect implements OpenDeezer Connect: LAN discovery and remote control of OpenDeezer devices, in both directions.
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.
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.
Package deezer is the OpenDeezer SDK's Deezer API layer: account login via ARL, browse (favorites, playlists, albums, search, charts, Flow, artists, lyrics, podcasts), library write operations (like/unlike, playlist CRUD), stream resolution, and Blowfish BF_CBC_STRIPE decryption.
Package deezer is the OpenDeezer SDK's Deezer API layer: account login via ARL, browse (favorites, playlists, albums, search, charts, Flow, artists, lyrics, podcasts), library write operations (like/unlike, playlist CRUD), stream resolution, and Blowfish BF_CBC_STRIPE decryption.
Package player provides in-process Deezer audio playback via Player.
Package player provides in-process Deezer audio playback via Player.

Jump to

Keyboard shortcuts

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