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
|
Parse an iTunes Library and produce JSON - for ELS
|
||||||
"""
|
"""
|
||||||
def __init__(self, library_file):
|
def __init__(self):
|
||||||
|
self._tracks = {}
|
||||||
self._albums = {}
|
self._albums = {}
|
||||||
self._artists = {}
|
self._artists = {}
|
||||||
self.library_file = library_file
|
|
||||||
|
|
||||||
def to_json(self):
|
def _read_tracks(self, library_file):
|
||||||
"""
|
"""
|
||||||
Just do processSong()
|
Read library file and return Tracks key of dict.
|
||||||
or do process_songs, then _write_artists and _write_albums.
|
Dict may contains
|
||||||
Note: process_songs do a process_artists and process_albums...
|
- Major Version
|
||||||
This method suck.
|
- Minor Version
|
||||||
|
- Date
|
||||||
|
- Application Version
|
||||||
|
- Features
|
||||||
|
- Show Content Ratings
|
||||||
|
- Music Folder
|
||||||
|
- Library Persistent ID
|
||||||
|
- Tracks
|
||||||
|
- ...
|
||||||
"""
|
"""
|
||||||
ret = self._process_songs()
|
plist = plistlib.load(open(library_file, 'rb'))
|
||||||
|
|
||||||
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'))
|
|
||||||
return plist['Tracks']
|
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
|
Return an output JSON for an ELS Bulk request - Not a correct format
|
||||||
This method call process_album & process_artist
|
This method call process_album & process_artist
|
||||||
TODO Just return a _correct_ JSON and treat in another place/class
|
TODO Just return a _correct_ JSON and treat in another place/class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tracks = self._read_tracks()
|
tracks = self._read_tracks(library_file)
|
||||||
ret = ""
|
|
||||||
|
|
||||||
for _, track in tracks.items():
|
for _, track in tracks.items():
|
||||||
# Filter out any non-music
|
# Filter out any non-music
|
||||||
@@ -110,20 +105,19 @@ class ITunesParser:
|
|||||||
if 'Podcast' in track or 'Has Video' in track:
|
if 'Podcast' in track or 'Has Video' in track:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
persistent_id = track['Persistent ID']
|
# Each keeped track are stored
|
||||||
json_track_index = {
|
self._tracks[track['Persistent ID']] = track
|
||||||
"index": {"_index": "itunessongs", "_type": "song", "_id": persistent_id}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Retrieve for each track artist information
|
# Retrieve for each track artist information
|
||||||
self._process_artist(track)
|
self._process_artist(track)
|
||||||
# Retrieve for each track album information
|
# Retrieve for each track album information
|
||||||
self._process_album(track)
|
self._process_album(track)
|
||||||
|
|
||||||
ret += json.dumps(json_track_index, indent=None, cls=SetEncoder)
|
ret = {
|
||||||
ret += "\n"
|
'songs': self._tracks,
|
||||||
ret += json.dumps(track, indent=None, cls=SetEncoder)
|
'albums': self._albums,
|
||||||
ret += "\n"
|
'artists': self._artists
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _process_artist(self, track):
|
def _process_artist(self, track):
|
||||||
@@ -138,6 +132,8 @@ class ITunesParser:
|
|||||||
# Add artist
|
# Add artist
|
||||||
if akey not in self._artists:
|
if akey not in self._artists:
|
||||||
a_id = self.calc_id(akey)
|
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] = {
|
self._artists[akey] = {
|
||||||
'Persistent ID': a_id,
|
'Persistent ID': a_id,
|
||||||
'Name': akey,
|
'Name': akey,
|
||||||
@@ -173,6 +169,8 @@ class ITunesParser:
|
|||||||
akey = track['Album']
|
akey = track['Album']
|
||||||
if akey not in self._albums:
|
if akey not in self._albums:
|
||||||
a_id = self.calc_id(akey)
|
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] = {
|
self._albums[akey] = {
|
||||||
'Persistent ID': a_id,
|
'Persistent ID': a_id,
|
||||||
'Name': akey,
|
'Name': akey,
|
||||||
@@ -205,42 +203,6 @@ class ITunesParser:
|
|||||||
self._albums[akey]['Album Rating'] = track['Album Rating']
|
self._albums[akey]['Album Rating'] = track['Album Rating']
|
||||||
self._albums[akey]['Album Rating Computed'] = True
|
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
|
@classmethod
|
||||||
def calc_rating(cls, added_value, current_rating, count):
|
def calc_rating(cls, added_value, current_rating, count):
|
||||||
"""
|
"""
|
||||||
@@ -257,6 +219,82 @@ class ITunesParser:
|
|||||||
md5.update(key.encode('UTF-8'))
|
md5.update(key.encode('UTF-8'))
|
||||||
return md5.hexdigest()
|
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 ####
|
#### main block ####
|
||||||
|
|
||||||
# Default input & output files
|
# Default input & output files
|
||||||
@@ -279,15 +317,18 @@ parser.add_argument('-c', '--console', action='store_true',
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
itunes_parser = ITunesParser(args.file)
|
itunes_parser = ITunesParser().parse(args.file)
|
||||||
output = itunes_parser.to_json()
|
|
||||||
|
|
||||||
if args.console:
|
WriteElsJson.write_songs(itunes_parser['songs'], "es-songs.json")
|
||||||
print(output)
|
WriteElsJson.write_artists(itunes_parser['artists'], "es-artists.json")
|
||||||
else:
|
WriteElsJson.write_albums(itunes_parser['albums'], "es-albums.json")
|
||||||
with io.open(args.output, 'wb') as outfile:
|
|
||||||
if sys.version_info.major == 2:
|
# if args.console:
|
||||||
outfile.write(bytes(output))
|
# print(output)
|
||||||
elif sys.version_info.major == 3:
|
# else:
|
||||||
outfile.write(bytes(output, 'UTF-8'))
|
# with io.open(args.output, 'wb') as outfile:
|
||||||
print('JSON data written to: ' + args.output)
|
# 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