我如何将我的 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
我们在这里安装了 3 个依赖项,但只需要express
和dotenv
即可获取令牌。那么如何获取令牌呢?首先,我们需要 和 OAuth2client_id
以及client_secret
。访问此处了解更多信息。
因此,我们在这里所做的就是使用 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(); |
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(); |
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(); |
在这里,我们使用
refresh_token
、client_id
和 来client_secret
获取新的access_token
并获取我们的个人资料信息。作为额外奖励,我还使用了编程引言 API来获取每小时的引言。
第 4 部分:整合
现在我们已经创建了脚本,我们需要让它每小时自动更新一次 README。为此,我们将使用 GitHub 的操作。
在此之前,我们需要将refresh_token
、client_id
和 的client_secret
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 }} |
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 }} |
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 }} |
在这里,我们每小时都会进行一次这样的动作,然后奇迹就发生了 :P
结论
已完成的 README 这是我的第一篇开发文章,请评论我如何改进。另外,别忘了查看我的README。