Ejemplo n.º 1
0
    def getFastToc(self, runner, toc_pickle, device):
        """
        Retrieve the normal TOC table from a toc pickle or the drive.
        Also retrieves the cdrdao version

        @rtype: tuple of L{table.Table}, str
        """
        def function(r, t):
            r.run(t)

        ptoc = cache.Persister(toc_pickle or None)
        if not ptoc.object:
            from pkg_resources import parse_version as V
            version = cdrdao.getCDRDAOVersion()
            if V(version) < V('1.2.3rc2'):
                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')
            t = cdrdao.ReadTOCTask(device)
            ptoc.persist(t.table)
        toc = ptoc.object
        assert toc.hasTOC()
        return toc
Ejemplo n.º 2
0
    def do(self, args):
        prog = program.Program(self.getRootCommand().config)
        runner = ctask.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)
        table = t.table

        self.debug("CDDB disc id: %r", table.getCDDBDiscId())
        url = table.getAccurateRipURL()
        self.debug("AccurateRip URL: %s", url)

        # FIXME: download url as a task too
        responses = []
        import urllib2
        try:
            handle = urllib2.urlopen(url)
            data = handle.read()
            responses = accurip.getAccurateRipResponses(data)
        except urllib2.HTTPError, e:
            if e.code == 404:
                self.stdout.write(
                    'Album not found in AccurateRip database.\n')
                return 1
            else:
                raise
Ejemplo n.º 3
0
def main():
    log.init()

    parser = optparse.OptionParser()

    default = 0
    parser.add_option('-o', '--offset',
        action="store", dest="offset",
        help="sample offset (defaults to %d)" % default,
        default=default)

    options, args = parser.parse_args(sys.argv[1:])

    runner = task.SyncRunner()

    # first do a simple TOC scan
    t = cdrdao.ReadTOCTask()
    runner.run(t)
    toc = t.table

    offset = t.table.tracks[0].getIndex(1).absolute

    if offset < 150:
        print 'Disc is unlikely to have Hidden Track One Audio.'
    else:
        print 'Disc seems to have a %d frame HTOA.' % offset


    # now do a more extensive scan
    t = cdrdao.ReadTableTask()
    runner.run(t)

    # now check if we have a hidden track one audio
    track = t.table.tracks[0]
    try:
        index = track.getIndex(0)
    except KeyError:
        print 'No Hidden Track One Audio found.'
        return

    start = index.absolute
    stop = track.getIndex(1).absolute
    print 'Found Hidden Track One Audio from frame %d to %d' % (start, stop)
        
    # rip it
    riptask = cdparanoia.ReadVerifyTrackTask('track00.wav', t.table,
        start, stop - 1,
        offset=int(options.offset))
    runner.run(riptask)

    print 'runner done'

    if riptask.checksum is not None:
        print 'Checksums match'
    else:
        print 'Checksums did not match'
Ejemplo n.º 4
0
    def do(self, args):
        prog = program.Program(self.getRootCommand().config)
        runner = ctask.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
Ejemplo n.º 5
0
    def getFastToc(self, runner, toc_pickle, device):
        """
        Retrieve the normal TOC table from a toc pickle or the drive.
        Also retrieves the cdrdao version

        @rtype: tuple of L{table.Table}, str
        """
        def function(r, t):
            r.run(t)

        ptoc = cache.Persister(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)
        toc = ptoc.object
        assert toc.hasTOC()
        return toc
Ejemplo n.º 6
0
def main(argv):
    parser = optparse.OptionParser()

    default = 'cli'
    parser.add_option('-r',
                      '--runner',
                      action="store",
                      dest="runner",
                      help="runner ('cli' or 'gtk', defaults to %s)" % default,
                      default=default)

    # see http://www.accuraterip.com/driveoffsets.htm
    default = "0, 6, 12, 48, 91, 97, 102, 108, 120, " + \
        "564, 594, 667, 685, 691, 704, 738, 1194, 1292, 1336, 1776, -582"
    parser.add_option('-o',
                      '--offsets',
                      action="store",
                      dest="offsets",
                      help="list of offsets, comma-separated, "
                      "colon-separated for ranges (defaults to %s)" % default,
                      default=default)

    options, args = parser.parse_args(argv[1:])

    offsets = []
    blocks = options.offsets.split(',')
    for b in blocks:
        if ':' in b:
            a, b = b.split(':')
            offsets.extend(range(int(a), int(b) + 1))
        else:
            offsets.append(int(b))

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

    if options.runner == 'cli':
        runner = task.SyncRunner()
        function = climain
    elif options.runner == 'gtk':
        from morituri.common import taskgtk
        runner = taskgtk.GtkProgressRunner()
        function = gtkmain

    function(runner, t)
    table = t.table

    print "CDDB disc id", table.getCDDBDiscId()
    url = table.getAccurateRipURL()
    print "AccurateRip URL", url

    # FIXME: download url as a task too
    responses = []
    import urllib2
    try:
        handle = urllib2.urlopen(url)
        data = handle.read()
        responses = image.getAccurateRipResponses(data)
    except urllib2.HTTPError, e:
        if e.code == 404:
            print 'Album not found in AccurateRip database'
            sys.exit(1)
        else:
            raise
Ejemplo n.º 7
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()
Ejemplo n.º 8
0
def main(argv):
    parser = optparse.OptionParser()

    default = 'cli'
    parser.add_option('-r', '--runner',
        action="store", dest="runner",
        help="runner ('cli' or 'gtk', defaults to %s)" % default,
        default=default)
    default = 0
    parser.add_option('-o', '--offset',
        action="store", dest="offset",
        help="sample offset (defaults to %d)" % default,
        default=default)
    parser.add_option('-t', '--table-pickle',
        action="store", dest="table_pickle",
        help="pickle to use for reading and writing the table",
        default=default)
    parser.add_option('-T', '--toc-pickle',
        action="store", dest="toc_pickle",
        help="pickle to use for reading and writing the TOC",
        default=default)
    default = '%A - %d/%t. %a - %n'
    parser.add_option('', '--track-template',
        action="store", dest="track_template",
        help="template for track file naming (default %s)" % default,
        default=default)
    default = '%A - %d/%A - %d'
    parser.add_option('', '--disc-template',
        action="store", dest="disc_template",
        help="template for disc file naming (default %s)" % default,
        default=default)


    options, args = parser.parse_args(argv[1:])

    if options.runner == 'cli':
        runner = task.SyncRunner()
        function = climain
    elif options.runner == 'gtk':
        from morituri.common import taskgtk
        runner = taskgtk.GtkProgressRunner()
        function = gtkmain

    # first, read the normal TOC, which is fast
    ptoc = common.Persister(options.toc_pickle or None)
    if not ptoc.object:
        t = cdrdao.ReadTOCTask()
        function(runner, t)
        ptoc.persist(t.table)
    ittoc = ptoc.object
    assert ittoc.hasTOC()

    # already show us some info based on this
    print "CDDB disc id", ittoc.getCDDBDiscId()
    metadata = musicbrainz(ittoc.getMusicBrainzDiscId())

    # now, read the complete index table, which is slower
    ptable = common.Persister(options.table_pickle or None)
    if not ptable.object:
        t = cdrdao.ReadTableTask()
        function(runner, t)
        ptable.persist(t.table)
    itable = ptable.object

    assert itable.hasTOC()

    assert itable.getCDDBDiscId() == ittoc.getCDDBDiscId(), \
        "full table's id %s differs from toc id %s" % (
            itable.getCDDBDiscId(), ittoc.getCDDBDiscId())
    assert itable.getMusicBrainzDiscId() == ittoc.getMusicBrainzDiscId()

    lastTrackStart = 0

    # check for hidden track one audio
    htoapath = None
    index = None
    track = itable.tracks[0]
    try:
        index = track.getIndex(0)
    except KeyError:
        pass

    if index:
        start = index.absolute
        stop = track.getIndex(1).absolute
        print 'Found Hidden Track One Audio from frame %d to %d' % (start, stop)
            
        # rip it
        htoapath = getPath(options.track_template, metadata, -1) + '.wav'
        htoalength = stop - start
        if not os.path.exists(htoapath):
            print 'Ripping track %d: %s' % (0, os.path.basename(htoapath))
            t = cdparanoia.ReadVerifyTrackTask(htoapath, ittoc,
                start, stop - 1,
                offset=int(options.offset))
            function(runner, t)
            if t.checksum:
                print 'Checksums match for track %d' % 0
            else:
                print 'ERROR: checksums did not match for track %d' % 0
            # overlay this rip onto the Table
        itable.setFile(1, 0, htoapath, htoalength, 0)


    for i, track in enumerate(itable.tracks):
        path = getPath(options.track_template, metadata, i) + '.wav'
        dirname = os.path.dirname(path)
        if not os.path.exists(dirname):
            os.makedirs(dirname)

        # FIXME: optionally allow overriding reripping
        if not os.path.exists(path):
            print 'Ripping track %d: %s' % (i + 1, os.path.basename(path))
            t = cdparanoia.ReadVerifyTrackTask(path, ittoc,
                ittoc.getTrackStart(i + 1),
                ittoc.getTrackEnd(i + 1),
                offset=int(options.offset))
            t.description = 'Reading Track %d' % (i + 1)
            function(runner, t)
            if t.checksum:
                print 'Checksums match for track %d' % (i + 1)
            else:
                print 'ERROR: checksums did not match for track %d' % (i + 1)

        # overlay this rip onto the Table
        itable.setFile(i + 1, 1, path, ittoc.getTrackLength(i + 1), i + 1)


    ### write disc files
    discName = getPath(options.disc_template, metadata, i)
    dirname = os.path.dirname(discName)
    if not os.path.exists(dirname):
        os.makedirs(dirname)

    # write .cue file
    cuePath = '%s.cue' % discName
    handle = open(cuePath, 'w')
    handle.write(itable.cue())
    handle.close()

    # write .m3u file
    m3uPath = '%s.m3u' % discName
    handle = open(m3uPath, 'w')
    handle.write('#EXTM3U\n')
    if htoapath:
        handle.write('#EXTINF:%d,%s\n' % (
            htoalength / common.FRAMES_PER_SECOND,
                os.path.basename(htoapath[:-4])))
        handle.write('%s\n' % os.path.basename(htoapath))

    for i, track in enumerate(itable.tracks):
        path = getPath(options.track_template, metadata, i) + '.wav'
        handle.write('#EXTINF:%d,%s\n' % (
            itable.getTrackLength(i + 1) / common.FRAMES_PER_SECOND,
            os.path.basename(path)))
        handle.write('%s\n' % os.path.basename(path))
    handle.close()

    # verify using accuraterip
    print "CDDB disc id", itable.getCDDBDiscId()
    print "MusicBrainz disc id", itable.getMusicBrainzDiscId()
    url = itable.getAccurateRipURL()
    print "AccurateRip URL", url

    # FIXME: download url as a task too
    responses = []
    import urllib2
    try:
        handle = urllib2.urlopen(url)
        data = handle.read()
        responses = image.getAccurateRipResponses(data)
    except urllib2.HTTPError, e:
        if e.code == 404:
            print 'Album not found in AccurateRip database'
        else:
            raise