Skip to content

feat: Shazam-based track identification#1

Open
MWhyte wants to merge 4 commits into
mainfrom
feature/shazam-identification
Open

feat: Shazam-based track identification#1
MWhyte wants to merge 4 commits into
mainfrom
feature/shazam-identification

Conversation

@MWhyte
Copy link
Copy Markdown
Owner

@MWhyte MWhyte commented May 13, 2026

Summary

  • New i keybinding identifies the playing track via Shazam's reverse-engineered recognition endpoint — pure Go, no API key, no third-party service. The fingerprint algorithm is vendored from lukechampine/barbershop (MIT, attribution preserved in pkg/identifier/shazam/LICENSE).
  • Pipeline: tap stream URL → MP3 decode (with frame-sync recovery for mid-stream connects) → downmix to mono → resample to 16 kHz → fingerprint → POST to amp.shazam.com/discovery/v5 → modal renders title/artist/album/year with o to open https://www.shazam.com/track/<key> in the default browser.
  • MP3-only for now. AAC/Ogg streams short-circuit on Content-Type with a friendly "Sorry, only MP3 streams are currently supported" message instead of a confusing decoder error.
  • cmd/test-shazam standalone CLI included for diagnosing streams without booting the TUI — prints sample count, sample rate, capture wall time and Shazam round-trip, then the identified track.

How it works

  1. Press i while a station is playing.
  2. Spinner appears for ~12s while we capture audio from a parallel HTTP read of the stream URL.
  3. Fingerprint is sent to Shazam's mobile endpoint.
  4. Result modal shows the track; o opens it on shazam.com, enter/esc dismisses.
  5. esc mid-spinner aborts the in-flight request, MP3 decode, and rate-limiter wait cleanly via context.CancelFunc.

Test plan

  • make fmt, make build, make lint all clean (0 lint issues across the strict golangci-lint v2 ruleset)
  • go vet ./... clean
  • go test ./... passes (fingerprint hashes match upstream)
  • Identifies tracks on multiple Top-40 stations (verified with Bruno Mars, Taylor Swift, Ravyn Lenae)
  • Press i on a playing MP3 station in ./rig → modal shows correct title/artist within ~15s
  • Press o → default browser opens the Shazam track page
  • Press esc mid-spinner → cancels (no zombie goroutine, no extra network use)
  • AAC station → "Sorry, only MP3 streams are currently supported"
  • Station Shazam doesn't recognise → "No match found"

🤖 Generated with Claude Code

MWhyte and others added 4 commits May 13, 2026 21:44
Adds an `i` keybinding that captures ~12s of audio from the playing
stream, fingerprints it locally in pure Go, and queries Shazam's
recognition endpoint. Results appear in a modal with title/artist/album
and an `o` shortcut to open the canonical Shazam page in the default
browser. Completely free, no API key required.

The fingerprinting algorithm is vendored from lukechampine/barbershop
(MIT, attribution preserved in pkg/identifier/shazam/LICENSE) and runs
against the same `amp.shazam.com/discovery` endpoint Shazam's mobile
client uses. Audio is captured via a parallel HTTP read of the stream
URL, MP3-decoded with hajimehoshi/go-mp3, frame-synced to recover from
mid-stream connects, downmixed to mono and resampled to 16 kHz before
fingerprinting.

Includes `cmd/test-shazam` for diagnosing streams from the CLI. Pipeline
is MP3-only; AAC/Ogg streams short-circuit with a friendly error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
golangci-lint v2.12.2 (latest, used by CI) tightened goconst's
duplication detection and flags "command" (5 uses) and "set_property"
(3 uses) in pkg/player/player.go. Local lint at v2.11.4 didn't.

Extracts both into named constants alongside the rest of the mpv IPC
protocol layer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`version: latest` makes CI fail unpredictably whenever golangci-lint
ships a release with stricter defaults — exactly what happened on
PR #1 (v2.12.2 added new goconst occurrences). Pin to v2.12.2 (the
current latest, matching local installs via brew) so version bumps
are deliberate, surfaced as PRs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- README: new feature bullet, dedicated section with gif, and i/o
  keyboard shortcuts in the controls table
- Website: new feature card and showcase entry on docs/index.html
- New asset: docs/assets/identify.gif (recorded via asciinema, .cast
  preserved alongside the other showcase casts)

Ordered after Favourites in both surfaces to match the existing
showcase flow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant