Exemplo n.º 1
0
    def do(self, args):
        runner = task.SyncRunner()
        t = cdparanoia.AnalyzeTask(self.options.device)
        runner.run(t)

        if t.defeatsCache is None:
            self.stdout.write(
                'Cannot analyze the drive.  Is there a CD in it?\n')
            return
        if not t.defeatsCache:
            self.stdout.write(
                'cdparanoia cannot defeat the audio cache on this drive.\n')
        else:
            self.stdout.write(
                'cdparanoia can defeat the audio cache on this drive.\n')

        info = drive.getDeviceInfo(self.options.device)
        if not info:
            self.stdout.write(
                'Drive caching behaviour not saved: could not get device info (requires pycdio).\n'
            )
            return

        self.stdout.write(
            'Adding drive cache behaviour to configuration file.\n')

        self.getRootCommand().config.setDefeatsCache(info[0], info[1], info[2],
                                                     t.defeatsCache)
Exemplo n.º 2
0
    def _testSuffix(self, suffix):
        # because of https://bugzilla.gnome.org/show_bug.cgi?id=688625
        # we first create the file with a 'normal' filename, then rename
        self.runner = task.SyncRunner(verbose=False)
        fd, path = tempfile.mkstemp()

        cmd = "gst-launch " \
            "audiotestsrc num-buffers=100 samplesperbuffer=1024 ! " \
            "audioconvert ! audio/x-raw-int,width=16,depth=16,channels =2 ! " \
            "wavenc ! " \
            "filesink location=\"%s\" > /dev/null 2>&1" % (
            gstreamer.quoteParse(path).encode('utf-8'), )
        self.debug('Running cmd %r' % cmd)
        os.system(cmd)
        self.failUnless(os.path.exists(path))
        os.close(fd)

        fd, newpath = tempfile.mkstemp(suffix=suffix)
        os.rename(path, newpath)

        encodetask = encode.EncodeTask(newpath, newpath + '.out',
            encode.WavProfile())
        self.runner.run(encodetask, verbose=False)
        os.close(fd)
        os.unlink(newpath)
        os.unlink(newpath + '.out')
Exemplo n.º 3
0
    def testWrite(self):
        fd, inpath = tempfile.mkstemp(suffix=u'.morituri.tagwrite.flac')

        # wave is pink-noise because a pure sine is encoded too efficiently
        # by flacenc and triggers not enough frames in parsing
        # FIXME: file a bug for this in GStreamer
        os.system('gst-launch '
                  'audiotestsrc '
                  'wave=pink-noise num-buffers=10 samplesperbuffer=588 ! '
                  'audioconvert ! '
                  'audio/x-raw-int,channels=2,width=16,height=16,rate=44100 ! '
                  'flacenc ! filesink location=%s > /dev/null 2>&1' % inpath)
        os.close(fd)

        fd, outpath = tempfile.mkstemp(suffix=u'.morituri.tagwrite.flac')
        self.runner = task.SyncRunner(verbose=False)
        taglist = gst.TagList()
        taglist[gst.TAG_ARTIST] = 'Artist'
        taglist[gst.TAG_TITLE] = 'Title'

        t = encode.TagWriteTask(inpath, outpath, taglist)
        self.runner.run(t)

        t = encode.TagReadTask(outpath)
        self.runner.run(t)
        self.failUnless(t.taglist)
        self.assertEquals(t.taglist['audio-codec'], 'FLAC')
        self.assertEquals(t.taglist['description'], 'audiotest wave')
        self.assertEquals(t.taglist[gst.TAG_ARTIST], 'Artist')
        self.assertEquals(t.taglist[gst.TAG_TITLE], 'Title')

        os.unlink(inpath)
        os.unlink(outpath)
Exemplo n.º 4
0
    def do(self, args):
        prog = program.Program()
        runner = task.SyncRunner()

        for arg in args:
            print 'Retagging image %r' % arg
            arg = arg.decode('utf-8')
            cueImage = image.Image(arg)
            cueImage.setup(runner)

            mbdiscid = cueImage.table.getMusicBrainzDiscId()
            prog.metadata = prog.getMusicBrainz(cueImage.table, mbdiscid)

            if not prog.metadata:
                print 'Not in MusicBrainz database, skipping'
                continue

            # FIXME: this feels like we're poking at internals.
            prog.cuePath = arg
            prog.result = result.RipResult()
            for track in cueImage.table.tracks:
                path = track.indexes[1].path
                taglist = prog.getTagList(track.number)
                self.debug('possibly retagging %r with taglist %r', path,
                           taglist)
                t = encode.SafeRetagTask(path, taglist)
                runner.run(t)
                path = os.path.basename(path)
                if t.changed:
                    print 'Retagged %s' % path
                else:
                    print '%s already tagged correctly' % path
            print
Exemplo n.º 5
0
 def testRead(self):
     path = os.path.join(os.path.dirname(__file__), u'track.flac')
     self.runner = task.SyncRunner(verbose=False)
     t = encode.TagReadTask(path)
     self.runner.run(t)
     self.failUnless(t.taglist)
     self.assertEquals(t.taglist['audio-codec'], 'FLAC')
     self.assertEquals(t.taglist['description'], 'audiotest wave')
    def testDefeatsCache(self):
        self.runner = task.SyncRunner(verbose=False)

        path = os.path.join(os.path.dirname(__file__), 'cdparanoia',
                            'PX-L890SA.cdparanoia-A.stderr')
        t = AnalyzeFileTask(path)
        self.runner.run(t)
        self.failUnless(t.defeatsCache)
Exemplo n.º 7
0
    def setUp(self):
        self._fd, self._path = tempfile.mkstemp(suffix=u'.morituri.retag.flac')

        os.system('gst-launch '
            'audiotestsrc '
                'num-buffers=40 samplesperbuffer=588 wave=pink-noise ! '
            'audioconvert ! '
            'audio/x-raw-int,channels=2,width=16,height=16,rate=44100 ! '
            'flacenc ! filesink location=%s > /dev/null 2>&1' % self._path)
        os.close(self._fd)
        self.runner = task.SyncRunner(verbose=False)
Exemplo n.º 8
0
    def do(self, args):
        # here to avoid import gst eating our options
        from morituri.common import encode

        prog = program.Program(self.getRootCommand().config,
                               stdout=self.stdout)
        runner = task.SyncRunner()

        for arg in args:
            self.stdout.write('Retagging image %r\n' % arg)
            arg = arg.decode('utf-8')
            cueImage = image.Image(arg)
            cueImage.setup(runner)

            mbdiscid = cueImage.table.getMusicBrainzDiscId()
            self.stdout.write('MusicBrainz disc id is %s\n' % mbdiscid)

            self.stdout.write("MusicBrainz lookup URL %s\n" %
                              cueImage.table.getMusicBrainzSubmitURL())
            prog.metadata = prog.getMusicBrainz(
                cueImage.table,
                mbdiscid,
                release=self.options.release_id,
                country=self.options.country,
                prompt=self.options.prompt)

            if not prog.metadata:
                print 'Not in MusicBrainz database, skipping'
                continue

            prog.metadata.discid = mbdiscid

            # FIXME: this feels like we're poking at internals.
            prog.cuePath = arg
            prog.result = result.RipResult()
            for track in cueImage.table.tracks:
                path = cueImage.getRealPath(track.indexes[1].path)

                taglist = prog.getTagList(track.number)
                self.debug(
                    'possibly retagging %r from cue path %r with taglist %r',
                    path, arg, taglist)
                t = encode.SafeRetagTask(path, taglist)
                runner.run(t)
                path = os.path.basename(path)
                if t.changed:
                    print 'Retagged %s' % path
                else:
                    print '%s already tagged correctly' % path
            print
Exemplo n.º 9
0
 def _testSuffix(self, suffix):
     self.runner = task.SyncRunner(verbose=False)
     fd, path = tempfile.mkstemp(suffix=suffix)
     t = image.AudioLengthTask(path)
     e = self.assertRaises(task.TaskException,
                           self.runner.run,
                           t,
                           verbose=False)
     self.failUnless(
         isinstance(e.exception, gstreamer.GstException),
         "%r is not a gstreamer.GstException" % e.exceptionMessage)
     self.assertEquals(e.exception.gerror.domain, gst.STREAM_ERROR)
     # our empty file triggers TYPE_NOT_FOUND
     self.assertEquals(e.exception.gerror.code,
                       gst.STREAM_ERROR_TYPE_NOT_FOUND)
     os.unlink(path)
Exemplo n.º 10
0
    def do(self, args):
        prog = program.Program(self.getRootCommand().config)
        prog.outdir = (self.options.output_directory or os.getcwd())
        prog.outdir = prog.outdir.decode('utf-8')

        # here to avoid import gst eating our options
        from morituri.common import encode

        profile = encode.ALL_PROFILES[self.options.profile]()

        runner = task.SyncRunner()

        for arg in args:
            arg = arg.decode('utf-8')
            indir = os.path.dirname(arg)
            cueImage = image.Image(arg)
            cueImage.setup(runner)
            # FIXME: find a decent way to get an album-specific outdir
            root = os.path.basename(indir)
            outdir = os.path.join(prog.outdir, root)
            try:
                os.makedirs(outdir)
            except:
                # FIXME: handle other exceptions than OSError Errno 17
                pass
            # FIXME: handle this nicer
            assert outdir != indir

            taskk = image.ImageEncodeTask(cueImage, profile, outdir)
            runner.run(taskk)

            # FIXME: translate .m3u file if it exists
            root, ext = os.path.splitext(arg)
            m3upath = root + '.m3u'
            if os.path.exists(m3upath):
                self.debug('translating .m3u file')
                inm3u = open(m3upath)
                outm3u = open(os.path.join(outdir, os.path.basename(m3upath)),
                              'w')
                for line in inm3u.readlines():
                    root, ext = os.path.splitext(line)
                    if ext:
                        # newline is swallowed by splitext here
                        outm3u.write('%s.%s\n' % (root, profile.extension))
                    else:
                        outm3u.write('%s' % root)
                outm3u.close()
Exemplo n.º 11
0
    def do(self, args):
        prog = program.Program()
        runner = task.SyncRunner()

        device = self.options.device

        # if necessary, load and unmount
        self.stdout.write('Checking device %s\n' % device)

        prog.loadDevice(device)
        prog.unmountDevice(device)

        # first get the Table Of Contents of the CD
        t = cdrdao.ReadTOCTask(device=device)

        try:
            runner.run(t)
        except cdrdao.DeviceOpenException, e:
            self.error(e.msg)
            return 3
Exemplo n.º 12
0
    def do(self, args):
        prog = program.Program(self.getRootCommand.config(),
                               stdout=self.stdout)
        runner = task.SyncRunner()

        for arg in args:
            self.stdout.write('Renaming image %r\n' % arg)
            arg = arg.decode('utf-8')
            cueImage = image.Image(arg)
            cueImage.setup(runner)

            mbdiscid = cueImage.table.getMusicBrainzDiscId()

            operator = renamer.Operator(statePath, mbdiscid)

            self.stdout.write('MusicBrainz disc id is %s\n' % mbdiscid)
            prog.metadata = prog.getMusicBrainz(
                cueImage.table, mbdiscid, release=self.options.release_id)

            if not prog.metadata:
                print 'Not in MusicBrainz database, skipping'
                continue

            # FIXME: this feels like we're poking at internals.
            prog.cuePath = arg
            prog.result = result.RipResult()
            for track in cueImage.table.tracks:
                path = cueImage.getRealPath(track.indexes[1].path)

                taglist = prog.getTagList(track.number)
                self.debug(
                    'possibly retagging %r from cue path %r with taglist %r',
                    path, arg, taglist)
                t = encode.SafeRetagTask(path, taglist)
                runner.run(t)
                path = os.path.basename(path)
                if t.changed:
                    print 'Retagged %s' % path
                else:
                    print '%s already tagged correctly' % path
            print
Exemplo n.º 13
0
    def do(self, args):
        prog = program.Program(self.getRootCommand().config)
        runner = task.SyncRunner()
        cache = accurip.AccuCache()

        for arg in args:
            arg = arg.decode('utf-8')
            cueImage = image.Image(arg)
            cueImage.setup(runner)

            url = cueImage.table.getAccurateRipURL()
            responses = cache.retrieve(url)

            # FIXME: this feels like we're poking at internals.
            prog.cuePath = arg
            prog.result = result.RipResult()
            for track in cueImage.table.tracks:
                tr = result.TrackResult()
                tr.number = track.number
                prog.result.tracks.append(tr)

            prog.verifyImage(runner, responses)

            print "\n".join(prog.getAccurateRipResults()) + "\n"
Exemplo n.º 14
0
 def testLength(self):
     path = os.path.join(os.path.dirname(__file__), u'track.flac')
     t = image.AudioLengthTask(path)
     runner = task.SyncRunner()
     runner.run(t, verbose=False)
     self.assertEquals(t.length, 10 * common.SAMPLES_PER_FRAME)
Exemplo n.º 15
0
 def setUp(self):
     self.image = image.Image(
         os.path.join(os.path.dirname(__file__), u'track-separate.cue'))
     self.runner = task.SyncRunner(verbose=False)
     self.image.setup(self.runner)
Exemplo n.º 16
0
    def do(self, args):
        prog = program.Program(record=self.getRootCommand().record)
        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.loadDevice(device)
        prog.unmountDevice(device)

        version = None

        # first, read the normal TOC, which is fast
        ptoc = common.Persister(self.options.toc_pickle or None)
        if not ptoc.object:
            t = cdrdao.ReadTOCTask(device=device)
            function(runner, t)
            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.
See  http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171
''')
            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,
                                            self.options.release)

        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 or os.getcwd())
        prog.outdir = prog.outdir.decode('utf-8')
        # here to avoid import gst eating our options
        from morituri.common import encode
        profile = encode.PROFILES[self.options.profile]()

        # result

        prog.result.cdrdao_version = version
        prog.result.cdparanoia_version = cdparanoia.ParanoiaVersion()
        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'

        # FIXME: turn this into a method

        def ripIfNotRipped(number):
            # we can have a previous result
            trackResult = prog.result.getTrackResult(number)
            if not trackResult:
                trackResult = result.TrackResult()
                prog.result.tracks.append(trackResult)

            path = prog.getPath(prog.outdir, self.options.track_template,
                                mbdiscid, number) + '.' + profile.extension
            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()

            # FIXME: optionally allow overriding reripping
            if os.path.exists(path):
                self.stdout.write('Verifying track %d of %d: %s\n' %
                                  (number, len(itable.tracks),
                                   os.path.basename(path).encode('utf-8')))
                if not prog.verifyTrack(runner, trackResult):
                    self.stdout.write('Verification failed, reripping...\n')
                    os.unlink(path)

            if not os.path.exists(path):
                tries = 0
                self.stdout.write('Ripping track %d of %d: %s\n' %
                                  (number, len(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,
                                      offset=int(self.options.offset),
                                      device=self.parentCommand.options.device,
                                      profile=profile,
                                      taglist=prog.getTagList(number),
                                      what='track %d of %d' %
                                      (number, len(itable.tracks)))
                        break
                    except Exception, e:
                        self.debug('Got exception %r on try %d', e, tries)

                if tries == MAX_TRIES:
                    self.error('Giving up on track %d after %d times' %
                               (number, tries))
                if trackResult.testcrc == trackResult.copycrc:
                    self.stdout.write('Checksums match for track %d\n' %
                                      number)
                else:
                    self.stdout.write(
                        'ERROR: checksums did not match for track %d\n' %
                        number)
                    raise

                self.stdout.write('Peak level: %.2f %%\n' %
                                  (math.sqrt(trackResult.peak) * 100.0, ))
                self.stdout.write('Rip quality: %.2f %%\n' %
                                  (trackResult.quality * 100.0, ))

            # 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)
            else:
                itable.setFile(number, 1, trackResult.filename,
                               ittoc.getTrackLength(number), number)

            prog.saveRipResult()