From 880483d44864ebc17dfb3a908eead1e985ae0bdb Mon Sep 17 00:00:00 2001 From: ssbg04 Date: Tue, 7 Jul 2026 21:53:05 +0800 Subject: [PATCH] feat: align Spotify widget with centered content and clean diagnostic code --- scripts/get-refresh-token.js | 50 +++++++++++++++++++++ src/components/SpotifyWidget.tsx | 20 +++++---- src/pages/api/now-playing.ts | 75 ++++++++++++-------------------- 3 files changed, 89 insertions(+), 56 deletions(-) create mode 100644 scripts/get-refresh-token.js diff --git a/scripts/get-refresh-token.js b/scripts/get-refresh-token.js new file mode 100644 index 0000000..f4d4b24 --- /dev/null +++ b/scripts/get-refresh-token.js @@ -0,0 +1,50 @@ +const client_id = "ee972078e4f747f59dce341b0a493986"; +const client_secret = "c068836397cb4b22840ae4e6249aa3d0"; +const redirect_uri = "https://sisibigi.vercel.app/callback"; + +const code = process.argv[2]; + +if (!code) { + console.error("\x1b[31mError: Please provide your Spotify authorization code as an argument.\x1b[0m"); + console.log("\nUsage:\n node scripts/get-refresh-token.js "); + console.log("\nTo get a fresh code, visit:\n https://accounts.spotify.com/authorize?client_id=ee972078e4f747f59dce341b0a493986&response_type=code&redirect_uri=https://sisibigi.vercel.app/callback&scope=user-read-currently-playing%20user-read-playback-state\n"); + process.exit(1); +} + +const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64'); +const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`; + +console.log("Trading authorization code for Spotify tokens..."); + +fetch(TOKEN_ENDPOINT, { + method: 'POST', + headers: { + Authorization: `Basic ${basic}`, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + code: code.trim(), + redirect_uri, + }), +}) + .then(async (response) => { + const text = await response.text(); + if (!response.ok) { + console.error(`\x1b[31mSpotify Token Exchange Failed (${response.status}):\x1b[0m`, text); + process.exit(1); + } + const data = JSON.parse(text); + console.log("\n\x1b[32m✔ Success! Here are your tokens:\x1b[0m"); + console.log("\n----------------------------------------"); + console.log(`\x1b[36mAccess Token (Expires in 1 hour):\x1b[0m\n${data.access_token}\n`); + console.log(`\x1b[36mRefresh Token (Save this!):\x1b[0m\n${data.refresh_token}`); + console.log("----------------------------------------"); + console.log("\n\x1b[33mInstructions:\x1b[0m"); + console.log("1. Copy the Refresh Token (starts with AQ... or different)."); + console.log("2. Paste it into your .env file as: SPOTIFY_REFRESH_TOKEN=..."); + console.log("3. Add it to your Vercel Project environment variables and trigger a redeploy.\n"); + }) + .catch((err) => { + console.error("\x1b[31mRequest Error:\x1b[0m", err); + }); diff --git a/src/components/SpotifyWidget.tsx b/src/components/SpotifyWidget.tsx index 463f53f..d6cdeb4 100644 --- a/src/components/SpotifyWidget.tsx +++ b/src/components/SpotifyWidget.tsx @@ -99,14 +99,16 @@ export default function SpotifyWidget() { }, [isPlaying, isApiActive]); return ( - setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - initial={{ opacity: 0, y: -20 }} - animate={{ opacity: 1, y: 0 }} - transition={{ type: "spring", stiffness: 260, damping: 25, delay: 0.8 }} - > +
+
+ setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + initial={{ opacity: 0, y: -20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ type: "spring", stiffness: 260, damping: 25, delay: 0.8 }} + > +
+
); } diff --git a/src/pages/api/now-playing.ts b/src/pages/api/now-playing.ts index 3294b9c..dcbfc43 100644 --- a/src/pages/api/now-playing.ts +++ b/src/pages/api/now-playing.ts @@ -5,15 +5,6 @@ const client_id = import.meta.env.SPOTIFY_CLIENT_ID || process.env.SPOTIFY_CLIEN const client_secret = import.meta.env.SPOTIFY_CLIENT_SECRET || process.env.SPOTIFY_CLIENT_SECRET || ''; const refresh_token = import.meta.env.SPOTIFY_REFRESH_TOKEN || process.env.SPOTIFY_REFRESH_TOKEN || ''; -console.log('Spotify Config Diagnostic:', { - clientIdPresent: !!client_id, - clientIdLength: client_id.length, - clientSecretPresent: !!client_secret, - clientSecretLength: client_secret.length, - refreshTokenPresent: !!refresh_token, - refreshTokenLength: refresh_token.length, -}); - const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64'); const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`; const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`; @@ -21,56 +12,44 @@ const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`; // Helper to retrieve a fresh Spotify access token using the refresh token async function getAccessToken() { if (!client_id || !client_secret || !refresh_token) { - throw new Error('Spotify API keys are missing in env.'); + console.error('Spotify API keys are missing in env.'); + return null; } - const response = await fetch(TOKEN_ENDPOINT, { - method: 'POST', - headers: { - Authorization: `Basic ${basic}`, - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams({ - grant_type: 'refresh_token', - refresh_token, - }), - }); + try { + const response = await fetch(TOKEN_ENDPOINT, { + method: 'POST', + headers: { + Authorization: `Basic ${basic}`, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token, + }), + }); - if (!response.ok) { - const errText = await response.text(); - throw new Error(`Spotify token error: ${response.status} - ${errText}`); + if (!response.ok) { + const errText = await response.text(); + console.error('Failed to fetch Spotify access token:', response.status, errText); + return null; + } + + const data = await response.json(); + return data.access_token; + } catch (error) { + console.error('Error fetching Spotify access token:', error); + return null; } - - const data = await response.json(); - return data.access_token; } // Server-side GET API handler export const GET: APIRoute = async () => { - let token = null; - let tokenError = null; - - try { - token = await getAccessToken(); - } catch (error: any) { - tokenError = error.message || String(error); - } + const token = await getAccessToken(); if (!token) { return new Response( - JSON.stringify({ - isPlaying: false, - message: 'Spotify integration not configured or credentials missing.', - debug: { - clientIdPresent: !!client_id, - clientIdLength: client_id.length, - clientSecretPresent: !!client_secret, - clientSecretLength: client_secret.length, - refreshTokenPresent: !!refresh_token, - refreshTokenLength: refresh_token.length, - tokenError - } - }), + JSON.stringify({ isPlaying: false, message: 'Spotify integration not configured or credentials missing.' }), { status: 200, headers: {