Files
LEDMatrix/src/authenticate_spotify.py
2025-05-23 13:35:43 -05:00

129 lines
5.6 KiB
Python

import spotipy
from spotipy.oauth2 import SpotifyOAuth
import logging
import json
import os
import sys
# Setup basic logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Define paths relative to this file's location (assuming it's in src)
CONFIG_DIR = os.path.join(os.path.dirname(__file__), '..', 'config')
SECRETS_PATH = os.path.join(CONFIG_DIR, 'config_secrets.json')
SPOTIFY_AUTH_CACHE_PATH = os.path.join(CONFIG_DIR, 'spotify_auth.json') # Explicit cache path
# Resolve to absolute paths
CONFIG_DIR = os.path.abspath(CONFIG_DIR)
SECRETS_PATH = os.path.abspath(SECRETS_PATH)
SPOTIFY_AUTH_CACHE_PATH = os.path.abspath(SPOTIFY_AUTH_CACHE_PATH)
SCOPE = "user-read-currently-playing user-read-playback-state"
def load_spotify_credentials():
"""Loads Spotify credentials from config_secrets.json."""
if not os.path.exists(SECRETS_PATH):
logging.error(f"Secrets file not found at {SECRETS_PATH}")
return None, None, None
try:
with open(SECRETS_PATH, 'r') as f:
secrets = json.load(f)
music_secrets = secrets.get("music", {})
client_id = music_secrets.get("SPOTIFY_CLIENT_ID")
client_secret = music_secrets.get("SPOTIFY_CLIENT_SECRET")
redirect_uri = music_secrets.get("SPOTIFY_REDIRECT_URI")
if not all([client_id, client_secret, redirect_uri]):
logging.error("One or more Spotify credentials missing in config_secrets.json under the 'music' key.")
return None, None, None
return client_id, client_secret, redirect_uri
except json.JSONDecodeError:
logging.error(f"Error decoding JSON from {SECRETS_PATH}")
return None, None, None
except Exception as e:
logging.error(f"Error loading Spotify credentials: {e}")
return None, None, None
if __name__ == "__main__":
logging.info("Starting Spotify Authentication Process...")
client_id, client_secret, redirect_uri = load_spotify_credentials()
if not all([client_id, client_secret, redirect_uri]):
logging.error("Could not load Spotify credentials. Please check config/config_secrets.json. Exiting.")
sys.exit(1)
# Ensure the config directory exists for the cache file
if not os.path.exists(CONFIG_DIR):
try:
logging.info(f"Config directory {CONFIG_DIR} not found. Attempting to create it.")
os.makedirs(CONFIG_DIR)
logging.info(f"Successfully created config directory: {CONFIG_DIR}")
except OSError as e:
logging.error(f"Fatal: Could not create config directory {CONFIG_DIR}: {e}. Please create it manually. Exiting.")
sys.exit(1)
sp_oauth = SpotifyOAuth(
client_id=client_id,
client_secret=client_secret,
redirect_uri=redirect_uri,
scope=SCOPE,
cache_path=SPOTIFY_AUTH_CACHE_PATH, # Use explicit cache path
open_browser=False
)
# Step 1: Get the authorization URL
auth_url = sp_oauth.get_authorize_url()
print("-" * 50)
print("SPOTIFY AUTHORIZATION NEEDED:")
print("1. Please visit this URL in a browser (on any device):")
print(f" {auth_url}")
print("2. Authorize the application.")
print("3. You will be redirected to a URL (likely showing an error). Copy that FULL redirected URL.")
print("-" * 50)
# Step 2: Get the redirected URL from the user
redirected_url = input("4. Paste the full redirected URL here and press Enter: ").strip()
if not redirected_url:
logging.error("No redirected URL provided. Exiting.")
sys.exit(1)
# Step 3: Parse the code from the redirected URL
try:
# Spotipy's parse_auth_response_url is not directly part of the public API of SpotifyOAuth
# for this specific flow where we manually handle the redirect.
# We need to extract the 'code' query parameter.
# A more robust way would be to use urllib.parse, but for simplicity:
if "?code=" in redirected_url:
auth_code = redirected_url.split("?code=")[1].split("&")[0]
elif "&code=" in redirected_url: # Should not happen if code is first param
auth_code = redirected_url.split("&code=")[1].split("&")[0]
else:
logging.error("Could not find 'code=' in the redirected URL. Please ensure you copied the full URL.")
logging.error(f"Received URL: {redirected_url}")
sys.exit(1)
except Exception as e:
logging.error(f"Error parsing authorization code from redirected URL: {e}")
logging.error(f"Received URL: {redirected_url}")
sys.exit(1)
# Step 4: Get the access token using the code and cache it
try:
# check_cache=False forces it to use the provided code rather than a potentially stale cached one for this specific step.
# The token will still be written to the cache_path.
token_info = sp_oauth.get_access_token(auth_code, check_cache=False)
if token_info:
logging.info(f"Spotify authentication successful. Token info cached at {SPOTIFY_AUTH_CACHE_PATH}")
else:
logging.error("Failed to obtain Spotify token info with the provided code.")
logging.error("Please ensure the code was correct and not expired.")
sys.exit(1)
except Exception as e:
logging.error(f"Error obtaining Spotify access token: {e}")
logging.error("This can happen if the authorization code is incorrect, expired, or already used.")
sys.exit(1)
logging.info("Spotify Authentication Process Finished.")