mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
132 lines
5.3 KiB
Python
132 lines
5.3 KiB
Python
import spotipy
|
|
from spotipy.oauth2 import SpotifyOAuth
|
|
import logging
|
|
import json
|
|
import os
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
# Define paths relative to this file's location
|
|
CONFIG_DIR = os.path.join(os.path.dirname(__file__), '..', 'config')
|
|
SECRETS_PATH = os.path.join(CONFIG_DIR, 'config_secrets.json')
|
|
|
|
class SpotifyClient:
|
|
def __init__(self):
|
|
self.client_id = None
|
|
self.client_secret = None
|
|
self.redirect_uri = None
|
|
self.scope = "user-read-currently-playing user-read-playback-state"
|
|
self.sp = None
|
|
self.load_credentials()
|
|
if self.client_id and self.client_secret and self.redirect_uri:
|
|
self._authenticate()
|
|
else:
|
|
logging.warning("Spotify credentials not loaded. Cannot authenticate.")
|
|
|
|
|
|
def load_credentials(self):
|
|
if not os.path.exists(SECRETS_PATH):
|
|
logging.error(f"Secrets file not found at {SECRETS_PATH}")
|
|
return
|
|
|
|
try:
|
|
with open(SECRETS_PATH, 'r') as f:
|
|
secrets = json.load(f)
|
|
music_secrets = secrets.get("music", {})
|
|
self.client_id = music_secrets.get("SPOTIFY_CLIENT_ID")
|
|
self.client_secret = music_secrets.get("SPOTIFY_CLIENT_SECRET")
|
|
self.redirect_uri = music_secrets.get("SPOTIFY_REDIRECT_URI")
|
|
if not all([self.client_id, self.client_secret, self.redirect_uri]):
|
|
logging.warning("One or more Spotify credentials missing in config_secrets.json under the 'music' key.")
|
|
except json.JSONDecodeError:
|
|
logging.error(f"Error decoding JSON from {SECRETS_PATH}")
|
|
except Exception as e:
|
|
logging.error(f"Error loading Spotify credentials: {e}")
|
|
|
|
def _authenticate(self):
|
|
"""Handles the OAuth authentication flow."""
|
|
try:
|
|
# Spotipy handles token caching in .cache file by default
|
|
self.sp = spotipy.Spotify(auth_manager=SpotifyOAuth(
|
|
client_id=self.client_id,
|
|
client_secret=self.client_secret,
|
|
redirect_uri=self.redirect_uri,
|
|
scope=self.scope,
|
|
open_browser=False # Important for headless environments
|
|
))
|
|
# Try making a call to ensure authentication is working or trigger refresh
|
|
self.sp.current_user()
|
|
logging.info("Spotify authenticated successfully.")
|
|
except Exception as e:
|
|
logging.error(f"Spotify authentication failed: {e}")
|
|
self.sp = None # Ensure sp is None if auth fails
|
|
|
|
def is_authenticated(self):
|
|
"""Checks if the client is authenticated."""
|
|
# Check if sp object exists and try a lightweight API call
|
|
if not self.sp:
|
|
return False
|
|
try:
|
|
# A simple call to verify token validity
|
|
self.sp.current_user()
|
|
return True
|
|
except Exception as e:
|
|
# Log specific auth errors if needed
|
|
logging.warning(f"Spotify token validation failed: {e}")
|
|
return False
|
|
|
|
def get_auth_url(self):
|
|
"""Gets the authorization URL for the user."""
|
|
# Create a temporary auth manager just to get the URL
|
|
try:
|
|
auth_manager = SpotifyOAuth(
|
|
client_id=self.client_id,
|
|
client_secret=self.client_secret,
|
|
redirect_uri=self.redirect_uri,
|
|
scope=self.scope,
|
|
open_browser=False
|
|
)
|
|
return auth_manager.get_authorize_url()
|
|
except Exception as e:
|
|
logging.error(f"Could not get Spotify auth URL: {e}")
|
|
return None
|
|
|
|
def get_current_track(self):
|
|
"""Fetches the currently playing track from Spotify."""
|
|
if not self.is_authenticated():
|
|
logging.warning("Spotify not authenticated. Cannot fetch track.")
|
|
# Maybe try re-authenticating?
|
|
self._authenticate()
|
|
if not self.is_authenticated():
|
|
return None
|
|
|
|
try:
|
|
track_info = self.sp.current_playback()
|
|
if track_info and track_info['item']:
|
|
# Simplify structure slightly if needed, or return raw
|
|
return track_info
|
|
else:
|
|
return None # Nothing playing or unavailable
|
|
except Exception as e:
|
|
logging.error(f"Error fetching current track from Spotify: {e}")
|
|
# Check for specific errors like token expiration if spotipy doesn't handle it
|
|
if "expired" in str(e).lower():
|
|
logging.info("Spotify token might be expired, attempting refresh...")
|
|
self._authenticate() # Try to refresh/re-authenticate
|
|
return None
|
|
|
|
# Example Usage (for testing)
|
|
# if __name__ == '__main__':
|
|
# client = SpotifyClient()
|
|
# if client.is_authenticated():
|
|
# track = client.get_current_track()
|
|
# if track:
|
|
# print(json.dumps(track, indent=2))
|
|
# else:
|
|
# print("No track currently playing or error fetching.")
|
|
# else:
|
|
# auth_url = client.get_auth_url()
|
|
# if auth_url:
|
|
# print(f"Please authorize here: {auth_url}")
|
|
# else:
|
|
# print("Could not authenticate or get auth URL. Check credentials and config.") |