Пример #1
0
 def test_report_no_result(self):
     track = TrackResult()
     track.number = 1
     self.result.tracks[0] = track
     print_report(self.result)
     self.assertEqual(sys.stdout.getvalue(),
                      'track  1: unknown          (error)\n')
Пример #2
0
 def test_report_v1_and_v2_max_confidence(self):
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  1: rip accurate     (max confidence     12)'
         ' v1 [284fc705], v2 [dc77f9ab], DB [284fc705, dc77f9ab]\n'
     )
Пример #3
0
 def test_htoa_not_tracked(self):
     self.result.tracks[0].number = 0
     self.result.tracks[0].AR['v1']['CRC'] = None
     self.result.tracks[0].AR['v2']['CRC'] = None
     print_report(self.result)
     self.assertEqual(sys.stdout.getvalue(),
                      'track  0: unknown          (not tracked)\n')
Пример #4
0
    def do(self):
        prog = program.Program(config.Config())
        runner = task.SyncRunner()

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

            # 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)

            verified = False
            try:
                verified = prog.verifyImage(runner, cueImage.table)
            except accurip.EntryNotFound:
                print('AccurateRip entry not found')
            accurip.print_report(prog.result)
            if not verified:
                sys.exit(1)
Пример #5
0
 def test_report_v1_and_v2(self):
     self.result.tracks[0].AR['DBMaxConfidence'] = 66
     print_report(self.result)
     self.assertEqual(
         sys.stdout.getvalue(),
         'track  1: rip accurate     (confidence  12 of  66)'
         ' v1 [284fc705], v2 [dc77f9ab], DB [284fc705, dc77f9ab]\n')
Пример #6
0
 def test_track_not_found(self):
     self.result.tracks[0].AR['DBMaxConfidence'] = None
     print_report(self.result)
     self.assertEqual(
         sys.stdout.getvalue(),
         'track  1: rip NOT accurate (not found)            '
         ' v1 [284fc705], v2 [dc77f9ab], DB [notfound]\n')
Пример #7
0
    def do(self):
        prog = program.Program(config.Config())
        runner = task.SyncRunner()

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

            # 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)

            verified = False
            try:
                verified = prog.verifyImage(runner, cueImage.table)
            except accurip.EntryNotFound:
                print('AccurateRip entry not found')
            accurip.print_report(prog.result)
            if not verified:
                sys.exit(1)
Пример #8
0
 def test_report_v1_and_v2(self):
     self.result.tracks[0].AR['DBMaxConfidence'] = 66
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  1: rip accurate     (confidence  12 of  66)'
         ' v1 [284fc705], v2 [dc77f9ab], DB [284fc705, dc77f9ab]\n'
     )
Пример #9
0
 def test_track_not_found(self):
     self.result.tracks[0].AR['DBMaxConfidence'] = None
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  1: rip NOT accurate (not found)            '
         ' v1 [284fc705], v2 [dc77f9ab], DB [notfound]\n'
     )
Пример #10
0
 def test_report_v2_only(self):
     self.result.tracks[0].AR['v1']['DBCRC'] = None
     self.result.tracks[0].AR['v1']['DBConfidence'] = None
     print_report(self.result)
     self.assertEqual(
         sys.stdout.getvalue(),
         'track  1: rip accurate     (confidence   4 of  12)'
         ' v1 [284fc705], v2 [dc77f9ab], DB [dc77f9ab]\n')
Пример #11
0
 def test_htoa_not_tracked(self):
     self.result.tracks[0].number = 0
     self.result.tracks[0].AR['v1']['CRC'] = None
     self.result.tracks[0].AR['v2']['CRC'] = None
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  0: unknown          (not tracked)\n'
     )
Пример #12
0
 def test_report_no_result(self):
     track = TrackResult()
     track.number = 1
     self.result.tracks[0] = track
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  1: unknown          (error)\n'
     )
Пример #13
0
 def test_report_v2_only(self):
     self.result.tracks[0].AR['v1']['DBCRC'] = None
     self.result.tracks[0].AR['v1']['DBConfidence'] = None
     print_report(self.result)
     self.assertEquals(
         sys.stdout.getvalue(),
         'track  1: rip accurate     (confidence   4 of  12)'
         ' v1 [284fc705], v2 [dc77f9ab], DB [dc77f9ab]\n'
     )
Пример #14
0
    def doCommand(self):
        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)
        self.program.result.overread = self.options.overread
        self.program.result.logger = self.options.logger

        discName = self.program.getPath(self.program.outdir,
                                        self.options.disc_template,
                                        self.mbdiscid,
                                        self.program.metadata)
        dirname = os.path.dirname(discName)
        if os.path.exists(dirname):
            logs = glob.glob(os.path.join(dirname, '*.log'))
            if logs:
                msg = ("output directory %s is a finished rip" %
                       dirname.encode('utf-8'))
                logger.critical(msg)
                raise RuntimeError(msg)
            else:
                sys.stdout.write("output directory %s already exists\n" %
                                 dirname.encode('utf-8'))
        else:
            print("creating output directory %s" % dirname.encode('utf-8'))
            os.makedirs(dirname)

        # FIXME: turn this into a method

        def _ripIfNotRipped(number):
            logger.debug('ripIfNotRipped for track %d' % number)
            # we can have a previous result
            trackResult = self.program.result.getTrackResult(number)
            if not trackResult:
                trackResult = result.TrackResult()
                self.program.result.tracks.append(trackResult)
            else:
                logger.debug('ripIfNotRipped have trackresult, path %r' %
                             trackResult.filename)

            path = self.program.getPath(self.program.outdir,
                                        self.options.track_template,
                                        self.mbdiscid,
                                        self.program.metadata,
                                        track_number=number) + '.flac'
            logger.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 = self.itable.tracks[number - 1].getPregap()

                trackResult.pre_emphasis = (
                    self.itable.tracks[number - 1].pre_emphasis
                )

            # FIXME: optionally allow overriding reripping
            if os.path.exists(path):
                if path != trackResult.filename:
                    # the path is different (different name/template ?)
                    # but we can copy it
                    logger.debug('previous result %r, expected %r' % (
                        trackResult.filename, path))

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

            if not os.path.exists(path):
                logger.debug('path %r does not exist, ripping...' % path)
                tries = 0
                # we reset durations for test and copy here
                trackResult.testduration = 0.0
                trackResult.copyduration = 0.0
                extra = ""
                while tries < MAX_TRIES:
                    tries += 1
                    if tries > 1:
                        extra = " (try %d)" % tries
                    sys.stdout.write('Ripping track %d of %d%s: %s\n' % (
                        number, len(self.itable.tracks), extra,
                        os.path.basename(path).encode('utf-8')))
                    try:
                        logger.debug('ripIfNotRipped: track %d, try %d',
                                     number, tries)
                        self.program.ripTrack(self.runner, trackResult,
                                              offset=int(self.options.offset),
                                              device=self.device,
                                              taglist=self.program.getTagList(
                                                  number),
                                              overread=self.options.overread,
                                              what='track %d of %d%s' % (
                                                  number,
                                                  len(self.itable.tracks),
                                                  extra))
                        break
                    except Exception as e:
                        logger.debug('Got exception %r on try %d',
                                     e, tries)

                if tries == MAX_TRIES:
                    logger.critical('Giving up on track %d after %d times' % (
                        number, tries))
                    raise RuntimeError(
                        "track can't be ripped. "
                        "Rip attempts number is equal to 'MAX_TRIES'")
                if trackResult.testcrc == trackResult.copycrc:
                    sys.stdout.write('CRCs match for track %d\n' % number)
                else:
                    raise RuntimeError(
                        "CRCs did not match for track %d\n" % number
                    )

                sys.stdout.write(
                    'Peak level: {:.2%} \n'.format(trackResult.peak))

                sys.stdout.write(
                    'Rip quality: {:.2%}\n'.format(trackResult.quality))

            # overlay this rip onto the Table
            if number == 0:
                # HTOA goes on index 0 of track 1
                # ignore silence in PREGAP
                if trackResult.peak <= SILENT:
                    logger.debug(
                        'HTOA peak %r is below SILENT '
                        'threshold, disregarding', trackResult.peak)
                    self.itable.setFile(1, 0, None,
                                        self.ittoc.getTrackStart(1), number)
                    logger.debug('Unlinking %r', trackResult.filename)
                    os.unlink(trackResult.filename)
                    trackResult.filename = None
                    sys.stdout.write(
                        'HTOA discarded, contains digital silence\n')
                else:
                    self.itable.setFile(1, 0, trackResult.filename,
                                        self.ittoc.getTrackStart(1), number)
            else:
                self.itable.setFile(number, 1, trackResult.filename,
                                    self.ittoc.getTrackLength(number), number)

            self.program.saveRipResult()

        # check for hidden track one audio
        htoa = self.program.getHTOA()
        if htoa:
            start, stop = htoa
            print('found Hidden Track One Audio from frame %d to %d' % (
                  start, stop))
            _ripIfNotRipped(0)

        for i, track in enumerate(self.itable.tracks):
            # FIXME: rip data tracks differently
            if not track.audio:
                print('skipping data track %d, not implemented' % (i + 1))
                # FIXME: make it work for now
                track.indexes[1].relative = 0
                continue
            _ripIfNotRipped(i + 1)

        logger.debug('writing cue file for %r', discName)
        self.program.writeCue(discName)

        logger.debug('writing m3u file for %r', discName)
        self.program.write_m3u(discName)

        try:
            self.program.verifyImage(self.runner, self.ittoc)
        except accurip.EntryNotFound:
            print('AccurateRip entry not found')

        accurip.print_report(self.program.result)

        self.program.saveRipResult()

        self.program.writeLog(discName, self.logger)
Пример #15
0
    def doCommand(self):
        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)
        self.program.result.overread = self.options.overread
        self.program.result.logger = self.options.logger

        discName = self.program.getPath(self.program.outdir,
                                        self.options.disc_template,
                                        self.mbdiscid,
                                        self.program.metadata)
        dirname = os.path.dirname(discName)
        if os.path.exists(dirname):
            logs = glob.glob(os.path.join(dirname, '*.log'))
            if logs:
                msg = ("output directory %s is a finished rip" %
                       dirname.encode('utf-8'))
                logger.critical(msg)
                raise RuntimeError(msg)
            else:
                sys.stdout.write("output directory %s already exists\n" %
                                 dirname.encode('utf-8'))
        print("creating output directory %s" % dirname.encode('utf-8'))
        os.makedirs(dirname)

        # FIXME: turn this into a method

        def _ripIfNotRipped(number):
            logger.debug('ripIfNotRipped for track %d' % number)
            # we can have a previous result
            trackResult = self.program.result.getTrackResult(number)
            if not trackResult:
                trackResult = result.TrackResult()
                self.program.result.tracks.append(trackResult)
            else:
                logger.debug('ripIfNotRipped have trackresult, path %r' %
                             trackResult.filename)

            path = self.program.getPath(self.program.outdir,
                                        self.options.track_template,
                                        self.mbdiscid,
                                        self.program.metadata,
                                        track_number=number) + '.flac'
            logger.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 = self.itable.tracks[number - 1].getPregap()

                trackResult.pre_emphasis = (
                    self.itable.tracks[number - 1].pre_emphasis
                )

            # FIXME: optionally allow overriding reripping
            if os.path.exists(path):
                if path != trackResult.filename:
                    # the path is different (different name/template ?)
                    # but we can copy it
                    logger.debug('previous result %r, expected %r' % (
                        trackResult.filename, path))

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

            if not os.path.exists(path):
                logger.debug('path %r does not exist, ripping...' % path)
                tries = 0
                # we reset durations for test and copy here
                trackResult.testduration = 0.0
                trackResult.copyduration = 0.0
                extra = ""
                while tries < MAX_TRIES:
                    tries += 1
                    if tries > 1:
                        extra = " (try %d)" % tries
                    sys.stdout.write('Ripping track %d of %d%s: %s\n' % (
                        number, len(self.itable.tracks), extra,
                        os.path.basename(path).encode('utf-8')))
                    try:
                        logger.debug('ripIfNotRipped: track %d, try %d',
                                     number, tries)
                        self.program.ripTrack(self.runner, trackResult,
                                              offset=int(self.options.offset),
                                              device=self.device,
                                              taglist=self.program.getTagList(
                                                  number),
                                              overread=self.options.overread,
                                              what='track %d of %d%s' % (
                                                  number,
                                                  len(self.itable.tracks),
                                                  extra))
                        break
                    except Exception as e:
                        logger.debug('Got exception %r on try %d',
                                     e, tries)

                if tries == MAX_TRIES:
                    logger.critical('Giving up on track %d after %d times' % (
                        number, tries))
                    raise RuntimeError(
                        "track can't be ripped. "
                        "Rip attempts number is equal to 'MAX_TRIES'")
                if trackResult.testcrc == trackResult.copycrc:
                    sys.stdout.write('CRCs match for track %d\n' % number)
                else:
                    raise RuntimeError(
                        "CRCs did not match for track %d\n" % number
                    )

                sys.stdout.write(
                    'Peak level: {:.2%} \n'.format(trackResult.peak))

                sys.stdout.write(
                    'Rip quality: {:.2%}\n'.format(trackResult.quality))

            # overlay this rip onto the Table
            if number == 0:
                # HTOA goes on index 0 of track 1
                # ignore silence in PREGAP
                if trackResult.peak <= SILENT:
                    logger.debug(
                        'HTOA peak %r is below SILENT '
                        'threshold, disregarding', trackResult.peak)
                    self.itable.setFile(1, 0, None,
                                        self.ittoc.getTrackStart(1), number)
                    logger.debug('Unlinking %r', trackResult.filename)
                    os.unlink(trackResult.filename)
                    trackResult.filename = None
                    sys.stdout.write(
                        'HTOA discarded, contains digital silence\n')
                else:
                    self.itable.setFile(1, 0, trackResult.filename,
                                        self.ittoc.getTrackStart(1), number)
            else:
                self.itable.setFile(number, 1, trackResult.filename,
                                    self.ittoc.getTrackLength(number), number)

            self.program.saveRipResult()

        # check for hidden track one audio
        htoa = self.program.getHTOA()
        if htoa:
            start, stop = htoa
            print('found Hidden Track One Audio from frame %d to %d' % (
                  start, stop))
            _ripIfNotRipped(0)

        for i, track in enumerate(self.itable.tracks):
            # FIXME: rip data tracks differently
            if not track.audio:
                print('skipping data track %d, not implemented' % (i + 1))
                # FIXME: make it work for now
                track.indexes[1].relative = 0
                continue
            _ripIfNotRipped(i + 1)

        logger.debug('writing cue file for %r', discName)
        self.program.writeCue(discName)

        logger.debug('writing m3u file for %r', discName)
        self.program.write_m3u(discName)

        try:
            self.program.verifyImage(self.runner, self.ittoc)
        except accurip.EntryNotFound:
            print('AccurateRip entry not found')

        accurip.print_report(self.program.result)

        self.program.saveRipResult()

        self.program.writeLog(discName, self.logger)
Пример #16
0
class Rip(_CD):
    summary = "rip CD"
    # see whipper.common.program.Program.getPath for expansion
    description = """
Rips a CD.

%s

Paths to track files referenced in .cue and .m3u files will be made
relative to the directory of the disc files.

All files will be created relative to the given output directory.
Log files will log the path to tracks relative to this directory.
""" % TEMPLATE_DESCRIPTION
    formatter_class = argparse.ArgumentDefaultsHelpFormatter

    # Requires opts.record
    # Requires opts.device

    def add_arguments(self):
        loggers = result.getLoggers().keys()
        default_offset = None
        info = drive.getDeviceInfo(self.opts.device)
        if info:
            try:
                default_offset = config.Config().getReadOffset(*info)
                sys.stdout.write("Using configured read offset %d\n" %
                                 default_offset)
            except KeyError:
                pass

        _CD.add_arguments(self.parser)

        self.parser.add_argument('-L',
                                 '--logger',
                                 action="store",
                                 dest="logger",
                                 default='whipper',
                                 help="logger to use (choose from '"
                                 "', '".join(loggers) + "')")
        # FIXME: get from config
        self.parser.add_argument('-o',
                                 '--offset',
                                 action="store",
                                 dest="offset",
                                 default=default_offset,
                                 help="sample read offset")
        self.parser.add_argument('-x',
                                 '--force-overread',
                                 action="store_true",
                                 dest="overread",
                                 default=False,
                                 help="Force overreading into the "
                                 "lead-out portion of the disc. Works only "
                                 "if the patched cdparanoia package is "
                                 "installed and the drive "
                                 "supports this feature. ")
        self.parser.add_argument('-O',
                                 '--output-directory',
                                 action="store",
                                 dest="output_directory",
                                 default=os.path.relpath(os.getcwd()),
                                 help="output directory; will be included "
                                 "in file paths in log")
        self.parser.add_argument('-W',
                                 '--working-directory',
                                 action="store",
                                 dest="working_directory",
                                 help="working directory; whipper will "
                                 "change to this directory "
                                 "and files will be created relative to "
                                 "it when not absolute")
        self.parser.add_argument('--track-template',
                                 action="store",
                                 dest="track_template",
                                 default=DEFAULT_TRACK_TEMPLATE,
                                 help="template for track file naming")
        self.parser.add_argument('--disc-template',
                                 action="store",
                                 dest="disc_template",
                                 default=DEFAULT_DISC_TEMPLATE,
                                 help="template for disc file naming")
        self.parser.add_argument('-U',
                                 '--unknown',
                                 action="store_true",
                                 dest="unknown",
                                 help="whether to continue ripping if "
                                 "the CD is unknown",
                                 default=False)
        self.parser.add_argument('--cdr',
                                 action="store_true",
                                 dest="cdr",
                                 help="whether to continue ripping if "
                                 "the disc is a CD-R",
                                 default=False)

    def handle_arguments(self):
        self.options.output_directory = os.path.expanduser(
            self.options.output_directory)

        self.options.track_template = self.options.track_template.decode(
            'utf-8')
        self.options.disc_template = self.options.disc_template.decode('utf-8')

        if self.options.offset is None:
            raise ValueError("Drive offset is unconfigured.\n"
                             "Please install pycdio and run 'whipper offset "
                             "find' to detect your drive's offset or set it "
                             "manually in the configuration file. It can "
                             "also be specified at runtime using the "
                             "'--offset=value' argument")

        if self.options.working_directory is not None:
            self.options.working_directory = os.path.expanduser(
                self.options.working_directory)

        if self.options.logger:
            try:
                self.logger = result.getLoggers()[self.options.logger]()
            except KeyError:
                msg = "No logger named %s found!" % self.options.logger
                logger.critical(msg)
                raise ValueError(msg)

    def doCommand(self):
        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)
        self.program.result.overread = self.options.overread
        self.program.result.logger = self.options.logger

        discName = self.program.getPath(self.program.outdir,
                                        self.options.disc_template,
                                        self.mbdiscid, self.program.metadata)
        dirname = os.path.dirname(discName)
        if os.path.exists(dirname):
            logs = glob.glob(os.path.join(dirname, '*.log'))
            if logs:
                msg = ("output directory %s is a finished rip" %
                       dirname.encode('utf-8'))
                logger.critical(msg)
                raise RuntimeError(msg)
            else:
                sys.stdout.write("output directory %s already exists\n" %
                                 dirname.encode('utf-8'))
        print("creating output directory %s" % dirname.encode('utf-8'))
        os.makedirs(dirname)

        # FIXME: turn this into a method

        def _ripIfNotRipped(number):
            logger.debug('ripIfNotRipped for track %d' % number)
            # we can have a previous result
            trackResult = self.program.result.getTrackResult(number)
            if not trackResult:
                trackResult = result.TrackResult()
                self.program.result.tracks.append(trackResult)
            else:
                logger.debug('ripIfNotRipped have trackresult, path %r' %
                             trackResult.filename)

            path = self.program.getPath(self.program.outdir,
                                        self.options.track_template,
                                        self.mbdiscid,
                                        self.program.metadata,
                                        track_number=number) + '.flac'
            logger.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 = self.itable.tracks[number - 1].getPregap()

                trackResult.pre_emphasis = (self.itable.tracks[number -
                                                               1].pre_emphasis)

            # FIXME: optionally allow overriding reripping
            if os.path.exists(path):
                if path != trackResult.filename:
                    # the path is different (different name/template ?)
                    # but we can copy it
                    logger.debug('previous result %r, expected %r' %
                                 (trackResult.filename, path))

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

            if not os.path.exists(path):
                logger.debug('path %r does not exist, ripping...' % path)
                tries = 0
                # we reset durations for test and copy here
                trackResult.testduration = 0.0
                trackResult.copyduration = 0.0
                extra = ""
                while tries < MAX_TRIES:
                    tries += 1
                    if tries > 1:
                        extra = " (try %d)" % tries
                    sys.stdout.write('Ripping track %d of %d%s: %s\n' %
                                     (number, len(self.itable.tracks), extra,
                                      os.path.basename(path).encode('utf-8')))
                    try:
                        logger.debug('ripIfNotRipped: track %d, try %d',
                                     number, tries)
                        self.program.ripTrack(
                            self.runner,
                            trackResult,
                            offset=int(self.options.offset),
                            device=self.device,
                            taglist=self.program.getTagList(number),
                            overread=self.options.overread,
                            what='track %d of %d%s' %
                            (number, len(self.itable.tracks), extra))
                        break
                    except Exception, e:
                        logger.debug('Got exception %r on try %d', e, tries)

                if tries == MAX_TRIES:
                    logger.critical('Giving up on track %d after %d times' %
                                    (number, tries))
                    raise RuntimeError(
                        "track can't be ripped. "
                        "Rip attempts number is equal to 'MAX_TRIES'")
                if trackResult.testcrc == trackResult.copycrc:
                    sys.stdout.write('CRCs match for track %d\n' % number)
                else:
                    raise RuntimeError("CRCs did not match for track %d\n" %
                                       number)

                sys.stdout.write('Peak level: {:.2%} \n'.format(
                    trackResult.peak))

                sys.stdout.write('Rip quality: {:.2%}\n'.format(
                    trackResult.quality))

            # overlay this rip onto the Table
            if number == 0:
                # HTOA goes on index 0 of track 1
                # ignore silence in PREGAP
                if trackResult.peak <= SILENT:
                    logger.debug(
                        'HTOA peak %r is below SILENT '
                        'threshold, disregarding', trackResult.peak)
                    self.itable.setFile(1, 0, None,
                                        self.ittoc.getTrackStart(1), number)
                    logger.debug('Unlinking %r', trackResult.filename)
                    os.unlink(trackResult.filename)
                    trackResult.filename = None
                    sys.stdout.write(
                        'HTOA discarded, contains digital silence\n')
                else:
                    self.itable.setFile(1, 0, trackResult.filename,
                                        self.ittoc.getTrackStart(1), number)
            else:
                self.itable.setFile(number, 1, trackResult.filename,
                                    self.ittoc.getTrackLength(number), number)

            self.program.saveRipResult()

        # check for hidden track one audio
        htoa = self.program.getHTOA()
        if htoa:
            start, stop = htoa
            print('found Hidden Track One Audio from frame %d to %d' %
                  (start, stop))
            _ripIfNotRipped(0)

        for i, track in enumerate(self.itable.tracks):
            # FIXME: rip data tracks differently
            if not track.audio:
                print('skipping data track %d, not implemented' % (i + 1))
                # FIXME: make it work for now
                track.indexes[1].relative = 0
                continue
            _ripIfNotRipped(i + 1)

        logger.debug('writing cue file for %r', discName)
        self.program.writeCue(discName)

        logger.debug('writing m3u file for %r', discName)
        self.program.write_m3u(discName)

        try:
            self.program.verifyImage(self.runner, self.ittoc)
        except accurip.EntryNotFound:
            print('AccurateRip entry not found')

        accurip.print_report(self.program.result)

        self.program.saveRipResult()

        self.program.writeLog(discName, self.logger)
Пример #17
0
    def doCommand(self):
        self.program.setWorkingDirectory(self.options.working_directory)
        self.program.outdir = self.options.output_directory
        self.program.result.offset = int(self.options.offset)
        self.program.result.overread = self.options.overread
        self.program.result.logger = self.options.logger

        discName = self.program.getPath(self.program.outdir,
                                        self.options.disc_template,
                                        self.mbdiscid,
                                        self.program.metadata)
        dirname = os.path.dirname(discName)
        if os.path.exists(dirname):
            logs = glob.glob(os.path.join(dirname, '*.log'))
            if logs:
                msg = ("output directory %s is a finished rip" % dirname)
                logger.debug(msg)
                raise RuntimeError(msg)
        else:
            logger.info("creating output directory %s", dirname)
            os.makedirs(dirname)

        self.coverArtPath = None
        if (self.options.cover_art in {"embed", "complete"} and
                importlib.util.find_spec("PIL") is None):
            logger.warning("the cover art option '%s' won't be honored "
                           "because the 'pillow' module isn't available",
                           self.options.cover_art)
        elif self.options.cover_art in {"file", "embed", "complete"}:
            if getattr(self.program.metadata, "mbid", None) is not None:
                self.coverArtPath = self.program.getCoverArt(
                                        dirname,
                                        self.program.metadata.mbid)
            else:
                logger.warning("the cover art option '%s' won't be honored "
                               "because disc metadata isn't available",
                               self.options.cover_art)
        if self.options.cover_art == "file":
            self.coverArtPath = None  # NOTE: avoid image embedding (hacky)

        # FIXME: turn this into a method
        def _ripIfNotRipped(number):
            logger.debug('ripIfNotRipped for track %d', number)
            # we can have a previous result
            trackResult = self.program.result.getTrackResult(number)
            if not trackResult:
                trackResult = result.TrackResult()
                self.program.result.tracks.append(trackResult)
            else:
                logger.debug('ripIfNotRipped have trackresult, path %r',
                             trackResult.filename)

            path = self.program.getPath(self.program.outdir,
                                        self.options.track_template,
                                        self.mbdiscid,
                                        self.program.metadata,
                                        track_number=number) + '.flac'
            logger.debug('ripIfNotRipped: path %r', path)
            trackResult.number = number

            assert isinstance(path, str), "%r is not str" % path
            trackResult.filename = path
            if number > 0:
                trackResult.pregap = self.itable.tracks[number - 1].getPregap()

                trackResult.pre_emphasis = (
                    self.itable.tracks[number - 1].pre_emphasis
                )

            # FIXME: optionally allow overriding reripping
            if os.path.exists(path):
                if path != trackResult.filename:
                    # the path is different (different name/template ?)
                    # but we can copy it
                    logger.debug('previous result %r, expected %r',
                                 trackResult.filename, path)

                logger.info('verifying track %d of %d: %s',
                            number, len(self.itable.tracks),
                            os.path.basename(path))
                if not self.program.verifyTrack(self.runner, trackResult):
                    logger.warning('verification failed, reripping...')
                    os.unlink(path)

            if not os.path.exists(path):
                logger.debug('path %r does not exist, ripping...', path)
                # we reset durations for test and copy here
                trackResult.testduration = 0.0
                trackResult.copyduration = 0.0
                extra = ""
                tries = 1
                while tries <= self.options.max_retries:
                    if tries > 1:
                        extra = " (try %d)" % tries
                    logger.info('ripping track %d of %d%s: %s',
                                number, len(self.itable.tracks), extra,
                                os.path.basename(path))

                    logger.debug('ripIfNotRipped: track %d, try %d', number,
                                 tries)
                    tag_list = self.program.getTagList(number, self.mbdiscid)
                    # An HTOA can't have an ISRC value
                    if (number > 0 and
                            self.itable.tracks[number - 1].isrc is not None):
                        tag_list['ISRC'] = self.itable.tracks[number - 1].isrc

                    try:
                        self.program.ripTrack(self.runner, trackResult,
                                              offset=int(self.options.offset),
                                              device=self.device,
                                              taglist=tag_list,
                                              overread=self.options.overread,
                                              what='track %d of %d%s' % (
                                                  number,
                                                  len(self.itable.tracks),
                                                  extra),
                                              coverArtPath=self.coverArtPath)
                        break
                    # FIXME: catching too general exception (Exception)
                    except Exception as e:
                        logger.debug('got exception %r on try %d', e, tries)
                        tries += 1

                if tries > self.options.max_retries:
                    tries -= 1
                    logger.critical('giving up on track %d after %d times',
                                    number, tries)
                    if self.options.keep_going:
                        logger.warning("track %d failed to rip.", number)
                        logger.debug("adding %s to skipped_tracks",
                                     trackResult)
                        self.skipped_tracks.append(trackResult)
                        logger.debug("skipped_tracks = %s",
                                     self.skipped_tracks)
                        trackResult.skipped = True
                    else:
                        raise RuntimeError("track can't be ripped. "
                                           "Rip attempts number is equal "
                                           "to %d",
                                           self.options.max_retries)
                if trackResult in self.skipped_tracks:
                    print("Skipping CRC comparison for track %d "
                          "due to rip failure" % number)
                else:
                    if trackResult.testcrc == trackResult.copycrc:
                        logger.info('CRCs match for track %d', number)
                    else:
                        raise RuntimeError(
                            "CRCs did not match for track %d" % number
                        )

                    print('Peak level: %.6f' % (trackResult.peak / 32768.0))
                    print('Rip quality: {:.2%}'.format(trackResult.quality))

            # overlay this rip onto the Table
            if number == 0:
                # HTOA goes on index 0 of track 1
                # ignore silence in PREGAP
                if trackResult.peak == SILENT:
                    logger.debug('HTOA peak %r is equal to the SILENT '
                                 'threshold, disregarding', trackResult.peak)
                    self.itable.setFile(1, 0, None,
                                        self.itable.getTrackStart(1), number)
                    logger.debug('unlinking %r', trackResult.filename)
                    os.unlink(trackResult.filename)
                    trackResult.filename = None
                    logger.info('HTOA discarded, contains digital silence')
                else:
                    self.itable.setFile(1, 0, trackResult.filename,
                                        self.itable.getTrackStart(1), number)
            else:
                self.itable.setFile(number, 1, trackResult.filename,
                                    self.itable.getTrackLength(number),
                                    number)

        # check for hidden track one audio
        htoa = self.program.getHTOA()
        if htoa:
            start, stop = htoa
            logger.info('found Hidden Track One Audio from frame %d to %d',
                        start, stop)
            _ripIfNotRipped(0)

        for i, track in enumerate(self.itable.tracks):
            # FIXME: rip data tracks differently
            if not track.audio:
                logger.warning('skipping data track %d, not implemented',
                               i + 1)
                # FIXME: make it work for now
                track.indexes[1].relative = 0
                continue
            _ripIfNotRipped(i + 1)

        # NOTE: Seems like some kind of with … or try: … finally: … clause
        # would be more appropriate, since otherwise this would potentially
        # leave stray files lying around in case of crashes etc.
        # <Freso 2020-01-03, GitHub comment>
        if (self.options.cover_art == "embed" and
                self.coverArtPath is not None):
            logger.debug('deleting cover art file at: %r', self.coverArtPath)
            os.remove(self.coverArtPath)

        logger.debug('writing cue file for %r', discName)
        self.program.writeCue(discName)

        logger.debug('writing m3u file for %r', discName)
        self.program.write_m3u(discName)

        if len(self.skipped_tracks) > 0:
            logger.warning("the generated cue sheet references %d track(s) "
                           "which failed to rip so the associated file(s) "
                           "won't be available", len(self.skipped_tracks))
            self.program.skipped_tracks = self.skipped_tracks

        try:
            self.program.verifyImage(self.runner, self.itable)
        except accurip.EntryNotFound:
            logger.warning('AccurateRip entry not found')

        accurip.print_report(self.program.result)

        self.program.writeLog(discName, self.logger)

        if len(self.skipped_tracks) > 0:
            logger.warning('%d tracks have been skipped from this rip attempt',
                           len(self.skipped_tracks))
            return 5