audd

package module
v1.5.13 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: MIT Imports: 21 Imported by: 12

README

audd-go

CI Contract Go Reference Go Report Card

Official Go SDK for music recognition API: identify music from a short audio clip, a long audio file, or a live stream.

The API itself is so simple that it can easily be used even without an SDK: docs.audd.io.

Hello, AudD

go get github.com/AudDMusic/audd-go

Get your API token at dashboard.audd.io.

Identify a song hosted at a URL:

package main

import (
    "fmt"
    "log"

    audd "github.com/AudDMusic/audd-go"
)

func main() {
    client := audd.NewClient("your-api-token")
    defer client.Close()

    result, err := client.Recognize("https://audd.tech/example.mp3", nil)
    if err != nil {
        log.Fatal(err)
    }
    if result == nil {
        fmt.Println("no match")
        return
    }
    fmt.Printf("%s — %s\n", result.Artist, result.Title)
}

Identify a song from a local file path:

result, err := client.Recognize("/path/to/clip.mp3", nil)

Recognize accepts a URL string, a file-path string, []byte, or any io.Reader. For files longer than ~25 seconds, use client.RecognizeEnterprise(source, &audd.EnterpriseOptions{Limit: ptr(1)}), which returns []EnterpriseMatch across the file's chunks. Each match carries the same core tags plus Score, StartOffset, EndOffset, ISRC, UPC. Access to ISRC, UPC, and Score requires a Startup plan or higher — contact us for enterprise features.

Every method has an explicit-context twin: RecognizeContext(ctx, source, opts), Streams().AddContext(ctx, req), Advanced().FindLyricsContext(ctx, query), and so on. The plain form is the default for short scripts; the *Context form is what you reach for in servers and pipelines that need cancellation, deadlines, or a context-propagated tracing span.

Requires Go 1.21+.

Authentication

Pass your token to NewClient:

client := audd.NewClient("your-api-token")

Or leave it empty and the SDK reads the AUDD_API_TOKEN environment variable:

// AUDD_API_TOKEN=your-token ...
client := audd.NewClient("")

Get a real token at dashboard.audd.io. The public "test" token works for the snippets above but is capped at 10 requests.

For long-running services that pull tokens from a secret manager and need to swap them without restarting:

if err := client.SetAPIToken(newToken); err != nil {
    log.Fatal(err)
}

In-flight requests continue with the previous token; subsequent ones use the new value.

If you'd rather fail fast at construction time when no token is configured, use NewClientStrict, which returns audd.ErrMissingAPIToken.

What you get back

By default Recognize returns the core tags plus AudD's universal song link — no metadata-block opt-in needed:

result, err := client.Recognize("https://audd.tech/example.mp3", nil)
if err != nil { log.Fatal(err) }
if result == nil { return } // no match

fmt.Println(result.Artist, "—", result.Title)
fmt.Println("Album:        ", result.Album)
fmt.Println("Released:     ", result.ReleaseDate)
fmt.Println("Label:        ", result.Label)
fmt.Println("AudD song:    ", result.SongLink) // links into every provider

// Helpers, driven off SongLink — work without any Return opt-in:
fmt.Println("Cover art:    ", result.ThumbnailURL())
fmt.Println("On Spotify:   ", result.StreamingURL(audd.ProviderSpotify))
for provider, url := range result.StreamingURLs() {
    fmt.Printf("  %s -> %s\n", provider, url)
}

If you need provider-specific metadata blocks, opt in per call. Request only what you need — each provider you ask for adds latency:

result, _ := client.Recognize("https://audd.tech/example.mp3", &audd.RecognizeOptions{
    Return: "apple_music,spotify",
})
fmt.Println("Apple Music:", result.AppleMusic.URL)
fmt.Println("Spotify URI:", result.Spotify.URI)
fmt.Println("Preview:    ", result.PreviewURL())  // first preview across requested providers, "" if none

Valid Return values: apple_music, spotify, deezer, napster, musicbrainz. The metadata-block fields (AppleMusic, Spotify, Deezer, Napster) are pointers and may be nil; MusicBrainz is a slice — guard accordingly.

Reading additional metadata

result.Extras is a map[string]json.RawMessage of every server field outside the typed surface; result.RawResponse is the original JSON object. Use them to read undocumented metadata or beta fields not yet exposed as typed properties:

if raw, ok := result.Extras["song_length"]; ok {
    var seconds int
    _ = json.Unmarshal(raw, &seconds)
    fmt.Println("song length:", seconds)
}

// Same channel exists on every metadata block:
if raw, ok := result.AppleMusic.Extras["genreNames"]; ok {
    var genres []string
    _ = json.Unmarshal(raw, &genres)
}

For the request side, every options struct has an ExtraParameters map[string]string field that's sent as additional form fields — useful for undocumented parameters or beta features not yet typed:

result, _ := client.Recognize(url, &audd.RecognizeOptions{
    Return: "apple_music",
    ExtraParameters: map[string]string{
        "some_beta_flag": "true",
    },
})

Typed fields win on collision: if the same key appears in both ExtraParameters and a typed field, the typed value is sent.

Errors

Match by category with sentinel errors:

import "errors"

result, err := client.Recognize(source, nil)
switch {
case errors.Is(err, audd.ErrAuthentication):
    // 900 / 901 / 903 — token problems
case errors.Is(err, audd.ErrQuota):
    // 902 — quota exceeded
case errors.Is(err, audd.ErrInvalidAudio):
    // 300 / 400 / 500 — audio is the problem
case errors.Is(err, audd.ErrRateLimit):
    // 611 — back off and retry
case errors.Is(err, audd.ErrServer):
    // 5xx, non-JSON gateway responses
case err != nil:
    log.Println("audd:", err)
}

For the underlying numeric code, message, and request ID, extract the typed error:

var apiErr *audd.AudDAPIError
if errors.As(err, &apiErr) {
    log.Printf("[#%d] %s (request_id=%s)", apiErr.ErrorCode, apiErr.Message, apiErr.RequestID)
}

Sentinels: ErrAuthentication, ErrQuota, ErrSubscription, ErrCustomCatalogAccess, ErrInvalidRequest, ErrInvalidAudio, ErrRateLimit, ErrStreamLimit, ErrNotReleased, ErrBlocked, ErrNeedsUpdate, ErrServer, ErrConnection, ErrSerialization.

Configuration

client := audd.NewClient("your-api-token",
    audd.WithMaxAttempts(5),
    audd.WithBackoffFactor(time.Second),
    audd.WithStandardTimeout(2*time.Minute),
    audd.WithEnterpriseTimeout(2*time.Hour),
    audd.WithHTTPClient(&http.Client{ /* corporate proxy, mTLS, etc. */ }),
    audd.WithOnEvent(func(e audd.AudDEvent) { /* see Observability */ }),
    audd.WithOnDeprecation(func(msg string) {
        // Server-side soft-deprecation warnings (code 51) land here.
        slog.Warn("audd-deprecation", "msg", msg)
    }),
)

Retries are cost-aware:

  • Read endpoints retry on 408/429/5xx and any net error.
  • Recognition endpoints retry only on 5xx and pre-upload connection failures (DNS, TCP dial). Post-upload errors are not retried — the server may have already done the metered work.
  • Mutating endpoints retry only on pre-upload connection failures.

Observability

WithOnEvent receives a structured AudDEvent for every request / response / exception on the wire — method/URL/status/elapsed/request_id, no api_token, no body bytes. It pairs cleanly with the standard library's log/slog, so every API call shows up as a structured JSON log record. See examples/observability_slog for a ~50-line drop-in.

Streams

Stream recognition turns AudD into a continuous monitor for an audio stream (internet radio, Twitch, YouTube live, raw HLS/Icecast) and notifies you for every recognized song. Set up streams once, then either receive matches via a callback URL or poll for them.

streams := client.Streams()

// 1. Tell AudD where to POST recognition results for your account.
streams.SetCallbackUrl("https://your.app/audd/callback", &audd.SetCallbackUrlOptions{
    ReturnMetadata: "apple_music,spotify",
})

// 2. Add streams to monitor.
streams.Add(audd.AddStreamRequest{
    URL: "https://example.com/radio.m3u8", RadioID: 1,
})
streams.Add(audd.AddStreamRequest{URL: "twitch:somechannel", RadioID: 2})

// 3. Inspect what you have configured.
list, _ := streams.List()
for _, s := range list {
    fmt.Println(s.RadioID, s.URL, "running:", s.StreamRunning)
}

Inside your callback receiver, parse the POST body into a typed payload:

http.HandleFunc("/audd/callback", func(w http.ResponseWriter, r *http.Request) {
    match, notif, err := audd.HandleCallback(r)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    if match != nil {
        fmt.Println("matched:", match.Song.Artist, "—", match.Song.Title)
        for _, alt := range match.Alternatives {
            fmt.Println("  alt:", alt.Artist, "—", alt.Title)
        }
    }
    if notif != nil {
        fmt.Println("notification:", notif.NotificationMessage)
    }
})

HandleCallback(r) reads the body and parses it. Use audd.ParseCallback(body) instead if you already have the bytes (queue consumer, replay tool).

See examples/streams_callback_handler and examples/streams_setup for runnable code.

Receiving events without a callback URL (longpoll)

If hosting a callback receiver isn't an option, longpoll for events from the client side. Three typed channels — Matches, Notifications, Errors — drive a select loop:

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

radioID := 1 // any integer you choose — your handle for this stream
poll, err := streams.LongpollByRadioIDContext(ctx, radioID, nil)
if err != nil { log.Fatal(err) }
defer poll.Close()

for {
    select {
    case m := <-poll.Matches:
        fmt.Println("matched:", m.Song.Artist, "—", m.Song.Title)
    case n := <-poll.Notifications:
        fmt.Println("notification:", n.NotificationMessage)
    case err := <-poll.Errors:
        log.Fatal(err)
    case <-ctx.Done():
        return
    }
}

For browser widgets, embedded UIs, or anywhere you need to consume a category without leaking the API token, use the tokenless variant — same channels, same select loop:

consumer := audd.NewLongpollConsumer(category)
defer consumer.Close()
poll := consumer.Iterate(nil)
defer poll.Close()
// then the same select loop as above

audd.DeriveLongpollCategory(token, radioID) is also available as a package function for computing categories on a server and shipping them to a frontend that runs NewLongpollConsumer.

Migrating from v0.x

The v0 flat methods (RecognizeByUrl, AddStream, FindLyrics, …) still work as deprecated wrappers and will be removed in v2.0.0. The current API is namespaced:

v0 v1
client.RecognizeByUrl(url, "apple_music", nil) client.Recognize(url, &audd.RecognizeOptions{Return: "apple_music"})
client.RecognizeByFile(reader, "", nil) client.Recognize(reader, nil)
client.AddStream(url, 7, "before", nil) client.Streams().Add(audd.AddStreamRequest{URL: url, RadioID: 7, Callbacks: "before"})
client.FindLyrics(query, nil) client.Advanced().FindLyrics(query)
client.SetCallbackUrl(url) client.Streams().SetCallbackUrl(url, nil)
client.GetStreams() client.Streams().List()
client.AddSongToCustomDB(id, src) client.CustomCatalog().Add(id, src)

See examples/migration_v0_to_v1 for a side-by-side runnable example.

Custom catalog (advanced)

[!WARNING] The custom-catalog endpoint is not music recognition. It adds songs to your account's private fingerprint database, so AudD's recognition can later identify your own tracks for your account only. If you intended to identify music, use client.Recognize (or client.RecognizeEnterprise for files longer than 25 seconds) instead.

err := client.CustomCatalog().Add(audioID, "/path/to/track.mp3")

Custom-catalog access requires a separate subscription. Contact api@audd.io to get it enabled.

Advanced

client.Advanced() exposes the typed FindLyrics(query) method plus a generic raw-method escape hatch for AudD endpoints not yet wrapped on this SDK:

body, err := client.Advanced().RawRequest("newMethodName", map[string]string{
    "param": "value",
})

License & support

MIT — see LICENSE. Security policy: SECURITY.md.

Bug reports and PRs welcome. For account / API questions, email api@audd.io.

Documentation

Overview

Package audd is the official Go SDK for the AudD music recognition API.

See https://docs.audd.io for the API reference and https://github.com/AudDMusic/audd-go for source.

Index

Constants

View Source
const Version = "1.5.13"

Version is the SDK version reported in the User-Agent header.

Variables

View Source
var (
	ErrAuthentication      = errors.New("audd: authentication error")
	ErrQuota               = errors.New("audd: quota exceeded")
	ErrSubscription        = errors.New("audd: endpoint not enabled on token")
	ErrCustomCatalogAccess = errors.New("audd: custom catalog access denied")
	ErrInvalidRequest      = errors.New("audd: invalid request")
	ErrInvalidAudio        = errors.New("audd: invalid audio")
	ErrRateLimit           = errors.New("audd: rate limit reached")
	ErrStreamLimit         = errors.New("audd: stream slot limit reached")
	ErrNotReleased         = errors.New("audd: song not yet released")
	ErrBlocked             = errors.New("audd: blocked by audd security")
	ErrNeedsUpdate         = errors.New("audd: client update required")
	ErrServer              = errors.New("audd: server error")

	ErrConnection    = errors.New("audd: connection error")
	ErrSerialization = errors.New("audd: serialization error")
)

Sentinels for errors.Is matching. Each AudD error code maps to one of these via *AudDAPIError.Is so callers can write:

if errors.Is(err, audd.ErrAuthentication) { ... }

while still extracting the typed *AudDAPIError via errors.As.

View Source
var ErrMissingAPIToken = errors.New(
	"audd: api_token not supplied and AUDD_API_TOKEN env var is unset; " +
		"get a token at https://dashboard.audd.io",
)

ErrMissingAPIToken is returned by NewClientStrict when neither a token argument nor the AUDD_API_TOKEN env var is set.

Functions

func DeriveLongpollCategory added in v1.3.0

func DeriveLongpollCategory(apiToken string, radioID int) string

DeriveLongpollCategory computes the 9-char longpoll category for a token + radio_id. Pure function — no network call.

Formula (per docs.audd.io/streams.md): hex-MD5 of (hex-MD5 of api_token, concatenated with the radio_id rendered as a decimal string), truncated to the first 9 hex chars.

Use this to share categories with browser/widget code without exposing the api_token.

func HandleCallback added in v1.5.0

HandleCallback reads and parses a callback POST body from an *http.Request. Closes the request body. Exactly one of (match, notification) is non-nil on success; both are nil on error.

Use in your HTTP handler that receives AudD callbacks:

match, notification, err := audd.HandleCallback(r)

func JoinProviders added in v1.5.12

func JoinProviders(providers ...string) string

JoinProviders joins provider names into the comma-separated string accepted by RecognizeOptions.Return and SetCallbackUrlOptions.ReturnMetadata. Useful when the caller already has a []string in hand from configuration or user input.

func ParseCallback added in v1.3.0

func ParseCallback(body []byte) (*StreamCallbackMatch, *StreamCallbackNotification, error)

ParseCallback parses a callback POST body into a typed match or notification. Recognition callbacks have an outer `result` block; notification callbacks have a `notification` block; the discrimination is by-key. Exactly one of (match, notification) is non-nil on success.

Prefer HandleCallback when you have an *http.Request — ParseCallback is for unusual transports (queue consumers, replay tools, raw bytes from a webhook framework).

Types

type AddStreamRequest added in v1.3.0

type AddStreamRequest struct {
	// URL is the stream URL. Accepts direct stream URLs (DASH, Icecast,
	// HLS, m3u/m3u8) and shortcuts: twitch:<channel>, youtube:<video_id>,
	// youtube-ch:<channel_id>.
	URL string
	// RadioID is the integer ID you assign to this stream slot.
	RadioID int
	// Callbacks: pass "before" to fire callbacks at song start (default is at song end).
	Callbacks string
	// ExtraParameters lets you pass additional form fields the typed
	// options don't cover. Typed fields take precedence on collision.
	ExtraParameters map[string]string
}

AddStreamRequest describes a stream to subscribe to.

type AdvancedClient added in v1.3.0

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

AdvancedClient is the escape-hatch namespace: lyrics search and a raw-method-name request helper. Reach via Client.Advanced().

This client uses the RECOGNITION retry policy — find_lyrics is metered, so we don't double-bill on read timeouts.

func (*AdvancedClient) FindLyrics added in v1.3.0

func (a *AdvancedClient) FindLyrics(query string) ([]LyricsResult, error)

FindLyrics is the no-context convenience wrapper around FindLyricsContext. Defaults to context.Background().

func (*AdvancedClient) FindLyricsContext added in v1.4.0

func (a *AdvancedClient) FindLyricsContext(ctx context.Context, query string) ([]LyricsResult, error)

FindLyricsContext searches AudD's lyrics database. Returns an empty slice on no match.

func (*AdvancedClient) RawRequest added in v1.3.0

func (a *AdvancedClient) RawRequest(method string, params map[string]string) (map[string]any, error)

RawRequest is the no-context convenience wrapper around RawRequestContext. Defaults to context.Background().

func (*AdvancedClient) RawRequestContext added in v1.4.0

func (a *AdvancedClient) RawRequestContext(ctx context.Context, method string, params map[string]string) (map[string]any, error)

RawRequestContext is the escape hatch for any AudD endpoint not yet wrapped by a typed method on this SDK. Hits `https://api.audd.io/<method>/` with the given form params and returns the parsed JSON body.

type AppleMusicMetadata added in v1.3.0

type AppleMusicMetadata struct {
	ArtistName       string `json:"artistName,omitempty"`
	URL              string `json:"url,omitempty"`
	DurationInMillis int    `json:"durationInMillis,omitempty"`
	Name             string `json:"name,omitempty"`
	ISRC             string `json:"isrc,omitempty"`
	AlbumName        string `json:"albumName,omitempty"`
	TrackNumber      int    `json:"trackNumber,omitempty"`
	ComposerName     string `json:"composerName,omitempty"`
	DiscNumber       int    `json:"discNumber,omitempty"`
	ReleaseDate      string `json:"releaseDate,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

AppleMusicMetadata is the Apple Music metadata block on a recognition. All fields are best-effort optional — the AudD payload is rich and changes over time.

func (*AppleMusicMetadata) UnmarshalJSON added in v1.3.0

func (a *AppleMusicMetadata) UnmarshalJSON(data []byte) error

type AudDAPIError added in v1.5.8

type AudDAPIError struct {
	// ErrorCode is AudD's numeric code (e.g. 900, 904). 0 indicates an HTTP-level
	// failure with no JSON body.
	ErrorCode int
	// Message is the server's human-readable message.
	Message string
	// HTTPStatus is the HTTP response status, if any.
	HTTPStatus int
	// RequestID is the X-Request-Id header from the response, if present.
	RequestID string
	// RequestedParams is the server's redacted echo of the request fields.
	RequestedParams map[string]any
	// RequestMethod is the server's `request_api_method` field (informational).
	RequestMethod string
	// BrandedMessage is the artist/title text from a branded denial response
	// (e.g. abuse-prevention "Sorry, your IP was banned"). Empty when absent.
	// Surfaced on the error, never as a recognition.
	BrandedMessage string
	// RawResponse is the unparsed response body (string or map[string]any).
	RawResponse any
}

AudDAPIError is the typed error returned for any `status: error` response from the AudD API. It also covers HTTP non-2xx with a non-JSON body (mapped to ErrServer with ErrorCode=0).

Use errors.As to extract:

var apiErr *audd.AudDAPIError
if errors.As(err, &apiErr) {
    fmt.Println(apiErr.ErrorCode, apiErr.Message)
}

func (*AudDAPIError) Error added in v1.5.8

func (e *AudDAPIError) Error() string

func (*AudDAPIError) Is added in v1.5.8

func (e *AudDAPIError) Is(target error) bool

Is allows errors.Is(err, audd.ErrAuthentication) etc. to match the right sentinel for the underlying AudD error code.

type AudDConnectionError added in v1.5.8

type AudDConnectionError struct {
	Message string
	Cause   error
}

AudDConnectionError wraps a transport-level failure (DNS, TCP, TLS, timeout). errors.Is(err, ErrConnection) returns true.

func (*AudDConnectionError) Error added in v1.5.8

func (e *AudDConnectionError) Error() string

func (*AudDConnectionError) Is added in v1.5.8

func (e *AudDConnectionError) Is(target error) bool

func (*AudDConnectionError) Unwrap added in v1.5.8

func (e *AudDConnectionError) Unwrap() error

type AudDCustomCatalogAccessError added in v1.5.8

type AudDCustomCatalogAccessError struct {
	*AudDAPIError
	ServerMessage string
}

AudDCustomCatalogAccessError is raised specifically from CustomCatalog.Add when the token lacks subscription access (codes 904/905 in that context). It carries an overridden user-facing message that disambiguates the custom-catalog footgun.

func (*AudDCustomCatalogAccessError) Error added in v1.5.8

func (*AudDCustomCatalogAccessError) Is added in v1.5.8

func (e *AudDCustomCatalogAccessError) Is(target error) bool

Is matches both the custom-catalog sentinel and the parent subscription sentinel.

type AudDEvent added in v1.5.8

type AudDEvent struct {
	Kind       string // "request" | "response" | "exception"
	Method     string // AudD method name, e.g. "recognize", "addStream"
	URL        string
	RequestID  string // X-Request-Id header value, if present
	HTTPStatus int    // 0 for request/exception kinds
	Elapsed    time.Duration
	ErrorCode  int // AudD error_code, if any
	Extras     map[string]any
}

AudDEvent is emitted by the SDK request lifecycle when an OnEvent hook is registered. Frozen plain-data; never carries the api_token or request body bytes.

type AudDSerializationError added in v1.5.8

type AudDSerializationError struct {
	Message string
	RawText string
}

AudDSerializationError is returned for 2xx HTTP responses whose body is not parseable as the expected JSON shape.

func (*AudDSerializationError) Error added in v1.5.8

func (e *AudDSerializationError) Error() string

func (*AudDSerializationError) Is added in v1.5.8

func (e *AudDSerializationError) Is(target error) bool

type AuddAPIError deprecated added in v1.3.0

type AuddAPIError = AudDAPIError

Audd* type aliases — the typed error and event symbols were renamed to AudD* (brand-correct PascalCase) in v1.5.7. The old names remain as aliases for code already on v1.5.6 or earlier; they will be removed in v2.0.0. Update to the AudD* names at your convenience.

Deprecated: use AudDAPIError.

type AuddConnectionError deprecated added in v1.3.0

type AuddConnectionError = AudDConnectionError

Deprecated: use AudDConnectionError.

type AuddCustomCatalogAccessError deprecated added in v1.3.0

type AuddCustomCatalogAccessError = AudDCustomCatalogAccessError

Deprecated: use AudDCustomCatalogAccessError.

type AuddEvent deprecated added in v1.3.0

type AuddEvent = AudDEvent

Deprecated: use AudDEvent.

type AuddSerializationError deprecated added in v1.3.0

type AuddSerializationError = AudDSerializationError

Deprecated: use AudDSerializationError.

type Client

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

Client is the top-level AudD SDK client. Construct with NewClient(token, ...).

Methods that perform I/O take a context.Context as their first argument and honor its deadline / cancellation. Sub-clients (Streams, CustomCatalog, Advanced) are accessed via methods on this Client.

Client is safe for concurrent use; sub-clients share state.

func NewClient

func NewClient(token string, opts ...Option) *Client

NewClient builds an AudD client. Use the public token "test" for examples (capped at 10 requests). For production, get a token from dashboard.audd.io.

If token is empty, the SDK falls back to the AUDD_API_TOKEN environment variable. If that's also empty, NewClient returns a Client with an empty token; the first API call will fail with a clear error. Use NewClientStrict if you want construction-time validation.

func NewClientStrict added in v1.3.0

func NewClientStrict(token string, opts ...Option) (*Client, error)

NewClientStrict is NewClient with construction-time validation: returns ErrMissingAPIToken when no token is available.

func (*Client) APIToken added in v1.3.0

func (c *Client) APIToken() string

APIToken returns the in-effect token (after any rotation).

func (*Client) AddSongToCustomDB deprecated added in v1.3.0

func (c *Client) AddSongToCustomDB(audioID int, source any) error

AddSongToCustomDB is the deprecated flat-API wrapper for CustomCatalog.Add.

Deprecated: use client.CustomCatalog().Add(audioID, source) instead.

func (*Client) AddStream deprecated

func (c *Client) AddStream(streamURL string, radioID int, callbacks string, _ map[string]string) error

AddStream is the deprecated flat-API wrapper.

Deprecated: use client.Streams().Add(AddStreamRequest{...}) instead. This shim will be removed in v2.0.0.

func (*Client) Advanced added in v1.3.0

func (c *Client) Advanced() *AdvancedClient

Advanced returns the advanced sub-client (lyrics + escape-hatch raw_request). Uses the RECOGNITION retry policy because find_lyrics is metered.

func (*Client) Close added in v1.3.0

func (c *Client) Close() error

Close releases connections owned by the client. Safe to call multiple times. Implements io.Closer.

func (*Client) CustomCatalog added in v1.3.0

func (c *Client) CustomCatalog() *CustomCatalogClient

CustomCatalog returns the custom-catalog sub-client. Lazy-initialized.

func (*Client) DeleteStream deprecated

func (c *Client) DeleteStream(radioID int) error

DeleteStream is the deprecated flat-API wrapper.

Deprecated: use client.Streams().Delete(radioID) instead.

func (*Client) FindLyrics deprecated

func (c *Client) FindLyrics(query string, _ map[string]string) ([]LyricsResult, error)

FindLyrics is the deprecated flat-API wrapper.

Deprecated: use client.Advanced().FindLyrics(query) instead. This shim will be removed in v2.0.0.

func (*Client) GetCallbackUrl deprecated

func (c *Client) GetCallbackUrl() (string, error)

GetCallbackUrl is the deprecated flat-API wrapper.

Deprecated: use client.Streams().GetCallbackUrl() instead. This shim will be removed in v2.0.0.

func (*Client) GetStreams deprecated

func (c *Client) GetStreams() ([]Stream, error)

GetStreams is the deprecated flat-API wrapper.

Deprecated: use client.Streams().List() instead.

func (*Client) Recognize

func (c *Client) Recognize(source Source, opts *RecognizeOptions) (*Recognition, error)

Recognize is the no-context convenience wrapper around RecognizeContext. Defaults to context.Background(). Use RecognizeContext for cancellation, deadlines, or distributed tracing.

Source can be a URL string, a file path string, []byte, or io.Reader. See the Source type for details.

func (*Client) RecognizeByFile deprecated

func (c *Client) RecognizeByFile(file io.Reader, metadata string, options map[string]string) (*Song, error)

RecognizeByFile is the deprecated flat-API wrapper.

Deprecated: use client.Recognize(ctx, reader, &RecognizeOptions{...}) instead. This shim will be removed in v2.0.0.

func (*Client) RecognizeByUrl deprecated

func (c *Client) RecognizeByUrl(urlStr, metadata string, options map[string]string) (*Song, error)

RecognizeByUrl is the deprecated flat-API wrapper.

Deprecated: use client.Recognize(ctx, url, &RecognizeOptions{Return: ...}) instead. This shim will be removed in v2.0.0.

func (*Client) RecognizeContext added in v1.3.0

func (c *Client) RecognizeContext(ctx context.Context, source Source, opts *RecognizeOptions) (*Recognition, error)

RecognizeContext sends the source to the standard recognize endpoint and returns the typed result. Returns (nil, nil) when the server returns status=success with result=null (no match).

Source can be a URL string, a file path string, []byte, or io.Reader. See the Source type for details.

func (*Client) RecognizeEnterprise added in v1.3.0

func (c *Client) RecognizeEnterprise(source Source, opts *EnterpriseOptions) ([]EnterpriseMatch, error)

RecognizeEnterprise sends the source to the enterprise endpoint and returns the flattened list of matches. Empty slice when no matches were found. RecognizeEnterprise is the no-context convenience wrapper. Defaults to context.Background(). Use RecognizeEnterpriseContext for cancellation / deadline support — recommended for the enterprise endpoint, which can take up to an hour for very large files.

func (*Client) RecognizeEnterpriseContext added in v1.3.0

func (c *Client) RecognizeEnterpriseContext(ctx context.Context, source Source, opts *EnterpriseOptions) ([]EnterpriseMatch, error)

RecognizeEnterpriseContext sends the source to the enterprise recognize endpoint and returns the matches across all chunks of the response.

func (*Client) SetAPIToken added in v1.3.0

func (c *Client) SetAPIToken(newToken string) error

SetAPIToken atomically swaps the token used for subsequent requests. In-flight requests continue with the old token.

func (*Client) SetCallbackUrl deprecated

func (c *Client) SetCallbackUrl(callbackURL string) error

SetCallbackUrl is the deprecated flat-API wrapper.

Deprecated: use client.Streams().SetCallbackUrl(url, opts) instead. This shim will be removed in v2.0.0.

func (*Client) SetStreamUrl deprecated

func (c *Client) SetStreamUrl(radioID int, urlStr string) error

SetStreamUrl is the deprecated flat-API wrapper.

Deprecated: use client.Streams().SetURL(radioID, url) instead.

func (*Client) Streams added in v1.3.0

func (c *Client) Streams() *StreamsClient

Streams returns the streams sub-client. Lazy-initialized on first access.

type CustomCatalogClient added in v1.3.0

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

CustomCatalogClient handles uploads to your private fingerprint catalog.

**This is NOT how you submit audio for music recognition.** For recognition, use Client.Recognize (or Client.RecognizeEnterprise for files longer than 25 seconds). This client manipulates your **private fingerprint catalog** so AudD's recognition can later identify *your own* tracks for *your account only*. Requires special access — contact api@audd.io if you need it enabled.

func (*CustomCatalogClient) Add added in v1.3.0

func (cc *CustomCatalogClient) Add(audioID int, source Source) error

Add is the no-context convenience wrapper around AddContext. Defaults to context.Background().

**Reminder: this is NOT for music recognition.** For recognition, use Client.Recognize / Client.RecognizeEnterprise.

func (*CustomCatalogClient) AddContext added in v1.4.0

func (cc *CustomCatalogClient) AddContext(ctx context.Context, audioID int, source Source) error

AddContext fingerprints `source` and stores it under the given audio_id slot. Calling again with the same audio_id re-fingerprints that slot. There is no public list/delete endpoint; track audio_id ↔ song mappings on your side.

**Reminder: this is NOT for music recognition.** For recognition, use Client.Recognize / Client.RecognizeEnterprise.

type DeezerMetadata added in v1.3.0

type DeezerMetadata struct {
	ID       int    `json:"id,omitempty"`
	Title    string `json:"title,omitempty"`
	Duration int    `json:"duration,omitempty"`
	Link     string `json:"link,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

DeezerMetadata is the Deezer metadata block.

func (*DeezerMetadata) UnmarshalJSON added in v1.3.0

func (d *DeezerMetadata) UnmarshalJSON(data []byte) error

type EnterpriseChunkResult added in v1.3.0

type EnterpriseChunkResult struct {
	Songs  []EnterpriseMatch `json:"songs"`
	Offset string            `json:"offset"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

EnterpriseChunkResult wraps an array of matches for a single processed chunk of the enterprise upload (the response has one element per chunk).

func (*EnterpriseChunkResult) UnmarshalJSON added in v1.3.0

func (r *EnterpriseChunkResult) UnmarshalJSON(data []byte) error

type EnterpriseMatch added in v1.3.0

type EnterpriseMatch struct {
	Score       int    `json:"score"`
	Timecode    string `json:"timecode"`
	Artist      string `json:"artist,omitempty"`
	Title       string `json:"title,omitempty"`
	Album       string `json:"album,omitempty"`
	ReleaseDate string `json:"release_date,omitempty"`
	Label       string `json:"label,omitempty"`
	ISRC        string `json:"isrc,omitempty"`
	UPC         string `json:"upc,omitempty"`
	SongLink    string `json:"song_link,omitempty"`
	StartOffset int    `json:"start_offset,omitempty"`
	EndOffset   int    `json:"end_offset,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

EnterpriseMatch is one match within a chunk of the enterprise endpoint's response. Multiple matches per file are common.

func (*EnterpriseMatch) StreamingURL added in v1.3.0

func (m *EnterpriseMatch) StreamingURL(provider StreamingProvider) string

StreamingURL returns the lis.tn redirect URL for a streaming provider, or "" when SongLink is non-lis.tn (EnterpriseMatch doesn't have full metadata blocks; only the lis.tn redirect path applies).

func (*EnterpriseMatch) StreamingURLs added in v1.3.0

func (m *EnterpriseMatch) StreamingURLs() map[StreamingProvider]string

StreamingURLs returns all providers with a lis.tn redirect URL available.

func (*EnterpriseMatch) ThumbnailURL added in v1.3.0

func (m *EnterpriseMatch) ThumbnailURL() string

ThumbnailURL returns the cover-art URL for lis.tn-hosted song_links, else "".

func (*EnterpriseMatch) UnmarshalJSON added in v1.3.0

func (m *EnterpriseMatch) UnmarshalJSON(data []byte) error

UnmarshalJSON for EnterpriseMatch.

type EnterpriseOptions added in v1.3.0

type EnterpriseOptions struct {
	// Return is the comma-separated list of metadata sources to include
	// (e.g. "apple_music,spotify"). Valid values: "apple_music", "spotify",
	// "deezer", "napster", "musicbrainz".
	Return           string
	Skip             *int
	Every            *int
	Limit            *int
	SkipFirstSeconds *int
	UseTimecode      *bool
	AccurateOffsets  *bool
	Timeout          time.Duration
	// ExtraParameters lets you pass additional form fields the typed
	// options don't cover. Typed fields take precedence on collision.
	ExtraParameters map[string]string
}

EnterpriseOptions controls the enterprise recognize endpoint.

type LongpollConsumer added in v1.3.0

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

LongpollConsumer is the tokenless long-polling consumer. Use it from browser/widget/extension contexts where you only have a category (and no api_token).

Implements io.Closer (Close releases the owned HTTP transport).

Hardening:

  • HTTP non-2xx → channel emits an event with Err set to *AudDAPIError mapped to ErrServer.
  • JSON decode failure on a 2xx → emits Err *AudDSerializationError.
  • READ-class retries on 5xx + connection errors with configurable MaxAttempts / BackoffFactor for parity with the authenticated client.

func NewLongpollConsumer added in v1.3.0

func NewLongpollConsumer(category string, opts ...LongpollConsumerOption) *LongpollConsumer

NewLongpollConsumer builds a tokenless consumer for the given category.

func (*LongpollConsumer) Close added in v1.3.0

func (c *LongpollConsumer) Close() error

Close releases the owned HTTP transport. Idempotent.

func (*LongpollConsumer) Iterate added in v1.3.0

Iterate is the no-context convenience wrapper around IterateContext. Defaults to context.Background(). Callers that want to stop the background goroutine without draining the channels should use IterateContext with a cancellable context (or call Close on the returned poll).

func (*LongpollConsumer) IterateContext added in v1.4.0

func (c *LongpollConsumer) IterateContext(ctx context.Context, opts *LongpollConsumerOptions) *LongpollPoll

IterateContext returns a LongpollPoll whose Matches / Notifications / Errors channels are filled by a background goroutine. The poll terminates when ctx is cancelled, Close() is called, or a terminal error fires.

Tokenless: no api_token is sent. The category alone authorizes the subscription. The user/server who derived the category is responsible for ensuring a callback URL is configured on their account (we can't preflight that without a token).

type LongpollConsumerOption added in v1.3.0

type LongpollConsumerOption func(*LongpollConsumer)

LongpollConsumerOption configures a LongpollConsumer.

func LongpollConsumerWithBackoffFactor added in v1.3.0

func LongpollConsumerWithBackoffFactor(d time.Duration) LongpollConsumerOption

LongpollConsumerWithBackoffFactor overrides the default initial-backoff.

func LongpollConsumerWithHTTPClient added in v1.3.0

func LongpollConsumerWithHTTPClient(hc *http.Client) LongpollConsumerOption

LongpollConsumerWithHTTPClient injects a caller-managed *http.Client.

func LongpollConsumerWithMaxAttempts added in v1.3.0

func LongpollConsumerWithMaxAttempts(n int) LongpollConsumerOption

LongpollConsumerWithMaxAttempts overrides the default retry attempts.

type LongpollConsumerOptions added in v1.3.0

type LongpollConsumerOptions struct {
	SinceTime int
	Timeout   int
}

LongpollConsumerOptions controls a single Iterate call.

type LongpollOptions added in v1.3.0

type LongpollOptions struct {
	// SinceTime is the unix timestamp to resume from. 0 means "start from now".
	SinceTime int
	// Timeout is the longpoll timeout in seconds (server-side default: 50).
	Timeout int
	// SkipCallbackCheck disables the preflight that detects the "no callback URL"
	// misconfiguration. Default false (preflight is on).
	SkipCallbackCheck bool
}

LongpollOptions controls the longpoll iterator. Zero values use sane defaults.

type LongpollPoll added in v1.5.0

type LongpollPoll struct {
	// Matches yields one StreamCallbackMatch per recognition. Closed when
	// the poll terminates.
	Matches <-chan StreamCallbackMatch
	// Notifications yields stream-lifecycle events.
	Notifications <-chan StreamCallbackNotification
	// Errors yields a single terminal error and then closes. After an
	// error fires, Matches and Notifications close too.
	Errors <-chan error
	// contains filtered or unexported fields
}

LongpollPoll is an active long-poll subscription. Three typed channels surface its output; consume them with `select`. Errors is single-shot and closing — when an error fires, the consumer is terminal.

Closing the parent context (or calling Close) tears down the background poller and closes all channels.

func (*LongpollPoll) Close added in v1.5.0

func (p *LongpollPoll) Close() error

Close stops the background poll. Idempotent.

type LyricsResult

type LyricsResult struct {
	Artist    string `json:"artist"`
	Title     string `json:"title"`
	Lyrics    string `json:"lyrics,omitempty"`
	SongID    int    `json:"song_id,omitempty"`
	Media     string `json:"media,omitempty"`
	FullTitle string `json:"full_title,omitempty"`
	ArtistID  int    `json:"artist_id,omitempty"`
	SongLink  string `json:"song_link,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

LyricsResult is one entry in the findLyrics response array.

func (*LyricsResult) UnmarshalJSON added in v1.3.0

func (l *LyricsResult) UnmarshalJSON(data []byte) error

type MusicBrainzEntry added in v1.3.0

type MusicBrainzEntry struct {
	ID     string          `json:"id"`
	Score  json.RawMessage `json:"score,omitempty"` // server returns int OR string
	Title  string          `json:"title,omitempty"`
	Length int             `json:"length,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

MusicBrainzEntry is one entry in the `musicbrainz` array.

func (*MusicBrainzEntry) UnmarshalJSON added in v1.3.0

func (m *MusicBrainzEntry) UnmarshalJSON(data []byte) error

type NapsterMetadata added in v1.3.0

type NapsterMetadata struct {
	ID         string `json:"id,omitempty"`
	Name       string `json:"name,omitempty"`
	ISRC       string `json:"isrc,omitempty"`
	ArtistName string `json:"artistName,omitempty"`
	AlbumName  string `json:"albumName,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

NapsterMetadata is the Napster metadata block.

func (*NapsterMetadata) UnmarshalJSON added in v1.3.0

func (n *NapsterMetadata) UnmarshalJSON(data []byte) error

type OnEventHook added in v1.3.0

type OnEventHook func(AudDEvent)

OnEventHook is the signature for the inspection hook. Hook errors are swallowed by the SDK so observability never breaks the request path.

type Option added in v1.3.0

type Option func(*Client)

Option configures a Client. Pass via NewClient(token, opts...).

func WithBackoffFactor added in v1.3.0

func WithBackoffFactor(d time.Duration) Option

WithBackoffFactor overrides the default initial-backoff for retries.

func WithEnterpriseTimeout added in v1.3.0

func WithEnterpriseTimeout(d time.Duration) Option

WithEnterpriseTimeout overrides the per-request timeout for enterprise endpoints.

func WithHTTPClient added in v1.3.0

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient injects a caller-managed *http.Client. Useful for corporate proxies, mTLS, observability. The same client is used for both the standard and enterprise transports.

func WithMaxAttempts added in v1.3.0

func WithMaxAttempts(n int) Option

WithMaxAttempts overrides the default retry attempt count for all classes.

func WithOnDeprecation added in v1.3.0

func WithOnDeprecation(fn func(string)) Option

WithOnDeprecation registers a hook called when the server returns a code-51 deprecation warning alongside a usable result. Default is a stdlib log.Println. Pass a no-op to silence.

func WithOnEvent added in v1.3.0

func WithOnEvent(fn OnEventHook) Option

WithOnEvent registers an inspection hook that receives lifecycle events (request/response/exception) for every API call. Off by default. Hook panics/errors are recovered and ignored.

func WithStandardTimeout added in v1.3.0

func WithStandardTimeout(d time.Duration) Option

WithStandardTimeout overrides the per-request timeout for non-enterprise endpoints.

type Recognition added in v1.3.0

type Recognition struct {
	Timecode    string              `json:"timecode"`
	AudioID     *int                `json:"audio_id,omitempty"`
	Artist      string              `json:"artist,omitempty"`
	Title       string              `json:"title,omitempty"`
	Album       string              `json:"album,omitempty"`
	ReleaseDate string              `json:"release_date,omitempty"`
	Label       string              `json:"label,omitempty"`
	SongLink    string              `json:"song_link,omitempty"`
	ISRC        string              `json:"isrc,omitempty"`
	UPC         string              `json:"upc,omitempty"`
	AppleMusic  *AppleMusicMetadata `json:"apple_music,omitempty"`
	Spotify     *SpotifyMetadata    `json:"spotify,omitempty"`
	Deezer      *DeezerMetadata     `json:"deezer,omitempty"`
	Napster     *NapsterMetadata    `json:"napster,omitempty"`
	MusicBrainz []MusicBrainzEntry  `json:"musicbrainz,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

Recognition is the typed result of Client.Recognize. Public-DB matches populate Artist/Title/etc.; custom-DB matches populate AudioID instead. Use IsPublicMatch / IsCustomMatch to discriminate.

func (*Recognition) IsCustomMatch added in v1.3.0

func (r *Recognition) IsCustomMatch() bool

IsCustomMatch reports whether this is a custom-DB match (audio_id populated).

func (*Recognition) IsPublicMatch added in v1.3.0

func (r *Recognition) IsPublicMatch() bool

IsPublicMatch reports whether this is a public-DB match (artist/title set, audio_id absent).

func (*Recognition) PreviewURL added in v1.3.0

func (r *Recognition) PreviewURL() string

PreviewURL returns the first available 30-second preview URL across apple_music.previews[0].url → spotify.preview_url → deezer.preview, in that priority order. Empty string if no metadata block carries a preview.

Note: previews are governed by the respective providers' terms of use (Apple Music, Spotify, Deezer). The SDK consumer is responsible for honoring caching/attribution/redistribution constraints.

func (*Recognition) StreamingURL added in v1.3.0

func (r *Recognition) StreamingURL(provider StreamingProvider) string

StreamingURL returns a direct or redirect URL for a streaming provider.

Resolution order:

  1. Direct URL from the metadata block (apple_music.url, spotify.external_urls.spotify, deezer.link, napster.href) when the user requested that provider via Return. Direct = no redirect, faster.
  2. lis.tn redirect "<SongLink>?<provider>" when SongLink is on lis.tn.
  3. "" otherwise. YouTube has no metadata-block fallback.

func (*Recognition) StreamingURLs added in v1.3.0

func (r *Recognition) StreamingURLs() map[StreamingProvider]string

StreamingURLs returns the union of all providers with a resolvable URL — direct or via lis.tn redirect. Empty map when neither path resolves.

func (*Recognition) ThumbnailURL added in v1.3.0

func (r *Recognition) ThumbnailURL() string

ThumbnailURL returns the cover-art URL for lis.tn-hosted song_links, else "". YouTube and other hosts return "".

func (*Recognition) UnmarshalJSON added in v1.3.0

func (r *Recognition) UnmarshalJSON(data []byte) error

UnmarshalJSON populates Extras + RawResponse alongside the typed fields.

type RecognizeOptions added in v1.3.0

type RecognizeOptions struct {
	// Return is the comma-separated list of metadata sources to include
	// (e.g. "apple_music,spotify"). Valid values: "apple_music", "spotify",
	// "deezer", "napster", "musicbrainz".
	Return string
	// Market is the ISO country code (server default: "us").
	Market string
	// Timeout overrides the per-request HTTP timeout for this call only.
	Timeout time.Duration
	// ExtraParameters lets you pass additional form fields the typed
	// options don't cover — undocumented parameters, beta features, or
	// any other API field not yet surfaced as a typed property. Typed
	// fields take precedence: if a key here collides with a typed field
	// that's been set, the typed value wins.
	ExtraParameters map[string]string
}

RecognizeOptions controls the standard recognize endpoint.

type RetryClass added in v1.3.0

type RetryClass int

RetryClass determines retry semantics.

RetryClassRead        — idempotent reads (Streams.List, Streams.GetCallbackUrl):
                        retry on 408/429/5xx + any connection error.
RetryClassRecognition — Recognize, RecognizeEnterprise, Advanced.FindLyrics:
                        retry on pre-upload connection failures + 5xx.
                        DO NOT retry on read-timeout-after-upload (cost protection).
RetryClassMutating    — Streams.Add, Streams.Delete, etc.:
                        retry only on pre-upload connection failures.
                        DO NOT retry 5xx (the side effect may have happened).
                        NOTE: CustomCatalog.Add does NOT use this class —
                        upload is metered, so it pins to 1 attempt to
                        avoid double-charging on transient failures.
const (
	// RetryClassRead is for idempotent read endpoints.
	RetryClassRead RetryClass = iota
	// RetryClassRecognition is for cost-metered recognition endpoints.
	RetryClassRecognition
	// RetryClassMutating is for endpoints with server-side side effects.
	RetryClassMutating
)

type RetryPolicy added in v1.3.0

type RetryPolicy struct {
	Class         RetryClass
	MaxAttempts   int           // default 3 (retryDo applies the default if 0)
	BackoffFactor time.Duration // default 500ms; doubles per attempt with jitter
	BackoffMax    time.Duration // default 30s; upper cap on a single delay
}

RetryPolicy controls automatic retries. Zero value means "use defaults" when passed to retryDo.

type SetCallbackUrlOptions added in v1.3.0

type SetCallbackUrlOptions struct {
	// ReturnMetadata, if non-empty, is added as a `?return=<csv>` query
	// parameter on the callback URL (e.g. "apple_music,spotify"). If the
	// URL already has a `return` param, the call returns an error rather
	// than silently overwriting.
	ReturnMetadata string
	// ExtraParameters lets you pass additional form fields on the
	// setCallbackUrl call itself (not appended to the callback URL).
	// Typed fields take precedence on collision.
	ExtraParameters map[string]string
}

SetCallbackUrlOptions controls SetCallbackUrl.

type Song deprecated added in v1.3.0

type Song = Recognition

Song is the legacy result-shape alias used by the v0 RecognizeByUrl / RecognizeByFile / FindLyrics signatures. Internally it's the same as Recognition (and LyricsResult, depending on the call-site).

Deprecated: use Recognition / LyricsResult.

type Source added in v1.3.0

type Source any

Source is what callers pass to Recognize / RecognizeEnterprise. Acceptable concrete types are:

  • string — an HTTP(S) URL or an existing file path on disk.
  • []byte — raw bytes; safe to retry.
  • io.Reader — caller's choice. Must be an io.Seeker if retries are possible; non-seekers will surface a clean error on attempt 2 rather than silently sending an empty body.

(We don't define this as a closed sum type because Go interfaces don't constrain that way; runtime type-switches in prepareSource accept the supported set and reject everything else.)

type SpotifyMetadata added in v1.3.0

type SpotifyMetadata struct {
	ID          string `json:"id,omitempty"`
	Name        string `json:"name,omitempty"`
	DurationMs  int    `json:"duration_ms,omitempty"`
	Explicit    bool   `json:"explicit,omitempty"`
	Popularity  int    `json:"popularity,omitempty"`
	TrackNumber int    `json:"track_number,omitempty"`
	Type        string `json:"type,omitempty"`
	URI         string `json:"uri,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

SpotifyMetadata is the Spotify metadata block on a recognition.

func (*SpotifyMetadata) UnmarshalJSON added in v1.3.0

func (s *SpotifyMetadata) UnmarshalJSON(data []byte) error

type Stream

type Stream struct {
	RadioID          int    `json:"radio_id"`
	URL              string `json:"url"`
	StreamRunning    bool   `json:"stream_running"`
	LongpollCategory string `json:"longpoll_category,omitempty"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

Stream describes one running stream subscription.

func (*Stream) UnmarshalJSON added in v1.3.0

func (s *Stream) UnmarshalJSON(data []byte) error

type StreamCallbackMatch added in v1.5.0

type StreamCallbackMatch struct {
	RadioID    int64  `json:"radio_id"`
	Timestamp  string `json:"timestamp,omitempty"`
	PlayLength int    `json:"play_length,omitempty"`

	Song         StreamCallbackSong   `json:"-"`
	Alternatives []StreamCallbackSong `json:"-"`

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

StreamCallbackMatch is one recognition event from a stream callback or longpoll. Carries the top match in Song; rare extra candidates (which may have a different artist or title — variant releases, near-duplicates) live in Alternatives.

type StreamCallbackNotification added in v1.3.0

type StreamCallbackNotification struct {
	RadioID             int    `json:"radio_id"`
	StreamRunning       *bool  `json:"stream_running,omitempty"`
	NotificationCode    int    `json:"notification_code"`
	NotificationMessage string `json:"notification_message"`
	Time                int    `json:"-"` // outer `time` field (not nested under `notification`)

	Extras      map[string]json.RawMessage `json:"-"`
	RawResponse json.RawMessage            `json:"-"`
}

StreamCallbackNotification is the lifecycle-event variant of a stream callback (e.g. "stream stopped", "can't connect").

func (*StreamCallbackNotification) UnmarshalJSON added in v1.3.0

func (n *StreamCallbackNotification) UnmarshalJSON(data []byte) error

type StreamCallbackSong added in v1.5.0

type StreamCallbackSong struct {
	Score       int                 `json:"score"`
	Artist      string              `json:"artist"`
	Title       string              `json:"title"`
	Album       string              `json:"album,omitempty"`
	ReleaseDate string              `json:"release_date,omitempty"`
	Label       string              `json:"label,omitempty"`
	SongLink    string              `json:"song_link,omitempty"`
	ISRC        string              `json:"isrc,omitempty"`
	UPC         string              `json:"upc,omitempty"`
	AppleMusic  *AppleMusicMetadata `json:"apple_music,omitempty"`
	Spotify     *SpotifyMetadata    `json:"spotify,omitempty"`
	Deezer      *DeezerMetadata     `json:"deezer,omitempty"`
	Napster     *NapsterMetadata    `json:"napster,omitempty"`
	MusicBrainz []MusicBrainzEntry  `json:"musicbrainz,omitempty"`

	Extras map[string]json.RawMessage `json:"-"`
}

StreamCallbackSong is one candidate song in a recognition match. Almost every match has exactly one Song; multiple candidates only appear when the same fingerprint resolves to several near-identical catalog records.

func (*StreamCallbackSong) UnmarshalJSON added in v1.5.0

func (s *StreamCallbackSong) UnmarshalJSON(data []byte) error

type StreamingProvider added in v1.3.0

type StreamingProvider string

StreamingProvider names the streaming services reachable via the lis.tn `?<provider>` redirect helper.

const (
	ProviderSpotify    StreamingProvider = "spotify"
	ProviderAppleMusic StreamingProvider = "apple_music"
	ProviderDeezer     StreamingProvider = "deezer"
	ProviderNapster    StreamingProvider = "napster"
	ProviderYouTube    StreamingProvider = "youtube"
)

type StreamsClient added in v1.3.0

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

StreamsClient handles stream-management methods (set callback URL, add/remove streams, list, longpoll). Reach via Client.Streams().

func (*StreamsClient) Add added in v1.3.0

func (s *StreamsClient) Add(req AddStreamRequest) error

Add is the no-context convenience wrapper around AddContext. Defaults to context.Background().

func (*StreamsClient) AddContext added in v1.4.0

func (s *StreamsClient) AddContext(ctx context.Context, req AddStreamRequest) error

AddContext subscribes the account to the given stream.

func (*StreamsClient) Delete added in v1.3.0

func (s *StreamsClient) Delete(radioID int) error

Delete is the no-context convenience wrapper around DeleteContext. Defaults to context.Background().

func (*StreamsClient) DeleteContext added in v1.4.0

func (s *StreamsClient) DeleteContext(ctx context.Context, radioID int) error

DeleteContext removes a stream subscription.

func (*StreamsClient) DeriveLongpollCategory added in v1.3.0

func (s *StreamsClient) DeriveLongpollCategory(radioID int) string

DeriveLongpollCategory computes the 9-char longpoll category locally for the authenticated client's token + radio_id. No network call. Useful for sharing categories with browser/widget code without leaking the api_token.

func (*StreamsClient) GetCallbackUrl added in v1.3.0

func (s *StreamsClient) GetCallbackUrl() (string, error)

GetCallbackUrl is the no-context convenience wrapper around GetCallbackUrlContext. Defaults to context.Background().

func (*StreamsClient) GetCallbackUrlContext added in v1.4.0

func (s *StreamsClient) GetCallbackUrlContext(ctx context.Context) (string, error)

GetCallbackUrlContext returns the configured callback URL, or "" if none is set (server returns error #19 in that case, which we surface as ErrInvalidRequest).

func (*StreamsClient) List added in v1.3.0

func (s *StreamsClient) List() ([]Stream, error)

List is the no-context convenience wrapper around ListContext. Defaults to context.Background().

func (*StreamsClient) ListContext added in v1.4.0

func (s *StreamsClient) ListContext(ctx context.Context) ([]Stream, error)

ListContext returns all configured streams.

func (*StreamsClient) Longpoll added in v1.3.0

func (s *StreamsClient) Longpoll(category string, opts *LongpollOptions) (*LongpollPoll, error)

Longpoll is the no-context convenience wrapper around LongpollContext. Defaults to context.Background(). Callers wanting cancellation should use LongpollContext or rely on the poll's Close() method.

func (*StreamsClient) LongpollByRadioID added in v1.5.8

func (s *StreamsClient) LongpollByRadioID(radioID int, opts *LongpollOptions) (*LongpollPoll, error)

LongpollByRadioID is the no-context convenience wrapper around LongpollByRadioIDContext. Defaults to context.Background().

One-step entry point for the common case where the caller has the api_token + radio_id and wants a longpoll subscription without computing the category by hand. Equivalent to:

category := audd.DeriveLongpollCategory(token, radioID)
poll, err := client.Streams().Longpoll(category, opts)

The category-string form (Longpoll / LongpollContext) is still the path for tokenless consumers — the server derives the category and ships only the 9-char string to a browser/mobile/embedded client.

func (*StreamsClient) LongpollByRadioIDContext added in v1.5.8

func (s *StreamsClient) LongpollByRadioIDContext(ctx context.Context, radioID int, opts *LongpollOptions) (*LongpollPoll, error)

LongpollByRadioIDContext derives the longpoll category locally from the authenticated client's token + radioID and starts a long-poll subscription. Same retry/timeout/preflight policy as LongpollContext.

func (*StreamsClient) LongpollContext added in v1.4.0

func (s *StreamsClient) LongpollContext(ctx context.Context, category string, opts *LongpollOptions) (*LongpollPoll, error)

LongpollContext starts a long-poll subscription. Returns a LongpollPoll whose Matches / Notifications / Errors channels are filled by a background goroutine. The goroutine exits when ctx is cancelled, the poll's Close() is called, or a terminal error fires (which is sent on Errors then closes all three channels).

On entry, runs a preflight GetCallbackUrlContext() unless SkipCallbackCheck is set — catches the common silent-failure mode where no callback URL is configured.

func (*StreamsClient) SetCallbackUrl added in v1.3.0

func (s *StreamsClient) SetCallbackUrl(urlStr string, opts *SetCallbackUrlOptions) error

SetCallbackUrl is the no-context convenience wrapper around SetCallbackUrlContext. Defaults to context.Background(). Use SetCallbackUrlContext for cancellation, deadlines, or distributed tracing.

func (*StreamsClient) SetCallbackUrlContext added in v1.4.0

func (s *StreamsClient) SetCallbackUrlContext(ctx context.Context, urlStr string, opts *SetCallbackUrlOptions) error

SetCallbackUrlContext tells AudD to POST recognition results for your account to `url`.

func (*StreamsClient) SetURL added in v1.3.0

func (s *StreamsClient) SetURL(radioID int, urlStr string) error

SetURL is the no-context convenience wrapper around SetURLContext. Defaults to context.Background().

func (*StreamsClient) SetURLContext added in v1.4.0

func (s *StreamsClient) SetURLContext(ctx context.Context, radioID int, urlStr string) error

SetURLContext changes the stream URL for an existing radio_id.

Directories

Path Synopsis
examples module
custom_catalog_add command
Add a song to your private fingerprint catalog.
Add a song to your private fingerprint catalog.
migration_v0_to_v1 command
Side-by-side: v0 deprecated flat API vs v1 namespaced API.
Side-by-side: v0 deprecated flat API vs v1 namespaced API.
observability_slog command
Bridge the SDK's OnEvent hook to log/slog so every request, response, and exception lands as a structured JSON record on stdout.
Bridge the SDK's OnEvent hook to log/slog so every request, response, and exception lands as a structured JSON record on stdout.
recognize_enterprise command
Recognize a long file via the enterprise endpoint.
Recognize a long file via the enterprise endpoint.
recognize_file command
Recognize a song from a local file.
Recognize a song from a local file.
recognize_url command
Recognize a song from a URL using the public test token.
Recognize a song from a URL using the public test token.
streams_callback_handler command
Receive AudD stream callbacks via a net/http handler.
Receive AudD stream callbacks via a net/http handler.
streams_longpoll command
Subscribe to longpoll events for a category.
Subscribe to longpoll events for a category.
streams_setup command
Configure streams: set the callback URL, add a stream, list streams.
Configure streams: set the callback URL, add a stream, list streams.

Jump to

Keyboard shortcuts

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