#!/usr/bin/python3 # ex: set filetype=python import argparse import os import urllib.parse import xml.etree.cElementTree as xml from mutagen.easyid3 import EasyID3 from mutagen.mp3 import MP3 from shutil import copyfile class Track(): """ Stores all the information of a track inside an object. Can be used to easily access the tracks stored in the database. """ def __init__(self, xml_doc): it = iter(xml_doc) for k, v in zip(it, it): setattr(self, k.text.replace(' ', ''), v.text) def parseXml(xml_file): """ Parses an xml file and returns the DOM tree. """ tree = xml.parse(xml_file) root = tree.getroot() tracks = [] for t in root.findall('.//dict/dict/dict'): tracks.append(Track(t)) return tracks def copy_file(track: Track, targetFolder, cnt, max) -> str: """ Copies a track from its source to the destination folder """ path = urllib.parse.unquote(track.Location[7:]) dst = os.path.join(targetFolder, os.path.basename(path)) if (os.path.exists(path)): print('Copying file {0} [{1}/{2}]'.format(path,cnt,max)) copyfile(path, dst) else: print('File {0} not found.'.format(path)) return None return dst def tag_file(track: Track, file_name: str, cnt, max): """ Adds ID3 tags to a file. """ if not file_name.endswith('.mp3'): print('Skipping file {0}. It\'s not an mp3 file. [{1}/{2}]' .format(file_name, cnt, max)) return print('Tagging file {0} [{1}/{2}]'.format(file_name, cnt, max)) mp3file = MP3(file_name, ID3=EasyID3) if hasattr(track, 'Album'): mp3file['album'] = track.Album if hasattr(track, 'BPM'): mp3file['bpm'] = track.BPM if hasattr(track, 'Compilation'): mp3file['compilation'] = 'true' if hasattr(track, 'Composer'): mp3file['composer'] = track.Composer if hasattr(track, 'TotalTime'): mp3file['length'] = track.TotalTime if hasattr(track, 'Name'): mp3file['title'] = track.Name if hasattr(track, 'Artist'): mp3file['artist'] = track.Artist if hasattr(track, 'AlbumArtist'): mp3file['albumartist'] = track.AlbumArtist if hasattr(track, 'DiscNumber'): mp3file['discnumber'] = track.DiscNumber if hasattr(track, 'TrackNumber'): if hasattr(track, 'TrackCount'): mp3file['tracknumber'] = '{0}/{1}'.format(track.TrackNumber, track.TrackCount) else: mp3file['tracknumber'] = track.TrackNumber if hasattr(track, 'Genre'): mp3file['genre'] = track.Genre mp3file.save() def main(): """ Setup our main program """ parser = argparse.ArgumentParser() parser.add_argument('-t', '--target', type=str, help='The target path to store the scraped \ files into', default='~/itunesscrape') parser.add_argument('-l', '--logfile', type=str, help='The path to the logfile to use.', default='~/itunesscrape.log') parser.add_argument('libraryFile', help='The iTunes library file in XML format.') args = parser.parse_args() print('Parsing library file...') tracks = parseXml(args.libraryFile) print('{0} tracks found.'.format(len(tracks))) if not os.path.isdir(args.target): os.mkdir(args.target) count = 0 maxcount = len(tracks) for t in tracks: count += 1 new_file = copy_file(t, args.target) if new_file is not None: tag_file(t, new_file) print('Done. Copied {0} of {1} files.'.format(count, maxcount)) if __name__ == "__main__": main()