[SCM] morituri/master: feature: add 'rip cd info'

js at users.alioth.debian.org js at users.alioth.debian.org
Sun Oct 19 20:09:58 UTC 2014


The following commit has been merged in the master branch:
commit 7c3118e1f2d5257e779c79fb74b157ead64580de
Author: Thomas Vander Stichele <thomas (at) apestaart (dot) org>
Date:   Sat Feb 2 17:06:16 2013 +0100

    feature: add 'rip cd info'
    
    split up CD command into a base class and two subclasses.
    Make instance variables accordingly.

diff --git a/morituri/rip/cd.py b/morituri/rip/cd.py
index ebe8283..ebcc09e 100644
--- a/morituri/rip/cd.py
+++ b/morituri/rip/cd.py
@@ -38,7 +38,138 @@ from morituri.extern.task import task
 MAX_TRIES = 5
 
 
-class Rip(logcommand.LogCommand):
+class _CD(logcommand.LogCommand):
+
+    def addOptions(self):
+        # FIXME: have a cache of these pickles somewhere
+        self.parser.add_option('-T', '--toc-pickle',
+            action="store", dest="toc_pickle",
+            help="pickle to use for reading and writing the TOC")
+        self.parser.add_option('-R', '--release-id',
+            action="store", dest="release_id",
+            help="MusicBrainz release id to match to (if there are multiple)")
+
+
+    def do(self, args):
+        self.program = program.Program(record=self.getRootCommand().record,
+            stdout=self.stdout)
+        self.runner = task.SyncRunner()
+
+        def function(r, t):
+            r.run(t)
+
+        # if the device is mounted (data session), unmount it
+        self.device = self.parentCommand.options.device
+        self.stdout.write('Checking device %s\n' % self.device)
+
+        self.program.loadDevice(self.device)
+        self.program.unmountDevice(self.device)
+
+        version = None
+
+        # first, read the normal TOC, which is fast
+        ptoc = cache.Persister(self.options.toc_pickle or None)
+        if not ptoc.object:
+            tries = 0
+            while True:
+                tries += 1
+                t = cdrdao.ReadTOCTask(device=self.device)
+                try:
+                    function(self.runner, t)
+                    break
+                except:
+                    if tries > 3:
+                        raise
+                    self.debug('failed to read TOC after %d tries, retrying' % tries)
+
+            version = t.tasks[1].parser.version
+            from pkg_resources import parse_version as V
+            # we've built a cdrdao 1.2.3rc2 modified package with the patch
+            if V(version) < V('1.2.3rc2p1'):
+                self.stdout.write('Warning: cdrdao older than 1.2.3 has a '
+                    'pre-gap length bug.\n'
+                    'See http://sourceforge.net/tracker/?func=detail'
+                    '&aid=604751&group_id=2171&atid=102171\n')
+            ptoc.persist(t.table)
+        self.ittoc = ptoc.object
+        assert self.ittoc.hasTOC()
+
+        # already show us some info based on this
+        self.program.getRipResult(self.ittoc.getCDDBDiscId())
+        self.stdout.write("CDDB disc id: %s\n" % self.ittoc.getCDDBDiscId())
+        self.mbdiscid = self.ittoc.getMusicBrainzDiscId()
+        self.stdout.write("MusicBrainz disc id %s\n" % self.mbdiscid)
+
+        self.stdout.write("MusicBrainz lookup URL %s\n" %
+            self.ittoc.getMusicBrainzSubmitURL())
+
+        self.program.metadata = self.program.getMusicBrainz(self.ittoc, self.mbdiscid,
+            release=self.options.release_id)
+
+        if not self.program.metadata:
+            # fall back to FreeDB for lookup
+            cddbid = self.ittoc.getCDDBValues()
+            cddbmd = self.program.getCDDB(cddbid)
+            if cddbmd:
+                self.stdout.write('FreeDB identifies disc as %s\n' % cddbmd)
+
+            if not self.options.unknown:
+                self.program.ejectDevice(self.device)
+                return -1
+
+        # now, read the complete index table, which is slower
+        self.itable = self.program.getTable(self.runner, self.ittoc.getCDDBDiscId(), self.device)
+
+        assert self.itable.getCDDBDiscId() == self.ittoc.getCDDBDiscId(), \
+            "full table's id %s differs from toc id %s" % (
+                self.itable.getCDDBDiscId(), self.ittoc.getCDDBDiscId())
+        assert self.itable.getMusicBrainzDiscId() == self.ittoc.getMusicBrainzDiscId(), \
+            "full table's mb id %s differs from toc id mb %s" % (
+            self.itable.getMusicBrainzDiscId(), self.ittoc.getMusicBrainzDiscId())
+        assert self.itable.getAccurateRipURL() == self.ittoc.getAccurateRipURL(), \
+            "full table's AR URL %s differs from toc AR URL %s" % (
+            self.itable.getAccurateRipURL(), self.ittoc.getAccurateRipURL())
+
+        # result
+
+        self.program.result.cdrdaoVersion = version
+        self.program.result.cdparanoiaVersion = cdparanoia.getCdParanoiaVersion()
+        info = drive.getDeviceInfo(self.parentCommand.options.device)
+        if info:
+            try:
+                self.program.result.cdparanoiaDefeatsCache = self.getRootCommand(
+                    ).config.getDefeatsCache(*info)
+            except KeyError, e:
+                self.debug('Got key error: %r' % (e, ))
+        self.program.result.artist = self.program.metadata and self.program.metadata.artist \
+            or 'Unknown Artist'
+        self.program.result.title = self.program.metadata and self.program.metadata.title \
+            or 'Unknown Title'
+        # cdio is optional for now
+        try:
+            import cdio
+            _, self.program.result.vendor, self.program.result.model, self.program.result.release = \
+                cdio.Device(self.device).get_hwinfo()
+        except ImportError:
+            self.stdout.write(
+                'WARNING: pycdio not installed, cannot identify drive\n')
+            self.program.result.vendor = 'Unknown'
+            self.program.result.model = 'Unknown'
+            self.program.result.release = 'Unknown'
+
+        self.doCommand()
+
+        self.program.ejectDevice(self.device)
+
+    def doCommand(self):
+        pass
+
+
+class Info(_CD):
+    pass
+
+
+class Rip(_CD):
     summary = "rip CD"
 
     # see morituri.common.program.Program.getPath for expansion
@@ -55,6 +186,8 @@ Log files will log the path to tracks relative to this directory.
 """ % rcommon.TEMPLATE_DESCRIPTION
 
     def addOptions(self):
+        _CD.addOptions(self)
+
         loggers = result.getLoggers().keys()
 
         self.parser.add_option('-L', '--logger',
@@ -77,17 +210,9 @@ Log files will log the path to tracks relative to this directory.
             action="store", dest="working_directory",
             help="working directory; morituri will change to this directory "
                 "and files will be created relative to it when not absolute ")
-        # FIXME: have a cache of these pickles somewhere
-        self.parser.add_option('-T', '--toc-pickle',
-            action="store", dest="toc_pickle",
-            help="pickle to use for reading and writing the TOC")
 
         rcommon.addTemplate(self)
 
-        self.parser.add_option('-R', '--release-id',
-            action="store", dest="release_id",
-            help="MusicBrainz release id to match to (if there are multiple)")
-
         default = 'flac'
 
         # here to avoid import gst eating our options
@@ -125,151 +250,55 @@ Log files will log the path to tracks relative to this directory.
         if self.options.output_directory is None:
             self.options.output_directory = os.getcwd()
 
-    def do(self, args):
-        prog = program.Program(record=self.getRootCommand().record,
-            stdout=self.stdout)
-        runner = task.SyncRunner()
-
-        def function(r, t):
-            r.run(t)
-
-        # if the device is mounted (data session), unmount it
-        device = self.parentCommand.options.device
-        self.stdout.write('Checking device %s\n' % device)
-
-        prog.setWorkingDirectory(self.options.working_directory)
-        prog.loadDevice(device)
-        prog.unmountDevice(device)
-
-        version = None
-
-        # first, read the normal TOC, which is fast
-        ptoc = cache.Persister(self.options.toc_pickle or None)
-        if not ptoc.object:
-            tries = 0
-            while True:
-                tries += 1
-                t = cdrdao.ReadTOCTask(device=device)
-                try:
-                    function(runner, t)
-                    break
-                except:
-                    if tries > 3:
-                        raise
-                    self.debug('failed to read TOC after %d tries, retrying' % tries)
-
-            version = t.tasks[1].parser.version
-            from pkg_resources import parse_version as V
-            # we've built a cdrdao 1.2.3rc2 modified package with the patch
-            if V(version) < V('1.2.3rc2p1'):
-                self.stdout.write('Warning: cdrdao older than 1.2.3 has a '
-                    'pre-gap length bug.\n'
-                    'See http://sourceforge.net/tracker/?func=detail'
-                    '&aid=604751&group_id=2171&atid=102171\n')
-            ptoc.persist(t.table)
-        ittoc = ptoc.object
-        assert ittoc.hasTOC()
-
-        # already show us some info based on this
-        prog.getRipResult(ittoc.getCDDBDiscId())
-        self.stdout.write("CDDB disc id: %s\n" % ittoc.getCDDBDiscId())
-        mbdiscid = ittoc.getMusicBrainzDiscId()
-        self.stdout.write("MusicBrainz disc id %s\n" % mbdiscid)
-
-        self.stdout.write("MusicBrainz lookup URL %s\n" %
-            ittoc.getMusicBrainzSubmitURL())
-
-        prog.metadata = prog.getMusicBrainz(ittoc, mbdiscid,
-            release=self.options.release_id)
-
-        if not prog.metadata:
-            # fall back to FreeDB for lookup
-            cddbid = ittoc.getCDDBValues()
-            cddbmd = prog.getCDDB(cddbid)
-            if cddbmd:
-                self.stdout.write('FreeDB identifies disc as %s\n' % cddbmd)
-
-            if not self.options.unknown:
-                prog.ejectDevice(device)
-                return -1
-
-        # now, read the complete index table, which is slower
-        itable = prog.getTable(runner, ittoc.getCDDBDiscId(), device)
-
-        assert itable.getCDDBDiscId() == ittoc.getCDDBDiscId(), \
-            "full table's id %s differs from toc id %s" % (
-                itable.getCDDBDiscId(), ittoc.getCDDBDiscId())
-        assert itable.getMusicBrainzDiscId() == ittoc.getMusicBrainzDiscId(), \
-            "full table's mb id %s differs from toc id mb %s" % (
-            itable.getMusicBrainzDiscId(), ittoc.getMusicBrainzDiscId())
-        assert itable.getAccurateRipURL() == ittoc.getAccurateRipURL(), \
-            "full table's AR URL %s differs from toc AR URL %s" % (
-            itable.getAccurateRipURL(), ittoc.getAccurateRipURL())
-
-        prog.outdir = self.options.output_directory
-        prog.outdir = prog.outdir.decode('utf-8')
+    def doCommand(self):
         # here to avoid import gst eating our options
         from morituri.common import encode
         profile = encode.PROFILES[self.options.profile]()
+        self.program.result.profileName = profile.name
+        self.program.result.profilePipeline = profile.pipeline
+        elementFactory = profile.pipeline.split(' ')[0]
+        self.program.result.gstreamerVersion = gstreamer.gstreamerVersion()
+        self.program.result.gstPythonVersion = gstreamer.gstPythonVersion()
+        self.program.result.encoderVersion = gstreamer.elementFactoryVersion(
+            elementFactory)
 
-        # result
+        self.program.setWorkingDirectory(self.options.working_directory)
+        self.program.outdir = self.options.output_directory.decode('utf-8')
+        self.program.result.offset = int(self.options.offset)
 
-        prog.result.cdrdaoVersion = version
-        prog.result.cdparanoiaVersion = cdparanoia.getCdParanoiaVersion()
-        info = drive.getDeviceInfo(self.parentCommand.options.device)
-        if info:
-            try:
-                prog.result.cdparanoiaDefeatsCache = self.getRootCommand(
-                    ).config.getDefeatsCache(*info)
-            except KeyError, e:
-                self.debug('Got key error: %r' % (e, ))
-        prog.result.offset = int(self.options.offset)
-        prog.result.artist = prog.metadata and prog.metadata.artist \
-            or 'Unknown Artist'
-        prog.result.title = prog.metadata and prog.metadata.title \
-            or 'Unknown Title'
-        # cdio is optional for now
-        try:
-            import cdio
-            _, prog.result.vendor, prog.result.model, prog.result.release = \
-                cdio.Device(device).get_hwinfo()
-        except ImportError:
-            self.stdout.write(
-                'WARNING: pycdio not installed, cannot identify drive\n')
-            prog.result.vendor = 'Unknown'
-            prog.result.model = 'Unknown'
-            prog.result.release = 'Unknown'
+    ### write disc files
+        discName = self.program.getPath(self.program.outdir, self.options.disc_template,
+            self.mbdiscid, 0, profile=profile)
+        dirname = os.path.dirname(discName)
+        if not os.path.exists(dirname):
+            self.stdout.write("Creating output directory %s\n" % dirname)
+            os.makedirs(dirname)
+        # FIXME: say when we're continuing a rip
+        # FIXME: disambiguate if the pre-existing rip is different
 
-        prog.result.profileName = profile.name
-        prog.result.profilePipeline = profile.pipeline
-        elementFactory = profile.pipeline.split(' ')[0]
-        prog.result.gstreamerVersion = gstreamer.gstreamerVersion()
-        prog.result.gstPythonVersion = gstreamer.gstPythonVersion()
-        prog.result.encoderVersion = gstreamer.elementFactoryVersion(
-            elementFactory)
 
         # FIXME: turn this into a method
 
         def ripIfNotRipped(number):
             self.debug('ripIfNotRipped for track %d' % number)
             # we can have a previous result
-            trackResult = prog.result.getTrackResult(number)
+            trackResult = self.program.result.getTrackResult(number)
             if not trackResult:
                 trackResult = result.TrackResult()
-                prog.result.tracks.append(trackResult)
+                self.program.result.tracks.append(trackResult)
             else:
                 self.debug('ripIfNotRipped have trackresult, path %r' %
                     trackResult.filename)
 
-            path = prog.getPath(prog.outdir, self.options.track_template,
-                mbdiscid, number, profile=profile) + '.' + profile.extension
+            path = self.program.getPath(self.program.outdir, self.options.track_template,
+                self.mbdiscid, number, profile=profile) + '.' + profile.extension
             self.debug('ripIfNotRipped: path %r' % path)
             trackResult.number = number
 
             assert type(path) is unicode, "%r is not unicode" % path
             trackResult.filename = path
             if number > 0:
-                trackResult.pregap = itable.tracks[number - 1].getPregap()
+                trackResult.pregap = self.itable.tracks[number - 1].getPregap()
 
             # FIXME: optionally allow overriding reripping
             if os.path.exists(path):
@@ -280,9 +309,9 @@ Log files will log the path to tracks relative to this directory.
                         trackResult.filename, path))
 
                 self.stdout.write('Verifying track %d of %d: %s\n' % (
-                    number, len(itable.tracks),
+                    number, len(self.itable.tracks),
                     os.path.basename(path).encode('utf-8')))
-                if not prog.verifyTrack(runner, trackResult):
+                if not self.program.verifyTrack(self.runner, trackResult):
                     self.stdout.write('Verification failed, reripping...\n')
                     os.unlink(path)
 
@@ -293,20 +322,20 @@ Log files will log the path to tracks relative to this directory.
                 trackResult.testduration = 0.0
                 trackResult.copyduration = 0.0
                 self.stdout.write('Ripping track %d of %d: %s\n' % (
-                    number, len(itable.tracks),
+                    number, len(self.itable.tracks),
                     os.path.basename(path).encode('utf-8')))
                 while tries < MAX_TRIES:
                     tries += 1
                     try:
                         self.debug('ripIfNotRipped: track %d, try %d',
                             number, tries)
-                        prog.ripTrack(runner, trackResult,
+                        self.program.ripTrack(self.runner, trackResult,
                             offset=int(self.options.offset),
                             device=self.parentCommand.options.device,
                             profile=profile,
-                            taglist=prog.getTagList(number),
+                            taglist=self.program.getTagList(number),
                             what='track %d of %d' % (
-                                number, len(itable.tracks)))
+                                number, len(self.itable.tracks)))
                         break
                     except Exception, e:
                         self.debug('Got exception %r on try %d',
@@ -333,18 +362,18 @@ Log files will log the path to tracks relative to this directory.
             # overlay this rip onto the Table
             if number == 0:
                 # HTOA goes on index 0 of track 1
-                itable.setFile(1, 0, trackResult.filename,
-                    ittoc.getTrackStart(1), number)
+                self.itable.setFile(1, 0, trackResult.filename,
+                    self.ittoc.getTrackStart(1), number)
             else:
-                itable.setFile(number, 1, trackResult.filename,
-                    ittoc.getTrackLength(number), number)
+                self.itable.setFile(number, 1, trackResult.filename,
+                    self.ittoc.getTrackLength(number), number)
 
-            prog.saveRipResult()
+            self.program.saveRipResult()
 
 
         # check for hidden track one audio
         htoapath = None
-        htoa = prog.getHTOA()
+        htoa = self.program.getHTOA()
         if htoa:
             start, stop = htoa
             self.stdout.write(
@@ -353,9 +382,9 @@ Log files will log the path to tracks relative to this directory.
 
             # rip it
             ripIfNotRipped(0)
-            htoapath = prog.result.tracks[0].filename
+            htoapath = self.program.result.tracks[0].filename
 
-        for i, track in enumerate(itable.tracks):
+        for i, track in enumerate(self.itable.tracks):
             # FIXME: rip data tracks differently
             if not track.audio:
                 self.stdout.write(
@@ -368,14 +397,14 @@ Log files will log the path to tracks relative to this directory.
             ripIfNotRipped(i + 1)
 
         ### write disc files
-        discName = prog.getPath(prog.outdir, self.options.disc_template,
-            mbdiscid, 0, profile=profile)
+        discName = self.program.getPath(self.program.outdir, self.options.disc_template,
+            self.mbdiscid, 0, profile=profile)
         dirname = os.path.dirname(discName)
         if not os.path.exists(dirname):
             os.makedirs(dirname)
 
         self.debug('writing cue file for %r', discName)
-        prog.writeCue(discName)
+        self.program.writeCue(discName)
 
         # write .m3u file
         self.debug('writing m3u file for %r', discName)
@@ -393,21 +422,21 @@ Log files will log the path to tracks relative to this directory.
 
         if htoapath:
             writeFile(handle, htoapath,
-                itable.getTrackStart(1) / common.FRAMES_PER_SECOND)
+                self.itable.getTrackStart(1) / common.FRAMES_PER_SECOND)
 
-        for i, track in enumerate(itable.tracks):
+        for i, track in enumerate(self.itable.tracks):
             if not track.audio:
                 continue
 
-            path = prog.getPath(prog.outdir, self.options.track_template,
-                mbdiscid, i + 1, profile=profile) + '.' + profile.extension
+            path = self.program.getPath(self.program.outdir, self.options.track_template,
+                self.mbdiscid, i + 1, profile=profile) + '.' + profile.extension
             writeFile(handle, path,
-                itable.getTrackLength(i + 1) / common.FRAMES_PER_SECOND)
+                self.itable.getTrackLength(i + 1) / common.FRAMES_PER_SECOND)
 
         handle.close()
 
         # verify using accuraterip
-        url = ittoc.getAccurateRipURL()
+        url = self.ittoc.getAccurateRipURL()
         self.stdout.write("AccurateRip URL %s\n" % url)
 
         accucache = accurip.AccuCache()
@@ -420,34 +449,34 @@ Log files will log the path to tracks relative to this directory.
             self.stdout.write('%d AccurateRip reponses found\n' %
                 len(responses))
 
-            if responses[0].cddbDiscId != itable.getCDDBDiscId():
+            if responses[0].cddbDiscId != self.itable.getCDDBDiscId():
                 self.stdout.write(
                     "AccurateRip response discid different: %s\n" %
                     responses[0].cddbDiscId)
 
 
-        prog.verifyImage(runner, responses)
+        self.program.verifyImage(self.runner, responses)
 
-        self.stdout.write("\n".join(prog.getAccurateRipResults()) + "\n")
+        self.stdout.write("\n".join(self.program.getAccurateRipResults()) + "\n")
 
-        prog.saveRipResult()
+        self.program.saveRipResult()
 
         # write log file
         try:
             klazz = result.getLoggers()[self.options.logger]
-            prog.writeLog(discName, klazz())
+            self.program.writeLog(discName, klazz())
         except KeyError:
             self.stderr.write("No logger named %s found!\n" % (
                 self.options.logger))
 
-        prog.ejectDevice(device)
+        self.program.ejectDevice(self.device)
 
 
 class CD(logcommand.LogCommand):
 
     summary = "handle CD's"
 
-    subCommandClasses = [Rip, ]
+    subCommandClasses = [Info, Rip, ]
 
     def addOptions(self):
         self.parser.add_option('-d', '--device',

-- 
morituri packaging



More information about the pkg-multimedia-commits mailing list