DEV Community

Cover image for How I added my Spotify statistics to my GitHub readme πŸ“œ
Akshit Garg
Akshit Garg

Posted on

34 11

How I added my Spotify statistics to my GitHub readme πŸ“œ

So there was a new GitHub feature spotted in the wild, where you could have a README on your GitHub profile. So I had an idea, why not build a dynamic README using GitHub actions

GitHub profile README

So what is that GitHub profile README thingy? Its a cool new feature by GitHub which allows you to have a README on your profile. Sounds cool? Surely it is. Time to get creative πŸ˜‹.

How did I include the Spotify stats on my README?

Part 1: Introduction

The Spotify API allows you to fetch a ton of info, including your liked tracks, your saved albums and your playlists. It requires an OAuth2 authentication for the API

Part 2: Getting an OAuth2 token

So to access the Spotify API, you need to have an OAuth2 token. So how do we get one? Well, the answer is really easy. So we will do it in NodeJS, as I am really comfortable with it. So first, we need to install some dependencies. We will use yarn for it, however, npm will work just fine too.

yarn add isomorphic-unfetch express dotenv
Enter fullscreen mode Exit fullscreen mode

We installed 3 dependencies here, but express and dotenv are only required to obtain a token. So how do we obtain it? Firstly, we need and OAuth2 client_id and client_secret. Visit here to learn more.

require("dotenv").config();
require("isomorphic-unfetch");
const express = require("express");
const app = express();
const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const scopes = [
"user-library-read",
"playlist-read-private",
"playlist-read-collaborative",
"user-read-recently-played",
];
console.log("Please visit");
console.log(
"https://accounts.spotify.com/authorize" +
"?response_type=code" +
"&client_id=" +
clientId +
(scopes ? "&scope=" + encodeURIComponent(scopes.join(" ")) : "") +
"&redirect_uri=" +
encodeURIComponent("http://localhost:3000")
);
app.get("/", async (req, res) => {
const { code } = req.query;
if (!code) {
return res.status(401).send("Not Authorized");
}
const data = await (
await fetch(
`https://accounts.spotify.com/api/token?grant_type=authorization_code&code=${encodeURIComponent(
code
)}&redirect_uri=${encodeURIComponent(
"http://localhost:3000"
)}&client_id=${clientId}&client_secret=${clientSecret}`,
{
headers: {
"content-type": "application/x-www-form-urlencoded ",
},
method: "POST",
}
)
).text();
console.log(data);
return res.send("Authorized, please check console");
});
app.listen(3000);
view raw authorize.js hosted with ❀ by GitHub



So what we did here was used the Spotify API to obtain an access_token and a refresh_token. Keep both of them safe, as we need them for later use.

Part 3: The self updating README

So now create a README.template.md with replacement tags like I like {sp_liked} songs accross {sp_abl} albums. I have {sp_pl} playlists of awesome music. Now we need to create an index.js file which does all the magic.

require("isomorphic-unfetch");
const { promises: fs } = require("fs");
const path = require("path");
const clientId = process.env.SPOTIFY_CLIENT_ID;
const clientSecret = process.env.SPOTIFY_CLIENT_SECRET;
const refreshToken = process.env.SPOTIFY_REFRESH_TOKEN;
async function main() {
const readmeTemplate = (
await fs.readFile(path.join(process.cwd(), "./README.template.md"))
).toString("utf-8");
const { en: qoth, author: qoth_author } = await (
await fetch("https://programming-quotes-api.herokuapp.com/quotes/random")
).json();
const { access_token } = await (
await fetch(
`https://accounts.spotify.com/api/token?grant_type=refresh_token&client_id=${clientId}&client_secret=${clientSecret}&refresh_token=${refreshToken}`,
{
headers: {
"content-type": "application/x-www-form-urlencoded ",
},
method: "POST",
}
)
).json();
const { total: sp_liked } = await (
await fetch("https://api.spotify.com/v1/me/tracks", {
headers: {
Authorization: `Bearer ${access_token}`,
},
})
).json();
const { total: sp_abl } = await (
await fetch("https://api.spotify.com/v1/me/albums", {
headers: {
Authorization: `Bearer ${access_token}`,
},
})
).json();
const { total: sp_pl } = await (
await fetch("https://api.spotify.com/v1/me/playlists", {
headers: {
Authorization: `Bearer ${access_token}`,
},
})
).json();
const readme = readmeTemplate
.replace("{qoth}", qoth)
.replace("{qoth_author}", qoth_author)
.replace("{sp_liked}", sp_liked)
.replace("{sp_abl}", sp_abl)
.replace("{sp_pl}", sp_pl);
await fs.writeFile("README.md", readme);
}
main();
view raw index.js hosted with ❀ by GitHub

Here, we use the refresh_token, the client_id and the client_secret to get a new access_token and get our profile information. As a bonus, I also used the Programming Quotes API to get the quote of the hour.

Part 4: Putting it all together

Now we have created the scripts, we need to automate it to update the README every hour. For this, we will use GitHub's actions.
Before that, we need to put out refresh_token, the client_id and the client_secret in out GitHub secrets as we will need them for the action.

name: Generate README every 1 hour
on:
schedule:
- cron: "0 * * * *"
workflow_dispatch:
jobs:
stuff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Let the magic happen
uses: actions/setup-node@v1
with:
node-version: 14.6.0
- run: yarn
- run: node .
env:
SPOTIFY_CLIENT_ID: ${{ secrets.SPOTIFY_CLIENT_ID }}
SPOTIFY_CLIENT_SECRET: ${{ secrets.SPOTIFY_CLIENT_SECRET }}
SPOTIFY_REFRESH_TOKEN: ${{ secrets.SPOTIFY_REFRESH_TOKEN }}
- name: Add to git repo
run: |
git add .
git config --global user.name "Your Name"
git config --global user.email "Your E-Mail"
git commit -m "[Magic] Automated README update"
- name: Push
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
view raw action.yml hosted with ❀ by GitHub

Here, we run the action every hour, and boom, the magic happens :P

Conclusion

The finished README
The finished README
This was my first dev article, please comment on how can I improve them. Also, don't forget to checkout my README.

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (4)

Collapse
 
pavelloz profile image
PaweΕ‚ Kowalski β€’

why

Collapse
 
midasxiv profile image
Midas/XIV β€’

Adding an image of the finished "widget" would be very helpful 😁

Collapse
 
gargakshit profile image
Akshit Garg β€’ β€’ Edited

Thanks for the suggestion Midas :)
Edit: Added

Collapse
 
khan_5055_464959d2cbf7f35 profile image
FredJackson12 β€’

I’ve been using spotipie.com/ for my Spotify stats, and it’s pretty cool. You might find it useful too.

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay