Exemple #1
0
    def logRip(self, ripResult, epoch):

        lines = []

        ### global

        lines.append("Logfile created by: morituri %s" % configure.version)
        # FIXME: when we localize this, see #49 to handle unicode properly.
        import locale
        old = locale.getlocale(locale.LC_TIME)
        locale.setlocale(locale.LC_TIME, 'C')
        date = time.strftime("%b %d %H:%M:%S", time.localtime(epoch))
        locale.setlocale(locale.LC_TIME, old)
        lines.append("Logfile created on: %s" % date)
        lines.append("")

        # album
        lines.append("Album: %s - %s" % (ripResult.artist, ripResult.title))
        lines.append("")

        lines.append("CDDB disc id:           %s" %
                     ripResult.table.getCDDBDiscId())
        lines.append("MusicBrainz disc id:    %s" %
                     ripResult.table.getMusicBrainzDiscId())
        lines.append("MusicBrainz lookup URL: %s" %
                     ripResult.table.getMusicBrainzSubmitURL())
        lines.append("")

        # drive
        lines.append("Drive: vendor %s, model %s" %
                     (ripResult.vendor, ripResult.model))
        lines.append("")

        lines.append("Read offset correction: %d" % ripResult.offset)
        lines.append("")

        # toc
        lines.append("Table of Contents:")
        lines.append("")
        lines.append("     Track |   Start           |  Length")
        lines.append("     ------------------------------------------------")
        table = ripResult.table

        for t in table.tracks:
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            lines.append("       %2d  | %6d - %s | %6d - %s" %
                         (t.number, start, common.framesToMSF(start), length,
                          common.framesToMSF(length)))

        lines.append("")
        lines.append("")

        ### per-track
        for t in ripResult.tracks:
            lines.extend(self.trackLog(t))
            lines.append('')

        return lines
    def trackLog(self, trackResult):
        """Returns Tracks section lines: data picked from trackResult"""

        lines = []

        # Track number
        lines.append("  %02d:" % trackResult.number)

        # Filename (including path) of ripped track
        lines.append("    Filename: %s" % trackResult.filename)

        # Pre-gap length
        pregap = trackResult.pregap
        if pregap:
            lines.append("    Pre-gap length: %s" % common.framesToMSF(pregap))

        # Peak level
        peak = trackResult.peak
        lines.append("    Peak level: %.6f" % peak)

        # Extraction speed
        if trackResult.copyspeed:
            lines.append("    Extraction speed: %.1f X" % (trackResult.copyspeed))

        # Extraction quality
        if trackResult.quality and trackResult.quality > 0.001:
            lines.append("    Extraction quality: %.2f %%" % (trackResult.quality * 100.0,))

        # Ripper Test CRC
        if trackResult.testcrc is not None:
            lines.append("    Test CRC: %08X" % trackResult.testcrc)

        # Ripper Copy CRC
        if trackResult.copycrc is not None:
            lines.append("    Copy CRC: %08X" % trackResult.copycrc)

        # AccurateRip track status
        # Currently there's no support for AccurateRip V2
        if trackResult.accurip:
            lines.append("    AccurateRip V1:")
            self._inARDatabase += 1
            if trackResult.ARCRC == trackResult.ARDBCRC:
                lines.append("      Result: Found, exact match")
                self._accuratelyRipped += 1
            else:
                lines.append("      Result: Found, NO exact match")
            lines.append("      Confidence: %d" % trackResult.ARDBConfidence)
            lines.append("      Local CRC: %08X" % trackResult.ARCRC)
            lines.append("      Remote CRC: %08X" % trackResult.ARDBCRC)
        elif trackResult.number != 0:
            lines.append("    AccurateRip V1:")
            lines.append("      Result: Track not present in " "AccurateRip database")

        # Check if Test & Copy CRCs are equal
        if trackResult.testcrc == trackResult.copycrc:
            lines.append("    Status: Copy OK")
        else:
            self._errors = True
            lines.append("    Status: Error, CRC mismatch")
        return lines
Exemple #3
0
    def trackLog(self, trackResult):

        lines = []

        lines.append('Track %2d' % trackResult.number)
        lines.append('')
        lines.append('     Filename %s' % trackResult.filename)
        lines.append('')
        if trackResult.pregap:
            lines.append('     Pre-gap length %s' % common.framesToMSF(
                trackResult.pregap))
            lines.append('')

        lines.append('     Peak level %.06f' % trackResult.peak)
        if trackResult.testspeed:
            lines.append('     Extraction Speed (Test) %.4f X' % (
                trackResult.testspeed))
        if trackResult.copyspeed:
            lines.append('     Extraction Speed (Copy) %.4f X' % (
                trackResult.copyspeed))
        if trackResult.testcrc:
            lines.append('     Test CRC %08X' % trackResult.testcrc)
        if trackResult.copycrc:
            lines.append('     Copy CRC %08X' % trackResult.copycrc)
        if trackResult.ARCRC:
            lines.append('     AccurateRip signature %08X' % trackResult.ARCRC)

        if trackResult.accurip:
            lines.append('     Accurately ripped (confidence %d)' % (
                trackResult.ARDBConfidence))
        else:
            if trackResult.ARDBCRC:
                lines.append('     Cannot be verified as accurate, '
                    'AccurateRip returned [%08X]' % (
                        trackResult.ARDBCRC))
            else:
                lines.append('     Track not present in AccurateRip database')

        if trackResult.testcrc:
            if trackResult.testcrc == trackResult.copycrc:
                lines.append('     Copy OK')
            else:
                lines.append("     WARNING: CRCs don't match!")
        else:
            lines.append("     WARNING: no CRC check done")

        return lines
Exemple #4
0
    def trackLog(self, trackResult):
        lines = []
        lines.append("  %02d:" % trackResult.number)
        lines.append("    Filename: %s" % trackResult.filename)
        pregap = trackResult.pregap
        if pregap:
            lines.append("    Pre-gap length: %s" % common.framesToMSF(pregap))
        peak = trackResult.peak
        lines.append("    Peak level: %.6f %%" % peak)
        if trackResult.copyspeed:
            lines.append("    Extraction speed: %.1f X" % (
                trackResult.copyspeed))
        if trackResult.quality and trackResult.quality > 0.001:
            lines.append("    Track quality: %.2f %%" %
                         (trackResult.quality * 100.0, ))
        if trackResult.testcrc is not None:
            lines.append("    Test CRC: %08X" % trackResult.testcrc)
        if trackResult.copycrc is not None:
            lines.append("    Copy CRC: %08X" % trackResult.copycrc)
        if trackResult.accurip:
            lines.append("    AccurateRip v1:")
            self._inARDatabase += 1
            if trackResult.ARCRC == trackResult.ARDBCRC:
                lines.append("      Result: Found, exact match")
                lines.append("      Confidence: %d" %
                             trackResult.ARDBConfidence)
                lines.append("      Checksum: %08X" % trackResult.ARCRC)
                self._accuratelyRipped += 1
            else:
                lines.append("      Result: Found, NO exact match "
                             "(confidence %d [%08X], AccurateRip "
                             "returned [%08x])" % (trackResult.ARDBConfidence,
                                                   trackResult.ARCRC,
                                                   trackResult.ARDBCRC))
        elif trackResult.number != 0:
            lines.append("    AccurateRip v1:")
            lines.append("      Result: Track not present in "
                         "AccurateRip database")

        if trackResult.testcrc == trackResult.copycrc:
            lines.append("    Status: Copy OK")
        else:
            self._errors = True
            lines.append("    Status: Error, CRC mismatch")
        return lines
Exemple #5
0
    def trackLog(self, trackResult):

        lines = []

        lines.append('Track %2d' % trackResult.number)
        lines.append('')
        lines.append('  Filename %s' % trackResult.filename)
        lines.append('')
        if trackResult.pregap:
            lines.append('  Pre-gap: %s' % common.framesToMSF(
                trackResult.pregap))
            lines.append('')

        lines.append('  Peak level %.1f %%' % (trackResult.peak * 100.0))
        if trackResult.copyspeed:
            lines.append('  Extraction Speed (Copy) %.4f X' % (
                trackResult.copyspeed))
        if trackResult.testspeed:
            lines.append('  Extraction Speed (Test) %.4f X' % (
                trackResult.testspeed))

        if trackResult.copycrc is not None:
            lines.append('  Copy CRC %08X' % trackResult.copycrc)
        if trackResult.testcrc is not None:
            lines.append('  Test CRC %08X' % trackResult.testcrc)
            if trackResult.testcrc == trackResult.copycrc:
                lines.append('  Copy OK')
            else:
                lines.append("  WARNING: CRCs don't match!")
        else:
            lines.append("  WARNING: no CRC check done")


        if trackResult.accurip:
            lines.append('  Accurately ripped (confidence %d) [%08X]' % (
                trackResult.ARDBConfidence, trackResult.ARCRC))
        else:
            if trackResult.ARDBCRC:
                lines.append('  Cannot be verified as accurate '
                    '[%08X], AccurateRip returned [%08X]' % (
                        trackResult.ARCRC, trackResult.ARDBCRC))
            else:
                lines.append('  Track not present in AccurateRip database')

        return lines
Exemple #6
0
    def trackLog(self, trackResult):

        lines = []

        lines.append("Track %2d" % trackResult.number)
        lines.append("")
        lines.append("     Filename %s" % trackResult.filename)
        lines.append("")
        if trackResult.pregap:
            lines.append("     Pre-gap length %s" % common.framesToMSF(trackResult.pregap))
            lines.append("")

        lines.append("     Peak level %.06f" % trackResult.peak)
        if trackResult.testspeed:
            lines.append("     Extraction Speed (Test) %.4f X" % (trackResult.testspeed))
        if trackResult.copyspeed:
            lines.append("     Extraction Speed (Copy) %.4f X" % (trackResult.copyspeed))
        if trackResult.testcrc:
            lines.append("     Test CRC %08X" % trackResult.testcrc)
        if trackResult.copycrc:
            lines.append("     Copy CRC %08X" % trackResult.copycrc)
        if trackResult.ARCRC:
            lines.append("     AccurateRip signature %08X" % trackResult.ARCRC)

        if trackResult.accurip:
            lines.append("     Accurately ripped (confidence %d)" % (trackResult.ARDBConfidence))
        else:
            if trackResult.ARDBCRC:
                lines.append(
                    "     Cannot be verified as accurate, " "AccurateRip returned [%08X]" % (trackResult.ARDBCRC)
                )
            else:
                lines.append("     Track not present in AccurateRip database")

        if trackResult.testcrc:
            if trackResult.testcrc == trackResult.copycrc:
                lines.append("     Copy OK")
            else:
                lines.append("     WARNING: CRCs don't match!")
        else:
            lines.append("     WARNING: no CRC check done")

        return lines
Exemple #7
0
    def trackLog(self, trackResult):
        lines = []
        lines.append("  %02d:" % trackResult.number)
        lines.append("    Filename: %s" % trackResult.filename)
        pregap = trackResult.pregap
        if pregap:
            lines.append("    Pre-gap length: %s" % common.framesToMSF(pregap))
        peak = trackResult.peak
        lines.append("    Peak level: %.6f %%" % peak)
        if trackResult.copyspeed:
            lines.append("    Extraction speed: %.1f X" %
                         (trackResult.copyspeed))
        if trackResult.quality and trackResult.quality > 0.001:
            lines.append("    Track quality: %.2f %%" %
                         (trackResult.quality * 100.0, ))
        if trackResult.testcrc is not None:
            lines.append("    Test CRC: %08X" % trackResult.testcrc)
        if trackResult.copycrc is not None:
            lines.append("    Copy CRC: %08X" % trackResult.copycrc)
        if trackResult.accurip:
            lines.append("    AccurateRip V1:")
            self._inARDatabase += 1
            if trackResult.ARCRC == trackResult.ARDBCRC:
                lines.append("      Result: Found, exact match")
                self._accuratelyRipped += 1
            else:
                lines.append("      Result: Found, NO exact match")
            lines.append("      Confidence: %d" % trackResult.ARDBConfidence)
            lines.append("      Local CRC: %08X" % trackResult.ARCRC)
            lines.append("      Remote CRC: %08X" % trackResult.ARDBCRC)
        elif trackResult.number != 0:
            lines.append("    AccurateRip V1:")
            lines.append("      Result: Track not present in "
                         "AccurateRip database")

        if trackResult.testcrc == trackResult.copycrc:
            lines.append("    Status: Copy OK")
        else:
            self._errors = True
            lines.append("    Status: Error, CRC mismatch")
        return lines
Exemple #8
0
    def cue(self, cuePath='', program='morituri'):
        """
        @param cuePath: path to the cue file to be written. If empty,
                        will treat paths as if in current directory.


        Dump our internal representation to a .cue file content.

        @rtype: C{unicode}
        """
        self.debug('generating .cue for cuePath %r', cuePath)

        lines = []

        def writeFile(path):
            targetPath = common.getRelativePath(path, cuePath)
            line = 'FILE "%s" WAVE' % targetPath
            lines.append(line)
            self.debug('writeFile: %r' % line)

        # header
        main = ['PERFORMER', 'TITLE']

        for key in CDTEXT_FIELDS:
                if key not in main and key in self.cdtext:
                    lines.append("    %s %s" % (key, self.cdtext[key]))

        assert self.hasTOC(), "Table does not represent a full CD TOC"
        lines.append('REM DISCID %s' % self.getCDDBDiscId().upper())
        lines.append('REM COMMENT "%s %s"' % (program, configure.version))

        if self.catalog:
            lines.append("CATALOG %s" % self.catalog)

        for key in main:
            if key in self.cdtext:
                lines.append('%s "%s"' % (key, self.cdtext[key]))

        # FIXME:
        # - the first FILE statement goes before the first TRACK, even if
        #   there is a non-file-using PREGAP
        # - the following FILE statements come after the last INDEX that
        #   use that FILE; so before a next TRACK, PREGAP silence, ...

        # add the first FILE line; EAC always puts the first FILE
        # statement before TRACK 01 and any possible PRE-GAP
        firstTrack = self.tracks[0]
        index = firstTrack.getFirstIndex()
        indexOne = firstTrack.getIndex(1)
        counter = index.counter
        track = firstTrack

        while not index.path:
            t, i = self.getNextTrackIndex(track.number, index.number)
            track = self.tracks[t - 1]
            index = track.getIndex(i)
            counter = index.counter

        if index.path:
            self.debug('counter %d, writeFile' % counter)
            writeFile(index.path)

        for i, track in enumerate(self.tracks):
            self.debug('track i %r, track %r' % (i, track))
            # FIXME: skip data tracks for now
            if not track.audio:
                continue

            indexes = track.indexes.keys()
            indexes.sort()

            wroteTrack = False

            for number in indexes:
                index = track.indexes[number]
                self.debug('index %r, %r' % (number, index))

                # any time the source counter changes to a higher value,
                # write a FILE statement
                # it has to be higher, because we can run into the HTOA
                # at counter 0 here
                if index.counter > counter:
                    if index.path:
                        self.debug('counter %d, writeFile' % counter)
                        writeFile(index.path)
                    self.debug('setting counter to index.counter %r' %
                        index.counter)
                    counter = index.counter

                # any time we hit the first index, write a TRACK statement
                if not wroteTrack:
                    wroteTrack = True
                    line = "  TRACK %02d %s" % (i + 1, 'AUDIO')
                    lines.append(line)
                    self.debug('%r' % line)

                    for key in CDTEXT_FIELDS:
                        if key in track.cdtext:
                            lines.append('    %s "%s"' % (
                                key, track.cdtext[key]))

                    if track.isrc is not None:
                        lines.append("    ISRC %s" % track.isrc)

                    # handle TRACK 01 INDEX 00 specially
                    if 0 in indexes:
                        index00 = track.indexes[0]
                        if i == 0:
                            # if we have a silent pre-gap, output it
                            if not index00.path:
                                length = indexOne.absolute - index00.absolute
                                lines.append("    PREGAP %s" %
                                    common.framesToMSF(length))
                                continue

                        # handle any other INDEX 00 after its TRACK
                        lines.append("    INDEX %02d %s" % (0,
                            common.framesToMSF(index00.relative)))

                if number > 0:
                    # index 00 is output after TRACK up above
                    lines.append("    INDEX %02d %s" % (number,
                        common.framesToMSF(index.relative)))

        lines.append("")

        return "\n".join(lines)
Exemple #9
0
    def logRip(self, ripResult, epoch):
        """Returns logfile lines list"""

        lines = []

        # Ripper version
        # Only implemented in whipper (ripResult.logger)
        lines.append("Log created by: whipper %s (%s logger)" % (
                    morituri.__version__, ripResult.logger))

        # Rip date
        date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(epoch)).strip()
        lines.append("Log creation date: %s" % date)
        lines.append("")

        # Rip technical settings
        lines.append("Ripping phase information:")
        lines.append("  Drive: %s%s (revision %s)" % (
            ripResult.vendor, ripResult.model, ripResult.release))
        if ripResult.cdparanoiaDefeatsCache is None:
            defeat = "Unknown"
        elif ripResult.cdparanoiaDefeatsCache:
            defeat = "Yes"
        else:
            defeat = "No"
        lines.append("  Defeat audio cache: %s" % defeat)
        lines.append("  Read offset correction: %+d" % ripResult.offset)
        # Currently unsupported by the official cdparanoia package
        over = "No"
        # Only implemented in whipper (ripResult.overread)
        if ripResult.overread:
            over = "Yes"
        lines.append("  Overread into lead-out: %s" % over)
        # Next one fully works only using the patched cdparanoia package
        # lines.append("Fill up missing offset samples with silence: Yes")
        lines.append("  Gap detection: cdrdao %s" % ripResult.cdrdaoVersion)
        lines.append("")

        # Rip encoding settings
        lines.append("Encoding phase information:")
        lines.append("  Used output format: %s" % ripResult.profileName)
        lines.append("  GStreamer:")
        lines.append("    Pipeline: %s" % ripResult.profilePipeline)
        lines.append("    Version: %s" % ripResult.gstreamerVersion)
        lines.append("    Python version: %s" % ripResult.gstPythonVersion)
        lines.append("    Encoder plugin version: %s" %
                     ripResult.encoderVersion)
        lines.append("")

        # CD metadata
        lines.append("CD metadata:")
        lines.append("  Album: %s - %s" % (ripResult.artist, ripResult.title))
        lines.append("  CDDB Disc ID: %s" % ripResult. table.getCDDBDiscId())
        lines.append("  MusicBrainz Disc ID: %s" %
                     ripResult. table.getMusicBrainzDiscId())
        lines.append("  MusicBrainz lookup url: %s" %
                     ripResult. table.getMusicBrainzSubmitURL())
        lines.append("")

        # TOC section
        lines.append("TOC:")
        table = ripResult.table

        # Test for HTOA presence
        htoa = None
        try:
            htoa = table.tracks[0].getIndex(0)
        except KeyError:
            pass

        # If True, include HTOA line into log's TOC
        if htoa and htoa.path:
            htoastart = htoa.absolute
            htoaend = table.getTrackEnd(0)
            htoalength = table.tracks[0].getIndex(1).absolute - htoastart
            lines.append("  00:")
            lines.append("    Start: %s" % common.framesToMSF(htoastart))
            lines.append("    Length: %s" % common.framesToMSF(htoalength))
            lines.append("    Start sector: %d" % htoastart)
            lines.append("    End sector: %d" % htoaend)
            lines.append("")

        # For every track include information in the TOC
        for t in table.tracks:
            # FIXME: what happens to a track start over 60 minutes ?
            # Answer: tested empirically, everything seems OK
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            end = table.getTrackEnd(t.number)
            lines.append("  %02d:" % t.number)
            lines.append("    Start: %s" % common.framesToMSF(start))
            lines.append("    Length: %s" % common.framesToMSF(length))
            lines.append("    Start sector: %d" % start)
            lines.append("    End sector: %d" % end)
            lines.append("")

        # Tracks section
        lines.append("Tracks:")
        duration = 0.0
        for t in ripResult.tracks:
            if not t.filename:
                continue
            lines.extend(self.trackLog(t))
            lines.append("")
            duration += t.testduration + t.copyduration

        # Status report
        lines.append("Conclusive status report:")
        arHeading = "  AccurateRip summary:"
        if self._inARDatabase == 0:
            lines.append("%s None of the tracks are present in the "
                         "AccurateRip database" % arHeading)
        else:
            nonHTOA = len(ripResult.tracks)
            if ripResult.tracks[0].number == 0:
                nonHTOA -= 1
            if self._accuratelyRipped == 0:
                lines.append("%s No tracks could be verified as accurate "
                             "(you may have a different pressing from the "
                             "one(s) in the database)" % arHeading)
            elif self._accuratelyRipped < nonHTOA:
                accurateTracks = nonHTOA - self._accuratelyRipped
                lines.append("%s Some tracks could not be verified as "
                             "accurate (%d/%d got no match)" % (
                              arHeading, accurateTracks, nonHTOA))
            else:
                lines.append("%s All tracks accurately ripped" % arHeading)

        hsHeading = "  Health status:"
        if self._errors:
            lines.append("%s There were errors" % hsHeading)
        else:
            lines.append("%s No errors occurred" % hsHeading)
        lines.append("  EOF: End of status report")
        lines.append("")

        # Log hash
        hasher = hashlib.sha256()
        hasher.update("\n".join(lines).encode("utf-8"))
        lines.append("SHA-256 hash: %s" % hasher.hexdigest().upper())
        lines.append("")
        return lines
Exemple #10
0
    def logRip(self, ripResult, epoch):

        lines = []

        ### global

        lines.append("Logfile created by: morituri %s" % configure.version)
        # FIXME: when we localize this, see #49 to handle unicode properly.
        import locale
        old = locale.getlocale(locale.LC_TIME)
        locale.setlocale(locale.LC_TIME, 'C')
        date = time.strftime("%b %d %H:%M:%S", time.localtime(epoch))
        locale.setlocale(locale.LC_TIME, old)
        lines.append("Logfile created on: %s" % date)
        lines.append("")

        # album
        lines.append("Album: %s - %s" % (ripResult.artist, ripResult.title))
        lines.append("")

        lines.append("CDDB disc id:           %s" % ripResult. table.getCDDBDiscId())
        lines.append("MusicBrainz disc id:    %s" % ripResult. table.getMusicBrainzDiscId())
        lines.append("MusicBrainz lookup URL: %s" % ripResult. table.getMusicBrainzSubmitURL())
        lines.append("")

        # drive
        lines.append(
            "Drive: vendor %s, model %s" % (
                ripResult.vendor, ripResult.model))
        lines.append("")

        lines.append("Read offset correction: %d" %
            ripResult.offset)
        lines.append("")

        # toc
        lines.append("Table of Contents:")
        lines.append("")
        lines.append(
            "     Track |   Start           |  Length")
        lines.append(
            "     ------------------------------------------------")
        table = ripResult.table


        for t in table.tracks:
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            lines.append(
            "       %2d  | %6d - %s | %6d - %s" % (
                t.number,
                start, common.framesToMSF(start),
                length, common.framesToMSF(length)))

        lines.append("")
        lines.append("")

        ### per-track
        for t in ripResult.tracks:
            lines.extend(self.trackLog(t))
            lines.append('')

        return lines
Exemple #11
0
    def cue(self, cuePath='', program='morituri'):
        """
        @param cuePath: path to the cue file to be written. If empty,
                        will treat paths as if in current directory.


        Dump our internal representation to a .cue file content.

        @rtype: C{unicode}
        """
        self.debug('generating .cue for cuePath %r', cuePath)

        lines = []

        def writeFile(path):
            targetPath = common.getRelativePath(path, cuePath)
            line = 'FILE "%s" WAVE' % targetPath
            lines.append(line)
            self.debug('writeFile: %r' % line)

        # header
        main = ['PERFORMER', 'TITLE']

        for key in CDTEXT_FIELDS:
            if key not in main and key in self.cdtext:
                lines.append("    %s %s" % (key, self.cdtext[key]))

        assert self.hasTOC(), "Table does not represent a full CD TOC"
        lines.append('REM DISCID %s' % self.getCDDBDiscId().upper())
        lines.append('REM COMMENT "%s %s"' % (program, configure.version))

        if self.catalog:
            lines.append("CATALOG %s" % self.catalog)

        for key in main:
            if key in self.cdtext:
                lines.append('%s "%s"' % (key, self.cdtext[key]))

        # FIXME:
        # - the first FILE statement goes before the first TRACK, even if
        #   there is a non-file-using PREGAP
        # - the following FILE statements come after the last INDEX that
        #   use that FILE; so before a next TRACK, PREGAP silence, ...

        # add the first FILE line; EAC always puts the first FILE
        # statement before TRACK 01 and any possible PRE-GAP
        firstTrack = self.tracks[0]
        index = firstTrack.getFirstIndex()
        indexOne = firstTrack.getIndex(1)
        counter = index.counter
        track = firstTrack

        while not index.path:
            t, i = self.getNextTrackIndex(track.number, index.number)
            track = self.tracks[t - 1]
            index = track.getIndex(i)
            counter = index.counter

        if index.path:
            self.debug('counter %d, writeFile' % counter)
            writeFile(index.path)

        for i, track in enumerate(self.tracks):
            self.debug('track i %r, track %r' % (i, track))
            # FIXME: skip data tracks for now
            if not track.audio:
                continue

            indexes = track.indexes.keys()
            indexes.sort()

            wroteTrack = False

            for number in indexes:
                index = track.indexes[number]
                self.debug('index %r, %r' % (number, index))

                # any time the source counter changes to a higher value,
                # write a FILE statement
                # it has to be higher, because we can run into the HTOA
                # at counter 0 here
                if index.counter > counter:
                    if index.path:
                        self.debug('counter %d, writeFile' % counter)
                        writeFile(index.path)
                    self.debug('setting counter to index.counter %r' %
                               index.counter)
                    counter = index.counter

                # any time we hit the first index, write a TRACK statement
                if not wroteTrack:
                    wroteTrack = True
                    line = "  TRACK %02d %s" % (i + 1, 'AUDIO')
                    lines.append(line)
                    self.debug('%r' % line)

                    for key in CDTEXT_FIELDS:
                        if key in track.cdtext:
                            lines.append('    %s "%s"' %
                                         (key, track.cdtext[key]))

                    if track.isrc is not None:
                        lines.append("    ISRC %s" % track.isrc)

                    if track.pre_emphasis is not None:
                        lines.append("    FLAGS PRE")

                    # handle TRACK 01 INDEX 00 specially
                    if 0 in indexes:
                        index00 = track.indexes[0]
                        if i == 0:
                            # if we have a silent pre-gap, output it
                            if not index00.path:
                                length = indexOne.absolute - index00.absolute
                                lines.append("    PREGAP %s" %
                                             common.framesToMSF(length))
                                continue

                        # handle any other INDEX 00 after its TRACK
                        lines.append("    INDEX %02d %s" %
                                     (0, common.framesToMSF(index00.relative)))

                if number > 0:
                    # index 00 is output after TRACK up above
                    lines.append("    INDEX %02d %s" %
                                 (number, common.framesToMSF(index.relative)))

        lines.append("")

        return "\n".join(lines)
Exemple #12
0
    def logRip(self, ripResult, epoch):

        lines = []

        ### global

        lines.append("morituri version %s" % configure.version)
        lines.append("")
        # FIXME: when we localize this, see #49 to handle unicode properly.
        import locale
        old = locale.getlocale(locale.LC_TIME)
        locale.setlocale(locale.LC_TIME, 'C')
        date = time.strftime("%b %d %H:%M:%S", time.localtime(epoch))
        locale.setlocale(locale.LC_TIME, old)
        lines.append("morituri logfile from %s" % date)
        lines.append("")

        # album
        lines.append("%s / %s" % (ripResult.artist, ripResult.title))
        lines.append("")

        # drive
        lines.append(
            "Used Drive  : %s %s %s" % (
                ripResult.vendor, ripResult.model, ripResult.release))
        lines.append("")

        # Default for cdparanoia
        lines.append("Use cdparanoia mode      : Yes (%s)" % (
            ripResult.cdparanoia_version))

        # Default for cdparanoia by virtue of ripping whole tracks at a time
        lines.append("Defeat audio cache       : Yes")

        # Default for cdparanoia by virtue of having no C2 rip mode
        lines.append("Make use of C2 pointers  : No")

        lines.append("")
        lines.append("Read offset correction                      : %d" % (
            ripResult.offset))

        # Currently unsupported by cdparanoia
        lines.append("Overread into Lead-In and Lead-Out          : No")

        # Default for cdparanoia
        lines.append("Fill up missing offset samples with silence : Yes")

        # Default for cdparanoia
        lines.append("Delete leading and trailing silent blocks   : No")

        # Default
        lines.append("Null samples used in CRC calculations       : Yes")

        lines.append("Gap Detection                               : "
            "cdrdao version %s" % ripResult.cdrdao_version)
            
        # Default for cdparanoia
        lines.append("Gap handling                                : "
            "Appended to previous track")
        lines.append("")

        # toc
        lines.append("TOC of the extracted CD")
        lines.append("")
        lines.append(
            "     Track |   Start  |  Length  | Start sector | End sector")
        lines.append(
            "    ---------------------------------------------------------")
        table = ripResult.table


        for t in table.tracks:
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            lines.append(
            "       %2d  | %s | %s | %9d    | %8d" % (
                t.number,
                common.framesToMSF(start),
                common.framesToMSF(length),
                start,
                start + length - 1))

        lines.append("")
        lines.append("")

        ### per-track
        for t in ripResult.tracks:
            lines.extend(self.trackLog(t))
            lines.append('')

        return lines
Exemple #13
0
    def cue(self, cuePath='', program='Morituri'):
        """
        @param cuePath: path to the cue file to be written. If empty,
                        will treat paths as if in current directory.


        Dump our internal representation to a .cue file content.

        @rtype: C{unicode}
        """
        lines = []

        def writeFile(path):
            targetPath = common.getRelativePath(path, cuePath)
            lines.append('FILE "%s" WAVE' % targetPath)

        # header
        main = ['PERFORMER', 'TITLE']

        for key in CDTEXT_FIELDS:
                if key not in main and key in self.cdtext:
                    lines.append("    %s %s" % (key, self.cdtext[key]))

        assert self.hasTOC(), "Table does not represent a full CD TOC"
        lines.append('REM DISCID %s' % self.getCDDBDiscId().upper())
        lines.append('REM COMMENT "%s"' % program)

        if self.catalog:
            lines.append("CATALOG %s" % self.catalog)

        for key in main:
            if key in self.cdtext:
                lines.append('%s "%s"' % (key, self.cdtext[key]))

        # add the first FILE line
        path = self.tracks[0].getFirstIndex().path
        counter = self.tracks[0].getFirstIndex().counter
        writeFile(path)

        for i, track in enumerate(self.tracks):
            # FIXME: skip data tracks for now
            if not track.audio:
                continue

            # if there is no index 0, but there is a new file, advance
            # FILE line here
            if not 0 in track.indexes:
                index = track.indexes[1]
                if index.counter != counter:
                    writeFile(index.path)
                    counter = index.counter
            lines.append("  TRACK %02d %s" % (i + 1, 'AUDIO'))
            for key in CDTEXT_FIELDS:
                if key in track.cdtext:
                    lines.append('    %s "%s"' % (key, track.cdtext[key]))

            if track.isrc is not None:
                lines.append("    ISRC %s" % track.isrc)

            indexes = track.indexes.keys()
            indexes.sort()

            for number in indexes:
                index = track.indexes[number]
                if index.counter != counter:
                    writeFile(index.path)
                    counter = index.counter
                lines.append("    INDEX %02d %s" % (number,
                    common.framesToMSF(index.relative)))

        lines.append("")

        return "\n".join(lines)
Exemple #14
0
    def logRip(self, ripResult, epoch):
        lines = []
        lines.append("Ripper: morituri %s" % configure.version)
        date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(epoch)).strip()
        lines.append("Ripped at: %s" % date)
        lines.append("Drive: %s%s (revision %s)" %
                     (ripResult.vendor, ripResult.model, ripResult.release))
        lines.append("")

        defeat = "Unknown"
        if ripResult.cdparanoiaDefeatsCache is True:
            defeat = "Yes"
        elif ripResult.cdparanoiaDefeatsCache is False:
            defeat = "No"
        lines.append("Defeat audio cache: %s" % defeat)
        lines.append("Read offset correction: %+d" % ripResult.offset)
        # Currently unsupported by the official cdparanoia package
        over = "Unknown"
        if ripResult.overread is True:
            over = "Yes"
        elif ripResult.overread is False:
            over = "No"
        lines.append("Overread into lead-out: %s" % over)
        # Next one fully works only using the patched cdparanoia package
        # lines.append("Fill up missing offset samples with silence: Yes")
        lines.append("Gap detection: cdrdao %s" % ripResult.cdrdaoVersion)
        lines.append("")

        lines.append("Used output format: %s" % ripResult.profileName)
        lines.append("GStreamer:")
        lines.append("  Pipeline: %s" % ripResult.profilePipeline)
        lines.append("  Version: %s" % ripResult.gstreamerVersion)
        lines.append("  Python version: %s" % ripResult.gstPythonVersion)
        lines.append("  Encoder plugin version: %s" % ripResult.encoderVersion)
        lines.append("")

        lines.append("TOC:")
        table = ripResult.table
        htoa = None
        try:
            htoa = table.tracks[0].getIndex(0)
        except KeyError:
            pass
        if htoa and htoa.path:
            htoastart = htoa.absolute
            htoaend = table.getTrackEnd(0)
            htoalength = table.tracks[0].getIndex(1).absolute - htoastart
            lines.append("  00:")
            lines.append("    Start: %s" % common.framesToMSF(htoastart))
            lines.append("    Length: %s" % common.framesToMSF(htoalength))
            lines.append("    Start sector: %d" % htoastart)
            lines.append("    End sector: %d" % htoaend)
        for t in table.tracks:
            # FIXME: what happens to a track start over 60 minutes ?
            # Answer: tested empirically, everything seems OK
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            end = table.getTrackEnd(t.number)
            lines.append("  %02d:" % t.number)
            lines.append("    Start: %s" % common.framesToMSF(start))
            lines.append("    Length: %s" % common.framesToMSF(length))
            lines.append("    Start sector: %d" % start)
            lines.append("    End sector: %d" % end)
            lines.append("")

        lines.append("Tracks:")
        duration = 0.0
        for t in ripResult.tracks:
            if not t.filename:
                continue
            lines.extend(self.trackLog(t))
            lines.append("")
            duration += t.testduration + t.copyduration

        lines.append("Information:")
        lines.append("  AccurateRip summary:")
        if self._inARDatabase == 0:
            lines.append("    Result: None of the tracks are present in "
                         "the AccurateRip database")
        else:
            nonHTOA = len(ripResult.tracks)
            if ripResult.tracks[0].number == 0:
                nonHTOA -= 1
            if self._accuratelyRipped == 0:
                lines.append("    Result: No tracks could be verified as "
                             "accurate (you may have a different pressing "
                             "from the one(s) in the database")
            elif self._accuratelyRipped < nonHTOA:
                lines.append("    %d track(s) accurately ripped" %
                             self._accuratelyRipped)
                lines.append("    %d track(s) could not be verified as "
                             "accurate" % (nonHTOA - self._accuratelyRipped))
                lines.append("")
                lines.append("    Result: Some tracks could not be verified "
                             "as accurate (%d/%d got no match)" % (
                                (nonHTOA - self._accuratelyRipped), nonHTOA))
            else:
                lines.append("    Result: All tracks accurately ripped")
        lines.append("")

        lines.append("  Health status:")
        if self._errors:
            lines.append("    Result: There were errors")
        else:
            lines.append("    Result: No errors occurred")
        lines.append("")
        lines.append("  EOF: End of status report")
        lines.append("")

        hasher = hashlib.sha256()
        hasher.update("\n".join(lines).encode("utf-8"))
        lines.append("SHA-256 hash: %s" % hasher.hexdigest().upper())
        lines.append("")
        return lines
Exemple #15
0
    def logRip(self, ripResult, epoch):
        """Returns logfile lines list"""

        lines = []

        # Ripper version
        # Only implemented in whipper (ripResult.logger)
        lines.append("Log created by: whipper %s (%s logger)" %
                     (configure.version, ripResult.logger))

        # Rip date
        date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(epoch)).strip()
        lines.append("Log creation date: %s" % date)
        lines.append("")

        # Rip technical settings
        lines.append("Ripping phase information:")
        lines.append("  Drive: %s%s (revision %s)" %
                     (ripResult.vendor, ripResult.model, ripResult.release))
        if ripResult.cdparanoiaDefeatsCache is None:
            defeat = "Unknown"
        elif ripResult.cdparanoiaDefeatsCache:
            defeat = "Yes"
        else:
            defeat = "No"
        lines.append("  Defeat audio cache: %s" % defeat)
        lines.append("  Read offset correction: %+d" % ripResult.offset)
        # Currently unsupported by the official cdparanoia package
        over = "No"
        # Only implemented in whipper (ripResult.overread)
        if ripResult.overread:
            over = "Yes"
        lines.append("  Overread into lead-out: %s" % over)
        # Next one fully works only using the patched cdparanoia package
        # lines.append("Fill up missing offset samples with silence: Yes")
        lines.append("  Gap detection: cdrdao %s" % ripResult.cdrdaoVersion)
        lines.append("")

        # Rip encoding settings
        lines.append("Encoding phase information:")
        lines.append("  Used output format: %s" % ripResult.profileName)
        lines.append("  GStreamer:")
        lines.append("    Pipeline: %s" % ripResult.profilePipeline)
        lines.append("    Version: %s" % ripResult.gstreamerVersion)
        lines.append("    Python version: %s" % ripResult.gstPythonVersion)
        lines.append("    Encoder plugin version: %s" %
                     ripResult.encoderVersion)
        lines.append("")

        # CD metadata
        lines.append("CD metadata:")
        lines.append("  Album: %s - %s" % (ripResult.artist, ripResult.title))
        lines.append("  CDDB Disc ID: %s" % ripResult.table.getCDDBDiscId())
        lines.append("  MusicBrainz Disc ID: %s" %
                     ripResult.table.getMusicBrainzDiscId())
        lines.append("  MusicBrainz lookup url: %s" %
                     ripResult.table.getMusicBrainzSubmitURL())
        lines.append("")

        # TOC section
        lines.append("TOC:")
        table = ripResult.table

        # Test for HTOA presence
        htoa = None
        try:
            htoa = table.tracks[0].getIndex(0)
        except KeyError:
            pass

        # If True, include HTOA line into log's TOC
        if htoa and htoa.path:
            htoastart = htoa.absolute
            htoaend = table.getTrackEnd(0)
            htoalength = table.tracks[0].getIndex(1).absolute - htoastart
            lines.append("  00:")
            lines.append("    Start: %s" % common.framesToMSF(htoastart))
            lines.append("    Length: %s" % common.framesToMSF(htoalength))
            lines.append("    Start sector: %d" % htoastart)
            lines.append("    End sector: %d" % htoaend)
            lines.append("")

        # For every track include information in the TOC
        for t in table.tracks:
            # FIXME: what happens to a track start over 60 minutes ?
            # Answer: tested empirically, everything seems OK
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            end = table.getTrackEnd(t.number)
            lines.append("  %02d:" % t.number)
            lines.append("    Start: %s" % common.framesToMSF(start))
            lines.append("    Length: %s" % common.framesToMSF(length))
            lines.append("    Start sector: %d" % start)
            lines.append("    End sector: %d" % end)
            lines.append("")

        # Tracks section
        lines.append("Tracks:")
        duration = 0.0
        for t in ripResult.tracks:
            if not t.filename:
                continue
            lines.extend(self.trackLog(t))
            lines.append("")
            duration += t.testduration + t.copyduration

        # Status report
        lines.append("Conclusive status report:")
        arHeading = "  AccurateRip summary:"
        if self._inARDatabase == 0:
            lines.append("%s None of the tracks are present in the "
                         "AccurateRip database" % arHeading)
        else:
            nonHTOA = len(ripResult.tracks)
            if ripResult.tracks[0].number == 0:
                nonHTOA -= 1
            if self._accuratelyRipped == 0:
                lines.append("%s No tracks could be verified as accurate "
                             "(you may have a different pressing from the "
                             "one(s) in the database)" % arHeading)
            elif self._accuratelyRipped < nonHTOA:
                accurateTracks = nonHTOA - self._accuratelyRipped
                lines.append("%s Some tracks could not be verified as "
                             "accurate (%d/%d got no match)" %
                             (arHeading, accurateTracks, nonHTOA))
            else:
                lines.append("%s All tracks accurately ripped" % arHeading)

        hsHeading = "  Health status:"
        if self._errors:
            lines.append("%s There were errors" % hsHeading)
        else:
            lines.append("%s No errors occurred" % hsHeading)
        lines.append("  EOF: End of status report")
        lines.append("")

        # Log hash
        hasher = hashlib.sha256()
        hasher.update("\n".join(lines).encode("utf-8"))
        lines.append("SHA-256 hash: %s" % hasher.hexdigest().upper())
        lines.append("")
        return lines
Exemple #16
0
    def trackLog(self, trackResult):
        """Returns Tracks section lines: data picked from trackResult"""

        lines = []

        # Track number
        lines.append("  %02d:" % trackResult.number)

        # Filename (including path) of ripped track
        lines.append("    Filename: %s" % trackResult.filename)

        # Pre-gap length
        pregap = trackResult.pregap
        if pregap:
            lines.append("    Pre-gap length: %s" % common.framesToMSF(pregap))

        # Peak level
        peak = trackResult.peak
        lines.append("    Peak level: %.6f" % peak)

        # Extraction speed
        if trackResult.copyspeed:
            lines.append("    Extraction speed: %.1f X" %
                         (trackResult.copyspeed))

        # Extraction quality
        if trackResult.quality and trackResult.quality > 0.001:
            lines.append("    Extraction quality: %.2f %%" %
                         (trackResult.quality * 100.0, ))

        # Ripper Test CRC
        if trackResult.testcrc is not None:
            lines.append("    Test CRC: %08X" % trackResult.testcrc)

        # Ripper Copy CRC
        if trackResult.copycrc is not None:
            lines.append("    Copy CRC: %08X" % trackResult.copycrc)

        # AccurateRip track status
        # Currently there's no support for AccurateRip V2
        if trackResult.accurip:
            lines.append("    AccurateRip V1:")
            self._inARDatabase += 1
            if trackResult.ARCRC == trackResult.ARDBCRC:
                lines.append("      Result: Found, exact match")
                self._accuratelyRipped += 1
            else:
                lines.append("      Result: Found, NO exact match")
            lines.append("      Confidence: %d" % trackResult.ARDBConfidence)
            lines.append("      Local CRC: %08X" % trackResult.ARCRC)
            lines.append("      Remote CRC: %08X" % trackResult.ARDBCRC)
        elif trackResult.number != 0:
            lines.append("    AccurateRip V1:")
            lines.append("      Result: Track not present in "
                         "AccurateRip database")

        # Check if Test & Copy CRCs are equal
        if trackResult.testcrc == trackResult.copycrc:
            lines.append("    Status: Copy OK")
        else:
            self._errors = True
            lines.append("    Status: Error, CRC mismatch")
        return lines
Exemple #17
0
    def cue(self, program='Morituri'):
        """
        Dump our internal representation to a .cue file content.
        """
        lines = []

        def writeFile(path):
            lines.append('FILE "%s" WAVE' % os.path.basename(path))

        # header
        main = ['PERFORMER', 'TITLE']

        for key in CDTEXT_FIELDS:
            if key not in main and key in self.cdtext:
                lines.append("    %s %s" % (key, self.cdtext[key]))

        assert self.hasTOC(), "Table does not represent a full CD TOC"
        lines.append('REM DISCID %s' % self.getCDDBDiscId().upper())
        lines.append('REM COMMENT "%s"' % program)

        if self.catalog:
            lines.append("CATALOG %s" % self.catalog)

        for key in main:
            if key in self.cdtext:
                lines.append('%s "%s"' % (key, self.cdtext[key]))

        # add the first FILE line
        path = self.tracks[0].getFirstIndex().path
        counter = self.tracks[0].getFirstIndex().counter
        writeFile(path)

        for i, track in enumerate(self.tracks):
            # FIXME: skip data tracks for now
            if not track.audio:
                continue

            # if there is no index 0, but there is a new file, advance
            # FILE line here
            if not 0 in track.indexes:
                index = track.indexes[1]
                if index.counter != counter:
                    writeFile(index.path)
                    counter = index.counter
            lines.append("  TRACK %02d %s" % (i + 1, 'AUDIO'))
            for key in CDTEXT_FIELDS:
                if key in track.cdtext:
                    lines.append('    %s "%s"' % (key, track.cdtext[key]))

            if track.isrc is not None:
                lines.append("    ISRC %s" % track.isrc)

            indexes = track.indexes.keys()
            indexes.sort()

            for number in indexes:
                index = track.indexes[number]
                if index.counter != counter:
                    writeFile(index.path)
                    counter = index.counter
                lines.append("    INDEX %02d %s" %
                             (number, common.framesToMSF(index.relative)))

        lines.append("")

        return "\n".join(lines)
Exemple #18
0
    def logRip(self, ripResult, epoch):

        lines = []

        ### global

        lines.append("morituri version %s" % configure.version)
        lines.append("")
        # FIXME: when we localize this, see #49 to handle unicode properly.
        import locale

        old = locale.getlocale(locale.LC_TIME)
        locale.setlocale(locale.LC_TIME, "C")
        date = time.strftime("%b %d %H:%M:%S", time.localtime(epoch))
        locale.setlocale(locale.LC_TIME, old)
        lines.append("morituri logfile from %s" % date)
        lines.append("")

        # album
        lines.append("%s / %s" % (ripResult.artist, ripResult.title))
        lines.append("")

        # drive
        lines.append("Used Drive  : %s %s %s" % (ripResult.vendor, ripResult.model, ripResult.release))
        lines.append("")

        # Default for cdparanoia
        lines.append("Use cdparanoia mode      : Yes (%s)" % (ripResult.cdparanoia_version))

        # Default for cdparanoia by virtue of ripping whole tracks at a time
        lines.append("Defeat audio cache       : Yes")

        # Default for cdparanoia by virtue of having no C2 rip mode
        lines.append("Make use of C2 pointers  : No")

        lines.append("")
        lines.append("Read offset correction                      : %d" % (ripResult.offset))

        # Currently unsupported by cdparanoia
        lines.append("Overread into Lead-In and Lead-Out          : No")

        # Default for cdparanoia
        lines.append("Fill up missing offset samples with silence : Yes")

        # Default for cdparanoia
        lines.append("Delete leading and trailing silent blocks   : No")

        # Default
        lines.append("Null samples used in CRC calculations       : Yes")

        lines.append("Gap Detection                               : " "cdrdao version %s" % ripResult.cdrdao_version)

        # Default for cdparanoia
        lines.append("Gap handling                                : " "Appended to previous track")
        lines.append("")

        # toc
        lines.append("TOC of the extracted CD")
        lines.append("")
        lines.append("     Track |   Start  |  Length  | Start sector | End sector")
        lines.append("    ---------------------------------------------------------")
        table = ripResult.table

        for t in table.tracks:
            start = t.getIndex(1).absolute
            length = table.getTrackLength(t.number)
            lines.append(
                "       %2d  | %s | %s | %9d    | %8d"
                % (t.number, common.framesToMSF(start), common.framesToMSF(length), start, start + length - 1)
            )

        lines.append("")
        lines.append("")

        ### per-track
        for t in ripResult.tracks:
            lines.extend(self.trackLog(t))
            lines.append("")

        return lines