Skip to content

riesvriend/mp3rec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mp3rec — record a Spotify track to a clean, tagged MP3 (macOS)

Play a song in Spotify, run one command, and get a properly tagged 320 kbps MP3 — correct title/artist/album, embedded cover art, exact length, no crackle. It records the audio the way your Mac actually plays it, so it works for anything Spotify can play.

For personal, private use only. Recording Spotify violates their Terms of Service. Don't share or redistribute what you make. If you love the music, buy it (Bandcamp, iTunes, etc.) — that's the only way artists get paid.


How it works (in plain language)

Your Mac can't hand you the raw file behind a Spotify stream (it's encrypted and locked to the app). So instead we record the sound as it plays, digitally — no microphone, no quality loss from speakers. The trick is a free "virtual cable" called BlackHole: we temporarily send your Mac's sound into it instead of your speakers, record what comes out the other end, then put your speakers back.

While it records, the tool reads the song's details (title, artist, album, length, cover art) straight from Spotify, plays the track from the beginning, waits for it to finish, and then trims and tags the result automatically. The recording is silent to you while it runs — that's normal, because your sound is going into the recorder instead of your speakers.

Why it's built this way (the non-obvious parts)

Getting clean audio took some doing. Two things matter a lot:

  1. Sample rate must match. Spotify plays at 44,100 Hz. If BlackHole is set to 48,000 Hz, macOS constantly converts between the two, and that mismatch makes the recording drop little chunks of sound → audible crackle. So the tool forces BlackHole to 44,100 Hz to match Spotify exactly. No conversion, no crackle.
  2. The recorder has to keep up. The obvious tool (ffmpeg's built-in audio capture) quietly drops ~8–13% of the sound when recording a virtual device — you hear it as crackle and the track ends up short. So capture is done by a tiny purpose-built recorder (recorder.swift) that uses macOS's proper real-time audio engine (the same robust approach Audacity uses). It does not drop samples. ffmpeg is still used afterward, but only to encode the already-clean recording into an MP3.

What's in this folder

File What it is
rec-spotify.sh The main command you run. Orchestrates everything.
recorder.swift Source for the audio recorder (a CoreAudio real-time capture tool).
recorder The compiled recorder binary (built from recorder.swift).
set_device_rate.swift Tiny helper that sets BlackHole's sample rate to 44.1 kHz.

One-time setup

You need a few free tools. If a rip ever fails, it'll tell you which piece is missing.

  1. Install the dependencies (Homebrew):

    brew install ffmpeg lame switchaudio-osx
    brew install blackhole-2ch          # virtual audio cable; needs your password + a reboot

    After installing BlackHole, reboot so macOS loads the audio driver.

  2. Grant Microphone permission. The app you run this from (Terminal, iTerm, the Claude Code host, etc.) needs Microphone access — recording a virtual device counts as "mic" to macOS. Go to System Settings → Privacy & Security → Microphone and enable your terminal app. Without this, recordings come out as pure silence with no error.

  3. Build the recorder (once):

    swiftc -O recorder.swift -o recorder

That's it — no GUI audio configuration needed. The tool sets the right sample rate and routes audio automatically each time.


Usage

  1. Open Spotify and load the track you want (Premium + "Very High" quality recommended).
  2. Run:
    ./rec-spotify.sh
  3. The song plays through (silently to you, ~its real length) and the finished MP3 lands in ~/Music/SpotifyRips/, named Artist - Title.mp3.

When it's done, your speakers/headphones are restored automatically. Don't play other audio while it's recording — anything else playing would be mixed into the recording.

Options (environment variables)

Variable Default Purpose
OUTDIR ~/Music/SpotifyRips Where MP3s are saved.
BITRATE 320k MP3 bitrate.
CAP_RATE 44100 Capture sample rate (matches Spotify; leave as-is).
POST_ROLL 4 Extra seconds recorded past the end so the tail is never clipped.
CAPTURE_DEV BlackHole 2ch Virtual capture device name.
DEBUG_KEEP (unset) If set, keeps the raw capture at /tmp/lastrec.caf for inspection.

Examples:

OUTDIR=~/Music/Rips ./rec-spotify.sh        # save somewhere else
BITRATE=256k ./rec-spotify.sh               # smaller files

Checking a result

The tool prints the final length next to Spotify's reported length — they should match to a fraction of a second. To inspect a file yourself:

ffprobe "~/Music/SpotifyRips/Artist - Title.mp3"

Look for: duration ≈ the track length, Audio: mp3 ... 320 kb/s, 44100 Hz, an attached mjpeg cover image, and the title/artist/album tags.


Troubleshooting

  • Recording is silent / "capture is shorter than the track" warning → Microphone permission isn't granted to your terminal app (setup step 2).
  • "Capture device not found" → BlackHole isn't installed, or you haven't rebooted since installing it.
  • "recorder binary missing" → run the swiftc build command (setup step 3).
  • Crackle is back → confirm BlackHole is at 44.1 kHz. The tool sets this automatically, but you can check/force it: swift set_device_rate.swift "BlackHole 2ch" 44100.
  • The wrong track recorded → it records whatever is currently loaded in Spotify. Make sure the track you want is the one showing in Spotify before you run it.

Notes & limits

  • Quality ceiling: Spotify's stream is already compressed (~320 kbps Ogg). This captures that faithfully at 44.1 kHz; it can't be better than the source. It's transparent for listening, but it isn't lossless "CD quality."
  • One track at a time. Whole-playlist auto-batching is a straightforward add-on if you want it later.
  • Silent capture by design. You won't hear the music while it records. (Hearing it live would require a one-time manual "Multi-Output Device" setup in Audio MIDI Setup.)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages