import spotipy import spotipy.util import tkinter as ttk from tkinter import ttk as tk import random import json import sv_ttk from urllib.request import urlopen import requests from time import sleep import sys import os import pyautogui import threading import platform import syncedlyrics import textwrap from PIL import Image, ImageTk from io import BytesIO # 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$" def wait_for_connection(): while True: try: urlopen('http://142.250.189.174', timeout=1) return True except: pass # 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 platform.system() == "Linux": 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() token = spotipy.util.prompt_for_user_token(username, scope, client_id, client_secret, redirect_uri) # Create a Spotify object with the user's authorization token def createToken(): spotify = spotipy.Spotify(auth=token) return spotify spotify = createToken() # 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") 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 = tk.Frame(root, width=(1280/3), height=400) # frame_controls = tk.Frame(root) lyrics_button = tk.Frame(root) album_art_frame = tk.Frame(root) lyrics_label_frame = tk.Frame(root, width=(1280/3), height=400) 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) 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.Button(frame_artist_song, image=play_img, command=play, borderwidth=0, relief=None) pause_button = ttk.Button(frame_artist_song, image=pause_img, command=pause, borderwidth=0) next_button = ttk.Button(frame_artist_song, image=next_img, command=next, borderwidth=0) previous_button = ttk.Button(frame_artist_song, image=previous_img, command=previous, 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", 32), wraplength=(1280/3), justify=ttk.CENTER) song_label = tk.Label(frame_artist_song, text="", font=("Helvetica", 24), wraplength=(1280/3), justify=ttk.CENTER) 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) 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()) album_art_label.bind("", lambda e:unloadLyrics_pressed()) # 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 try: current_playback = spotify.current_playback() except (spotipy.exceptions.SpotifyException, requests.exceptions.HTTPError): createToken() current_playback = spotify.current_playback() # 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: try: track_name = current_playback["item"]["name"] pass except TypeError: sleep(1000) update_song_label() 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 = ImageTk.PhotoImage(Image.open(BytesIO(album_art_img_data)).resize((300,300))) album_art_label.config(image=album_art_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=1, column=1) song_label.grid(row=2, 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() 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() 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 wait_for_connection() loadNow_playing() update_song_label() # Run the GUI root.mainloop()