#!/usr/bin/python # coding=utf-8 ''' rip2ogg (c) 2007-2008, IƱaki Silanes LICENSE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2), as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (http://www.gnu.org/licenses/gpl.txt). DESCRIPTION It rips a CD (after querying FreeDB) into OGG, in a format suitable for my music collection. USAGE Insert CD and execute: % rip2ogg.py This generates a file "rip2ogg.txt" with data of the CD. You can manually edit this file, if you wish. Then, execute: % rip2ogg.py again, to use info in rip2ogg.txt to rip and encode tracks from CD. VERSION svn_revision = r7 (2008-08-28 13:37:38) ''' import sys import re import os import optparse lookcddb = True try: import DiscID as D import CDDB except: print 'Could not load modules CDDB and/or DiscID!' print 'Disabling CDDB lookup features' lookcddb = False import System as S import DataManipulation as DM import FileManipulation as FM #--------------------------------------------------# # Read arguments: parser = optparse.OptionParser() parser.add_option("-d", "--device", dest="device", help="device CD is at. Default=/dev/cdrom.", metavar="DEV", default='/dev/cdrom') parser.add_option("-q", "--quality", dest="quality", help="quality of output Ogg file. Default=7.", metavar="Q", default='7') parser.add_option("-y", "--dryrun", help="Perform a dry run. Don't actually rip/encode anything. Default: Perform real run.", action="store_true", default=False) parser.add_option("-v", "--verbose", help="Be verbose. Default: don\'t be.", action="store_true", default=False) (o,args) = parser.parse_args() if o.dryrun: o.verbose = True #--------------------------------------------------# def read_cd(device='/dev/cdrom'): ''' Returns cd_id to query FreeDB with it. ''' cd = D.open(device) cd_id = D.disc_id(cd) cd.close() return cd_id #--------------------------------------------------# def query_cddb(id=None): ''' Uses cd_id to query FreeDB. Returns category and disc_id ''' if id == None: sys.exit('query_cddb: I need a CD id number!') (status, info) = CDDB.query(id) if status == 210 or status == 211: # multiple results: just pick first info = info[0] elif status != 200: sys.exit('Error: exit status of CDDB query was '+str(status)) return info['category'],info['disc_id'] #--------------------------------------------------# def read_cddb(cat=None, id=None): ''' Uses category and disc_id to read FreeDB info. Returns info dictionary. ''' if cat == None or id == None: sys.exit('read_cddb: I need a category and a disc_id as input!') (status, info) = CDDB.read(cat,id) return info #--------------------------------------------------# # Info file: dorip = 0 ifile = 'rip2ogg.txt' if os.path.exists(ifile): dorip = 1 print '\n#' print '# Warning: info file "%s" already exists! (this is probably what you want)' % (ifile) print '# Its contents follow:' print '#\n' ripcontent = FM.file2array(ifile,'cb') for line in ripcontent: print line, resp = raw_input('\nRip CD according to it? (Y/n): ') if resp == 'n': sys.exit('\nQuitting, as prompted by user...') #--------------------------------------------------# # Rip or get info (depending on above): if dorip == 0: if lookcddb: # Read info in CD: print "Reading CD info..." try: cd_id = read_cd(o.device) except: print 'Could not read CD ID information (maybe no CD in device?)' lookcddb = False if lookcddb: # Query DB: print "Querying FreeDB database..." try: cat,id = query_cddb(cd_id) except: print 'Could not find disc ID in FreeDB!' lookcddb = False if lookcddb: # Get info: print "Getting info for CD from FreeDB..." try: info = read_cddb(cat,id) except: print 'Could not get disc info from FreeDB!' # Build data string: string = 'CDTITLE: ' try: (a,t) = info['DTITLE'].split(' / ') string += '%s\nARTIST: %s' % (t,a) except: string += 'unknown\nARTIST: unknown' string += '\nYEAR: ' try: string += info['DYEAR'] except: string += 'unknown' string += '\nGENRE: ' try: string += info['DGENRE'] except: string += 'unknown' string += '\nTRACKS:\n' track = 0 while 1: try: nn = "%02i " % (track+1) nn += DM.mk_proper_utf(info['TTITLE%s' % (track)]) string += '%s\n' % (nn) track += 1 except: break # Print data: print "\nThe following info found (and written to file):\n" print string # Save to file: FM.w2file(ifile,string) # Closing notification: print 'The above info was written to file %s' % (ifile) print 'Open it, and modify to your heart\'s content.' print 'Then, run rip2ogg.py again to actually rip the CD' else: norip = False print "\nStarting ripping the CD..." album = 'unknown' artist = 'unknown' year = 'unknown' readtrk = False for l in ripcontent: ll = l.split() if ll[0] == 'CDTITLE:': album = ' '.join(ll[1:]) elif ll[0] == 'ARTIST:': artist = ' '.join(ll[1:]) elif ll[0] == 'GENRE:': genre = ' '.join(ll[1:]) elif ll[0] == 'YEAR:': year = ll[1] elif ll[0] == 'TRACKS:': readtrk = True elif readtrk: tnum = '%02i' % int(ll[0]) # Fix track name for ID3 tag: tname = ' '.join(ll[1:]) tname = re.sub('"','\'',tname) # convert double quotes in track names to single quotes # Fix track name for filename: ptname = DM.mk_proper_fn(tname) oggname = "%s-%s.ogg" % (tnum,ptname) # Fix album name for dirname: palbum = DM.mk_proper_fn(album) outdir = '%s-%s' % (year,palbum) if o.dryrun or not os.path.exists('%s/%s' % (outdir,oggname)): # Rip track to WAV: fwav = 'tmp/audio_%s.wav' % (tnum) if not os.path.isdir('tmp'): os.mkdir('tmp') if not os.path.isfile(fwav): cmnd = 'cd tmp/ && icedax -x -s -D %s --track %s+%s' % (o.device,tnum,tnum) if o.verbose: print cmnd if not o.dryrun: S.cli(cmnd) cmnd = 'mv -f tmp/audio.wav tmp/audio_%s.wav' % (tnum) if o.verbose: print cmnd if not o.dryrun: S.cli(cmnd) # If multiple artists: tartist = artist # by default, track artist is album artists sep = '::' if sep in tname: tname = re.sub(' *%s *' % (sep),sep,tname) # remove blanks around the separator tname,tartist = tname.split(sep) if not os.path.exists(outdir): if not o.dryrun: os.mkdir(outdir) # Encode to OGG: cmnd = 'oggenc tmp/audio_%s.wav -q %s -o %s/%s -l "%s" -a "%s" -d %s -G "%s" -t "%s" -N "%s"' % (tnum,o.quality,outdir,oggname,album,tartist,year,genre,tname,tnum) if o.verbose: print cmnd print '' if not o.dryrun: S.cli(cmnd) # Finally, delete rubish: if o.verbose: print 'rm -rf tmp' if not o.dryrun: S.cli('rm -rf tmp')