大家好,我是大帅,一个老程序猿。
前言
最近B站刚刚颁布了2021年的百大UP,要说我最喜欢的UP,那必然是 @老师好我叫何同学。何同学的每一个视频都让我感觉很惊艳,那么的有创意。
何同学也是一个极其注重细节的人,不知道大家有没有关注到何同学B站个人空间的头图,右边显示的数字其是何同学上次投稿距今的时间,每天都会变哦。
image.png
果真是个细节狂魔~
我并不知道何同学具体是如何实现的,但作为一个热爱编程的老程序猿,思路很快就在我脑海里浮现出来了。经过一天疯狂的敲代码,我已经完全实现了和何同学一样的效果,无需服务器无需打开电脑,每天会自动更新。代码已在github开源,如果你只是想使用它,不想知道技术细节,请直接跳到最后看使用教学。
本文会会手把手教你一步步去实现它,如果你想跟我一起用编程玩转创意,那么请点赞收藏分享支持一下吧。
手把手实现它
好的,接下来你会学习到
- 如何抓取B站的请求
- 在nodejs里生成图片
- 获得用户最新的投稿计算日子
- github action定时任务
如何抓取B站的请求
自动的前提是手动,所以我们要先了解自己要如何操作才可以更换个人空间头图(此功能需要B站的大会员),打开B站你的个人空间,点击头图右上角的这个区域更换皮肤
在网页底部会弹出更换头图的操作面板,上传任意图片作为头图的功能只有大会员才有。
我们按下F12
打开调试面板,切换到network
标签,此时我们上传一张图片,就可以抓取到这个上传头图的接口了
https://space.bilibili.com/ajax/topphoto/uploadTopPhotov2
点击鼠标右键,选择Copy -> Copy as Node.js fetch
打开VSCode
粘贴
fetch("https://space.bilibili.com/ajax/topphoto/uploadTopPhotov2", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"content-type": "application/x-www-form-urlencoded",
"sec-ch-ua": "" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": ""macOS"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"cookie": "",
"Referer": "https://space.bilibili.com/422646817",
"Referrer-Policy": "no-referrer-when-downgrade"
},
"body": "topphoto=xxxxxx&csrf=xxxxxx",
"method": "POST"
});
然后我们新建一个nodejs的项目,安装一下node-fetch
库
//如果你的环境支持ESModule,那么使用import
import fetch from 'node-fetch';
//如果是用require导入
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
现在你已经可以把刚才的上传图片的操作通过代码完成了,那么这一堆参数里,我们需要注意哪些呢?
- cookie
用户身份校验的参数,我们主要会用到
bili_jct
,SESSDATA
,DedeUserID
,DedeUserID__ckMd5
- body
topphoto为图片base64编码的数据,
csrf
就是bili_jct
如果是自己用,那么你只需要生成图片并转为base64编码后通过topphoto
参数提交给B站接口就可以了
在nodejs里生成图片
在网页里生成图片大概率你知道要用canvas,在node环境里生成图片,也有一个canvas的库可以用
代码语言:javascript复制npm install canvas
这个库在不同的系统下还需要安装不同的底层绘制库。
代码语言:javascript复制# MacOS X
`brew install pkg-config cairo pango libpng jpeg giflib librsvg`
# Linux
`sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev`
因为我很少用windows,所以windows的小伙伴自己去看官方介绍把,https://github.com/Automattic/node-canvas
使用这个库绘图的API设计和网页canvas基本相同。
代码语言:javascript复制//导入canvas库里的三个方法
const { createCanvas, loadImage ,registerFont } = require('canvas');
//B站头图的建议尺寸是2560x400
const canvasSize = {w:2560,h:400};
//创建画布
const canvas = createCanvas(canvasSize.w, canvasSize.h);
//获得画布的绘制对象
const ctx = canvas.getContext('2d');
async function painting(){
//添加背景图
const bgImage = await loadImage('bg.jpg');
//将图片绘制到画布的0,0坐标,并设置宽和高
ctx.drawImage(bgImage, 0, 0, canvasSize.w, canvasSize.h);
}
painting();
有了背景图,现在我们加入文字
代码语言:javascript复制//注册字体
registerFont('digit.ttf', { family: 'digit' });
//设置文字颜色和字号,字体
ctx.fillStyle = "#e6433a";
ctx.font = '97px digit';
let txt = "HELLO"
//计算文字尺寸
let size = ctx.measureText(txt);
//将文字绘制到指定坐标
ctx.fillText(txt, 0, 0);
image.png
何同学头图里的文字是有垂直方向上的倾斜的,这个在canvas
中也可以实现
//设置接下来倾斜的原点为文字的左上角
ctx.translate(txt_x, txt_y);
/*
transform(a,b,c,d,e,f)
a 水平缩放绘图
b 水平倾斜绘图
c 垂直倾斜绘图
d 垂直缩放绘图
e 水平移动绘图
f 垂直移动绘图
*/
ctx.transform(1,-0.3,0,1,0,0);
transform
倾斜的算法稍微有点复杂,以后再单独出教程教大家,想学习的朋友记得点个关注不迷路哦~
接下来使用canvas.toDataURL("image/png")
就可以将画布转换为base64
编码的数据了,这里需要注意一下,B站头图接口中的topphoto
参数是不需要前面22个字符的图片头信息,所以我们还要截取一下
canvas.toDataURL("image/png").substring(22);
当然,你现在并不能确定咱们生成的图片是否正确,所以你也可以将图片保存成本地文件先看看是不是对了
代码语言:javascript复制fs.writeFileSync("test.png",canvas.toBuffer());
获得用户最新的投稿计算日子
通过接口https://api.bilibili.com/x/space/arc/search
可以抓取指定用户的投稿视频
//pn为页数,ps为每页条数,order=pubdate代表按发布时间返回数据
fetch("https://api.bilibili.com/x/space/arc/search?mid=" DEDEUSERID "&pn=1&ps=1&order=pubdate&jsonp=jsonp");
在每条视频的信息里,created
属性代表了发布时间(单位:秒),我们需要计算一下这个时间和当前系统的时间差并转换为天为单位
//计算两个日期相差的天数
const diffDays = (date, otherDate) => Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));
这里推荐给大家一个网站,里面收录了各种用一行代码实现的功能 https://1loc.dev/
Github Action定时任务
Github Action是Github提供的虚拟容器服务,通俗点说就是免费给你一台云服务器,这个云服务器的系统是什么,具备哪些代码运行环境都可以根据配置自定义。我们只能通过github的工作流workflow
来使用它,有趣的是,我们还可以给它设置定时任务,定期运行我们的工作流,执行我们写好的代码,生成图片上传一气呵成!完全免费哦!
打开终端/命令行,在git项目目录下新建目录并创建schedule.yml配置文件
mkdir .github
mkdir .github/workflows
touch .github/workflows/schedule.yml
schedule.yml
配置
# 这个工作流的名称
name: CI
# 工作流什么时候可以运行
on:
# Schedule就是定时任务,由于服务在国外,所以时间需要减去8小时才是北京时间
schedule:
- cron: '0 16 * * *'
# 也允许这个工作流在github aciton面板中手动触发
workflow_dispatch:
# 工作流内有哪些任务
jobs:
# 此工作流包含一个任务名为build
build:
# 安装最新的ubuntu系统
runs-on: ubuntu-latest
# 此任务重包含的子任务/步骤
steps:
# 拉取最新的代码
- uses: actions/checkout@v2
# 安装好Nodejs的运行环境
- name: Setup Node.js environment
uses: actions/setup-node@v2.4.0
# 安装好node canvas必备的系统绘图库
- name: Setup Basically Packages
run:
sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
# 安装好我们自己项目的依赖包
- name: Install NPM dependencies
run:
npm install
# 执行我们自己的代码
- name: Run
run:
node index.js "${{secrets.BILI_JCT}}" "${{secrets.SESSDATA}}" "${{secrets.DEDEUSERID}}" "${{secrets.DEDEUSERID__CKMD5}}"
配置这样就结束了,在北京时间每天的零点(美国时间16点
)就会自动生成B站头图并上传啦。
配置中的
secrets.xxx
是我们代码运行时携带的参数,为了让大家更方便的fork此开源仓库,所以我将四个B站用户身份所对应的参数设置成了可自定义的。这种secrets
的参数在接受自定义的同时还能保护其在Github
不被泄露。
使用本项目
如果你只是想要用使用本仓库实现一样的效果,是非常简单的,因为我都封装好了,拿来即用
代码语言:javascript复制温馨提示:只有B站大会员可以自定义头图
https://github.com/ezshine/auto-bilibili-topphoto
步骤1:
fork本仓库
步骤2:
用Chrome浏览器打开B站,进入自己的个人空间,按下F12,切换到application
标签
在Cookie中找到这四个参数,然后打开自己分支仓库,点击Settings
,进入Secrets
,点击New repository secret
将四个参数一一配置好
步骤3:
手动执行一次工作流,以后就可以自动定时运行了!
恭喜,你已经拥有了和何同学一样有趣的B站个人空间头图哦