Skip to content

lelabdev/spotify-graph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

spotify-graph

Rust-powered musical graph — SQLite-backed, MCP-compatible, with a built-in local dashboard.

Why

Static playlists don't capture the fluid nature of musical tastes. spotify-graph models artists as a weighted graph where discovery happens through proximity — not platform algorithms.

Architecture

spotify-graph (single binary)
├── mcp        → MCP stdio server (current mode)
├── tracker    → Poll Last.fm (primary) + Spotify (fallback) → SQLite
└── serve      → axum HTTP API + Askama/HTMX dashboard

Everything in Rust. No Python, no Node, no separate services.

Data flow

  Spotify (listen) ──auto-scrobble──→ Last.fm (hub)
                                          │
                        ┌─────────────────┤
                        ▼                 ▼
                  plays history    similar artists + tags
                        │                 │
                        └────────┬────────┘
                                 ▼
                           SQLite (local)
                                 │
                    ┌────────────┼────────────┐
                    ▼            ▼            ▼
               MCP tools    REST API    Dashboard
              (stdio)      (axum)     (Askama+HTMX)

Stack

  • Rust — axum (HTTP), rmcp (MCP), rusqlite (SQLite), reqwest (API calls)
  • SQLite — single file, no ORM
  • Askama — compile-time HTML templates
  • HTMX — server-driven interactivity (no JS framework)
  • Cytoscape.js — graph visualization (bonus, post-v1)
  • Last.fm API — primary source for plays, tags, similar artists
  • Spotify API — fallback for plays + audio features

Data Model

Nodes — Artists / Tracks / Labels

Each node has 6 continuous axes (1–10) describing its sonic profile:

Axis 1 10
Energy Silence Full power
Tempo No beat 140+ BPM
Repetition Varied Pure hypnotic
Organic 100% synth 100% acoustic
Depth Surface Immersive / meditative
Brightness Dark Bright

Plus CSV tags, free-form notes, and an optional Spotify URI.

Edges — Relations

Types: similar_vibe, same_scene, same_label, influenced_by, collaborated_with, lastfm_similar

Each edge carries a weight (0–1) representing link strength.

Plays

Tracks played, sourced from Last.fm (primary) and Spotify (fallback). Artist, track name, timestamp, duration, URI.

Feedback (post-MVP)

liked / disliked / neutral per context (coding, chill, morning…).

CLI

# MCP server (stdio) — for Hermes/any MCP client
spotify-graph mcp

# Track plays — poll Last.fm + Spotify, enrich graph
spotify-graph tracker

# Serve dashboard + API
spotify-graph serve --port 3030

Default (no subcommand) starts MCP mode for backward compatibility.

API Endpoints

Reads

  • GET /api/stats — graph statistics
  • GET /api/plays?limit=50&offset=0&artist= — play history
  • GET /api/artists — artist list with tags
  • GET /api/artists/:name — artist detail + relations
  • GET /api/discover/:name?depth=2 — BFS traversal

Writes

  • POST /api/nodes — add a node
  • POST /api/edges — add a relation
  • PATCH /api/artists/:name — edit tags/axes/note
  • DELETE /api/nodes/:name — remove a node (cascade)

MCP Tools

Tool Description
spotify_graph_add_node Add a node with audio attributes
spotify_graph_link Link two nodes with a typed relation
spotify_graph_discover BFS traversal filtered by minimum weight
spotify_graph_log_play Log a single play event
spotify_graph_log_plays_batch Log multiple plays at once
spotify_graph_seed Bulk JSON import of nodes + edges
spotify_graph_stats Graph statistics

Configuration

# ~/.config/spotify-graph/config.toml

[server]
port = 3030
host = "0.0.0.0"

[database]
path = "~/.local/share/spotify-graph/graph.sqlite"

[lastfm]
api_key = "..."
username = "..."
rate_limit_ms = 250

[spotify]
client_id = "..."
auth_path = "~/.hermes/auth.json"

[tracker]
poll_interval_min = 120
max_similar_match = 0.4

Defaults are used if the file is missing. Override via SPOTIFY_GRAPH_* env vars.

Build

cargo build --release
# binary: target/release/spotify-graph

Dashboard Pages (v1)

Route Description
/ Quick stats
/plays Play history, filters, pagination
/artists Artist list + tags, inline edit
/artists/:name Detail: tags, axes, relations
/discover BFS discovery — interactive
/graph Force-directed visualization (Cytoscape.js, post-v1)

Project Structure (target)

spotify-graph/
├── src/
│   ├── main.rs           # CLI (clap subcommands)
│   ├── config.rs         # TOML config loading
│   ├── db/
│   │   ├── mod.rs
│   │   ├── schema.sql
│   │   └── queries.rs    # SQLite queries
│   ├── mcp/
│   │   ├── mod.rs
│   │   └── tools.rs      # MCP tool handlers
│   ├── tracker/
│   │   ├── mod.rs
│   │   ├── lastfm.rs     # Last.fm API client
│   │   └── spotify.rs    # Spotify API client
│   └── api/
│       ├── mod.rs
│       ├── routes.rs     # axum routes
│       ├── handlers.rs   # route handlers
│       ├── error.rs      # error types
│       └── templates/    # Askama HTML templates
│           ├── base.html
│           ├── index.html
│           ├── plays.html
│           ├── artists.html
│           ├── detail.html
│           └── discover.html
├── static/               # Cytoscape.js, HTMX, Tailwind
├── Cargo.toml
└── schema.sql

Roadmap

V0.1 — Foundation ✅

  • Schema + SQLite DB
  • 5 MCP tools (add_node, link, discover, seed, stats)
  • Initial dataset (Ludo's artists)
  • Python tracker (Spotify polling)

V2 — Full Rust + Dashboard 🚧

  • #21 — CLI subcommands (mcp / tracker / serve)
  • #22 — Last.fm tracker (primary) + Spotify fallback (Rust)
  • #23 — REST API (axum)
  • #24 — Dashboard (Askama + HTMX)
  • #25 — Graph visualization (Cytoscape.js)
  • #26 — Remove Python scripts
  • #27 — Config file (TOML)

Backlog

  • #17 — MCP tool: search
  • #18 — MCP tool: Graphviz export
  • Audio features from Spotify API (energy, tempo, etc.)
  • Feedback system (liked/disliked per context)

License

MITlelabdev

About

Music taste graph DB — Rust CLI for artist discovery via graph traversal

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors