Files
whipper-gui/whipper/result/logger.py
Frederik “Freso” S. Olesen 135cc9ce05 Include MusicBrainz Release URL in log output (#382)
* Include MusicBrainz Release URL in log output

This also passes *all* metadata to the `result` object, giving loggers a
lot more (release) metadata to work with, in case custom, “3rd party”
loggers (or even ourselves in the future!) want to do something more
fancy or expansive with the metadata in the log file.

Fixes https://github.com/whipper-team/whipper/issues/381

Signed-off-by: Frederik “Freso” S. Olesen <freso.dk@gmail.com>

* Uppercase "url" in output: "URL"

Signed-off-by: Frederik “Freso” S. Olesen <freso.dk@gmail.com>
2019-03-18 11:15:27 +00:00

245 lines
8.9 KiB
Python

import time
import hashlib
import whipper
from whipper.common import common
from whipper.result import result
class WhipperLogger(result.Logger):
_accuratelyRipped = 0
_inARDatabase = 0
_errors = False
def log(self, ripResult, epoch=time.time()):
"""Returns big str: logfile joined text lines"""
lines = self.logRip(ripResult, epoch=epoch)
return "\n".join(lines)
def logRip(self, ripResult, epoch):
"""Returns logfile lines list"""
lines = []
# Ripper version
lines.append("Log created by: whipper %s (internal logger)" %
whipper.__version__)
# 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))
lines.append(" Extraction engine: cdparanoia %s" %
ripResult.cdparanoiaVersion)
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)
if ripResult.isCdr:
isCdr = "Yes"
else:
isCdr = "No"
lines.append(" CD-R detected: %s" % isCdr)
lines.append("")
# CD metadata
lines.append("CD metadata:")
lines.append(" Release: %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())
if ripResult.metadata:
lines.append(" MusicBrainz Release URL: %s" %
ripResult.metadata.url)
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(" 0:")
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:
start = t.getIndex(1).absolute
length = table.getTrackLength(t.number)
end = table.getTrackEnd(t.number)
lines.append(" %d:" % 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
track_lines, ARDB_entry, ARDB_match = self.trackLog(t)
self._inARDatabase += int(ARDB_entry)
self._accuratelyRipped += int(ARDB_match)
lines.extend(track_lines)
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
def trackLog(self, trackResult):
"""Returns Tracks section lines: data picked from trackResult"""
lines = []
# Track number
lines.append(" %d:" % 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 / 32768.0
lines.append(" Peak level: %.6f" % peak)
# Pre-emphasis status
# Only implemented in whipper (trackResult.pre_emphasis)
if trackResult.pre_emphasis:
preEmph = "Yes"
else:
preEmph = "No"
lines.append(" Pre-emphasis: %s" % preEmph)
# 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
ARDB_entry = 0
ARDB_match = 0
for v in ("v1", "v2"):
if trackResult.AR[v]["DBCRC"]:
lines.append(" AccurateRip %s:" % v)
ARDB_entry += 1
if trackResult.AR[v]["CRC"] == trackResult.AR[v]["DBCRC"]:
lines.append(" Result: Found, exact match")
ARDB_match += 1
else:
lines.append(" Result: Found, NO exact match")
lines.append(
" Confidence: %d" % trackResult.AR[v]["DBConfidence"]
)
lines.append(
" Local CRC: %s" % trackResult.AR[v]["CRC"].upper()
)
lines.append(
" Remote CRC: %s" % trackResult.AR[v]["DBCRC"].upper()
)
elif trackResult.number != 0:
lines.append(" AccurateRip %s:" % v)
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, bool(ARDB_entry), bool(ARDB_match)