Skip to content

Repository files navigation

DeckStream

Real-time DJ recommendation dashboard — load a track on deck 1 in Serato, instantly see the 10 best harmonically compatible tracks from your library.

How it works

Serato DJ Pro (deck 1)
    → serato_event_agent.py  (Windows host, ReadDirectoryChangesW)
    → Kafka topic: serato.track.events  (Redpanda broker)
    → Spark Structured Streaming  (Delta Lake lookup + Camelot scoring)
    → Kafka topic: serato.recommendations
    → SSE → browser  (sub-second latency)
  1. serato_event_agent.py watches master.sqlite on the Windows host. Only deck 1 triggers the pipeline — deck 2 (preparation) is ignored.
  2. Spark scores recommendations by harmonic key (Camelot Wheel), BPM, folder proximity, and acoustic similarity.
  3. Dashboard at http://localhost:8050 updates instantly via Server-Sent Events.

Requirements

  • Docker Desktop (Windows, with WSL2 backend)
  • Python 3.10+ on the Windows host (for serato_event_agent.py)
  • Serato DJ Pro 4+
  • NVIDIA GPU (optional — only needed for acoustic embeddings)

Quick start

1. Start the Docker stack

# First run — build images (takes a few minutes)
docker compose build

# Start all services
docker compose up -d

# Check everything is up
docker compose ps

2. Start the Windows host agent

Open a separate PowerShell terminal:

# Install dependencies once
pip install watchdog kafka-python

# Start the agent (keep this terminal open while mixing)
cd C:\Users\arnau\Documents\deckstream
python serato_event_agent.py

You should see:

INFO  Serato DB found — no active session yet (open Serato + load a track)
INFO  Kafka producer connected to localhost:19092
INFO  Watching : C:\Users\arnau\AppData\Local\Serato\Library

3. Open Serato DJ and load a track on deck 1

The agent will print:

INFO  Track changed → Your Track Title
INFO  → Produced to serato.track.events: /music/GENRE/track.mp3

Recommendations appear at http://localhost:8050 within ~1 second.


Services

URL Service Purpose
http://localhost:8050 Dashboard DJ view + library management
http://localhost:8080 Spark UI Spark cluster status
http://localhost:8090 Kafka UI Topics, consumer lag, message payloads, latency

Kafka UI — latency monitoring

Every recommendation message on serato.recommendations contains:

  • agent_ts — when the agent detected the track change
  • spark_ts — when Spark finished scoring

spark_ts − agent_ts = pipeline latency (typically 0.5–1.2 s).


Docker commands

# Normal start
docker compose up -d

# Rebuild after Dockerfile or dependency changes
docker compose build
docker compose up -d

# Force-recreate a specific service (picks up env var changes)
docker compose up -d --force-recreate dashboard
docker compose up -d --force-recreate stream-processor

# Restart streaming pipeline only
docker compose restart stream-processor

# Stop everything
docker compose down

# Follow logs
docker logs -f deckstream-dashboard
docker logs -f stream-processor
docker logs -f redpanda

# Check all container statuses
docker compose ps

Remote access (Tailscale)

Access the dashboard from your phone or any device without port forwarding.

Setup

# Install Tailscale on Windows
winget install tailscale.tailscale

Then install Tailscale on your phone (App Store / Play Store) and log in with the same account.

Usage

  1. Find your PC's Tailscale IP at login.tailscale.com/admin/machines (format: 100.x.x.x)
  2. On your phone: http://100.x.x.x:8050

Requirements:

  • docker compose up -d must be running on the Windows host
  • Tailscale must show "Connected" in the Windows system tray
  • The Docker port binding must be 0.0.0.0:8050 (not 127.0.0.1) — check docker-compose.yml

Ingesting your music library

Three phases — always run in order from the dashboard container:

# Phase 1 — scan audio files → extract metadata → Delta Lake
docker exec deckstream-dashboard python -m src.ingestion.cli ingest /music/HOUSE

# Phase 2 — generate acoustic embeddings (requires embedder container + GPU)
docker exec deckstream-dashboard python -m src.ingestion.cli embed /music/HOUSE

# Phase 3 — merge embeddings into Delta Lake
docker exec deckstream-dashboard python -m src.ingestion.cli merge

# Full pipeline in one command
docker exec deckstream-dashboard python -m src.ingestion.cli all /music/HOUSE

Or use the Library page at http://localhost:8050/library — paste a path, click Ingest.


Project structure

deckstream/
├── serato_event_agent.py          # Windows host agent (ReadDirectoryChangesW → Kafka)
├── src/
│   ├── dashboard/
│   │   ├── app.py                 # App factory, clientside SSE callback
│   │   ├── sse.py                 # SeratoSSEBroadcaster (Kafka consumer + fallback)
│   │   ├── scoring.py             # Hybrid additive scoring
│   │   ├── recommendation_engine.py  # Camelot Wheel 7-transition engine
│   │   ├── delta_utils.py         # PySpark Delta Lake queries + 3-layer cache
│   │   ├── serato_sqlite.py       # WAL-safe Serato SQLite reader
│   │   ├── layout.py              # All page layouts
│   │   ├── art.py                 # Album art cache
│   │   ├── colors.py              # Design tokens
│   │   ├── assets/
│   │   │   ├── style.css          # Glassmorphic design system
│   │   │   └── sse_client.js      # Browser EventSource client
│   │   └── callbacks/
│   │       ├── current_track.py   # Now Playing (fast path: Kafka / slow path: SQLite)
│   │       ├── recommendations.py # Recommendation rendering (fast path: Kafka payload)
│   │       ├── history.py         # Play history
│   │       ├── library.py         # Ingest / remove / embed jobs
│   │       └── routing.py         # Page routing
│   ├── streaming/
│   │   └── spark_recommender.py   # Spark Structured Streaming job
│   └── ingestion/
│       ├── cli.py                 # Entry point: ingest / embed / merge / all
│       ├── ingest.py              # Bulk PySpark ingestion (IngestionRunner)
│       ├── embedder.py            # Essentia discogs-effnet acoustic embeddings
│       ├── metadata_extractor.py  # mutagen tag extraction (MP3, FLAC, WAV)
│       ├── hierarchy_parser.py    # Path → party_type / genre / sub_genre / vibe
│       └── schema.py              # Spark schemas + Pandera validation
├── docs/
│   ├── schemas/
│   │   ├── live-workflow.md       # Mermaid: end-to-end live pipeline
│   │   └── ingestion-workflow.md  # Mermaid: three-phase ingestion
│   ├── EN/                        # English documentation
│   └── FR/                        # French documentation
├── data/                          # Delta Lake warehouse (git-ignored)
├── config/                        # config.yaml (scoring weights, paths)
├── Dockerfile                     # Spark + dashboard + ingestion image
├── Dockerfile.embedder            # Essentia GPU image
└── docker-compose.yml             # Full stack definition

Tech stack

Layer Technology Why
Event broker Redpanda (Kafka-compatible) Single container, no Zookeeper, ~512 MB RAM, <1 ms latency
Stream processor Spark Structured Streaming 500 ms micro-batch, Delta Lake integration, Camelot scoring
Storage Delta Lake (PySpark) ACID transactions, schema enforcement, time travel
Backend Python 3.11, PySpark 3.5 —
Frontend Dash 4.1, Plotly Reactive Python UI, SSE clientside callbacks
Live tracking Serato SQLite (master.sqlite) Serato DJ 4+ drops binary .session files, uses SQLite
Acoustic similarity Essentia discogs-effnet 200-dim embedding, GPU inference
Containerisation Docker, Docker Compose —
Remote access Tailscale (WireGuard) Phone access without port forwarding

Documentation

File Content
CLAUDE.md Full development guide — architecture, pitfalls, design decisions
docs/schemas/live-workflow.md Mermaid diagram — live pipeline
docs/schemas/ingestion-workflow.md Mermaid diagram — ingestion
docs/EN/ARCHITECTURE.md System architecture + latency budget
docs/EN/STREAMING.md Kafka/Redpanda/Spark deep dive (Netflix, Spotify, Uber, LinkedIn comparisons)
docs/EN/NOW_PLAYING.md Live detection implementation details
docs/EN/TECH_STACK.md Every tool and why it's there
docs/EN/SCORING.md Recommendation scoring algorithm
docs/EN/CAMELOT_WHEEL.md Camelot Wheel key compatibility reference
docs/EN/INGESTION.md Ingestion pipeline guide
docs/EN/TAILSCALE.md Remote access setup

About

Recommandation de musique en live depuis Serato.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages