// Spotify Web API actions function generateCodeVerifier(length = 128) { const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; let code_verifier = ''; for (let i = 0; i < length; i++) { code_verifier += possible.charAt(Math.floor(Math.random() * possible.length)); } return code_verifier; } async function generateCodeChallenge(code_verifier) { const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(code_verifier)); return btoa(String.fromCharCode(...new Uint8Array(digest))) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } const client_id = '5ed07e2a23384be495efff4d463aba54'; const redirect_uri = window.location.origin + window.location.pathname; const scope = 'user-read-private user-read-email user-read-playback-state user-read-currently-playing'; export function loginWithSpotify() { const code_verifier = generateCodeVerifier(); localStorage.setItem('code_verifier', code_verifier); generateCodeChallenge(code_verifier).then(code_challenge => { const params = new URLSearchParams({ response_type: 'code', client_id, scope, redirect_uri, code_challenge_method: 'S256', code_challenge }); window.location = 'https://accounts.spotify.com/authorize?' + params.toString(); }); } export async function handleRedirect() { const params = new URLSearchParams(window.location.search); const code = params.get('code'); if (!code) return null; const code_verifier = localStorage.getItem('code_verifier'); const body = new URLSearchParams({ client_id, grant_type: 'authorization_code', code, redirect_uri, code_verifier }); const response = await fetch('https://accounts.spotify.com/api/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body }); const data = await response.json(); if (data.access_token) { window.history.replaceState({}, document.title, window.location.pathname); localStorage.removeItem('code_verifier'); localStorage.setItem('access_token', data.access_token); return data.access_token; } else { document.getElementById('error-msg').textContent = 'Error: ' + JSON.stringify(data, null, 2); return null; } } // --- Profile and Current Track --- export async function getProfile(access_token) { const res = await fetch('https://api.spotify.com/v1/me', { headers: { Authorization: 'Bearer ' + access_token } }); if (!res.ok) return null; return await res.json(); } export async function getCurrentTrack(access_token) { const res = await fetch('https://api.spotify.com/v1/me/player/currently-playing', { headers: { Authorization: 'Bearer ' + access_token } }); if (res.status === 204 || !res.ok) return null; return await res.json(); } async function playerCommand(access_token, endpoint, method='POST') { const response = await fetch(`https://api.spotify.com/v1/me/player/${endpoint}`, { method, headers: { Authorization: 'Bearer ' + access_token } }); if (!response.ok) { const text = await response.text(); document.getElementById('data').innerText = `Spotify API Error (${endpoint}): ${response.status} ${text}`; console.error(`Spotify API Error (${endpoint}):`, response.status, text); } }