def evaluate_settings(self, log): """Evaluate the log for usage of proper rip settings.""" psettings = self.patterns['settings'] proper_settings = self.patterns['proper settings'] # Compile regex beforehand settings = {} colon = r' : (.*)' if log.language == 'english' else r'(?: :)? : (.*)' for key, setting in psettings.items(): settings[key] = re.compile(fmt_ptn(setting) + colon) # Iterate through line in the settings, and verify each setting in `sets` dict for line in log.contents[log.index_settings : log.index_toc]: for key, setting in list(settings.items()): result = setting.search(line) if result and key == 'Drive offset': drives.eval_offset(log, result.group(1)) del settings[key] elif result: if not re.search(fmt_ptn(proper_settings[key]), result.group(1)): log.add_deduction(key) del settings[key] break self.check_bad_settings(log, line) self.evaluate_unmatched_settings(log, settings)
def check_tracks(self, log): """Wrapper for the analyze_tracks method. Get track data for every track and check for errors. """ tsettings = self.patterns['track settings'] track_settings = { 'filename': re.compile(r'\s+' + fmt_ptn(tsettings['filename']) + r' (.*)'), 'pregap': re.compile(r'\s+' + fmt_ptn(tsettings['pregap']) + r' ([0-9:\.]+)'), 'peak': re.compile(r'\s+' + fmt_ptn(tsettings['peak']) + r' ([0-9\.]+) %'), 'test crc': re.compile(r'\s+' + fmt_ptn(tsettings['test crc']) + r' ([A-Z0-9]{8})'), 'copy crc': re.compile(r'\s+' + fmt_ptn(tsettings['copy crc']) + r' ([A-Z0-9]{8})') } self.analyze_tracks(log, track_settings, parsers.parse_errors_eac)
def all_range_index(self, log, line): """Match the Range Rip line in the log file.""" if log.all_tracks is None and re.match( fmt_ptn(self.patterns['All Tracks']), line ): return True return False
def is_there_a_htoa(self, log): """Check rip for Hidden Track One Audio.""" # 6 second minimum for HTOA per EAC standards # Only accepted HTOA extraction technique for EAC is range-based if log.toc[1][0] < 450 or not log.range: return for line in log.contents[log.index_tracks + 1:]: if line.strip(): result = re.search(fmt_ptn(self.patterns['htoa']), line) if result: log.htoa = True log.htoa_index = log.toc[1][0] - 1 # Remove the gap handling notification (doesn't appear for range rips) if log.has_deduction('Could not verify gap handling'): log.remove_deduction('Could not verify gap handling') if int(result.group(1)) == log.htoa_index: log.htoa_ripped = True log.add_deduction('HTOA extracted') else: log.add_deduction('Improper HTOA extraction') else: log.add_deduction('HTOA detected, but not extracted') break
def check_bad_settings(self, log, line): """Evaluate the instant -100 point deductions (destructive normalization and compression offset).""" bad_settings = self.patterns['bad settings'] for sett, pattern in bad_settings.items(): if re.search(fmt_ptn(pattern), line): log.add_deduction(sett)
def get_drive(self, regex, line): """Get the name of the ripping drive used.""" re_drive = re.compile(fmt_ptn(self.patterns['drive']) + regex) result = re_drive.match(line) if result: return result.group(1).strip() raise UnrecognizedException('Could not parse ripping drive')
def parse_errors_xld(log, err_patterns, track_num, line): """Parse line of a XLD log for a ripping error.""" for error, re_err in err_patterns: if track_num not in log.track_errors[error]: result = re.search(r' ' + fmt_ptn(re_err) + r' : ([0-9]+)', line) if result and result.group(1) != "0": log.track_errors[error].append( [track_num, int(result.group(1))])
def parse_accuraterip(log, ar_patterns, line): """Parse line for an AccurateRip result.""" for status, re_accurip in ar_patterns: result = re.search(fmt_ptn(re_accurip), line) if result and isinstance(result.lastindex, int) and result.lastindex >= 1: log.accuraterip.append([status, result.group(result.lastindex)]) elif result and result.lastindex is None: log.accuraterip.append([status, None])
def get_track_number(log, index, track_word): """Get the track number from the header line of a track block.""" result = re.search(r'{} ([0-9]+)'.format(fmt_ptn(track_word)), log.contents[index]) if result: return int(result.group(1)) elif log.range: # EAC range rip has no track number return 0 else: raise UnrecognizedException('A track has an invalid block header')
def check_tracks(self, log): """Get track data for each track and check for errors.""" tsettings = self.patterns['track settings'] track_settings = { 'filename': re.compile( r'\s+' + fmt_ptn(tsettings['filename']) + r' : (.*?\/.*?\..*)' ), 'pregap': re.compile( r'\s+' + fmt_ptn(tsettings['pregap']) + r' : ([0-9:\.]+)' ), 'gain': re.compile( r'\s+' + fmt_ptn(tsettings['gain']) + r' : ([A-Za-z0-9\.-]+)' ), 'peak': re.compile(r'\s+' + fmt_ptn(tsettings['peak']) + r' : ([0-9\.]+)'), 'test crc': re.compile( r'\s+' + fmt_ptn(tsettings['test crc']) + r' : ([A-Z0-9]{8})' ), 'copy crc': re.compile( r'\s+' + fmt_ptn(tsettings['copy crc']) + r' : ([A-Z0-9]{8})' ), } if log.all_tracks: for i in range(log.all_tracks, min(log.track_indices)): if re.match(track_settings['filename'], log.contents[i]): log.range = True break self.analyze_tracks(log, track_settings, parsers.parse_errors_xld)
def check_tracks(self, log): """Get track data for each track and check for errors.""" tsettings = self.patterns['track settings'] track_settings = { 'filename': re.compile(r' ' + fmt_ptn(tsettings['filename']) + r' (.*)'), 'pregap': re.compile(r' ' + fmt_ptn(tsettings['pregap']) + r' ([0-9:\.]+)'), 'peak': re.compile(r' ' + fmt_ptn(tsettings['peak']) + r' ([0-9\.])+ %'), 'test crc': re.compile(r' ' + fmt_ptn(tsettings['test crc']) + r' ([A-Z0-9]{8})'), 'copy crc': re.compile(r' ' + fmt_ptn(tsettings['copy crc']) + r' ([A-Z0-9]{8})'), } self.analyze_tracks(log, track_settings, parsers.parse_errors_eac, accuraterip=False)
def settings(log, patterns): """Mark up the settings block.""" for i, line in enumerate(log.full_contents[log.index_settings:log.index_toc]): i += log.index_settings if re.match(fmt_ptn(patterns['settings']['Read mode']), line) and log.ripper == 'EAC95': log.full_contents[i] = style_95_read_mode(line, patterns) continue for key, value in patterns['settings'].items(): if re.match(fmt_ptn(value), line.lstrip()): # lstrip() for EAC95 class_ = 'bad' if log.has_deduction(key) else 'good' log.full_contents[i] = style_setting(line, class_) break else: if log.ripper in ['EAC', 'EAC95']: for key, value in patterns['bad settings'].items(): if re.match(fmt_ptn(value), line.lstrip()): log.full_contents[i] = style_setting(line, 'bad') break else: log.full_contents[i] = style_setting(line, 'log4') else: log.full_contents[i] = style_setting(line, 'log4')
def index_log(self, log, ninety_five=False): """Index key line numbers inside the log.""" if ninety_five: read_mode = re.compile(re.sub(' +', ' ', fmt_ptn(self.translation['1234']))) else: read_mode = re.compile(fmt_ptn(self.patterns['settings']['Read mode'])) toc = ( re.compile(fmt_ptn(self.patterns['toc'])) if 'toc' in self.patterns else None ) for i, line in enumerate(log.contents): if log.index_settings is None and read_mode.match(line): log.index_settings = i elif log.index_toc is None and 'toc' in self.patterns and toc.match(line): log.index_toc = i elif self.all_range_index(log, line): self.all_range_index_action(log, i) elif re.match(fmt_ptn(self.patterns['track']) + r' [0-9]+$', line): log.track_indices.append(i) self.validate_indices(log)
def check_cdr(self, log): """Check the log to see if CD-R is flagged.""" result = re.search( fmt_ptn(self.patterns['disc type']) + r' : (.*)', log.concat_contents[4], ) if result: if result.group(1) == 'Pressed CD': return elif result.group(1) == 'CD-Recordable': log.cdr = True log.flagged = True log.add_deduction('CD-R') else: raise UnrecognizedException('Unknown disc type')
def evaluate_settings(self, log): """Evaluate the log for usage of proper rip settings. Overwriting the base class for different 0.95 behavior. """ psettings = self.patterns['settings'] full_psettings = self.patterns['full line settings'] proper_settings = self.patterns['proper settings'] # Compile regex beforehand settings, full_settings = {}, {} for key, regex in psettings.items(): settings[key] = re.compile(fmt_ptn(regex)) for key, regex in full_psettings.items(): full_settings[key] = re.compile(fmt_ptn(regex) + ' : (.*)') # Iterate through line in the settings, and verify each setting in `settings` dict for line in log.contents[log.index_settings:log.index_tracks]: for key, setting in list(settings.items()): result = setting.search(line) if result: if key == 'Drive offset': offset = re.search(r'.+: ([-0-9]+)', line) drives.eval_offset(log, offset.group(1)) del settings[key] for key, setting in list(full_settings.items()): result = setting.search(line) if result: if not re.search(fmt_ptn(proper_settings[key]), result.group(1)): log.add_deduction(key) del full_settings[key] break self.check_bad_settings(log, line) self.evaluate_unmatched_settings(log, settings)
def parse_checksum(log, regex, imp_version, deduc_line): """Parse line(s) for presence of a checksum.""" re_checksum = re.compile(fmt_ptn(regex)) for line in log.contents[log.index_footer:]: if re_checksum.match(line): log.checksum = True break else: # If checksum not found # Compare version numbers to see if Log is older than checksums. for version in VERSIONS[log.ripper]: if version[0] == log.version: log_version = version if version[0] == imp_version: imp_version = version if VERSIONS[log.ripper].index(log_version) <= VERSIONS[ log.ripper].index(imp_version): log.add_deduction('Checksum') else: log.add_deduction(deduc_line + ' (no checksum)')
def re_paren(line): """Regex the comma. Quality docstring.""" line = re.sub(r'\(', r'\(', fmt_ptn(line)) return re.sub(r'\)', r'\)', line)
def parse_errors_eac(log, err_patterns, track_num, line): """Parse line of an EAC log for a ripping error.""" for error, re_err in err_patterns: if track_num not in log.track_errors[error] and re.match( r' ' + fmt_ptn(re_err), line): log.track_errors[error].append(track_num)
def check_bad_settings(self, log, line): """Evaluate the instant -100 point deductions.""" bad_settings = self.patterns['bad settings'] for sett, pattern in bad_settings.items(): if re.match(fmt_ptn(pattern), line): log.add_deduction(sett)