|
import gradio as gr |
|
import spotipy |
|
from spotipy.oauth2 import SpotifyOAuth |
|
from collections import defaultdict |
|
import os |
|
|
|
|
|
CLIENT_ID = os.getenv("CLIENT_ID") |
|
CLIENT_SECRET = os.getenv("CLIENT_SECRET") |
|
REDIRECT_URI = os.getenv("REDIRECT_URI") |
|
|
|
|
|
SCOPE = "playlist-read-private playlist-read-collaborative user-top-read user-read-currently-playing user-read-recently-played user-modify-playback-state playlist-modify-public playlist-modify-private" |
|
|
|
sp = None |
|
|
|
id = None |
|
|
|
|
|
def auth_with_spotify(): |
|
|
|
""" |
|
It auths with the spotify and returns current user info to confirm the success of auth |
|
""" |
|
global sp |
|
global id |
|
|
|
try: |
|
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=SCOPE,client_id=CLIENT_ID,client_secret=CLIENT_SECRET,redirect_uri=REDIRECT_URI)) |
|
|
|
current_user = sp.current_user() |
|
|
|
if current_user.get("id") != None: |
|
id = current_user.get("id") |
|
|
|
return current_user |
|
|
|
except Exception as e: |
|
return f"error auth with spotify {e}" |
|
|
|
|
|
|
|
|
|
|
|
def get_artist_and_track(track_name): |
|
|
|
""" |
|
Searches for a track and returns artist info and URIs |
|
""" |
|
|
|
if not sp: |
|
return "Please authenticate with Spotify first!" |
|
|
|
if not track_name.strip(): |
|
return "Please enter a track name!" |
|
|
|
artist_song = defaultdict(list) |
|
|
|
response = sp.search(q="track:"+track_name,type="track") |
|
|
|
if response: |
|
items = response.get("tracks", {}).get("items", []) |
|
if items: |
|
for item in items: |
|
if item and item.get("artists")[0]: |
|
artist_song["uri"].append(item["uri"]) |
|
artist_song["name"].append(item["artists"][0].get("name")) |
|
else: |
|
artist_song["uri"].append(None) |
|
artist_song["name"].append(None) |
|
|
|
return artist_song |
|
|
|
|
|
|
|
def add_to_queue_song(uri_of_song): |
|
|
|
""" |
|
Adds a song to the Spotify queue using its URI |
|
""" |
|
|
|
if not sp: |
|
return "Please authenticate with Spotify first!" |
|
|
|
if not uri_of_song.strip(): |
|
return "Please enter a track name!" |
|
|
|
try: |
|
sp.add_to_queue(uri_of_song) |
|
return "success adding song to the queue" |
|
|
|
except Exception as e: |
|
return f"error adding song to the queue, check if you have a active session error- {e}" |
|
|
|
|
|
|
|
def get_recently_played_songs(limit_song=5): |
|
|
|
if not sp: |
|
return "Please authenticate with Spotify first!" |
|
|
|
if not limit_song: |
|
return "Please enter a number of songs" |
|
|
|
artist_song = defaultdict(list) |
|
|
|
res = sp.current_user_recently_played(limit_song) |
|
|
|
items = res.get("items",[]) |
|
|
|
if items: |
|
for item in items: |
|
if item and item.get("track"): |
|
track = item.get("track",{}) |
|
|
|
if (track and track.get("name",{})) or (track and track.get("artists",[])): |
|
|
|
artist_song["artist_name"].append(track.get("artists")[0].get("name")) |
|
artist_song["song_name"].append(track.get("name")) |
|
|
|
else: |
|
artist_song["artist_name"].append(None) |
|
artist_song["song_name"].append(None) |
|
|
|
|
|
return artist_song |
|
|
|
|
|
def create_playlist(id, name, description="", public=True, collaborative=False): |
|
""" |
|
Creates a playlist for the given user. |
|
|
|
Args: |
|
id (str): Spotify user ID. |
|
name (str): Name of the playlist (required). |
|
description (str, optional): Description of the playlist. Defaults to "". |
|
public (bool, optional): Whether the playlist is public. Defaults to True. |
|
collaborative (bool, optional): Whether the playlist is collaborative. Defaults to False. |
|
|
|
Keyword Args: |
|
Additional keyword arguments are not used in this function. |
|
|
|
Returns: |
|
str: Success or error message. |
|
""" |
|
if not sp: |
|
return "Please authenticate with Spotify first!" |
|
|
|
if not id and name: |
|
return "Please enter id of user and playlist name" |
|
|
|
try: |
|
res = sp.user_playlist_create(id, name, description, public, collaborative) |
|
|
|
if res.get("name") is not None: |
|
return "playlist created success" |
|
else: |
|
return "error creating playlist" |
|
|
|
except Exception as e: |
|
return f"failed to create playlist error {e}" |
|
|
|
|
|
|
|
|
|
|
|
def get_playlist_name_and_id(limit_playlist=10): |
|
|
|
""" |
|
Use this tool to get playlist name and id , mostly useful in tasks that needs id of playlist |
|
|
|
it takes args like limit_playlist which is number of paylist you want to retrieve |
|
|
|
""" |
|
playlist_name_and_id = defaultdict(list) |
|
|
|
try: |
|
result = sp.current_user_playlists(limit_playlist) |
|
|
|
if result.get("items") != None: |
|
|
|
for item in result["items"]: |
|
|
|
if (item and item.get("name")) or (item and item.get("id")): |
|
|
|
playlist_name_and_id["name"].append(item.get("name")) |
|
playlist_name_and_id["id"].append(item.get("id")) |
|
|
|
else: |
|
playlist_name_and_id["name"].append(None) |
|
playlist_name_and_id["id"].append(None) |
|
|
|
|
|
return playlist_name_and_id |
|
|
|
except Exception as e: |
|
return f"error getting playlists name and id error {e}" |
|
|
|
|
|
|
|
|
|
def add_songs_to_playlist(playlist_id: str, items: str, position=None): |
|
""" |
|
Adds a list of song URIs to the specified playlist. |
|
|
|
Args: |
|
playlist_id (str): The ID of the playlist. |
|
items (str): Comma-separated Spotify track URIs or string representation of list |
|
position (str, optional): Position to insert songs |
|
|
|
Returns: |
|
str: Success or error message |
|
""" |
|
try: |
|
|
|
if isinstance(items, str): |
|
|
|
if items.startswith('[') and items.endswith(']'): |
|
|
|
items = items.strip('[]').replace("'", "").replace('"', '') |
|
song_uris = [uri.strip() for uri in items.split(',')] |
|
else: |
|
|
|
song_uris = [uri.strip() for uri in items.split(',')] |
|
else: |
|
song_uris = items |
|
|
|
pos = int(position) if position and position.strip() else None |
|
|
|
add_to_playlist = sp.playlist_add_items(playlist_id, song_uris, pos) |
|
|
|
if add_to_playlist is not None: |
|
return "success adding songs to playlist" |
|
|
|
except Exception as e: |
|
return f"error adding song to playlist {e}" |
|
|
|
|
|
|
|
|
|
def get_users_top_artists(limit_artists=5,offset=0,time_range="medium_term"): |
|
|
|
""" |
|
Use this tool to get the top artist of the user |
|
|
|
Args: |
|
limit_artists (int): number of artists to retrieve |
|
time_range (str): it can be "medium_term", "short_term" , "long_term" default is "medium_term" |
|
|
|
Returns: |
|
dict: defaultdict containing genres and artist_name |
|
|
|
""" |
|
if not sp: |
|
return "Please authenticate with Spotify first!" |
|
|
|
if not limit_artists: |
|
return "Please enter number of artists to retireve " |
|
|
|
artist_and_genre = defaultdict(list) |
|
|
|
try: |
|
response = sp.current_user_top_artists(limit_artists, offset, time_range) |
|
|
|
if response.get("items"): |
|
for item in response["items"]: |
|
genres = item.get("genres") |
|
artist_name = item.get("name") |
|
|
|
artist_and_genre["artist_name"].append(artist_name) |
|
artist_and_genre["genres"].append(genres) |
|
else: |
|
return "failed to extract top artists please retry the tool" |
|
|
|
return artist_and_genre |
|
|
|
except Exception as e: |
|
return f"error getting top artists error {e}" |
|
|
|
|
|
|
|
|
|
|
|
def get_user_top_tracks(limit_songs=5,time_range="medium_term",offset=0): |
|
|
|
topTracks_and_their_artists = defaultdict(list) |
|
|
|
try: |
|
|
|
result = sp.current_user_top_tracks(limit_songs,offset,time_range) |
|
|
|
if result.get("items"): |
|
for item in result["items"]: |
|
topTracks_and_their_artists["track_name"].append(item.get("name")) |
|
|
|
album_artists = item.get("album", {}).get("artists", []) |
|
|
|
if album_artists: |
|
for artist in album_artists: |
|
|
|
topTracks_and_their_artists["artist_name"].append(artist.get("name")) |
|
|
|
else: |
|
topTracks_and_their_artists["artist_name"].append(None) |
|
else: |
|
return "error retrieving top tracks retry the tool again" |
|
|
|
return topTracks_and_their_artists |
|
|
|
except Exception as e: |
|
return f"error retieving top tracks error -{e}" |
|
|
|
|
|
|
|
gr.Markdown("hello") |
|
|
|
|
|
gr_mcp_tool1 = gr.Interface(fn=add_to_queue_song,inputs="text",outputs="text") |
|
gr_mcp_tool2 = gr.Interface(fn=get_artist_and_track,inputs="text",outputs="text") |
|
gr_mcp_tool3 = gr.Interface(fn=auth_with_spotify,inputs=None,outputs=gr.Textbox(label="Authentication Status")) |
|
gr_mcp_tool4 = gr.Interface(fn=get_recently_played_songs,inputs=gr.Number(label="Number of Songs"),outputs=gr.JSON(label="Recently Played Songs")) |
|
gr_mcp_tool5 = gr.Interface( |
|
fn=create_playlist, |
|
inputs=[ |
|
gr.Textbox(label="User ID", placeholder="Enter Spotify user ID"), |
|
gr.Textbox(label="Playlist Name", placeholder="Enter playlist name") |
|
], |
|
outputs="text") |
|
gr_mcp_tool6 = gr.Interface(fn=get_playlist_name_and_id,inputs=gr.Number(label="number of playlists"),outputs=gr.JSON(label="playlist name and id")) |
|
|
|
gr_mcp_tool7 = gr.Interface( |
|
fn=add_songs_to_playlist, |
|
inputs=[ |
|
gr.Textbox( |
|
label="Playlist ID", |
|
placeholder="e.g. 6PgF6BC39K31SCyMIhlNVs", |
|
info="The Spotify playlist ID where you want to add songs" |
|
), |
|
gr.Textbox( |
|
label="Song URIs (comma separated)", |
|
placeholder="e.g. ['spotify:track:abc123', 'spotify:track:def456', 'spotify:track:ghi789']", |
|
info="Enter Spotify track URIs separated by commas e.g. ['spotify:track:abc123', 'spotify:track:def456', 'spotify:track:ghi789']", |
|
lines=3 |
|
), |
|
gr.Textbox( |
|
label="Position (optional)", |
|
placeholder="e.g. 0 for beginning, leave empty for end", |
|
info="Position to insert songs (0 = beginning, empty = end)" |
|
) |
|
], |
|
outputs=gr.Textbox(label="Result")) |
|
|
|
gr_mcp_tool8 = gr.Interface(fn=get_users_top_artists,inputs=[gr.Number(label="number of artists to retrieve ") |
|
,gr.Textbox(label="time_range",info="time range has options of 'medium_term', 'short_term' , 'long_term' default is 'medium_term'")] |
|
,outputs=gr.JSON(label="genre and artist name")) |
|
|
|
gr_mcp_tool9 = gr.Interface(fn=get_user_top_tracks,inputs=[gr.Number(label="number of tracks to retrieve ") |
|
,gr.Textbox(label="time_range",info="time range has options of 'medium_term', 'short_term' , 'long_term' default is 'medium_term'")] |
|
,outputs=gr.JSON(label="topTrack and artist name")) |
|
|
|
with gr.Blocks() as app: |
|
gr.Markdown("# 🎵 Spotify MCP Tools") |
|
gr.Markdown("Welcome to the Spotify Music Control Panel, Below are the tools available in the Spotify MCP server.") |
|
gr.Markdown("IMPORTANT !! - Due to Limitations in the Authication of the Spotify account Please Run it locally with your Spotify Developer Credentials , checkout the Readme file to know more about the setup") |
|
|
|
|
|
gr.TabbedInterface( |
|
[gr_mcp_tool1, gr_mcp_tool2, gr_mcp_tool3, gr_mcp_tool4, |
|
gr_mcp_tool5, gr_mcp_tool6, gr_mcp_tool7, gr_mcp_tool8, gr_mcp_tool9], |
|
tab_names=[ |
|
"Add to Queue", "Get Artist & Track", "Authenticate", "Recently Played", |
|
"Create Playlist", "Playlist Info", "Add Songs to Playlist", "Top Artists", "Top Tracks" |
|
] |
|
) |
|
|
|
|
|
app.launch(mcp_server=True) |
|
|