Last active
February 12, 2023 21:40
-
-
Save izanbf1803/53f0816985a3f526212e56a686476586 to your computer and use it in GitHub Desktop.
Create a text backup of your spotify lists.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import TextIO | |
from datetime import date | |
import time | |
import requests | |
import json | |
import os | |
import sys | |
import re | |
def str_date() -> str: | |
return date.today().strftime("%d-%m-%Y") | |
def sanitize(s: str) -> str: | |
return re.sub(r'[^\w]', '_', s) | |
class Spotify: | |
_token: str | |
_user: dict | |
_id: str | |
def __init__(self, token: str): | |
self._token = token | |
self._user = self.request("https://api.spotify.com/v1/me") | |
self._id = self._user["id"] | |
def request(self, url: str) -> dict: | |
headers = { | |
"Accept": "application/json", | |
"Content-Type": "application/json", | |
"Authorization": f"Bearer {self._token}" | |
} | |
r = requests.get(url, headers=headers) | |
if r.status_code != 200: | |
print(f"ERROR {r.status_code}") | |
print(r.text) | |
sys.exit() | |
return json.loads(r.text) | |
def get_all_items(self, url: str) -> list[dict]: | |
all_items = [] | |
curl = url | |
while curl is not None and len(curl) > 0: | |
r = self.request(curl) | |
items = r["items"] | |
all_items = all_items + items | |
if len(items) == 0: | |
break | |
curl = r["next"] | |
return all_items | |
def playlists(self) -> list[dict]: | |
return self.get_all_items("https://api.spotify.com/v1/me/playlists") | |
def playlist_tracks(self, playlist: dict) -> list[dict]: | |
items = self.get_all_items(f"https://api.spotify.com/v1/playlists/{playlist['id']}/tracks") | |
tracks = [] | |
for item in items: | |
track = item["track"] | |
if track is not None: | |
tracks.append(track) | |
else: | |
print(f"Missing song in playlist {playlist['name']}") | |
return tracks | |
def backup(self): | |
def backup_playlist(f: TextIO, playlist: dict): | |
sep = " | " | |
width = 40 | |
songs = self.playlist_tracks(playlist) | |
fields = ["name", "artists", "album"] | |
f.write(sep.join(v.ljust(width) for v in fields)) | |
f.write("\n") | |
f.write("-"*(width*len(fields))) | |
f.write("\n") | |
for song in songs: | |
to_write = [] | |
for field in fields: | |
value = song[field] | |
if field == "album": | |
value = value["name"] | |
if field == "artists": | |
value = ", ".join(e["name"] for e in value) | |
if value is None: | |
value = "None" | |
value = value.ljust(width) | |
to_write.append(value) | |
f.write(sep.join(to_write)) | |
f.write("\n") | |
root = f"spotify-backup-{str_date()}-{int(time.time()*1000)}" | |
os.mkdir(root) | |
cwd = os.getcwd() | |
os.chdir(root) | |
playlists = self.playlists() | |
for plist in playlists: | |
fname = f"{sanitize(plist['name'])}_{plist['id']}.txt" | |
with open(fname, "w") as f: | |
backup_playlist(f, plist) | |
os.chdir(cwd) | |
def main() -> None: | |
with open("token.txt") as f: | |
oauth_token = f.read().strip() | |
spotify = Spotify(oauth_token) | |
spotify.backup() | |
print("BACKUP COMPLETED!") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment