Separate parser and writer
This commit is contained in:
197
iTunesParser.py
197
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)
|
||||
|
||||
Reference in New Issue
Block a user