Skip to content

Instantly share code, notes, and snippets.

@jabedzaman
Last active June 16, 2024 22:37
Show Gist options
  • Save jabedzaman/9df165ab6a2f22ff3bf1a1d6bc9f2d1b to your computer and use it in GitHub Desktop.
Save jabedzaman/9df165ab6a2f22ff3bf1a1d6bc9f2d1b to your computer and use it in GitHub Desktop.
Fetch currently playing song on Spotify
// pages/api/spotify.
import querystring from 'querystring';
const {
NEXT_PUBLIC_SPOTIFY_CLIENT_ID: client_id,
NEXT_PUBLIC_SPOTIFY_CLIENT_SECRET: client_secret,
NEXT_PUBLIC_SPOTIFY_REFRESH_TOKEN: refresh_token,
} = process.env;
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`;
const getAccessToken = async () => {
const response = await fetch(TOKEN_ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Basic ${basic}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: querystring.stringify({
grant_type: 'refresh_token',
refresh_token,
}),
});
return response.json();
};
export const getNowPlaying = async () => {
const { access_token } = await getAccessToken();
return fetch(NOW_PLAYING_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
};
export default async (_, res) => {
const response = await getNowPlaying();
if (response.status === 204 || response.status > 400) {
return res.status(200).json({ isPlaying: false });
}
const song = await response.json();
const isPlaying = song.is_playing;
const title = song.item.name;
const artist = song.item.artists.map((_artist) => _artist.name).join(', ');
const album = song.item.album.name;
const albumImageUrl = song.item.album.images[0].url;
const songUrl = song.item.external_urls.spotify;
return res.status(200).json({
album,
albumImageUrl,
artist,
isPlaying,
songUrl,
title,
});
};
import { useEffect } from "react";
import { animate } from "motion";
import useSWR from "swr";
function AnimatedBars() {
useEffect(() => {
animate(
"#bar1",
{
transform: [
"scaleY(1.0) translateY(0rem)",
"scaleY(1.5) translateY(-0.082rem)",
"scaleY(1.0) translateY(0rem)",
],
},
{
duration: 1.0,
repeat: Infinity,
easing: ["ease-in-out"],
}
);
animate(
"#bar2",
{
transform: [
"scaleY(1.0) translateY(0rem)",
"scaleY(3) translateY(-0.083rem)",
"scaleY(1.0) translateY(0rem)",
],
},
{
delay: 0.2,
duration: 1.5,
repeat: Infinity,
easing: ["ease-in-out"],
}
);
animate(
"#bar3",
{
transform: [
"scaleY(1.0) translateY(0rem)",
"scaleY(0.5) translateY(0.37rem)",
"scaleY(1.0) translateY(0rem)",
],
},
{
delay: 0.3,
duration: 1.5,
repeat: Infinity,
easing: ["ease-in-out"],
}
);
}, []);
return (
<div className="w-auto flex items-end overflow-hidden">
<span
id="bar1"
className="w-1 mr-[3px] h-2 bg-gray-300 dark:bg-gray-500 opacity-75"
/>
<span
id="bar2"
className="w-1 mr-[3px] h-1 bg-gray-300 dark:bg-gray-500"
/>
<span
id="bar3"
className="w-1 h-3 bg-gray-300 dark:bg-gray-500 opacity-80"
/>
</div>
);
}
export default function Spotify() {
const fetcher = (url) => fetch(url).then((r) => r.json());
const { data } = useSWR("../api/spotify", fetcher);
return (
<section className="max-w-4xl mx-auto p-5">
<div className="flex flex-row-reverse items-center sm:flex-row mb-8 space-x-0 sm:space-x-2 w-full">
{data?.isPlaying ? (
<AnimatedBars />
) : (
<svg className="h-4 w-4 ml-auto mt-[-2px]" viewBox="0 0 168 168">
<path
fill="#1ED760"
d="M83.996.277C37.747.277.253 37.77.253 84.019c0 46.251 37.494 83.741 83.743 83.741 46.254 0 83.744-37.49 83.744-83.741 0-46.246-37.49-83.738-83.745-83.738l.001-.004zm38.404 120.78a5.217 5.217 0 01-7.18 1.73c-19.662-12.01-44.414-14.73-73.564-8.07a5.222 5.222 0 01-6.249-3.93 5.213 5.213 0 013.926-6.25c31.9-7.291 59.263-4.15 81.337 9.34 2.46 1.51 3.24 4.72 1.73 7.18zm10.25-22.805c-1.89 3.075-5.91 4.045-8.98 2.155-22.51-13.839-56.823-17.846-83.448-9.764-3.453 1.043-7.1-.903-8.148-4.35a6.538 6.538 0 014.354-8.143c30.413-9.228 68.222-4.758 94.072 11.127 3.07 1.89 4.04 5.91 2.15 8.976v-.001zm.88-23.744c-26.99-16.031-71.52-17.505-97.289-9.684-4.138 1.255-8.514-1.081-9.768-5.219a7.835 7.835 0 015.221-9.771c29.581-8.98 78.756-7.245 109.83 11.202a7.823 7.823 0 012.74 10.733c-2.2 3.722-7.02 4.949-10.73 2.739z"
/>
</svg>
)}
<div className="inline-flex flex-col sm:flex-row w-full max-w-full truncate">
{data?.isPlaying ? (
<a
className="capsize text-gray-800 dark:text-gray-200 font-medium max-w-max truncate"
href={data.songUrl}
target="_blank"
rel="noopener noreferrer"
>
{data.title}
</a>
) : (
<p className="capsize text-gray-800 dark:text-gray-200 font-medium">
Not Playing
</p>
)}
<span className="capsize mx-2 text-gray-500 dark:text-gray-300 hidden sm:block">
{" – "}
</span>
{data?.isPlaying ? (
<p className="capsize text-gray-500 dark:text-gray-300 max-w-max truncate">
{data?.artist ?? "Spotify"}
</p>
) : (
<p className="capsize text-gray-500 dark:text-gray-300 max-w-max truncate">Is sleeping 🛌</p>
)}
</div>
</div>
</section>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment