Last active
May 29, 2024 09:13
-
-
Save adamshostack/ca17e69e3145f11d20c871a4a186be51 to your computer and use it in GitHub Desktop.
Spotify playlists from csv files. Useful for music festivals.
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
# Claude Opus 3 wrote most of the code below (I edited it as I went). After I was happy, I prompted | |
# "write me a prompt that will make you emit that code with all the relevant decisions we've made along the way." | |
# Claude produced the following: | |
I have a Spotify account and I want to create a Python script that does the following: | |
Reads a list of artist names from a file named after the artist. For example, if the file is named "artists.txt", the script should create a playlist named "artists". | |
For each artist in the list, the script should: | |
Search for an exact match of the artist name on Spotify. | |
If an exact match is found and the artist has albums, add the tracks from their latest album to the playlist. | |
If an exact match is found but the artist has no albums, or if no exact match is found, perform a broader search for the artist. | |
If the broader search finds a matching artist, display the artist's name, their latest album name, and the album URL. Open the album URL in the system's default web browser. | |
Prompt the user to confirm if they want to add the latest album of the matching artist to the playlist. If the user confirms or presses Enter (default to yes), add the album tracks to the playlist. | |
If no matching artist is found or the user chooses not to add the album, skip to the next artist. | |
Display appropriate messages for each action performed (e.g., artist found, album added to playlist, artist skipped). | |
Handle any potential errors gracefully and display informative error messages. | |
Additionally: | |
Use the Spotipy library to interact with the Spotify API. | |
Store the Spotify API credentials (client ID, client secret, redirect URI) directly in the script for simplicity. | |
Include a security note in the code to remind users to remove the line that opens the album URL in the browser if they don't trust Spotify. | |
Organize the code into functions for better readability and maintainability. | |
Provide clear instructions on how to set up and run the script. | |
Please provide the Python code that accomplishes the above requirements, along with any necessary explanations or instructions. | |
And remember, be concise in your responses and take your time to think through the code and design decisions. |
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
# sometimes the code overmatches; this lets you quickly delete an artist, with confirmations. | |
import spotipy | |
from spotipy.oauth2 import SpotifyOAuth | |
from difflib import get_close_matches | |
# Spotify API credentials | |
client_id = "your_client_id" | |
client_secret = "your_client_secret" | |
redirect_uri = "your_redirect_uri" | |
# Function to get user's playlists | |
def get_user_playlists(sp): | |
playlists = [] | |
offset = 0 | |
while True: | |
results = sp.current_user_playlists(offset=offset) | |
if not results["items"]: | |
break | |
playlists.extend(results["items"]) | |
offset += len(results["items"]) | |
return playlists | |
# Function to search for an artist in a playlist | |
def search_artist_in_playlist(sp, playlist_id, artist_name): | |
tracks = [] | |
artists = set() | |
offset = 0 | |
while True: | |
results = sp.playlist_items(playlist_id, offset=offset) | |
if not results["items"]: | |
break | |
for item in results["items"]: | |
track = item["track"] | |
track_artists = [artist["name"] for artist in track["artists"]] | |
artists.update(track_artists) | |
if any(get_close_matches(artist_name, track_artists, n=1, cutoff=0.6)): | |
tracks.append(track) | |
offset += len(results["items"]) | |
return tracks, artists | |
# Main function | |
def main(): | |
# Authenticate with Spotify API | |
scope = "playlist-read-private playlist-modify-private" | |
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope=scope)) | |
# Get user's playlists | |
print("Retrieving your playlists...") | |
playlists = get_user_playlists(sp) | |
# Display playlists for selection | |
print("Your playlists:") | |
for i, playlist in enumerate(playlists, start=1): | |
print(f"{i}. {playlist['name']}") | |
# Prompt user to select a playlist | |
selection = input("Enter the number of the playlist you want to work with: ") | |
try: | |
playlist_index = int(selection) - 1 | |
if playlist_index < 0 or playlist_index >= len(playlists): | |
raise ValueError | |
except ValueError: | |
print("Invalid playlist selection.") | |
return | |
selected_playlist = playlists[playlist_index] | |
print(f"Selected playlist: {selected_playlist['name']}") | |
# Prompt user to enter an artist to remove | |
artist_to_remove = input("Enter the name of the artist you want to remove: ") | |
# Search for the artist in the selected playlist | |
print(f"Searching for '{artist_to_remove}' in the playlist...") | |
matching_tracks, playlist_artists = search_artist_in_playlist(sp, selected_playlist["id"], artist_to_remove) | |
if not matching_tracks: | |
print("No matching tracks found.") | |
print("Available artists in the playlist:") | |
for artist in playlist_artists: | |
print(f"- {artist}") | |
return | |
# Display the list of matching tracks | |
print("Matching tracks:") | |
for i, track in enumerate(matching_tracks, start=1): | |
print(f"{i}. {track['name']} - {', '.join([artist['name'] for artist in track['artists']])}") | |
# Prompt user for confirmation to delete the tracks | |
confirmation = input("Would you like me to delete these songs? [Y/n]: ").lower() | |
if confirmation not in ["", "y", "yes"]: | |
print("Deletion canceled.") | |
return | |
# Remove the matching tracks from the playlist | |
track_ids = [track["id"] for track in matching_tracks] | |
sp.playlist_remove_all_occurrences_of_items(selected_playlist["id"], track_ids) | |
print("Matching tracks deleted from the playlist.") | |
# Run the script | |
if __name__ == "__main__": | |
main() |
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
import spotipy | |
from spotipy.oauth2 import SpotifyOAuth | |
from spotify_functions import process_artist | |
import os | |
# See developer.spotify.com | |
client_id = "you need one" | |
client_secret = "you need one" | |
redirect_uri = "http://localhost:8888/callback" | |
scope = "playlist-modify-private" | |
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope=scope)) | |
# Prompt for the filename | |
filename = input("Enter the filename containing artist names (comma-separated): ") | |
try: | |
with open(filename, "r") as file: | |
artist_names = file.read().strip() | |
artist_list = [name.strip() for name in artist_names.split(",")] | |
# Get the playlist name from the filename (without the extension) | |
playlist_name = os.path.splitext(filename)[0] | |
playlist = sp.user_playlist_create(user=sp.me()["id"], name=playlist_name, public=False) | |
for artist_name in artist_list: | |
process_artist(sp, artist_name, playlist) | |
print(f"Successfully created playlist '{playlist_name}' with the top 10 tracks of each artist.") | |
except FileNotFoundError: | |
print(f"File '{filename}' not found.") | |
except Exception as e: | |
print(f"Error processing the file: {e}") |
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
import subprocess | |
# Security: note this code passes URLs from Spotify to the system; if you don't | |
# trust Spotify, remove the subprocess.run line. | |
def process_artist(sp, original_artist_name, playlist): | |
# Search for the artist using an exact match | |
results = sp.search(q=f'artist:"{original_artist_name}"', type="artist", limit=1) | |
if results["artists"]["items"]: | |
artist = results["artists"]["items"][0] | |
albums = sp.artist_albums(artist["id"], album_type="album", limit=1)["items"] | |
if albums: | |
latest_album = albums[0] | |
album_tracks = sp.album_tracks(latest_album["id"])["items"] | |
track_uris = [track["uri"] for track in album_tracks] | |
sp.user_playlist_add_tracks(user=sp.me()["id"], playlist_id=playlist["id"], tracks=track_uris) | |
print(f"Added the latest album '{latest_album['name']}' by {artist['name']} to the playlist.") | |
else: | |
# If no albums found for exact match, try a broader search | |
process_broader_search(sp, original_artist_name, playlist) | |
else: | |
# If exact match fails, try a broader search | |
process_broader_search(sp, original_artist_name, playlist) | |
def process_broader_search(sp, original_artist_name, playlist): | |
results = sp.search(q=f'"{original_artist_name}"', type="artist", limit=1) | |
if results["artists"]["items"]: | |
artist = results["artists"]["items"][0] | |
albums = sp.artist_albums(artist["id"], album_type="album", limit=1)["items"] | |
if albums: | |
latest_album = albums[0] | |
print(f"Searched for '{original_artist_name}', found '{artist['name']}'.") | |
subprocess.run(["open", latest_album['external_urls']['spotify']]) | |
print(f"Latest album: '{latest_album['name']}', {latest_album['external_urls']['spotify']}") | |
confirmation = input("Add this album to the playlist? (Y/n): ") | |
if confirmation.lower() in ["", "y"]: | |
album_tracks = sp.album_tracks(latest_album["id"])["items"] | |
track_uris = [track["uri"] for track in album_tracks] | |
sp.user_playlist_add_tracks(user=sp.me()["id"], playlist_id=playlist["id"], tracks=track_uris) | |
print(f"Added the latest album '{latest_album['name']}' by {artist['name']} to the playlist.") | |
else: | |
print(f"Skipping artist: {artist['name']}") | |
else: | |
print(f"No albums found for artist: {artist['name']}") | |
else: | |
print(f"Artist '{original_artist_name}' not found. Skipping...") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The biggest issue that I'd work on if I were to continue would be