From d17829c36a18f0abbca253e87a6855323a1a7f20 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Mon, 15 Jun 2009 07:07:41 +0000 Subject: [PATCH] * morituri/result/result.py: Add max confidence from database. * morituri/common/program.py: * morituri/rip/cd.py: Move AccurateRip checking to program.py Re-rip if verification failed when continuing a rip. --- ChangeLog | 9 ++++++ morituri/common/program.py | 63 ++++++++++++++++++++++++++++++++++--- morituri/result/result.py | 3 ++ morituri/rip/cd.py | 64 +++++++++++++------------------------- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index bafe25e..f2d08a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-06-15 Thomas Vander Stichele + + * morituri/result/result.py: + Add max confidence from database. + * morituri/common/program.py: + * morituri/rip/cd.py: + Move AccurateRip checking to program.py + Re-rip if verification failed when continuing a rip. + 2009-06-15 Thomas Vander Stichele * morituri/image/cue.py: diff --git a/morituri/common/program.py b/morituri/common/program.py index 48df85b..98b8276 100644 --- a/morituri/common/program.py +++ b/morituri/common/program.py @@ -26,9 +26,10 @@ Common functionality and class for all programs using morituri. import os -from morituri.common import common, log +from morituri.common import common, log, checksum from morituri.result import result from morituri.program import cdrdao, cdparanoia +from morituri.image import image import gst @@ -121,7 +122,7 @@ def musicbrainz(discid): return ret -class Program(object): +class Program(log.Loggable): """ I maintain program state and functionality. @@ -229,7 +230,11 @@ class Program(object): v['d'] = mbdiscid v['a'] = v['A'] - v['n'] = 'Unknown Track %d' % i + if i == 0: + v['n'] = 'Hidden Track One Audio' + else: + v['n'] = 'Unknown Track %d' % i + if self.metadata: v['A'] = filterForPath(self.metadata.artist) @@ -244,7 +249,6 @@ class Program(object): else: # htoa defaults to disc's artist v['a'] = filterForPath(self.metadata.artist) - v['n'] = filterForPath('Hidden Track One Audio') import re template = re.sub(r'%(\w)', r'%(\1)s', template) @@ -334,6 +338,13 @@ class Program(object): stop = track.getIndex(1).absolute - 1 return (start, stop) + def verifyTrack(self, runner, trackResult): + t = checksum.CRC32Task(trackResult.filename) + + runner.run(t) + + return trackResult.testcrc == t.checksum + def ripTrack(self, runner, trackResult, offset, device, profile, taglist): """ @param number: track number (1-based) @@ -363,7 +374,51 @@ class Program(object): trackResult.peak = t.peak trackResult.quality = t.quality + def verifyImage(self, runner, responses): + + cueImage = image.Image(self.cuePath) + verifytask = image.ImageVerifyTask(cueImage) + cuetask = image.AccurateRipChecksumTask(cueImage) + runner.run(verifytask) + runner.run(cuetask) + + response = None # track which response matches, for all tracks + + # loop over tracks + for i, csum in enumerate(cuetask.checksums): + trackResult = self.result.getTrackResult(i + 1) + trackResult.accuripCRC = csum + + confidence = None + + # match against each response's checksum + for j, r in enumerate(responses or []): + if "%08x" % csum == r.checksums[i]: + if not response: + response = r + else: + assert r == response, \ + "checksum %s for %d matches wrong response %d, "\ + "checksum %s" % ( + csum, i + 1, j + 1, response.checksums[i]) + trackResult.accurip = True + # FIXME: maybe checksums should be ints + trackResult.accuripDatabaseCRC = int(response.checksums[i], 16) + # arsum = csum + confidence = response.confidences[i] + trackResult.accuripDatabaseConfidence = confidence + + if responses: + maxConfidence = max(r.confidences[i] for r in responses) + self.debug('found max confidence %d' % maxConfidence) + trackResult.accuripDatabaseMaxConfidence = maxConfidence + if not response: + self.warning('none of the responses matched.') + + def writeCue(self, discName): + self.debug('write .cue file') + import code; code.interact(local=locals()) assert self.result.table.canCue() cuePath = '%s.cue' % discName diff --git a/morituri/result/result.py b/morituri/result/result.py index f5215bc..bff9623 100644 --- a/morituri/result/result.py +++ b/morituri/result/result.py @@ -43,6 +43,9 @@ class TrackResult: accuripCRC = None accuripDatabaseCRC = None accuripDatabaseConfidence = None + accuripDatabaseMaxConfidence = None + + classVersion = 2 class RipResult: """ diff --git a/morituri/rip/cd.py b/morituri/rip/cd.py index 23032db..c31599d 100644 --- a/morituri/rip/cd.py +++ b/morituri/rip/cd.py @@ -165,6 +165,13 @@ class Rip(logcommand.LogCommand): trackResult.pregap = itable.tracks[number - 1].getPregap() # FIXME: optionally allow overriding reripping + if os.path.exists(path): + print 'Verifying track %d of %d: %s' % ( + number, len(itable.tracks), os.path.basename(path)) + if not prog.verifyTrack(runner, trackResult): + print 'Verification failed, reripping...' + os.unlink(path) + if not os.path.exists(path): print 'Ripping track %d of %d: %s' % ( number, len(itable.tracks), os.path.basename(path)) @@ -224,6 +231,7 @@ class Rip(logcommand.LogCommand): if not os.path.exists(dirname): os.makedirs(dirname) + self.debug('writing cue file for %s', discName) prog.writeCue(discName) # write .m3u file @@ -270,58 +278,30 @@ class Rip(logcommand.LogCommand): # FIXME: put accuraterip verification into a separate task/function # and apply here - cueImage = image.Image(prog.cuePath) - verifytask = image.ImageVerifyTask(cueImage) - cuetask = image.AccurateRipChecksumTask(cueImage) - function(runner, verifytask) - function(runner, cuetask) - - response = None # track which response matches, for all tracks + prog.verifyImage(runner, responses) # loop over tracks - for i, csum in enumerate(cuetask.checksums): - trackResult = prog.result.getTrackResult(i + 1) - trackResult.accuripCRC = csum + for trackResult in prog.result.tracks: status = 'rip NOT accurate' - confidence = None - - # match against each response's checksum - for j, r in enumerate(responses or []): - if "%08x" % csum == r.checksums[i]: - if not response: - response = r - else: - assert r == response, \ - "checksum %s for %d matches wrong response %d, "\ - "checksum %s" % ( - csum, i + 1, j + 1, response.checksums[i]) + if trackResult.accurip: status = 'rip accurate ' - trackResult.accurip = True - # FIXME: maybe checksums should be ints - trackResult.accuripDatabaseCRC = int(response.checksums[i], 16) - # arsum = csum - confidence = response.confidences[i] - trackResult.accuripDatabaseConfidence = confidence c = "(not found)" ar = "(not in database)" - if responses: - if not response: - print 'ERROR: none of the responses matched.' - else: - maxConfidence = max(r.confidences[i] for r in responses) - - c = "(max confidence %3d)" % maxConfidence - if confidence is not None: - if confidence < maxConfidence: - c = "(confidence %3d of %3d)" % ( - confidence, maxConfidence) + if trackResult.accuripDatabaseMaxConfidence: + c = "(max confidence %3d)" % trackResult.accuripDatabaseMaxConfidence + if trackResult.accuripDatabaseConfidence is not None: + if trackResult.accuripDatabaseConfidence \ + < trackResult.accuripDatabaseMaxConfidence: + c = "(confidence %3d of %3d)" % ( + trackResult.accuripDatabaseConfidence, + trackResult.accuripDatabaseMaxConfidence) - ar = ", AR [%s]" % response.checksums[i] - print "Track %2d: %s %s [%08x]%s" % ( - i + 1, status, c, csum, ar) + ar = ", AR [%08x]" % trackResult.accuripDatabaseCRC + print "Track %2d: %s %s [%08x]%s" % ( + i + 1, status, c, trackResult.accuripDatabaseCRC, ar) # write log file logger = result.getLogger()