Skip to content

Instantly share code, notes, and snippets.

@izanbf1803
Last active February 12, 2023 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save izanbf1803/53f0816985a3f526212e56a686476586 to your computer and use it in GitHub Desktop.
Save izanbf1803/53f0816985a3f526212e56a686476586 to your computer and use it in GitHub Desktop.
Create a text backup of your spotify lists.
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