Showing my listening activity
Spotify icon can be found in my Figma Community file (as well as a bunch of other icons)
TLDR: Grab your music and podcast info from Spotify using Next.js
- Lee Robinson's Spotify & Next.js tutorial π
 - View this site's GitHub Repo to see how I did it π¨βπ»
 - View what I designed/built π
 
Sticking to this site's ethos - designing in the open - I thought I could share a few new things that I've been finding a ton of fun.
Either while I'm driving, walking, sitting at my desk, or falling asleep, I'm regularly listening to a song or podcast via Spotify. Using their Web API, you're able to access:
- Music (playlists, artists, songs, albums, etc.)
 - Podcasts (episodes, shows)
 - User metrics (currently listening, top listens)
 - ...and probably a ton more
 
How to build
After a quick search, I came across Lee Robinson's Spotify & Next.js tutorial. Using the Spotify Web API and Next.js v10+, I threw together a way to grab my own Spotify data and pull it into this site.
Lee's tutorial is incredibly helpful in getting Spotify setup to show your own "Top Tracks", but I also wanted to have a way to show:
- if I'm currently listening to something
 - if I'm my currently playing item is a podcast or song
 - my last played song
 - my recently subscribed podcasts
 
I also wanted to design this in a way that was compact and not overly informative. Let's start with a component that let's me see if I'm currently listening to something, and whether that item is a song or podcast. We'll need 2 endpoints for this:
// spotify.js
const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`;const NOW_PLAYING_PODCAST_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing/?additional_types=episode`;
If you've followed Lee's tutorial and completed the token & auth setup, we just have to add 2 more functions in order to fetch these endpoints:
// spotify.js
export const getNowPlaying = async () => {  const { access_token } = await getAccessToken();
  return fetch(NOW_PLAYING_ENDPOINT, {    headers: {      Authorization: `Bearer ${access_token}`    }  });};
export const getPodcastPlaying = async () => {  const { access_token } = await getAccessToken();
  return fetch(NOW_PLAYING_PODCAST_ENDPOINT, {    headers: {      Authorization: `Bearer ${access_token}`,    }  });};
After that, we just need two routes to grab's playing. I kept the song and podcast routes separate in case I need them later. Using the route for grabbing the currently playing song as an example, we can import one of our new functions to grab the response from Spotify:
// /api/spotify/now-playing.js
import { getNowPlaying } from '@utils/spotify';
export default async (_, res) => {  const response = await getNowPlaying();
  if (response.status === 204 || response.status > 400 || response.status === 500) {    return res.status(200).json({ isPlaying: false, playing: null });  }
  const song = await response.json();
  if(song.context === null) {    return res.status(200).json({ isPlaying: false, playing: 'podcast' });  }
  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;
  res.setHeader(    'Cache-Control',    'public, s-maxage=60, stale-while-revalidate=30'  );
  return res.status(200).json({    album,    albumImageUrl,    artist,    isPlaying,    songUrl,    title    });};
We would repeat the same function for the currently playing podcast - making slight changes in the object we send back and the endpoint function we're referencing. The above function accounts for 3 scenarios:
- If a song is playing
 - If a song isn't playing, but a podcast is playing
 - If neither a song nor podcast is playing
 
Let's see how we can design a single component to account for all 3 of these states:

This component can account for each of the scenarios our API response may give us - helping us only surface the correct information in a way that is a bit more seamless to the user.
What's next?

I've been having some fun grabbing my recent top tracks and my recent podcast subscriptions - check it out! If you have feedback or ideas of what else could be a fun way to make this information more transparent and tangible, I'd love to know - let me know using the form below.

