Skip to content

Commit 88f2284

Browse files
committed
Add analytics script to analyze decade, allow fetching specific playlist
1 parent 022e05b commit 88f2284

File tree

5 files changed

+132
-52
lines changed

5 files changed

+132
-52
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ To automatically backup (in a script, on a schedule...):
4040
poetry run python src/main.py --backup
4141
```
4242

43+
To get only a specific playlist
44+
45+
```bash
46+
poetry run python src/main.py --backup --playlist <name of playlist>
47+
```
48+
49+
To get decade-distribution for any file
50+
51+
```bash
52+
poetry run python src/main.py --file <path to file>
53+
```
54+
55+
4356
## Time taken
4457

4558
> **Quick restore causes liked songs to lose order. Playlists are always ordered

poetry.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/analyze.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from json import load
2+
3+
4+
def analyze(file_path):
5+
raw_data = load(open(file_path, "r"))
6+
if "tracks" in raw_data:
7+
raw_data = raw_data["tracks"]
8+
9+
tracks = sorted(
10+
[
11+
int(x["release_date"].split("-")[0])
12+
for x in raw_data
13+
if x["release_date"] != "0000"
14+
]
15+
)
16+
17+
by_decade = {}
18+
19+
for t in tracks:
20+
decade = str(t)[:-1] + "0s"
21+
if decade in by_decade:
22+
by_decade[decade] = by_decade[decade] + 1
23+
else:
24+
by_decade[decade] = 1
25+
26+
if decade == "0s":
27+
print(t)
28+
29+
print(by_decade)
30+
31+
32+
# import matplotlib.pyplot as plt
33+
# plt.pie(data.values(), labels=data.keys())
34+
# plt.show()

src/backup.py

+51-45
Original file line numberDiff line numberDiff line change
@@ -161,81 +161,87 @@ def write(data, path):
161161
dump(data, open(path, "w"), indent="\t")
162162

163163

164-
def backup(sp: Spotify):
164+
def backup(sp: Spotify, playlist_name=None):
165165
print("Backing up... This might take a while")
166166

167167
backup = Path("backup")
168168
backup.mkdir(parents=True, exist_ok=True)
169169

170-
git_status = subprocess.run(
171-
["git", "status", "--porcelain"], cwd=backup, capture_output=True, text=True
172-
)
170+
if not playlist_name:
171+
git_status = subprocess.run(
172+
["git", "status", "--porcelain"], cwd=backup, capture_output=True, text=True
173+
)
173174

174-
if git_status.returncode != 0:
175-
subprocess.run(["git", "init"], cwd=backup).check_returncode()
175+
if git_status.returncode != 0:
176+
subprocess.run(["git", "init"], cwd=backup).check_returncode()
176177

177-
if git_status.stdout:
178-
print("You have uncommitted changes in backup/, exiting")
179-
exit(1)
178+
if git_status.stdout:
179+
print("You have uncommitted changes in backup/, exiting")
180+
exit(1)
180181

181-
subprocess.run(["git", "pull"], cwd=backup).check_returncode()
182+
subprocess.run(["git", "pull"], cwd=backup).check_returncode()
182183

183-
rmtree("backup/playlists", ignore_errors=True)
184-
Path("backup/liked-songs.json").unlink(missing_ok=True)
185-
Path("backup/saved-albums.json").unlink(missing_ok=True)
186-
Path("backup/followed-artists.json").unlink(missing_ok=True)
187-
Path("backup/blend-names.json").unlink(missing_ok=True)
184+
rmtree("backup/playlists", ignore_errors=True)
185+
Path("backup/liked-songs.json").unlink(missing_ok=True)
186+
Path("backup/saved-albums.json").unlink(missing_ok=True)
187+
Path("backup/followed-artists.json").unlink(missing_ok=True)
188+
Path("backup/blend-names.json").unlink(missing_ok=True)
188189

189190
Path("backup/playlists/owned").mkdir(parents=True, exist_ok=True)
190191
Path("backup/playlists/collaborative").mkdir(parents=True, exist_ok=True)
191192
Path("backup/playlists/followed").mkdir(parents=True, exist_ok=True)
192193

193-
print("Backing up liked songs...")
194-
songs = get_liked_songs(sp)
195-
write(songs, "backup/liked-songs.json")
194+
if not playlist_name:
195+
print("Backing up liked songs...")
196+
songs = get_liked_songs(sp)
197+
write(songs, "backup/liked-songs.json")
196198

197-
print("Backing up albums...")
198-
albums = get_albums(sp)
199-
write(albums, "backup/saved-albums.json")
199+
print("Backing up albums...")
200+
albums = get_albums(sp)
201+
write(albums, "backup/saved-albums.json")
200202

201-
print("Backing up followed artists...")
202-
followed = get_followed_artists(sp)
203-
write(followed, "backup/followed-artists.json")
203+
print("Backing up followed artists...")
204+
followed = get_followed_artists(sp)
205+
write(followed, "backup/followed-artists.json")
204206

205207
print("Backing up playlists...")
206208
playlists, blends = get_playlists(sp)
207209
for playlist in playlists:
210+
if playlist_name and playlist["name"] != playlist_name:
211+
continue
212+
208213
playlist["tracks"] = get_playlist_tracks(sp, playlist)
209214
write(
210215
playlist,
211216
f"backup/playlists/{playlist['type']}/{slugify(playlist['name'])}-{slugify(playlist['id'])}.json",
212217
)
213218

214-
write(blends, "backup/blend-names.json")
219+
if not playlist_name:
220+
write(blends, "backup/blend-names.json")
215221

216-
print("Commiting and pushing changes...")
222+
print("Commiting and pushing changes...")
217223

218-
subprocess.run(["git", "add", "."], cwd=backup).check_returncode()
224+
subprocess.run(["git", "add", "."], cwd=backup).check_returncode()
219225

220-
subprocess.run(
221-
"git diff-index --quiet HEAD || git commit -m 'Automated update'",
222-
cwd=backup,
223-
shell=True,
224-
).check_returncode()
226+
subprocess.run(
227+
"git diff-index --quiet HEAD || git commit -m 'Automated update'",
228+
cwd=backup,
229+
shell=True,
230+
).check_returncode()
225231

226-
subprocess.run(["git", "push"], cwd=backup)
232+
subprocess.run(["git", "push"], cwd=backup)
227233

228-
print("Backup complete!")
229-
print("* Your liked songs were backed up")
230-
print("* Your followed artists were backed up")
231-
print("* Your saved albums were backed up")
232-
print("* Names of people in blends were backed up (excluding large blends)")
233-
print("* The following playlists were backed up:")
234+
print("Backup complete!")
235+
print("* Your liked songs were backed up")
236+
print("* Your followed artists were backed up")
237+
print("* Your saved albums were backed up")
238+
print("* Names of people in blends were backed up (excluding large blends)")
239+
print("* The following playlists were backed up:")
234240

235-
print(
236-
tabulate(
237-
[[x["name"], x["type"]] for x in playlists],
238-
headers=["Name", "Type"],
239-
showindex=range(1, len(playlists) + 1),
241+
print(
242+
tabulate(
243+
[[x["name"], x["type"]] for x in playlists],
244+
headers=["Name", "Type"],
245+
showindex=range(1, len(playlists) + 1),
246+
)
240247
)
241-
)

src/main.py

+33-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from backup import backup
77
from clean_library import clean_library
88
from restore import restore
9+
from analyze import analyze
910

1011
client_id = "d93f79db5bbb41999a52734b9c95585a"
1112
redirect_uri = "http://localhost:3000/authed"
@@ -29,15 +30,25 @@
2930
)
3031

3132
if not auth_manager.validate_token(auth_manager.get_cached_token()):
32-
print("If your browser doesn't open automatically, open", auth_manager.get_authorize_url())
33+
print(
34+
"If your browser doesn't open automatically, open",
35+
auth_manager.get_authorize_url(),
36+
)
3337

3438
sp = spotipy.Spotify(auth_manager=auth_manager)
3539

3640
parser = argparse.ArgumentParser(description="Backup and restore spotify library")
37-
parser.add_argument('--backup', action='store_true')
41+
parser.add_argument("--backup", action="store_true")
42+
parser.add_argument("--playlist")
43+
parser.add_argument("--file")
3844
args = parser.parse_args()
3945

40-
choice = "y" if args.backup else input(f"Logged in as {sp.me()['display_name']}. Continue? [y/n/logout] ")
46+
choice = (
47+
"y"
48+
if args.backup or args.file
49+
else input(f"Logged in as {sp.me()['display_name']}. Continue? [y/n/logout] ")
50+
)
51+
4152
if choice == "y":
4253
pass
4354
elif choice == "logout":
@@ -47,20 +58,30 @@
4758
quit()
4859

4960

50-
choice = "1" if args.backup else input(
51-
"""What would you like to do? Available:
61+
choice = (
62+
"1"
63+
if args.backup
64+
else "5"
65+
if args.file
66+
else input(
67+
"""What would you like to do? Available:
5268
1. Backup
5369
2. Quick restore (doesn't preserve order of liked songs)
5470
3. Restore (preserves order of liked songs)
5571
4. [DANGEROUS] Clean library
72+
5. Analyze playlist
5673
5774
Note that while quick restore loses order for liked songs, playlists are always ordered correctly.
5875
5976
[1/2/3/4/q]: """
77+
)
6078
)
6179

6280
if choice == "1":
63-
backup(sp)
81+
if args.playlist:
82+
backup(sp, playlist_name=args.playlist)
83+
else:
84+
backup(sp)
6485
elif choice == "2":
6586
restore(sp, True)
6687
elif choice == "3":
@@ -73,5 +94,11 @@
7394
clean_library(sp)
7495
else:
7596
quit()
97+
elif choice == "5":
98+
if args.file:
99+
analyze(args.file)
100+
else:
101+
file_path = input("Input file path: ")
102+
analyze(file_path)
76103
else:
77104
quit()

0 commit comments

Comments
 (0)