我如何将我的 Spotify 统计数据添加到我的 GitHub readme 中📜

2025-06-08

我如何将我的 Spotify 统计数据添加到我的 GitHub readme 中📜

GitHub 上最近发现了一个新功能,可以在你的 GitHub 个人资料中添加 README 文件。于是我想到,为什么不使用 GitHub Actions 来构建一个动态的 README 文件呢?

GitHub 个人资料自述文件

那么 GitHub 个人资料的 README 是什么呢?这是 GitHub 推出的一个很酷的新功能,允许你在个人资料中添加 README。听起来很酷?确实很酷。是时候发挥创意了😋。

我如何将 Spotify 统计数据包含在我的 README 中?

第 1 部分:简介

Spotify API 允许您获取大量信息,包括您点赞的曲目、保存的专辑和播放列表。该 API 需要 OAuth2 身份验证

第 2 部分:获取 OAuth2 令牌

要访问 Spotify API,您需要一个 OAuth2 令牌。那么我们如何获取呢?答案很简单。我们将使用 NodeJS 来实现,因为我对它非常熟悉。首先,我们需要安装一些依赖项。我们将使用 Yarn 来实现,当然,使用 npm 也同样适用。

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

我们在这里安装了 3 个依赖项,但只需要expressdotenv即可获取令牌。那么如何获取令牌呢?首先,我们需要 和 OAuth2client_id以及client_secret。访问此处了解更多信息。

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
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
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



因此,我们在这里所做的就是使用 Spotify API 获取 anaccess_token和 a refresh_token。请妥善保管它们,因为我们稍后需要它们。

第 3 部分:自我更新的 README

现在创建一个带有替换标签的 README.template.md 文件,例如I like {sp_liked} songs accross {sp_abl} albums. I have {sp_pl} playlists of awesome music。现在我们需要创建一个index.js可以完成所有神奇工作的文件。

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
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
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

在这里,我们使用refresh_tokenclient_id和 来client_secret获取新的access_token并获取我们的个人资料信息。作为额外奖励,我还使用了编程引言 API来获取每小时的引言。

第 4 部分:整合

现在我们已经创建了脚本,我们需要让它每小时自动更新一次 README。为此,我们将使用 GitHub 的操作。
在此之前,我们需要将refresh_tokenclient_id和 的client_secretGitHub 密钥导出,因为后续的操作需要用到它们。

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
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
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

在这里,我们每小时都会进行一次这样的动作,然后奇迹就发生了 :P

结论

已完成的 README 这是我的第一篇开发文章,请评论我如何改进。另外,别忘了查看我的README
完成的 README

鏂囩珷鏉ユ簮锛�https://dev.to/gargakshit/how-i-added-my-spotify-statistics-to-my-github-readme-4jdd
PREV
Python 来自...Go
NEXT
什么是 gRPC?如何在 Node.js 中实现 gRPC