Listens to audio from your turntable or any physical source, identifies tracks with Shazam, scrobbles them to Last.fm, and saves local listening statistics you can browse from any device on your network.
Runs fully headless on a Raspberry Pi — no display, no graphical environment required.
- Captures audio from your source (turntable USB output, splitter, or microphone).
- Identifies the track with Shazam (artist, album, genre, cover art).
- Scrobbles automatically to Last.fm.
- Saves local statistics to a SQLite database (artists, albums, tracks, genres, listening time).
- Serves a web dashboard accessible from any device on your local network.
!(https://i.imgur.com/hBoUxfR.png) Open from any device connected to your network:
http://<your-raspberry-ip>:8000 [Or the port that you designated in the setup]
Includes:
- Top artists
- Top albums
- Top tracks
- Genre breakdown
- Total listening time
- Full playback history
Filterable by: Today / Week / Month / Year / All time.
- Raspberry Pi running Raspberry Pi OS (Bookworm recommended)
- Python 3.11+
- Audio source connected (turntable USB output, splitter + USB converter, or microphone)
- (OPCIONAL)Last.fm account with API key and secret — https://www.last.fm/api/
- (OPCIONAL)Spotify account with API key and secret - https://developer.spotify.com/dashboard
# 1. Clone or extract the project
cd VinylScrobbler
# 2. Run setup (without sudo)
chmod +x setup.sh
./setup.shThe script will:
- Create a virtual environment and install dependencies
- Generate backend/config.py and backend.sh When the setup is over, you just execute it with
./backend.shThen you enter the dashboard, where it will
- Let you select the audio input device
- Ask for your Last.fm and Spotify credentials
chmod +x autostart_setup.sh
./autostart_setup.sh
# Run once with sudo to keep the service alive without an active login session:
sudo loginctl enable-linger $(whoami)This creates a systemd user service (VinylScrobbler.service) that starts with the system, no graphical session needed.
./backend.shVinylScrobbler/
├── backend/
│ ├── main.py — FastAPI: detection loop, WebSocket, stats API
│ ├── audio.py — Audio capture
│ ├── shazam_service.py — Track identification (includes genre extraction)
│ ├── lastfm_service.py — Last.fm scrobbling
│ ├── stats_service.py — SQLite: save and query statistics
│ ├── state.py — Global app state
│ ├── logger.py — Logging
│ └── config.py — Generated by setup.sh
├── stats_web/
│ └── index.html — Web dashboard (served at /)
├── setup.sh
├── autostart_setup.sh
└── requirements.txt
| Endpoint | Description |
|---|---|
| GET / | Stats dashboard |
| GET /api/now | Currently playing track (JSON) |
| GET /api/stats/summary?period=week | Summary: top artists, albums, tracks, genres, listening time |
| GET /api/stats/history?page=1 | Paginated playback history |
| WS /ws | WebSocket for real-time status updates |
period accepts: today, week, month, year, all
tail -f ~/logs/vinylscrobbler.logEdit backend/config.py directly. Common parameters:
| Parameter | Default | Description |
|---|---|---|
| CHUNK_SECONDS | 10 | Seconds of audio sent to Shazam per attempt |
| RETRY_DELAY | 15 | Seconds between identification attempts |
| SILENCE_TIMEOUT | 30 | Seconds of silence before switching to idle |
| VOLUME_THRESHOLD | 0.01 | Minimum RMS level to consider audio present |
Restart the service after changing config:
systemctl --user restart VinylScrobblerThere are three common ways to feed audio into VinylScrobbler:
- Direct USB output from the source (e.g. i use a Audio-Technica AT-LP120XUSB, so it has a native usb output).
- A splitter between the source and your amplifier, with one output going to a USB audio converter.
- A microphone positioned near the speakers — less precise, may trigger on ambient noise.