forked from mk12/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathitunes.py
More file actions
executable file
·96 lines (80 loc) · 2.91 KB
/
itunes.py
File metadata and controls
executable file
·96 lines (80 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python3
"""This script prints top-played songs from iTunes for each year."""
from collections import defaultdict
from datetime import datetime
from pathlib import Path
import xml.etree.ElementTree as ET
import sys
from dateutil.parser import parse # pip3 install python-dateutil
# Note, this no longer exists with Music.app. Instead, you need to do File >
# Library > Export Library, and then pass that file to this script.
LIBRARY = Path.home() / "Music/iTunes/iTunes Library.xml"
def plist_iter(iterable, all_dicts=False):
a = iter(iterable)
for k, v in zip(a, a):
assert k.tag == "key"
if all_dicts:
if v.tag != "dict":
print(f"For key {k.text}, not dict but {v.tag}")
assert v.tag == "dict"
yield k.text, v
def extract_songs(tree):
root = tree.getroot()[0]
tracks = None
for key, node in plist_iter(root):
if key == "Tracks":
tracks = node
songs = []
for key, node in plist_iter(tracks, all_dicts=True):
is_music = False
song = {}
for k, n in plist_iter(node):
if k == "Kind":
if "audio" in n.text:
is_music = True
else:
break
elif k in ("Podcast", "Movie", "Audiobooks"):
is_music = False
break
elif k == "Play Count":
song["play_count"] = int(n.text)
elif k == "Date Added":
song["date_added"] = parse(n.text)
elif k == "Name":
if "wcpe" in n.text.lower():
is_music = False
break
song["name"] = n.text
elif k == "Album":
song["album"] = n.text
elif k == "Artist":
song["artist"] = n.text
if is_music:
songs.append(song)
return songs
def make_playlists(songs):
by_year = defaultdict(list)
for song in songs:
if "date_added" in song and "play_count" in song:
by_year[song["date_added"].year].append(song)
for _, song_list in by_year.items():
song_list.sort(key=lambda s: s["play_count"], reverse=True)
return by_year
def print_top_songs(playlists):
for year in range(2010, datetime.now().year):
print(f"{year}\n====")
for i, song in enumerate(playlists[year][:25]):
play_count = song["play_count"]
name = song.get("name", "Unknown name")
artist = song.get("artist", "Unknown artist")
album = song.get("album", "Unknown album")
print(f"{i+1}. [{play_count}] {name} | {artist} | {album}")
print("\n\n")
def main():
tree = ET.parse(sys.argv[1] if len(sys.argv) > 1 else LIBRARY)
songs = extract_songs(tree)
playlists = make_playlists(songs)
print_top_songs(playlists)
if __name__ == "__main__":
main()