"""SCPP XML Parser.""" import csv from collections import OrderedDict from typing import NamedTuple from datetime import datetime from os.path import join, splitext, exists from posix import listdir from sys import stderr from loguru import logger as log from lxml import etree as et from config import SCPP_FILE_DIR, OUTPUT_FILE_DIR from constants import XML_EXT # Loguru log formatting constant default_format = '{time:YYYY-MM-DD at h:mm:ss A zz} | {' \ 'level: ^10} | {message}' # Get script run datetime script_run_at = datetime.now().strftime('%Y-%m-%d_%H_%M_%S') def main(): """The main function.""" output = dict() error_output = list() # Log to user msg = f'Opening and loading {SCPP_FILE_DIR}.' log.info(msg) # Check path exists if not exists(SCPP_FILE_DIR): raise FileNotFoundError( f'SCPP XML file dir \'{SCPP_FILE_DIR}\' not found.') # Remove non-XML files file_list = [ f for f in listdir(SCPP_FILE_DIR) if splitext(f)[1] == XML_EXT ] # Log to user msg = f'Found {len(file_list)} \'{XML_EXT}\' files.' log.info(msg) # DEBUG - Limit to one file # file_list = [file_list[0]] # Each XML file for xml in file_list: log.info(f'Parsing file: {xml}.') xml_file = join(SCPP_FILE_DIR, xml) xml_tree = et.parse(xml_file) root = xml_tree.getroot() track_count = 0 # track_list = [] for track in root.iterfind('SoundRecording'): try: scppid = track.find('SoundrecordingSCPPId').text isrc = track.find('SoundRecordingId').find('ISRC').text if not output.get(scppid): pair = dict(isrc=isrc, filename=xml) output[scppid] = [pair] else: pair = dict(isrc=isrc, filename=xml) output[scppid].append(pair) track_count += 1 except Exception as e: error_msg = \ f'Error in {xml} (line {track.sourceline}): {str(e)}' log.error(error_msg) error_output.append(error_msg) # If no Sound Recordings if track_count is None: log.error(f'No sound recordings listed in {xml_file}') log.info(f'Sorting output by SCPPID.') # Sort the output by SCPPID ordered_output = OrderedDict(sorted(output.items())) suspicious_count = 0 suspicious_dict = dict() # Find suspicious SCPPID's for scppid, instances in ordered_output.items(): if len(instances) > 1: isrc_list = [] for pair in instances: if pair['isrc'] not in isrc_list: isrc_list.append(pair['isrc']) if len(isrc_list) > 1: suspicious_count += 1 suspicious_dict[scppid] = instances if suspicious_count > 0: log.warning(f'{suspicious_count} suspicious SCPPID\'s found.') else: log.info('No suspicious SCPPID\'s found.') # File output section ---------------------- log.info(f'Writing output files.') output_file = join(OUTPUT_FILE_DIR, f'scpp_audit_new_{script_run_at}.csv') # Output suspicious SCPPID's with open(output_file, 'w') as csvfile: audit_writer = csv.writer(csvfile) for scppid, instances in suspicious_dict.items(): for item in instances: row = [scppid, item['isrc'], item['filename']] audit_writer.writerow(row) log.info(f'{output_file} written.') error_output_file = \ join(OUTPUT_FILE_DIR, f'scpp_audit_errors_new_{script_run_at}.txt') # Output file parsing errors with open(error_output_file, 'w') as error_file: error_file.writelines(s + '\n' for s in error_output) log.info(f'{error_output_file} written.') return ordered_output if __name__ == '__main__': # Remove and replace default logger log.remove(0) # Default Main Logger log.add(stderr, format=default_format, colorize=True) main()