USB CD/DVD drives are pretty cheap nowadays, check out Amazon (UK, US), if you get one without a separate power supply, you will also need a powered USB hub.
When my program runs, it opens the cd drawer and waits for a CD to be put in, when a CD is inserted it will rip the CD and when finished open the drawer so you can put in the next. The plan is to stick it in by the tv and just let it rip.
Its a pretty simple python program which starts up a great command line cd ripper called Ripit plus an mp3 encoder called lame.
If you want to have a go yourself.
Install ripit, lame and eject
You will need a few utilities to do the CD ripping.
sudo apt-get install ripit lame eject
Download my program
You can download my program from github, github.com/martinohanlon/AutoRipper.git
sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/AutoRipper.git
cd ~
git clone https://github.com/martinohanlon/AutoRipper.git
Run it
You have to pass the program 2 parameters:
- an output directory of where the CD's will be ripped to
- a timeout in seconds which is the amount of time the program will wait in between CD rips before it quits
cd AutoRipper
python autoRipper.py /home/pi 60
python autoRipper.py /home/pi 60
The code
#!/usr/bin/env python
import subprocess
import time
import pygame
import datetime
import argparse
RIPITDIRTEMPLATE = "'\"/$artist/$album\"'"
class AutoRipper():
def __init__(self,cdDrive,outputPath,timeout):
self.cdDrive = cdDrive
self.outputPath = outputPath
self.timeout = timeout
self.cdDrive.init()
def start(self):
print "AutoRipper - Waiting for Audio Disk"
#loop until a disk hasnt been inserted within the timeout
lastTimeDiskFound = datetime.datetime.now()
while (lastTimeDiskFound + datetime.timedelta(0,self.timeout)) > datetime.datetime.now():
#is there a disk in the drive?
if self.cdDrive.get_empty() == False:
# Disk found
# is it an audio cd?
if self.cdDrive.get_track_audio(0) == True:
print "AutoRipper - Audio disk found, starting ripit."
#run ripit
# getting subprocess to run ripit was difficult
# due to the quotes in the --dirtemplate option
# this works though!
ripit = subprocess.Popen("ripit --outputdir " + self.outputPath + " --dirtemplate=" + RIPITDIRTEMPLATE + " --nointeraction", shell=True)
ripit.communicate()
# rip complete - eject disk
print "AutoRipper - rip complete, ejecting"
# use eject command rather than pygame.cd.eject as I had problems with my drive
subprocess.call(["eject"])
else:
print "AutoRipper - Disk inserted isnt an audio disk."
subprocess.call(["eject"])
lastTimeDiskFound = datetime.datetime.now()
print "AutoRipper - Waiting for disk"
else:
# No disk - eject the tray
subprocess.call(["eject"])
# wait for a bit, before checking if there is a disk
time.sleep(5)
# timed out, a disk wasnt inserted
print "AutoRipper - timed out waiting for a disk, quitting"
# close the drawer
subprocess.call(["eject", "-t"])
#finished - cleanup
self.cdDrive.quit()
if __name__ == "__main__":
print "StuffAboutCode.com Raspberry Pi Auto CD Ripper"
#Command line options
parser = argparse.ArgumentParser(description="Auto CD Ripper")
parser.add_argument("outputPath", help="The location to rip the CD to")
parser.add_argument("timeout", help="The number of seconds to wait for the next CD")
args = parser.parse_args()
#Initialize the CDROM device
pygame.cdrom.init()
# make sure we can find a drive
if pygame.cdrom.get_count() == 0:
print "AutoRipper - No drives found!"
elif pygame.cdrom.get_count() > 1:
print "AutoRipper - More than 1 drive found - this isnt supported - sorry!"
elif pygame.cdrom.get_count() == 1:
print "AutoRipper - Drive found - Starting"
autoRipper = AutoRipper(pygame.cdrom.CD(0),args.outputPath,int(args.timeout))
autoRipper.start()
#clean up
pygame.cdrom.quit()
import subprocess
import time
import pygame
import datetime
import argparse
RIPITDIRTEMPLATE = "'\"/$artist/$album\"'"
class AutoRipper():
def __init__(self,cdDrive,outputPath,timeout):
self.cdDrive = cdDrive
self.outputPath = outputPath
self.timeout = timeout
self.cdDrive.init()
def start(self):
print "AutoRipper - Waiting for Audio Disk"
#loop until a disk hasnt been inserted within the timeout
lastTimeDiskFound = datetime.datetime.now()
while (lastTimeDiskFound + datetime.timedelta(0,self.timeout)) > datetime.datetime.now():
#is there a disk in the drive?
if self.cdDrive.get_empty() == False:
# Disk found
# is it an audio cd?
if self.cdDrive.get_track_audio(0) == True:
print "AutoRipper - Audio disk found, starting ripit."
#run ripit
# getting subprocess to run ripit was difficult
# due to the quotes in the --dirtemplate option
# this works though!
ripit = subprocess.Popen("ripit --outputdir " + self.outputPath + " --dirtemplate=" + RIPITDIRTEMPLATE + " --nointeraction", shell=True)
ripit.communicate()
# rip complete - eject disk
print "AutoRipper - rip complete, ejecting"
# use eject command rather than pygame.cd.eject as I had problems with my drive
subprocess.call(["eject"])
else:
print "AutoRipper - Disk inserted isnt an audio disk."
subprocess.call(["eject"])
lastTimeDiskFound = datetime.datetime.now()
print "AutoRipper - Waiting for disk"
else:
# No disk - eject the tray
subprocess.call(["eject"])
# wait for a bit, before checking if there is a disk
time.sleep(5)
# timed out, a disk wasnt inserted
print "AutoRipper - timed out waiting for a disk, quitting"
# close the drawer
subprocess.call(["eject", "-t"])
#finished - cleanup
self.cdDrive.quit()
if __name__ == "__main__":
print "StuffAboutCode.com Raspberry Pi Auto CD Ripper"
#Command line options
parser = argparse.ArgumentParser(description="Auto CD Ripper")
parser.add_argument("outputPath", help="The location to rip the CD to")
parser.add_argument("timeout", help="The number of seconds to wait for the next CD")
args = parser.parse_args()
#Initialize the CDROM device
pygame.cdrom.init()
# make sure we can find a drive
if pygame.cdrom.get_count() == 0:
print "AutoRipper - No drives found!"
elif pygame.cdrom.get_count() > 1:
print "AutoRipper - More than 1 drive found - this isnt supported - sorry!"
elif pygame.cdrom.get_count() == 1:
print "AutoRipper - Drive found - Starting"
autoRipper = AutoRipper(pygame.cdrom.CD(0),args.outputPath,int(args.timeout))
autoRipper.start()
#clean up
pygame.cdrom.quit()
I had problems with my cd drive where occasionally it wouldn't open the drawer with the button on the front, if you have the same, just type the command eject and it'll pop right out.
apt-cache show abcde
ReplyDeleteHow hard would it be to run something like makeMKV with this?
ReplyDeleteI don't think it would be at all
DeleteThis should get you started https://github.com/JasonMillward/makeMKV-Autoripper
DeleteGreat tutorial! I think ill try to adapt this for burning cd's for audiobooks :)
ReplyDeleteHi,
ReplyDeleteThanks for your job. It's very appreciated. The script worked well on my desktop under Ubuntu.
I needed to install this package too: python-pygame. I thought you should add this on your tutorial.
Can you tell us what's your CD drive and your usb hub? Witch model?
(apologize for my english)
Hi,
DeleteI didn't include pygame as the package is included by default on raspbian.
The usb drive I use is a LITEON one, but any usb one should work. Mine has its own power supply so I didnt need a usb hub.
Mart
Hi,
ReplyDeleteI've tried using this script. It works for a while, allowing me to rip a few CDs, but then I start getting this error:
StuffAboutCode.com Raspberry Pi Auto CD Ripper
AutoRipper - Drive found - Starting
AutoRipper - Waiting for Audio Disk
Traceback (most recent call last):
File "./autorip.py", line 78, in
autoRipper.start()
File "./autorip.py", line 27, in start
if self.cdDrive.get_track_audio(0) == True:
IndexError: Invalid track number
I completely reinstalled raspberian, and the CD started working again. But after a few disks, I started getting the same error.
Any ideas please?
Did it fail when trying to rip the same disk? The error suggests something wierd with the disk, like it doesnt recognise it as a CD.
DeleteHi, nice coding - worked first time after installing, but may I ask a question? This is in no way a criticism, as I'm new to the RPi, so it's difficult for me to make comparisons, but It seemed to take a long time to rip individual tracks of a CD - typically 3 to 5 mins per track (at 128kbps). Is this to be expected? I'm using raspbian, BTW, with a 32GB SD card. It would obviously be a lot quicker to rip a whole audio CD in Windows on a PC using Media Player, copy to a memory stick and copy the tracks to the SD card. Of course, this pre-supposes one has a PC to hand!
ReplyDeleteKind Regards
I dont remember my Pi taking 3-5 mins per track, maybe 1-2 mins, but yes compared to a PC it is going to be much slower. The reason I created this was that I didnt want to sit in front of a PC putting CDs in and then copy them to my NAS.
DeleteI put my Pi in front of the TV, watched a movie and just let it rip, when it finished it popped out the drawer and I put another CD in.
Hi, nice coding! I just wanted to ask,if there is any posibility to encode the mp3s in a higher Bitrate. For example 256kbps instead of 128kbps.
ReplyDeleteGreetings from Germany
Just add the --bitrate option to the ripit command. You can see all the options for ripit on the man page http://manpages.ubuntu.com/manpages/lucid/man1/ripit.1.html
DeleteThanks :) everything is working (after some trying around)
DeleteJa Alex, du bist Deusch :)?
DeleteAwesome project! Finally getting around to ripping my girlfriend's music collection. I always just seemed like a hassle before this :D my only question is, how do I tell your script to rip to FLAC format, as I know it's an option in ripit. Is there a parameter I can feed your script to prefer FLAC over MP3? And it will still do the lookups and try to et metadata etc?
ReplyDeleteThe ripit readme (http://suwald.com/ripit/README) suggests you can set a different encoder using the --coder option, with 2 being flac. So just --coder 2 to the following line of code, presuming flac is installed and ready to go!
Deleteaddripit = subprocess.Popen("ripit --coder 2 --outputdir " + self.outputPath + " --dirtemplate=" + RIPITDIRTEMPLATE + " --nointeraction", shell=True)
What does the ++ mean in the encode bar?
ReplyDeleteWhat ++ in what encode bar?
DeleteI was mistaken(its the ripping progress not encoding).
ReplyDeleteWhen it rips the song, it displays a > that goes across the screen to show progress. Sometimes in there, I see "+" or a "V". Example: | +++ v + + > |
Does that represent issues reading the disc?
Absolutely no idea. Perhaps have a look at the ripit documentation and see if it gives any clues. use man ripit
DeleteThis is a really nice project which I am incorporating into the volumio build. I am by no means a programmer but would like to ask where the autoripper.py program files is installed so I can add a menu command to the Volumio interface
ReplyDeleteIf you follow the instructions in the post above the AutoRipper program will be installed at:
Delete/home/pi/AutoRipper/autoRipper.py
Doh, thanks for the reply Martin
DeleteHey Martin, excellent code! I'm new to programming and I wanted to know how it would be possible to rip multiple disks at the same time. I noticed the lines
ReplyDeleteelif pygame.cdrom.get_count() > 1:
print "AutoRipper - More than 1 drive found - this isnt supported - sorry!"
which made me wonder why that is. where is the limitation?
Thanks!
If you have more than 1 drive I see no reason why not, but you will have to make a small change to the program to pass the right cd drive number to the program, because as you have seen I coded it to just pick the first cd drive it found and raise an error if there was more than one.
DeleteThank you!
Deleteis there a way to keep this running? if no disk in x amount of time, close the tray, but when the tray is manually opened and a disk inserted it detects the new disk and continues on? I don't want to have to ssh in to the pi to start ripping again. Would like to just drop in disk and when it's popped back out it's done :)
ReplyDeleteThis is what it does.
DeleteThis script is amazing!
ReplyDeleteOne problem though: When a CD is not found by freedb, the tracks are ripped as "Unknown artist" - "Unknwown album", etc.
When more than one unknown CD is ripped in a session, does the second one overwrite the first one?
Is there any way to get an interaction with freedb in such cases (e.g. a search)?
I have no idea what would happen if there are 2 unknown CDs. In the time I used this to rip 400 CDs I never came across 1 it didn't know. Gut feel say ripit would create a unknown.1 or similar. Perhaps try it.
DeleteThank you Martin for a fine tutorial, and everyone for their comments and suggestions. I have this encoding FLAC on a Pi 3. Lots of fun.
ReplyDeleteIt seems to work well, but I get a dialog box 'Removable medium is inserted' each time I insert a CD. I have to press Cancel each time to make it go away. As OS I use most dist-updated Raspbian Jessie (PIXEL).
ReplyDeleteI got an error because my CD-player doesn't have a tray -- only a slit. It can eject, but it can't close the tray.
ReplyDeleteAutoRipper - rip complete, ejecting
AutoRipper - Waiting for disk
AutoRipper - timed out waiting for a disk, quitting
eject: CD-ROM tray close command failed: Input/output error
The playlists that are created (m3u) contain absolute paths. This is a disadvantage since you can't move the folders without the playlists stop working.
ReplyDeleteThat will be a feature of ripit rather than the AutoRipper program so Im not sure what I can do about that.
DeleteI discovered in the ripit manual that '--playlist 2' gives filenames without full path. I also need to use '--chars NTFS' because I save on NTFS drive.
DeleteAwesome, just change:
Deleteripit = subprocess.Popen("ripit --outputdir " + self.outputPath + " --dirtemplate=" + RIPITDIRTEMPLATE + " --nointeraction", shell=True)
and you should be good :)