On Fri, Nov 20, 2020 at 4:31 PM Frank Elsner <frank.elsner@xxxxxxxxxxx> wrote:
If it carrys an ISO9660 file system simpy mount it and play with any player.
No that's not what I meant by reading.
I meant before you actually write to a disc, you have to have the data from your original disc somewhere right ?
What would you use to record that from the original disc ? That's what I meant.
Sorry for the confusion.
You mean you want to copy the info off the CD and then re-record it? Below is an old script I used to use to do this. Easily adaptable. Everything is done with cdrdao.
I'll attach another one that I use to convert CDs to flac for my
music server. That one uses cdparanoia to rip the CD.
Riki
############################################################################################
#!/bin/bash
#TODO:
#Need to add an option for setting raw read or raw-subchan read
CDRDAO=`which cdrdao 2>/dev/null`;
if [ -z "$CDRDAO" ]; then
echo "This script uses the cdrdao utility. It does not appear to
be in your path.";
exit 1;
fi
READ_DEVICE='/dev/sr0';
WRITE_DEVICE='/dev/sr0';
DRIVER="generic-mmc";
PROG=`basename $0`;
function printUsage {
cat <<EOF
#######################################################################
USAGE: $PROG [-h] [-r READDEVICE] [-w WRITEDEVICE] [FILENAME]
$PROG copies the cd in READDEVICE to one in WRITEDEVICE. The user
can
choose the speed at which the copy is made, and multiple copies
can be
made from a single read.
Argument:
FILENAME: The filename to use for storage of the CD image, toc,
etc.
Defaults to "cd".
Options:
-d: Driver to use with cdrdao [defaults to generic-mmc]
-D: Show default drivers and exit.
-h: Print this message
-p: Set cdrdao --paranoia-mode [defaults to 0]
-r: Set the read device [defauts to $READ_DEVICE]
-R: --read-raw
-s: Set write speed [defaults to 1x]
-w: Set the write device [defauts to $WRITE_DEVICE]
-y: Assume yes (skip prompts).
The mentioned defaults may not make sense for your system. They
can be
changed in $0.
EOF
}
#Option processing
OPTIONS="";
VERBOSE="";
DEBUG="";
SPEED="";
YES="";
PARANOIA="0";
RAW="";
while getopts ":d:Dp:r:Rs:w:y" opt; do
case $opt in
d ) DRIVER="$OPTARG";;
D ) echo "Read: $READ_DEVICE";
echo "Write: $WRITE_DEVICE";
exit 0;;
p ) PARANOIA="$OPTARG";;
r ) READ_DEVICE="$OPTARG";;
R ) RAW="--read-raw";;
s ) SPEED="$OPTARG";;
w ) WRITE_DEVICE="$OPTARG";;
y ) YES="YES";;
\? ) printUsage; exit 1;;
esac
done
shift $(($OPTIND - 1));
if [ -z $1 ]; then
filename=cd;
else
filename=$1;
fi
if [ -z "$YES" ]; then
echo "Insert CD into DVD drive...";
read TEMP;
fi
if [ -f /tmp/$filename.toc ]; then rm -f /tmp/$filename.toc; fi
if [ -f /tmp/$filename.bin ]; then rm /tmp/$filename.bin; fi
echo "Reading from $READ_DEVICE, mode $PARANOIA";
cdrdao read-cd --paranoia-mode $PARANOIA $RAW --datafile
/tmp/$filename.bin --device $READ_DEVICE --driver $DRIVER
/tmp/$filename.toc
if [ "$?" != "0" ]; then
echo "Disk read failed!!";
exit 1;
fi
if [ -z "$SPEED" ]; then
if [ -z "$YES" ]; then
echo -n "CD Copied. Insert blank disk into Plextor drive
and ";
echo "Select speed for write..."
SPEED="";
while [ -z "$SPEED" ]; do
select SPEED in 1 4 8 16; do
if [ $SPEED ]; then
break;
else
SPEED=1;
break;
fi
done
done
else
SPEED="1";
fi
fi
if grep -q 'DISC_ID ""' /tmp/$filename.toc; then
cp /tmp/$filename.toc /tmp/$filename.toc2;
grep -v DISC_ID /tmp/$filename.toc2 > /tmp/$filename.toc;
rm /tmp/$filename.toc2;
fi
WRITE="Yes";
while [ "$WRITE" = "Yes" ]; do
echo "Writing to $WRITE_DEVICE at speed $SPEED";
cdrdao write -n --eject --device $WRITE_DEVICE --speed $SPEED
--driver $DRIVER /tmp/$filename.toc
if [ "$?" != "0" ]; then
echo "Disk write failed!!";
exit 1;
fi
echo "Write another?"
select WRITE in "Yes" "No"; do
break;
done
done
rm /tmp/$filename.bin /tmp/$filename.toc;
##########################################################################################
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import stat import time import shutil import tempfile import sys from getopt import getopt import re import CDDB import DiscID import filecmp from ripper import * import getcover origdir = os.getcwd() #FIXME option chardeny ropts = ripperopts() #FIXME Options ropts.formats['flac'] = ripformat("flac", "flac", "-V --best --replay-gain", "%n-%t.%x") ropts.filelocn = "/music/audio/%c/%A/%y-%T/" # ropts.filelocn = "/mnt/mail/multi/%c/%A/%y-%T/" usage = ''' cd2flac [-defhktv] [-Cn num] [-p opts] [-D device] [-E editor] -C: Number of returned CDDB matches to use -d: Debug -D: CD Reader device (/dev/sr0) -e: Create an empty list of titles, etc -E: Edit the CDDB info with <editor> -f: File containing info we'd otherwise get from CDDB. -G: Don't get cover file -h: Help -i: Write into directory, if it already exists -k: Keep intermediate files -n: Start numbering tracks with num -o: Ignore dates (for old rips) -p: Options to pass to cdparanoia -t: Trust the drive: Don't do two rips to make sure it's OK -v: Be verbose ''' try: (options, args) = getopt(sys.argv[1:], "C:dD:eE:f:Ghikn:op:tv") except: print usage sys.exit(1) if args: #nothing should be left print usage sys.exit(1) checkdates = True emptyfile = False for (opt, param) in options: if opt == "-C": ropts.discnum = int(param) elif opt == "-d": ropts.debug = True elif opt == "-D": ropts.cddev = param elif opt == "-E": ropts.editor = param elif opt == "-e": emptyfile = True elif opt == "-f": ropts.tagfile = param elif opt == "-G": ropts.docover = False elif opt == "-i": checkdates = False ropts.writinto = True elif opt == "-k": ropts.keeptemp = True elif opt == "-n": ropts.starttrk = int(param) elif opt == "-o": checkdates = False elif opt == "-p": ropts.cdpopts = param elif opt == "-t": ropts.tworips = False elif opt == "-v": ropts.verbose = True else: print usage sys.exit(0) # FIXME This ought to be a separate routine.... usedtmp = False if ropts.tagfile == "": if not emptyfile: # Get CDDB info usedtmp = True discid = DiscID.disc_id(DiscID.open(ropts.cddev)) #print discid (status, info) = CDDB.query(discid) if status != 200 and status != 211 and status != 210: print "Error accessing CDDB database!" sys.exit(1) if status != 200: if ropts.discnum == 0: ropts.discnum = showChoices(discid, info, ropts) if ropts.discnum == 0: sys.exit(0) info = info[ropts.discnum - 1] try: cd = getCDInfo(discid, info, ropts) except: print "Unable to get CD information." print discid print info exit(1) else: cd = cdinfo() discid = DiscID.disc_id(DiscID.open(ropts.cddev)) cd.discid = calcid(discid) cd.numtrax = discid[1] for i in range(1, cd.numtrax + 1): cd.addtune(tune(cd, i, "")) (fil, ropts.tagfile) = tempfile.mkstemp(".txt", "cd2flac", None, True) os.write(fil, repr(cd) + "\n") os.close(fil) cmd = ropts.editor + " " + ropts.tagfile os.system(cmd) cd = readCDInfo(ropts.tagfile) if usedtmp: os.unlink(ropts.tagfile) nambak = ropts.tagfile + "~" if os.path.exists(nambak): os.unlink(nambak) # FIXME if not year, abort with warning try: tmpdir = tempfile.mkdtemp(prefix = "cd2flac") os.chdir(tmpdir) except: exit(4) # FIXME Extract this, too. # Temporary check concerning old rips newdir = makeDirName(ropts.filelocn, cd, "flac") if checkdates: if os.path.exists(newdir): t = time.localtime(os.stat(newdir)[8]) year = t[0] month = t[1] if year >= 2009 and month >= 7: print "CD seems last to have been ripped in " + str(month) + "/" + str(year) exit(0) ############## # Rip the CD # FIXME Might want only to rip some trax cdparanoia(ropts, cd.numtrax) if ropts.tworips: # Rename trackXX.cdda.wav as 1trackXX.cdda.wav for i in range(1, cd.numtrax + 1): tname = int2track(i) if os.path.exists(tname): os.rename(tname, "1" + tname) # os.system("eject " + ropts.cddev) # os.system("eject -t " + ropts.cddev) # Rip it again cdparanoia(ropts, cd.numtrax) # Compare the old and new rips # FIXME Let's copy the right one to something like "ok-track..." # and then it will be easy to re-rip ones that don't match. # And we should mark the tunes themselves, too, so as to be # able to convert and copy ones that do match. failures = [] for i in range(1, cd.numtrax + 1): tname = int2track(i) if not os.path.exists(tname): continue if not filecmp.cmp(tname, "1" + tname, False): failures.append(i) if len(failures) > 0: for i in failures: print "Track " + str(i) + " did not rip correctly!" print "Files are in: " + tmpdir # Might try re-ripping those ones again.... sys.exit(56) print "All tracks matched." # Done ripping ############## cmd = "eject " + ropts.cddev os.system(cmd) for curtune in cd.tunes: wav2flac(curtune, ropts) if ropts.docover: cover = "" if not cd.graphic: # FIXME Amazon won't allow us to find the cover. pass cover = findImage(cd) else: cover = getcover.makeCover(cd.graphic) getcover.makeThumbnail(cover) if cover: os.system("display " + cover + " &") if not movetunes(cd, ropts, "flac"): print "Files are in ", tmpdir sys.exit(1) try: os.chdir(origdir) except: os.chdir('/') if not ropts.keeptemp: shutil.rmtree(tmpdir)
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import re import urllib # Routines for getting cover images from some source or other baseurl = "http://www.amazon.com/s?k=%s" imgs = re.compile("<img src=\"(https://m.media-amazon.com/[^\"]+jpg)\"") covername = "cover.jpg" def getCover(artist, title, cdir = ""): artist = artist.replace(" ", "+") artist = artist.replace("_", "+") artist = artist.replace("'", "") title = title.replace("'", "") title = title.replace(" ", "+") title = title.replace("_", "+") u = baseurl % (artist + "+" + title) s = urllib.urlopen(u).readlines() imgurl = "" for l in s: m = imgs.search(l) if m != None: imgurl = m.group(1) break if imgurl == "": print "***** Unable to find image URL *****" print "at %s" % (u) return "" print "Found image: " + m.group(1) return makeCover(m.group(1), cdir) def makeCover(u, cdir = ""): try: s = urllib.urlopen(u).read() except: print "Unable to get " + u return try: if cdir == "": cfile = covername else: cfile = cdir + "/" + covername cvr = open(cfile, 'w') cvr.write(s) cvr.close() except: print "***** Unable to make cover.jpg *****" return "" return cfile def makeThumbnail(img): from PIL import Image im = Image.open(img) #print im.size im.thumbnail((100,100), Image.ANTIALIAS) im.save(img) def coverExists(cdir): return os.path.exists(cdir + "/" + covername) usage = '''getcover.py artist title Attempts to retrieve a cover image for `title' by `artist' ''' if __name__ == "__main__": import sys try: artist = sys.argv[1] title = sys.argv[2] except: print usage sys.exit(1) cvr = getCover(artist, title) if not cvr: sys.exit(1) makeThumbnail(cvr)
#!/usr/bin/env python # -*- coding: utf-8 -*- import re import sys import os import shutil import CDDB import DiscID import getcover multid = re.compile("_\W*_+") befdot = re.compile("_(?=\.)") quote = re.compile("'") enddot = re.compile("[._]$") muldot = re.compile("\.\.+") dotdash = re.compile("\.(?=_)") theaetc = re.compile("^(?:the|a|an)_") def asciize(s, chardeny = "^-a-zA-Z0-9_.", nothe = False): keepers = re.compile("[" + chardeny + "]") s = quote.sub("", s) s = keepers.sub("_", s.lower()) s = multid.sub("_", s) s = befdot.sub("", s) s = muldot.sub(".", s) s = enddot.sub("", s) s = dotdash.sub("", s) if nothe: s = theaetc.sub("", s) return s def dasciize(s, nothe = False): '''Same but no dots''' return asciize(s, chardeny = "^-a-zA-Z0-9_", nothe = nothe) def execcmd(cmd, debug = False): if debug: sys.stderr.write(cmd + "\n") return success = os.system(cmd) if success: sys.stdout.write("Command `%s' failed! Aborting!\n" % (cmd)) sys.exit(success) #Calculate the disc id def calcid(id): numtracks = id[1] trax = hex(numtracks)[2:] if len(trax) < 2: trax = "0" + trax time = id[-1] - (id[2] / 75) time = hex(time)[2:] while len(time) < 4: time = "0" + time times = id[2:-1] chksum = 0 for t in times: s = str(t / 75) c = 0 for n in s: c += int(n) chksum += c chksum = hex(chksum % 255)[2:] if len(chksum) < 2: chksum = "0" + chksum return chksum + time + trax def int2track(i): j = str(i) if len(j) < 2: j = "0" + j return "track" + j + ".cdda.wav" # Implements a grip-like syntax for specifying filenames def makeTuneName(s, tun, extn, startnum): s = s.replace("%n", tun.normednum(startnum)) s = s.replace('%t', tun.title) s = s.replace('%T', tun.cd.title) s = s.replace('%a', tun.artist) s = s.replace('%A', tun.cd.artist) s = s.replace('%y', tun.cd.year) s = s.replace('%c', tun.cd.catgry) s = s.replace('%g', tun.cd.genre) s = s.replace('%x', extn) return s # Implements a grip-like syntax for specifying dirnames def makeDirName(s, cd, extn): s = s.replace('%T', dasciize(cd.title)) s = s.replace('%A', dasciize(cd.artist, nothe = True)) s = s.replace('%y', dasciize(cd.year)) s = s.replace('%c', dasciize(cd.catgry)) s = s.replace('%g', dasciize(cd.genre)) s = s.replace('%x', extn) return s # Wraps the call to cdparanoia def cdparanoia(ropts, numtrax): if not ropts.debug: cmd = "cdparanoia -d " + ropts.cddev + " -B " + ropts.cdpopts execcmd(cmd) return # If debugging, then we fake it and just create numtrax files # sanity check cmd = "cdparanoia -d " + ropts.cddev + " -B " + ropts.cdpopts print cmd if numtrax > 100: print "Won't create more than 100 files!" sys.exit(1) for i in range(1, numtrax + 1): cmd = "touch " + int2track(i) execcmd(cmd) class ripformat: def __init__(self, cmd, extn, opts, fname): self.cmd = cmd self.extn = extn self.opts = opts self.fname = fname class ripperopts: def __init__(self): self.chardeny = "^-a-zA-Z0-9_." #FIXME Sensible default self.cddev = "/dev/sr0" self.cdpopts = "" self.debug = False self.discnum = 0 self.docover = True self.editor = "kwrite" self.filelocn = "" self.formats = {} self.keeptemp = False self.ripfmt = "--output-wav" self.starttrk = 1 self.tagfile = "" self.tworips = True self.verbose = False self.writinto = False class cdinfo: def __init__(self): self.discid = "" self.artist = "" self.genre = "" self.year = "" self.catgry = "" self.title = "" self.graphic = "" self.tunes = [] self.numtrax = 0 def addtune(self, tune): self.tunes.append(tune) def __repr__(self): retval = ["DISCID: " + self.discid, "DISC ARTIST: " + self.artist, "DISC TITLE: " + self.title, "DISC YEAR: " + self.year, "DISC CATEGORY: " + self.catgry, "DISC GENRE: " + self.genre, "GRAPHIC: " + self.graphic] for f in self.tunes: retval.append(repr(f)) return "\n".join(retval) class tune: def __init__(self, cd, num, title, artist = ""): remfeat = re.compile("\s*\(?feat(?:\.|uring) .*\)?$") title = remfeat.sub("", title) self.cd = cd self.num = num self.title = title self.artist = artist self.cdpname = int2track(self.num) self.convname = "" self.ripped = False def normednum(self, startnum): n = str(self.num + startnum - 1) if len(n) < 2: n = "0" + n return n def __repr__(self): rval = "TITLE" + self.normednum(1) + ": " + self.title if self.artist: rval += "\nTITLE" + self.normednum() + "ARTIST: " + self.artist return rval def showChoices(discid, info, ropts): i = 1 for inf in info: try: cd = getCDInfo(discid, inf, ropts) except: continue print "Number", i print "--------" print repr(cd) print i += 1 val = raw_input("Select record... ") val = int(val) if val <= 0 or val > len(info): return 0 return val def getCDInfo(discid, discinfo, ropts): cd = cdinfo() cd.numtrax = discid[1] cd.catgry = discinfo["category"] cd.discid = calcid(discid) (status, info) = CDDB.read(cd.catgry, cd.discid) if status != 210: print "Error getting info for disc " + cd.catgry + "/" + cd.discid raise LookupError, "FDRogs" (cd.artist, cd.title) = info['DTITLE'].split('/', 1) cd.artist = cd.artist.strip() cd.title = cd.title.strip() if info.has_key('DYEAR'): cd.year = info['DYEAR'].strip() if info.has_key('DGENRE'): cd.genre = info['DGENRE'] #FIXME Other info on this tune? Esp matters for multi-artist for i in range(0, cd.numtrax): #cd.addtune(tune(cd, ropts.starttrk + i, info['TTITLE' + str(i)].strip())) cd.addtune(tune(cd, i + 1, info['TTITLE' + str(i)].strip())) return cd def makeflactag(key, val, val2 = ""): if not val: val = val2 if not val: return "" val = val.replace("\"", "\\\"") return " -T " + key + "=\"" + val + "\"" def wav2flac(curtune, ropts): format = ropts.formats['flac'] newtname = makeTuneName(format.fname, curtune, format.extn, ropts.starttrk) newtname = asciize(newtname, ropts.chardeny) curtune.convname = newtname cmd = format.cmd + " " + format.opts + " -o " + newtname cmd += makeflactag("TITLE", curtune.title) cmd += makeflactag("TRACKNUMBER", str(curtune.num)) cmd += makeflactag("GENRE", curtune.cd.genre, curtune.cd.catgry) cmd += makeflactag("ARTIST", curtune.cd.artist) cmd += makeflactag("ALBUM", curtune.cd.title) cmd += makeflactag("DATE", curtune.cd.year) cmd += makeflactag("PERFORMER", curtune.artist) cmd += " " + curtune.cdpname if ropts.debug: print cmd os.system("touch " + newtname) return if ropts.verbose: print "About to execute: " + cmd execcmd(cmd) def movetune(cd, ropts, extn): multi = cd.artist.find(',') if multi == -1: return movetunes(cd, ropts, extn) artists = cd.artist.split(',') art = artists[0].strip() tmpcd = cd tmpcd.artist = art realdir = makeDirName(ropts.filelocn, cd, extn) # Need to remove the makeDirName bit from that routine and # do it here so we know it. Of course, we'll also have to add it above. success = movetunes(tmpcd, ropts, extn) if not success: return False artists = artists[1:] for art in artists: art = art.strip() tmpcd.artist = art linkdir = makeDirName(ropts.filelocn, cd, extn) if os.path.exists(linkdir): print "Link directory:", linkdir, "already exists." continue try: os.symlink(realdir, linkdir) print "Linked", linkdir, "to", realdir except: print "Unable to link", linkdir, "to", realdir return True def movetunes(cd, ropts, extn): newdir = makeDirName(ropts.filelocn, cd, extn) if ropts.debug: newdir = "/tmp/" + newdir elif not os.path.exists(newdir): if not ropts.writinto: os.makedirs(newdir) elif not os.path.isdir(newdir): print newdir, "exists but is not a directory." print "Aborting copy." return False elif not ropts.writinto: # move old directory dircp = newdir[0:-1] while os.path.exists(dircp): dircp += ".old" os.rename(newdir, dircp) print newdir, "renamed to", dircp os.makedirs(newdir) for curtune in cd.tunes: tname = curtune.convname newtname = newdir + tname if ropts.debug: print "move:", tname, "to", newtname else: shutil.move(tname, newtname) if not ropts.debug and os.path.exists('cover.jpg'): shutil.move('cover.jpg', newdir + 'cover.jpg') print "Copied new files to", newdir return True def readCDInfo(fname): try: infile = open(fname) lines = infile.readlines() except: print "Unable to read from file `" + fname + "'!" sys.exit(1) infile.close() direg = re.compile("^DISCID:\s*(.*(..))") dareg = re.compile("^DISC ARTIST:\s*(.*)") dtreg = re.compile("^DISC TITLE:\s*(.*)") dyreg = re.compile("^DISC YEAR:\s*(.*)") dcreg = re.compile("^DISC CATEGORY:\s*(.*)$") dgreg = re.compile("^DISC GENRE:\s*(.*)$") ttreg = re.compile("^TITLE(\d\d):\s*(.*)") tareg = re.compile("^TITLE(\d\d)ARTIST:\s*(.*)") grreg = re.compile("^GRAPHIC:\s*(.*)") thiscd = cdinfo() tunelist = {} for line in lines: m = direg.match(line) if m != None: thiscd.discid = m.group(1) thiscd.numtrax = int(m.group(2), 16) continue m = dareg.match(line) if m != None: thiscd.artist = m.group(1) continue m = dtreg.match(line) if m != None: thiscd.title = m.group(1) continue m = dyreg.match(line) if m != None: thiscd.year = m.group(1) continue m = dcreg.match(line) if m != None: thiscd.catgry = m.group(1) continue m = dgreg.match(line) if m != None: thiscd.genre = m.group(1) continue m = grreg.match(line) if m != None: thiscd.graphic = m.group(1) continue m = ttreg.match(line) if m != None: num = m.group(1) name = m.group(2) tunelist[num] = tune(thiscd, int(num), name) continue m = tareg.match(line) if m != None: num = m.group(1) name = m.group(2) if not tunelist.has_key(num): print "Error: Got artist info for " + num + " without tune info!" continue tunelist[num].artist = name continue sys.stderr.write("Unrecognized Line: " + line) for t in tunelist: thiscd.addtune(tunelist[t]) return thiscd def findImage(cd): return getcover.getCover(cd.artist, cd.title)
_______________________________________________ users mailing list -- users@xxxxxxxxxxxxxxxxxxxxxxx To unsubscribe send an email to users-leave@xxxxxxxxxxxxxxxxxxxxxxx Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedoraproject.org/archives/list/users@xxxxxxxxxxxxxxxxxxxxxxx