Last active
August 17, 2023 04:19
-
-
Save RitamDey/33d4b62238d2ab47945442f311a33ef4 to your computer and use it in GitHub Desktop.
Automation script to sort liked tracks into years and create playlists based upon when they were added to liked playlist
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
import spotipy | |
from spotipy.oauth2 import SpotifyOAuth | |
from datetime import datetime, timezone | |
import logging | |
from logging.handlers import TimedRotatingFileHandler | |
from collections import defaultdict | |
def save_playlist_and_last_seen_data(spotify): | |
pass | |
def collect_and_sort_tracks(spotify): | |
songs_year_mapping = defaultdict(list) # Using defaultdict so as to not handle if a year key is absent | |
user_playlists = spotify.current_user_saved_tracks(limit=50, market="IN") | |
while user_playlists is not None and user_playlists["total"] > 0: | |
for track in user_playlists["items"]: | |
name = track["track"]["name"] | |
added_at = datetime.fromisoformat(track["added_at"]) | |
year = str(added_at.year) # int is not hashable, thus convert to string | |
songs_year_mapping[year].append(track["track"]["uri"]) # Only the Spotify URI is needed for adding tracks to playlists | |
logging.info(f"Sorted {name} in {track.added_year()}") | |
# Get the next set of saved tracks from the liked playlist | |
user_playlists = spotify.next(user_playlists) | |
return songs_year_mapping | |
def search_playlists(spotify, years): | |
pass | |
def create_playlists(spotify, years): | |
# TODO: Handle if a playlist with the same exists. Spotify doesn't allow fetching playlist by name | |
# Get the current user's ID | |
user = spotify.me() | |
user_id = user["id"] | |
# Template to be used for playlist names and descriptions | |
name_template = "{} Discoveries" | |
description_temple = "Songs that I liked in {}" | |
logging.info(f"Creating playlits for user ID {user_id}.") | |
created_playlist_data = {} | |
for year in years: | |
playlist = name_template.format(year) | |
description = description_temple.format(year) | |
created_playlist = spotify.user_playlist_create( | |
user = user_id, | |
name = playlist, | |
description = description, | |
public = False | |
) | |
spotify_id = created_playlist["id"] | |
created_playlist_data[year] = spotify_id | |
logging.info(f"Created playlist {playlist} (Spotify ID {spotify_id})") | |
return created_playlist_data | |
def add_tracks_to_playlist(spotify, playlist_data, tracks_data, years): | |
# Spotify currently allows a max of 100 items to be added at one | |
track_chunk_size = 100 | |
for year in years: | |
# Get the created playlist ID | |
playlist_id = playlist_data[year] | |
logging.info(f"Adding tracks for {year} playlist") | |
# Get all saved tracks from that year and have a count of the number of tracks added | |
tracks = tracks_data[year] | |
tracks_count = len(tracks) | |
# Chunk up the tracks into lists of 100 track chunks, this is done to reduce API calls to Spotify | |
# ref: https://www.programiz.com/python-programming/examples/list-chunks | |
tracks_chunked = [ tracks[i:i + track_chunk_size ] for i in range(0, tracks_count, track_chunk_size) ] | |
# Add each chunks to current pplaylist | |
for chunk in tracks_chunked: | |
spotify.playlist_add_items(playlist_id, chunk) | |
logging.info(f"Added {chunk} tracks to playlist {playlist_id}") | |
if __name__ == "__main__": | |
# Setup logging for the entire script | |
# log = TimedRotatingFileHandler(filename="execution.log", when="D", backupCount=10) | |
# log.setLevel(logging.INFO) | |
# log.setFormatter(logging.Formatter( | |
# fmt="%(asctime)s - %(filename)s - %(levelname)s: %(message)s", | |
# datefmt="%d/%m/%Y %I:%M:%S %p" | |
# )) | |
# logging.getLogger().addHandler(log) | |
logging.basicConfig( | |
format="%(asctime)s - %(filename)s - %(levelname)s: %(message)s", | |
datefmt="%d/%m/%Y %I:%M:%S %p", | |
level=logging.INFO | |
) | |
scope = "playlist-modify-private,user-library-modify,user-library-read,user-read-private,user-read-email" | |
auth = SpotifyOAuth(scope=scope) | |
spotify = spotipy.Spotify(auth_manager=auth) | |
logging.info("Authentication successful with Spotify APIs") | |
tokens = auth.get_cached_token() | |
if tokens: | |
auth.refresh_access_token(tokens['refresh_token']) | |
logging.info("Authentication successful with Spotify APIs") | |
sorted_tracks = collect_and_sort_tracks(spotify) | |
years = sorted_tracks.keys() | |
playlists = create_playlists(spotify, years) | |
add_tracks_to_playlist(spotify, playlists, sorted_tracks, years) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment