import spotipy import spotipy.util import tkinter as ttk from tkinter import ttk as tk import sv_ttk import requests import os import syncedlyrics from PIL import Image, ImageTk from io import BytesIO import math from time import sleep # Set the Spotify app's client ID and client secret client_id = "69b82a34d0fb40be80b020eae8e80f25" client_secret = "455575b0e3db44acbbfaa0c419bc3c10" redirect_uri = "http://127.0.0.1:8888/callback" # Set the user's Spotify username username = "thebrandon45" password = "Mariposa2502$" os.environ["DISPLAY"] = ":0" def setup(): checkDisplay() def checkDisplay(): while True: if os.name == 'posix': if "DISPLAY" in os.environ: break else: sleep(0.25) pass else: break # def wait_for_display(): # while True: # try: # test = ttk.Tk() # test.destroy() # return True # except: # pass # Get the user's Spotify authorization token scope = "user-read-playback-state,user-modify-playback-state" # if len(sys.argv) == 1: # pass # elif sys.argv[1] == "--setup": # try: # os.remove(".cache-" + username) # except OSError: # pass # elif sys.argv[1] == "--clear": # os.remove(".cache-" + username) # sys.exit("Deleting token from cache and exiting...") # elif sys.argv[1] == "--clearChromeCache": # if os.name() == "posix": # os.system("rm -rf ~/.cache/chromium") # os.system("rm -rf ~/.config/chromium") # sys.exit("Deleting Chrome cache and exiting...") # def oauthLogin(): # if os.path.isfile(".cache-" + username) == False: # sleep(25) # pyautogui.press('tab') # pyautogui.press('tab') # pyautogui.press('tab') # pyautogui.press('tab') # pyautogui.write(username) # pyautogui.press('tab') # pyautogui.write(password) # pyautogui.press('enter') # sleep(90) # if platform.system() == "Linux": # os.system("killall chromium-browser") # threading.Thread(target=oauthLogin).start() # oauthLogin() # Create a Spotify object with the user's authorization token def createToken(): token = spotipy.util.prompt_for_user_token(username, scope, client_id, client_secret, redirect_uri) spotify = spotipy.Spotify(auth=token) return spotify spotify = createToken() bg_color = "#000000" # Create the tkinter window root = ttk.Tk() root.title("Media Controller") root.geometry("1280x400") root.attributes("-topmost", True) root.overrideredirect(1) sv_ttk.use_dark_theme() # Function to call the Spotify API to play the current track def play(): spotify.start_playback() # Function to call the Spotify API to pause the current track def pause(): spotify.pause_playback() def next(): spotify.next_track() def previous(): spotify.previous_track() # def maxvolume(): # spotify.volume(100) # def minvolume(): # spotify.volume(0) # def randomvolume(): # spotify.volume(random.randint(0,100)) # def volumeslider(self): # spotify.volume(int(volumeslider_button.get())) # def search(event): # searched = track_search.get() # if searched.startswith(":t"): # track_searched_isolated = searched.replace(":t", "") # track_search_results = spotify.search(q='track:' + track_searched_isolated, type='track') # searched_track_id = track_search_results["tracks"]["items"][0]["id"] # spotify.start_playback(uris=["spotify:track:" + searched_track_id]) # if searched.startswith(":a"): # artist_searched_isolated = searched.replace(":a", "") # artist_search_results = spotify.search(q='artist:' + artist_searched_isolated, type='artist') # searched_artist_id = artist_search_results["artists"]["items"][0]["uri"] # spotify.start_playback(context_uri=searched_artist_id) # if searched.startswith(":l"): # album_searched_isolated = searched.replace(":l", "") # album_search_results = spotify.search(q='album:' + album_searched_isolated, type='album') # searched_album_id = album_search_results["albums"]["items"][0]["uri"] # spotify.start_playback(context_uri=searched_album_id) # if searched.startswith(":p"): # playlist_searched_isolated = searched.replace(":p", "") # playlist_search_results = spotify.search(q='playlist:' + playlist_searched_isolated, type='playlist') # searched_playlist_id = playlist_search_results["playlists"]["items"][0]["uri"] # spotify.start_playback(context_uri=searched_playlist_id) def start_playback_on_device(): device_selections = devices_list.curselection() try: list_of_devices = spotify.devices() except (spotipy.exceptions.SpotifyException, requests.exceptions.HTTPError): createToken() pass list_of_devices = spotify.devices() device_id = list_of_devices["devices"][device_selections[0]]["id"] spotify.transfer_playback(device_id=device_id) def get_devices(): list_of_devices = spotify.devices() unloadNow_playing() if list_of_devices == "{'devices': []}": unloadDevices_list() loadSearching_Devices() root.after(1000, get_devices) else: current_playback = spotify.current_playback() if current_playback != None: unloadSearching_Devices() unloadDevices_list() loadNow_playing() update_song_label() else: unloadSearching_Devices() loadDevices_list() devices_list.delete(0, ttk.END) try: list_of_devices = spotify.devices() except (spotipy.exceptions.SpotifyException, requests.exceptions.HTTPError): createToken() pass list_of_devices = spotify.devices() for num_of_device, garbage in enumerate(list_of_devices["devices"]): devices_list.insert(num_of_device, list_of_devices["devices"][num_of_device]["name"]) root.after(6500, get_devices) # def loadLyrics_pressed(): # unloadNow_playing() # loadLyrics() # def unloadLyrics_pressed(): # unloadLyrics() # loadNow_playing() # def hide_devices(): # get_devices_button.grid() # devices_list.grid_remove() # start_playback_on_device_button.grid_remove() # hide_devices_button.grid_remove() play_img = ttk.PhotoImage(file="icons/play-circle-x2.png") pause_img = ttk.PhotoImage(file="icons/pause-circle-x2.png") next_img = ttk.PhotoImage(file="icons/skip-next-x2.png") previous_img = ttk.PhotoImage(file="icons/skip-previous-x2.png") play_img_black = ttk.PhotoImage(file="icons/play-circle-x2-black.png") pause_img_black = ttk.PhotoImage(file="icons/pause-circle-x2-black.png") next_img_black = ttk.PhotoImage(file="icons/skip-next-x2-black.png") previous_img_black = ttk.PhotoImage(file="icons/skip-previous-x2-black.png") # lyrics_img = ttk.PhotoImage(file="icons/lyrics.png") album_art_img = "" # album_art_img = ttk.PhotoImage(file="album_art.png") # canvas = ttk.Canvas(root, width=480, height=320) # canvas.create_image(0, 0, image=album_art_img, anchor="nw") # canvas.grid() # canvas = ttk.Canvas(root, width=480, height=320) frame_artist_song = ttk.Frame(root, width=(1280/3), height=400, bg=bg_color) # frame_controls = tk.Frame(root) # lyrics_button = tk.Frame(root) album_art_frame = ttk.Frame(root, bg=bg_color) lyrics_label_frame = ttk.Frame(root, width=(1280/3), height=400, bg=bg_color) lyrics_label_frame.grid_propagate(0) root.grid_rowconfigure(0, weight=1) root.grid_rowconfigure(1, weight=1) root.grid_rowconfigure(2, weight=1) root.grid_columnconfigure(0, weight=1) root.grid_columnconfigure(1, weight=1) # root.grid_columnconfigure(2, weight=1) root.configure(background=bg_color) lyrics_label_frame.grid_rowconfigure(0, weight=1) lyrics_label_frame.grid_columnconfigure(0, weight=1) # Create the media control buttons and a text label play_button = ttk.Label(frame_artist_song, image=play_img, borderwidth=0) pause_button = ttk.Label(frame_artist_song, image=pause_img, borderwidth=0) next_button = ttk.Label(frame_artist_song, image=next_img, borderwidth=0) previous_button = ttk.Label(frame_artist_song, image=previous_img, borderwidth=0) # maxvolume_button = tk.Button(root, text="Max Volume", command=maxvolume) # minvolume_button = tk.Button(root, text="Min Volume", command=minvolume) # randomvolume_button = tk.Button(root, text="Random Volume", command=randomvolume) # volumeslider_button = tk.Scale(root, from_=100, to=0, orient=ttk.VERTICAL, length=240, command=volumeslider) #doaudio_analysis = tk.Button(root, text="Audio Analysis", command=doaudioanalysis) artist_label = tk.Label(frame_artist_song, text="", font=("Helvetica", 24), wraplength=(1280/3), justify=ttk.CENTER, background=bg_color) song_label = tk.Label(frame_artist_song, text="", font=("Helvetica", 32), wraplength=(1280/3), justify=ttk.CENTER, background=bg_color) # track_progress_label = tk.Label(root, text="") # track_duration_label = tk.Label(root, text="") # track_combined_label = tk.Label(root, text="") # track_search = tk.Entry(root, text="") # track_search_button = tk.Button(root, text="Search", command=search) get_devices_button = tk.Button(root, text="Get Devices", command=get_devices) start_playback_on_device_button = tk.Button(root, text="Start Playback on Device", command=start_playback_on_device) # hide_devices_button = tk.Button(root, text="Hide Devices", command=hide_devices) # username_label = tk.Label(root, text="Username: " + spotify.me()["display_name"]) devices_list = ttk.Listbox(root, selectmode=ttk.SINGLE, font=("Helvetica", 18)) progress_bar = tk.Progressbar(root, orient=ttk.HORIZONTAL, length=1280) searching_for_devices_label = tk.Label(root, text="Searching for Devices...", font=("Helvetica", 24)) device_name_label = tk.Label(frame_artist_song, text="", font=("Helvetica", 12)) # background_image_label = tk.Label(root, image=album_art_img) lyrics_label = tk.Label(lyrics_label_frame, text="", font=("Helvetica", 32), wraplength=(1280/3), justify=ttk.CENTER, background=bg_color) # loadLyrics_button = ttk.Button(lyrics_button, image=lyrics_img, command=loadLyrics_pressed, borderwidth=0) # album_art_canvas = ttk.Canvas(root) # album_art_canvas_create_image = album_art_canvas.create_image(0, 0, image=album_art_img) album_art_label = tk.Label(album_art_frame, image=album_art_img) # root.bind("", search) # lyrics_label.bind("", lambda e:unloadLyrics_pressed()) play_button.bind("", lambda e:play()) pause_button.bind("", lambda e:pause()) next_button.bind("", lambda e:next()) previous_button.bind("", lambda e:previous()) # Function to update the song label with the current track's name def update_song_label(): global lrc global album_art_img # Get the current playback information while True: try: current_playback = spotify.current_playback() break except (spotipy.exceptions.SpotifyException, requests.exceptions.HTTPError, requests.exceptions.ReadTimeout): createToken() sleep(0.25) # If there is no current playback, set the text of the song label to "No playback" if current_playback is None: # nothing_playing_obj = '{"item": {"artists": [{"name": "Nothing Playing"}],"duration_ms": 0,"name": "Nothing Playing"},"progress_ms": 0}' # current_playback = json.loads(nothing_playing_obj) get_devices() # Update the song label every 1 second else: track_name = current_playback["item"]["name"] artist_name = current_playback["item"]["artists"][0]["name"] track_duration = current_playback["item"]["duration_ms"] track_progress = current_playback["progress_ms"] # current_volume = current_playback["device"]["volume_percent"] playing_status = current_playback["is_playing"] device_name = current_playback["device"]["name"] album_art_url = current_playback["item"]["album"]["images"][0]["url"] track_progress_min = track_progress//(1000*60)%60 track_progress_sec = (track_progress//1000)%60 # track_duration_min = track_duration//(1000*60)%60 # track_duration_sec = (track_duration//1000)%60 # open_url = urlopen(album_art_url) # raw_image_data = open_url.read() # open_url.close() # album_art = ImageTk.PhotoImage(data=raw_image_data) # background_image_label.config(image=album_art) # print(background_image_label.cget("image")) # if raw_image_data == background_image_label.cget("image"): # print("this is the same image") # else: # pass # loadNow_playing() if track_name == song_label.cget("text"): track_progress_formatted = ("{}:{:02d}".format(track_progress_min, track_progress_sec)) # track_progress_label.config(text=track_progress_formatted) progress_bar.config(maximum=track_duration) progress_bar.config(value=track_progress) for line in str(lrc).splitlines(): if track_progress_formatted in line: lyric = line.split("]")[1] # wrapped_lyric = textwrap.fill(lyric, 21) lyrics_label.config(text=lyric) root.after(800, update_song_label) else: # album_art_data = Image.open(requests.get(album_art_url, stream=True).raw) # album_art_data.save("album_art.jpg") device_name_label.config(text=device_name) song_label.config(text=track_name) artist_label.config(text=artist_name) # track_duration_label.config(text=("{}:{:02d}".format(track_duration_min, track_duration_sec))) # volumeslider_button.set(value=current_volume) lyrics_label.config(text="") lrc = syncedlyrics.search("[" + track_name + "] [" + artist_name + "]") album_art_img_data = requests.get(album_art_url).content album_art_img_open = Image.open(BytesIO(album_art_img_data)) album_art_img = ImageTk.PhotoImage(album_art_img_open.resize((300,300))) album_art_label.config(image=album_art_img) bg_color_img = album_art_img_open.resize((1,1), resample=0) bg_color_img_pixel = bg_color_img.getpixel((0,0)) bg_color = "#" + '%02x%02x%02x' % (bg_color_img_pixel) root.config(background=bg_color) frame_artist_song.config(background=bg_color) device_name_label.config(background=bg_color) song_label.config(background=bg_color) artist_label.config(background=bg_color) play_button.config(background=bg_color) pause_button.config(background=bg_color) next_button.config(background=bg_color) previous_button.config(background=bg_color) lyrics_label_frame.config(background=bg_color) lyrics_label.config(background=bg_color) if math.sqrt(0.299 * (bg_color_img_pixel[0] ** 2) + 0.587 * (bg_color_img_pixel[1] ** 2) + 0.114 * (bg_color_img_pixel[2] ** 2)) > 170: song_label.config(foreground="black") artist_label.config(foreground="black") device_name_label.config(foreground="black") lyrics_label.config(foreground="black") play_button.config(image=play_img_black) pause_button.config(image=pause_img_black) next_button.config(image=next_img_black) previous_button.config(image=previous_img_black) else: song_label.config(foreground="white") artist_label.config(foreground="white") device_name_label.config(foreground="white") lyrics_label.config(foreground="white") play_button.config(image=play_img) pause_button.config(image=pause_img) next_button.config(image=next_img) previous_button.config(image=previous_img) # album_art_label.grid_forget() # album_art_label.grid() root.after(500, update_song_label) # if album_art_url == "12345": # open_url = urlopen(album_art_url) # raw_image_data = open_url.read() # open_url.close() # album_art = ImageTk.PhotoImage(data=raw_image_data) # background_image_label.config(image=album_art) # else: # pass if playing_status == True: play_button.grid_forget() pause_button.grid(row=3, column=1, pady=(100,0)) elif playing_status == False: pause_button.grid_forget() play_button.grid(row=3, column=1, pady=(100,0)) else: pass def loadNow_playing(): # background_image_label.place(x=0, y=0) # volumeslider_button.grid(row=1, column=1, rowspan=3, sticky="e", padx=(0,20)) # lyrics_button.grid(row=1, column=1, padx=(0,380)) frame_artist_song.grid(row=0, column=1, rowspan=3, pady=(20,0)) # frame_controls.grid(row=2, column=1) # loadLyrics_button.grid() device_name_label.grid(row=0, column=1) artist_label.grid(row=2, column=1) song_label.grid(row=1, column=1) previous_button.grid(row=3, column=1, padx=(0,200), pady=(100,0)) play_button.grid(row=3, column=1, pady=(100,0)) next_button.grid(row=3, column=1, padx=(200,0), pady=(100,0)) progress_bar.grid(row=3, column=0, columnspan=3) album_art_frame.grid(row=0, column=0, rowspan=4) album_art_label.grid(sticky="w") lyrics_label_frame.grid(row=0, column=2, rowspan=4) lyrics_label.grid() def unloadNow_playing(): # volumeslider_button.grid_forget() # frame_artist_song.grid_forget() # frame_controls.grid_forget() device_name_label.grid_forget() artist_label.grid_forget() song_label.grid_forget() previous_button.grid_forget() play_button.grid_forget() next_button.grid_forget() progress_bar.grid_forget() # loadLyrics_button.grid_forget() # lyrics_label_frame.grid_forget() lyrics_label.grid_forget() album_art_label.grid_forget() def loadDevices_list(): devices_list.grid(row=1, column=1, pady=10) start_playback_on_device_button.grid(row=0, column=1, ipadx=40, ipady=40) def unloadDevices_list(): devices_list.grid_forget() start_playback_on_device_button.grid_forget() def loadSearching_Devices(): searching_for_devices_label.grid() def unloadSearching_Devices(): searching_for_devices_label.grid_forget() # def loadLyrics(): # album_art_frame.grid(row=0, column=1) # album_art_label.grid() # lyrics_label.grid(row=0, column=1) # def unloadLyrics(): # album_art_frame.grid_forget() # album_art_label.grid_forget() # lyrics_label.grid_forget() # Start updating the song label setup() loadNow_playing() update_song_label() # Run the GUI root.mainloop()