From 06af68bf5af277775237e71c30d4dc2b239cea84 Mon Sep 17 00:00:00 2001 From: "Maxence G. de Montauzan" Date: Fri, 21 Apr 2017 12:42:23 +0200 Subject: [PATCH] Separate parser and writer --- iTunesParser.py | 197 +++++++++++++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 78 deletions(-) diff --git a/iTunesParser.py b/iTunesParser.py index af9def9..e2d5453 100644 --- a/iTunesParser.py +++ b/iTunesParser.py @@ -66,42 +66,37 @@ class ITunesParser: """ Parse an iTunes Library and produce JSON - for ELS """ - def __init__(self, library_file): + def __init__(self): + self._tracks = {} self._albums = {} self._artists = {} - self.library_file = library_file - def to_json(self): + def _read_tracks(self, library_file): """ - Just do processSong() - or do process_songs, then _write_artists and _write_albums. - Note: process_songs do a process_artists and process_albums... - This method suck. + Read library file and return Tracks key of dict. + Dict may contains + - Major Version + - Minor Version + - Date + - Application Version + - Features + - Show Content Ratings + - Music Folder + - Library Persistent ID + - Tracks + - ... """ - ret = self._process_songs() - - self._write_artists() - self._write_albums() - - # return json.dumps(jsonObj, indent=indent, cls=SetEncoder) - return ret - - def _read_tracks(self): - """ - Read library and return Tracks key of dict - """ - plist = plistlib.load(open(self.library_file, 'rb')) + plist = plistlib.load(open(library_file, 'rb')) return plist['Tracks'] - def _process_songs(self): + def parse(self, library_file): """ Return an output JSON for an ELS Bulk request - Not a correct format This method call process_album & process_artist TODO Just return a _correct_ JSON and treat in another place/class """ - tracks = self._read_tracks() - ret = "" + tracks = self._read_tracks(library_file) for _, track in tracks.items(): # Filter out any non-music @@ -110,20 +105,19 @@ class ITunesParser: if 'Podcast' in track or 'Has Video' in track: continue - persistent_id = track['Persistent ID'] - json_track_index = { - "index": {"_index": "itunessongs", "_type": "song", "_id": persistent_id} - } + # Each keeped track are stored + self._tracks[track['Persistent ID']] = track # Retrieve for each track artist information self._process_artist(track) # Retrieve for each track album information self._process_album(track) - ret += json.dumps(json_track_index, indent=None, cls=SetEncoder) - ret += "\n" - ret += json.dumps(track, indent=None, cls=SetEncoder) - ret += "\n" + ret = { + 'songs': self._tracks, + 'albums': self._albums, + 'artists': self._artists + } return ret def _process_artist(self, track): @@ -138,6 +132,8 @@ class ITunesParser: # Add artist if akey not in self._artists: a_id = self.calc_id(akey) + # Key is used to increment/precise some information + # So we use artist name as a key to avoid calculating an ID for each track self._artists[akey] = { 'Persistent ID': a_id, 'Name': akey, @@ -173,6 +169,8 @@ class ITunesParser: akey = track['Album'] if akey not in self._albums: a_id = self.calc_id(akey) + # Key is used to increment/precise some information + # So we use album name as a key to avoid calculating an ID for each track self._albums[akey] = { 'Persistent ID': a_id, 'Name': akey, @@ -205,42 +203,6 @@ class ITunesParser: self._albums[akey]['Album Rating'] = track['Album Rating'] self._albums[akey]['Album Rating Computed'] = True - def _write_artists(self): - """ - Write artists data to another JSON file - """ - - file_artist = io.open('es-artist-data.json', 'wb') - for artist in self._artists: - persistent_id = self._artists[artist]['Persistent ID'] - self._artists[artist]['Rating'] = round(self._artists[artist]['Rating']) - json_track_index = { - "index": {"_index": "itunessongs", "_type": "artist", "_id": persistent_id} - } - file_artist.write(bytes(json.dumps(json_track_index, indent=None, cls=SetEncoder), 'UTF-8')) - file_artist.write(bytes("\n", 'UTF-8')) - file_artist.write(bytes(json.dumps(self._artists[artist], indent=None, cls=SetEncoder), 'UTF-8')) - file_artist.write(bytes("\n", 'UTF-8')) - file_artist.close() - - def _write_albums(self): - """ - Write albums data to another JSON file - """ - - file_albums = io.open('es-albums-data.json', 'wb') - for album in self._albums: - persistent_id = self._albums[album]['Persistent ID'] - self._albums[album]['Rating'] = round(self._albums[album]['Rating']) - json_track_index = { - "index": {"_index": "itunessongs", "_type": "album", "_id": persistent_id} - } - file_albums.write(bytes(json.dumps(json_track_index, indent=None, cls=SetEncoder), 'UTF-8')) - file_albums.write(bytes("\n", 'UTF-8')) - file_albums.write(bytes(json.dumps(self._albums[album], indent=None, cls=SetEncoder), 'UTF-8')) - file_albums.write(bytes("\n", 'UTF-8')) - file_albums.close() - @classmethod def calc_rating(cls, added_value, current_rating, count): """ @@ -257,6 +219,82 @@ class ITunesParser: md5.update(key.encode('UTF-8')) return md5.hexdigest() + +class WriteElsJson: + def to_json(self): + """ + Just do processSong() + or do process_songs, then _write_artists and _write_albums. + Note: process_songs do a process_artists and process_albums... + This method suck. + """ + ret = self._process_songs() + + self._write_artists() + self._write_albums() + + # return json.dumps(jsonObj, indent=indent, cls=SetEncoder) + return ret + + @staticmethod + def write_artists(artists, output_file): + """ + Write artists data to another JSON file + """ + + file_artist = io.open(output_file, 'wb') + for _, artist in artists.items(): + persistent_id = artist['Persistent ID'] + artist['Rating'] = round(artist['Rating']) + + json_track_index = { + "index": {"_index": "itunessongs", "_type": "artist", "_id": persistent_id} + } + + file_artist.write(bytes(json.dumps(json_track_index, indent=None, cls=SetEncoder), 'UTF-8')) + file_artist.write(bytes("\n", 'UTF-8')) + file_artist.write(bytes(json.dumps(artist, indent=None, cls=SetEncoder), 'UTF-8')) + file_artist.write(bytes("\n", 'UTF-8')) + file_artist.close() + + @staticmethod + def write_albums(albums, output_file): + """ + Write albums data to another JSON file + """ + + file_albums = io.open(output_file, 'wb') + for _, album in albums.items(): + persistent_id = album['Persistent ID'] + album['Rating'] = round(album['Rating']) + + json_track_index = { + "index": {"_index": "itunessongs", "_type": "album", "_id": persistent_id} + } + + file_albums.write(bytes(json.dumps(json_track_index, indent=None, cls=SetEncoder), 'UTF-8')) + file_albums.write(bytes("\n", 'UTF-8')) + file_albums.write(bytes(json.dumps(album, indent=None, cls=SetEncoder), 'UTF-8')) + file_albums.write(bytes("\n", 'UTF-8')) + file_albums.close() + + @staticmethod + def write_songs(songs, output_file): + """ + Write songs to a JSON + """ + file = io.open(output_file, 'wb') + for persistent_id, song in songs.items(): + json_track_index = { + "index": {"_index": "itunessongs", "_type": "album", "_id": persistent_id} + } + + file.write(bytes(json.dumps(json_track_index, indent=None, cls=SetEncoder), 'UTF-8')) + file.write(bytes("\n", 'UTF-8')) + file.write(bytes(json.dumps(song, indent=None, cls=SetEncoder), 'UTF-8')) + file.write(bytes("\n", 'UTF-8')) + file.close() + #### main block #### # Default input & output files @@ -279,15 +317,18 @@ parser.add_argument('-c', '--console', action='store_true', if __name__ == '__main__': args = parser.parse_args() - itunes_parser = ITunesParser(args.file) - output = itunes_parser.to_json() + itunes_parser = ITunesParser().parse(args.file) - if args.console: - print(output) - else: - with io.open(args.output, 'wb') as outfile: - if sys.version_info.major == 2: - outfile.write(bytes(output)) - elif sys.version_info.major == 3: - outfile.write(bytes(output, 'UTF-8')) - print('JSON data written to: ' + args.output) + WriteElsJson.write_songs(itunes_parser['songs'], "es-songs.json") + WriteElsJson.write_artists(itunes_parser['artists'], "es-artists.json") + WriteElsJson.write_albums(itunes_parser['albums'], "es-albums.json") + + # if args.console: + # print(output) + # else: + # with io.open(args.output, 'wb') as outfile: + # if sys.version_info.major == 2: + # outfile.write(bytes(output)) + # elif sys.version_info.major == 3: + # outfile.write(bytes(output, 'UTF-8')) + # print('JSON data written to: ' + args.output)