Last active
July 14, 2023 20:46
-
-
Save ivystopia/ff29f92de0fe53586a2a47f4a8d24b65 to your computer and use it in GitHub Desktop.
Save Spotify playlists for a user
This file contains hidden or 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
#! /usr/bin/env python3 | |
# Need to set SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET env vars | |
# Then run with ./spotispy.py username | |
# It will save playlists in "data" directory relative to the current directory | |
import sys | |
import json | |
import spotipy | |
from pathlib import Path | |
# Idiot proof | |
if len(sys.argv) < 2: | |
print("Specify a username as the first argument.") | |
quit(1) | |
username = sys.argv[1] | |
# Create directory for the user | |
user_dir = "data/{}".format(username) | |
Path("{}/playlists".format(user_dir)).mkdir(parents=True, exist_ok=True) | |
class Client(spotipy.Spotify): | |
""" | |
Wrapper for Spotipy allowing infinite pagination | |
""" | |
def user_playlists(self, username): | |
offset = 0 | |
while True: | |
response = super().user_playlists(username, limit=50, offset=offset) | |
for playlist in response['items']: | |
# Ignore playlists which were not created by the user themselves | |
if playlist['owner']['id'] != username: | |
continue | |
# Remove snapshot ID as this sometimes changes with no actual track changes | |
del playlist['snapshot_id'] | |
# Remove images | |
del playlist['images'] | |
# Replace tracks URL with actual list of tracks | |
playlist['tracks'] = [track for track in self.playlist_tracks(playlist['id'])] | |
# Playlist followers | |
followers = self.playlist(playlist_id=playlist['id'])['followers']['total'] | |
playlist['followers'] = followers if followers else 0 | |
yield playlist | |
if not response.get('next'): | |
break | |
else: | |
offset = offset + 50 | |
def playlist_tracks(self, playlist_id): | |
offset = 0 | |
while True: | |
response = super().playlist_tracks(playlist_id, limit=100, offset=offset) | |
for item in response['items']: | |
if not item['track']: | |
# TODO why????? | |
continue | |
# Format track info | |
track = {} | |
track['added_at'] = item.get('added_at') | |
track['title'] = item.get('track').get('name') | |
track['album'] = item.get('track').get('album').get('name') | |
track['artist'] = item.get('track').get('artists')[0]['name'] | |
track['uri'] = item.get('track').get('uri') | |
yield track | |
if not response.get('next'): | |
break | |
else: | |
offset = offset + 100 | |
# Create client object with our API credentials (already set in env) | |
client = Client(client_credentials_manager=spotipy.oauth2.SpotifyClientCredentials()) | |
# Grab user overview and save to data/username/username.json | |
user_overview = client.user(username) | |
with open("{}/{}.json".format(user_dir, username), 'w') as file: | |
file.write(json.dumps(user_overview, indent=2)) | |
# Grab playlists and save to data/username/playlist_id.json | |
for playlist in client.user_playlists(user_overview['id']): | |
with open("{}/playlists/{}.json".format(user_dir, playlist['id']), 'w') as file: | |
file.write(json.dumps(playlist, indent=2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment