determines if new bg color is "dark" or "bright" text and buttons invert color when bg color is too bright
465 lines
19 KiB
Python
465 lines
19 KiB
Python
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
|
|
import math
|
|
|
|
# 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()
|
|
|
|
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.Button(frame_artist_song, image=play_img, command=play, borderwidth=0, relief=None, background=bg_color)
|
|
pause_button = ttk.Button(frame_artist_song, image=pause_img, command=pause, borderwidth=0, background=bg_color)
|
|
next_button = ttk.Button(frame_artist_song, image=next_img, command=next, borderwidth=0, background=bg_color)
|
|
previous_button = ttk.Button(frame_artist_song, image=previous_img, command=previous, borderwidth=0, background=bg_color)
|
|
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, background=bg_color)
|
|
song_label = tk.Label(frame_artist_song, text="", font=("Helvetica", 24), 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("<Return>", search)
|
|
lyrics_label.bind("<Button-1>", lambda e:unloadLyrics_pressed())
|
|
album_art_label.bind("<Button-1>", 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_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)) > 186:
|
|
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=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() |