A Last.fm scrobbler for macOS that works globally — across Spotify, Apple Music, YouTube, browsers, and anything else that plays audio on your Mac. Rewritten from scratch in Go with a full terminal UI and synchronized lyrics display.
- Scrobbles from any media source on macOS — not just dedicated music apps
- Detects and skips non-music content using parser rules
- Displays synchronized (LRC) lyrics with auto-scroll in the terminal
- Smart metadata extraction from video titles
- Secure credential storage via macOS Keychain
- Configurable parser rules via YAML
- Daemon mode for silent background operation
Before running, you need a Last.fm API account:
- Go to last.fm/api/account/create
- Fill in Application name (anything you like) and Application homepage
- Save your API key and Shared secret — you'll need these on first run
Keep these credentials private. BetterScrobbler stores them in your macOS Keychain.
Requirements: Go 1.22+, CMake, Perl, Git
git clone https://github.com/ecstasoy/BetterScrobblerGo.git
cd BetterScrobblerGo
./scripts/build.shThis compiles the mediaremote-adapter submodule and outputs a scrobbler binary in the project root.
./scrobblerOn first run, you'll be prompted to enter your API key and shared secret. These are stored in Keychain and won't be asked again. Your browser will open for Last.fm authorization — click Yes, allow access, then return to the terminal and press Enter.
./scrobblerThe terminal UI shows the currently playing track, playback progress, scrobble status, and synchronized lyrics. Keyboard shortcuts:
| Key | Action |
|---|---|
↑ / ↓ |
Scroll lyrics manually |
a |
Toggle auto-scroll |
s |
Toggle scrobbling for this session |
q |
Quit |
./scrobbler --daemon --log=/var/log/scrobbler.logDetaches from the terminal and runs silently in the background. A log path is required — there is no stdout in daemon mode.
To stop:
pkill scrobbler
# or, if you need to target a specific instance
kill $(pgrep scrobbler)scrobbler [flags]
Flags:
--daemon Run as a background daemon process
--no-lyrics Disable lyrics fetching and display
--plain-lyrics Prefer plain text lyrics over synced (LRC) lyrics
--quiet Minimal output (warnings and errors only)
--debug Enable verbose debug logging
--log PATH Write logs to file (default: stdout only)
--no-scrobble Dry-run mode — monitor without scrobbling
-v, --version Show version
Subcommands:
config export [path] Export current parser rules to YAML (default: parser_rules.yaml)
config reload Reload parser config from file without restarting
# Run as daemon with log file
./scrobbler --daemon --log=/var/log/scrobbler.log
# Run with debug logging to a file
./scrobbler --debug --log=/tmp/scrobbler.log
# Run without lyrics
./scrobbler --no-lyrics
# Dry-run (monitor only, no scrobbling)
./scrobbler --no-scrobble
# Export parser rules for customization
./scrobbler config export ~/.config/scrobbler/parser_rules.yaml~/.config/scrobbler/config.yaml:
lastfm:
api_key: "YOUR_API_KEY"
api_secret: "YOUR_API_SECRET"The session key is stored in Keychain, not this file.
BetterScrobbler parses raw media titles (especially video titles) to extract artist and track name. The default rules cover common formats, but you can customize them:
./scrobbler config export ~/.config/scrobbler/parser_rules.yaml
# edit the file, then:
./scrobbler config reloadSupported title formats out of the box:
Artist - Title
Artist: Title
Artist「Title」『Title』
Artist - Title (Official Music Video)
Artist - Title [2024]
Artist - Title @ Live Event
The parser automatically strips platform suffixes (- YouTube, - Topic, - VEVO, etc.) and common metadata tags.
By default, logs go to stdout (foreground mode only). Use --log PATH to write to a file.
# Foreground with file logging
./scrobbler --log=~/Library/Logs/scrobbler.log
# Daemon mode (log path required — no stdout)
./scrobbler --daemon --log=~/Library/Logs/scrobbler.log
# Watch logs in real time
tail -f ~/Library/Logs/scrobbler.logLog verbosity is controlled by --debug (all messages) and --quiet (warnings and errors only).
For audio files and streaming apps, metadata is usually clean and parsed correctly.
For video content (YouTube, Bilibili, etc.), BetterScrobbler does its best to extract artist and title from the video title — but non-standard naming will cause misses. If something looks wrong, check whether the video title matches one of the supported formats above.
Non-music content (podcasts, interviews, news, tutorials, gameplay, etc.) is filtered out automatically when detected.
BetterScrobbler is structured in clean, separated layers:
platform/ macOS MediaRemote adapter (Perl bridge) + AppleScript fallback
music/ Metadata extraction and validation
core/ Business logic — track state, scrobble timer, submission
scrobbler/ Last.fm API client and auth
lyrics/ LRCLib client with LRU cache
ui/ Bubble Tea TUI
logger/ Structured logging (slog) with daemon/quiet/debug support
config/ Parser rule loading and hot-reload
- lrclib.net for lyrics
- Charmbracelet for Bubble Tea, Bubbles, and Lip Gloss
- Last.fm API
- mediaremote-adapter for accessing MediaRemote framework on macOS 15.4 or above