wolframe-spotify-canvas 1.0.4

A Rust library for fetching Spotify Canvas (looping visuals) using the internal GraphQL Pathfinder API.
Documentation

Wolframe Spotify Canvas

Crates.io Docs.rs License Downloads

Rust library for fetching Spotify Canvas (looping visuals) via the internal GraphQL Pathfinder API.

English | Русский

This Rust library reverse-engineers the internal Spotify GraphQL Pathfinder API used by the official Spotify Web Player. It replaces the deprecated and non-functional REST API endpoints (canvaz-cache).


🚀 Features

  • Pathfinder API: Uses the correct api-partner.spotify.com/pathfinder/v2 endpoint with Persisted Queries.
  • Client Token Autonomy: Automatically fetches, generates, and manages the required client-token (imitating a real Web Player session).
  • Configurable: Built to withstand frontend updates. You can override the Persisted Query Hash and Operation Name if Spotify changes them.
  • Type-Safe: Robust error handling for network failures, missing tokens, and API changes.

📦 Installation

Add this to your Cargo.toml:

[dependencies]

wolframe-spotify-canvas = "1.0.0"

tokio = { version = "1", features = ["full", "macros"] }

Minimum Supported Rust Version (MSRV)

This crate requires Rust 1.83 or newer.

⚡ Usage

use wolframe_spotify_canvas::{CanvasClient, CanvasError};
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Get a valid Spotify Access Token (Bearer)
    //    You can grab this from the Spotify Web Player network tab (Authorization: Bearer ...)
    let access_token = env::var("SPOTIFY_TOKEN").expect("SPOTIFY_TOKEN not set");

    // 2. Initialize the client (now supports shared reqwest::Client if needed)
    let mut client = CanvasClient::new();

    // 3. Define a track URI (e.g., "KORE" by Zynyx)
    let track_uri = "spotify:track:72Xn6x8xqegX64AKeJDsZt";

    println!("Fetching canvas for: {}", track_uri);

    // 4. Fetch the canvas
    match client.get_canvas(track_uri, &access_token).await {
        Ok(canvas) => {
            println!("Canvas URL: {}", canvas.mp4_url);
        }
        Err(CanvasError::RateLimited { retry_after }) => {
            eprintln!("Rate limited! Retry after {:?}ms", retry_after);
        }
        Err(e) => eprintln!("Error: {}", e),
    }

    Ok(())
}

Check examples/simple.rs for a runnable example.

🔍 Observability

This crate uses tracing for structured logging.

Log Levels

  • INFO — Canvas fetch operations (default)
  • DEBUG — Token management internals
  • TRACE — Device ID generation, low-level details

Example Setup

tracing_subscriber::fmt()
    .with_env_filter("wolframe_spotify_canvas=debug")
    .init();

OpenTelemetry Integration

Spans are automatically propagated to distributed tracing backends (Jaeger, Datadog) when using tracing-opentelemetry.


🛠 Technical Details (Reverse Engineering)

Spotify moved away from the simple canvaz-cache REST API to a complex GraphQL implementation. This library bridges that gap.

The "Hash Trap"

Spotify's GraphQL API does not accept raw queries. It uses Persisted Queries, where the client sends a SHA-256 hash of the query.

  • Default Hash: 575138ab27cd5c1b3e54da54d0a7cc8d85485402de26340c2145f0f6bb5e7a9f (Hardcoded default, but overridable).
  • Operation Name: canvas (Crucial distinction: older attempts used getCanvas which returns 400).
  • Variable Name: trackUri (Crucial distinction: formerly uri).

Authentication

A standard access token is not enough. The API requires a client-token header.

  • This library emulates the flow of clienttoken.spotify.com, generating a random device_id and exchanging it for a valid, short-lived client-token.

🤝 Contributing

Contributions are welcome! Especially if Spotify updates their API hash—pull requests updating the DEFAULT_CANVAS_HASH are highly appreciated.

📄 License

MIT License. See LICENSE for details.


Built with ❤️ by the Wolframe Team.