Auto-rip Music CDs
Awhile back I found a stack of audio CDs I wished to digitize. It’s a bit of work to do the following steps quickly and while doing other more cerebral work:
- Open the disc tray
- Insert the disc
- Wait a few seconds for the disc to be detected by the OS
- Kick off
abcdeto rip the CD.
- Repeat ad infinitum.
The solution is to streamline the workflow:
- Open the disc tray (first time only)
- Insert the disc
- Wait until abcde is finished and ejects the CD, repeat from step #2.
Much simpler. This requires only one human action, whereas the above requires a bit of fumbling with telling the workstation to do the work. Read on to learn how to set this up for your own ‘ripping fun’.
§Tell udev to do something when the CD drive is ejected or inserted
Add this to your udev rules. On my box it is located at
SUBSYSTEM=="block", KERNEL=="sr*", ACTION=="change", RUN+="/usr/local/sbin/rip-music-cd"
udevadm control --reload to ask udev to look for new rules off disk.
§The script that udev runs
Create this script at
/usr/local/sbin/rip-music-cd and make it executable
chmod 755 /usr/local/sbin/rip-music-cd).
#!/usr/bin/env bash set -eu -o pipefail ripuser=winston if [[ -f /root/dont-rip ]]; then msg='/root/dont-rip exists, exiting.' echo "$msg" sudo -u "$ripuser" -i sh -c 'cat >> ~/ripper.log' <<<"$msg" exit 1 fi sleep 5 # https://superuser.com/a/1367091/302931 python - <<EOF """detect_tray reads status of the CDROM_DRIVE. Statuses: 1 = no disk in tray 2 = tray open 3 = reading tray 4 = disk in tray """ import fcntl import os import sys CDROM_DRIVE = '/dev/sr0' fd = os.open(CDROM_DRIVE, os.O_RDONLY | os.O_NONBLOCK) rv = fcntl.ioctl(fd, 0x5326) os.close(fd) sys.exit(rv != 4) EOF # Not reached when the ioctl retval is not equal to 4 (disk in tray). sudo -u "$ripuser" -i bash -c \ 'env INTERACTIVE=no abcde -B -G -x -d /dev/sr0 &>> ~/ripper.log'
Let’s break this script down.
#!/usr/bin/env bashtells the OS to run this script using the
bashprogram, wherever it is located in your
set -eu -o pipefailtells Bash to exit on unhandled error, raise an error when an unbound variable is dereferenced, and propagate pipeline failures to the shell environment.
[[ -f /root/dont-rip ]]test exits early if the file
/root/dont-ripexists. This is intended to disable the ripping tool when it is not in use - e.g. when watching DVDs or working with data CDs.
sleep 5I forgot why this is needed, I think it helps the device settle. Maybe this should be waiting for another udev event? :thinking:
- The python script opens the CDROM device, sends an ioctl to test the status
of the disc tray (
fcntl.ioctl(fd, 0x5326)). Then passes a non-zero exit code back to the shell when there is a disc in tray (
sys.exit(rv != 4)).
- Finally the
abcdeincantation kicks off the CD ripping program. The
env INTERACTIVE=nois important because it tells abcde to never prompt for user input. See the flag breakdown as follows:
-B: Embed album art
-G: Download album art
-x: Eject the CD after completion.
-d /dev/sr0: Specify the CDROM drive device.
You’ll also note this appears to log to a
ripper.log file. Find this in your
homedirectory of the
§Recommended settings for
There are three settings uncommented in my abcde config file. I recommend settings all of these to some value:
OUTPUTDIR=/mnt/stuff/rips WAVOUTPUTDIR=/tmp OUTPUTTYPE=flac
OUTPUTDIRis the output directory tree where finished rips should be placed.
WAVOUTPUTDIRis a temporary directory where the intermediate wav files should be placed prior to transcoding to whatever output format.
OUTPUTTYPEis the format you wish to store your music in. Highly recommend
flacor other lossless, otherwise you may as well pack up and go home, listen to music off YouTube instead.
Lug a stack of discs to your workstation, and get cracking - they won’t rip themselves!
Run this as your
$ripuser user to monitor activity and progress:
tail -f ~/ripper.log