# -*- Mode: Python; test-case-name: whipper.test.test_common_accurip -*- # vi:si:et:sw=4:sts=4:ts=4 # Copyright (C) 2017 Samantha Baldwin # Copyright (C) 2009 Thomas Vander Stichele # This file is part of whipper. # # whipper is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # whipper is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with whipper. If not, see . import requests import struct from errno import EEXIST from os import makedirs from os.path import dirname, exists, join from whipper.common import directory from whipper.program.arc import accuraterip_checksum import logging logger = logging.getLogger(__name__) ACCURATERIP_URL = "http://www.accuraterip.com/accuraterip/" _CACHE_DIR = join(directory.cache_path(), 'accurip') class EntryNotFound(Exception): pass class _AccurateRipResponse(object): """ An AccurateRip response contains a collection of metadata identifying a particular digital audio compact disc. For disc level metadata it contains the track count, two internal disc IDs, and the CDDB disc ID. A checksum and a confidence score is stored sequentially for each track in the disc index, which excludes any audio hidden in track pre-gaps (such as HTOA). The response is stored as a packed binary structure. """ def __init__(self, data): """ The checksums and confidences arrays are indexed by relative track position, so track 1 will have array index 0, track 2 will have array index 1, and so forth. HTOA and other hidden tracks are not included. """ self.num_tracks = struct.unpack("B", data[0])[0] self.discId1 = "%08x" % struct.unpack(" track.AR[v]['DBConfidence']: track.AR[v]['DBCRC'] = r.checksums[i] track.AR[v]['DBConfidence'] = r.confidences[i] logger.debug( 'track %d matched response %s in AccurateRip' ' database: %s crc %s confidence %s' % (i, r.cddbDiscId, v, track.AR[v]['DBCRC'], track.AR[v]['DBConfidence']) ) return any(( all([t.AR['v1']['DBCRC'] for t in tracks]), all([t.AR['v2']['DBCRC'] for t in tracks]) )) def verify_result(result, responses, checksums): """ Verify track AccurateRip checksums against database responses. Stores track checksums and database values on result. """ if not (result and responses and checksums): return False # exclude HTOA from AccurateRip verification # NOTE: if pre-gap hidden audio support is expanded to include # tracks other than HTOA, this is invalid. tracks = filter(lambda t: t.number != 0, result.tracks) if not tracks: return False _assign_checksums_and_confidences(tracks, checksums, responses) return _match_responses(tracks, responses) def print_report(result): """ Print AccurateRip verification results to stdout. """ for i, track in enumerate(result.tracks): status = 'rip NOT accurate' conf = '(not found)' db = 'notfound' if track.AR['DBMaxConfidence'] is not None: db = track.AR['DBMaxConfidenceCRC'] conf = '(max confidence %3d)' % track.AR['DBMaxConfidence'] if track.AR['v1']['DBCRC'] or track.AR['v2']['DBCRC']: status = 'rip accurate' db = ', '.join(filter(None, ( track.AR['v1']['DBCRC'], track.AR['v2']['DBCRC'] ))) max_conf = max( [track.AR[v]['DBConfidence'] for v in ('v1', 'v2')] ) if max_conf: if max_conf < track.AR['DBMaxConfidence']: conf = '(confidence %3d of %3d)' % ( max_conf, track.AR['DBMaxConfidence'] ) # htoa tracks (i == 0) do not have an ARCRC if track.number == 0: print('track 0: unknown (not tracked)') continue if not (track.AR['v1']['CRC'] or track.AR['v2']['CRC']): logger.error( 'no track AR CRC on non-HTOA track %d' % track.number ) print('track %2d: unknown (error)' % track.number) else: print('track %2d: %-16s %-23s v1 [%s], v2 [%s], DB [%s]' % ( track.number, status, conf, track.AR['v1']['CRC'], track.AR['v2']['CRC'], db ))