"""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()