我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!
前言
本文灵感来源于好朋友大帅的文章《用JS复原和同学头图创意》。大家如果用过B站,就会知道B站个人主页会有一张“头图”,一般情况下,大家的头图是一样的,但如果你有大会员会多一个头图自定义功能彰显个性。
我看到后第一个想法就是希望跟关注者们能有个互动,表达宠粉狂魔的感觉,没有什么比直接把他们可爱的头像装进去更合适了!大家可以点击村长的B站空间查看最终效果。
有不少小伙伴说没有看到自己,这是由于头图空间有限,以及B站1000条数据的限制,我只在这里显示最新关注的240个粉丝,且每天0点才能定时更新。所以如果你今天关注,明天就可能看到自己。最先关注我的十年老粉们如果降序排也是可以出现的,中间的小伙伴们就暂时不行啦😢
整体步骤
下面大家可以跟我一起来看看如何实现这个创意。 我们整体需要以下几步:
- 获取B站接口所需令牌
- 获取B站粉丝数据
- 使用
Canvas
绘制头图 - 请求B站接口设置头图
- 使用
GithubAction
定时更新
你也可以看配套视频操作:
获取B站接口所需令牌
请求B站的接口需要提供当前用户身份信息,我们可以访问B站个人空间
,通过Chrome浏览器开发者工具
找到它们:
开发者工具 -> Application -> Cookies -> https://space.bilibili.com
所需信息分别是:DedeUserID
、blili_jct
、SESSDATA
、DedeUserID__ckMd5
把它们存下来,后面我们请求B站接口时候需要提供。
如何获取粉丝数据
探索
还有个问题是如何获取粉丝数据,我发现点击用户中心粉丝数
可以查看自己粉丝情况
注意看这里有个分页获取粉丝数据的接口followers
看一下弹出的详情:https://api.bilibili.com/x/relation/followers
,注意vmid、pn、ps等参数。
但是竟然是个jsonp
请求,能不能直接请求呢?去掉jsonp
后面的部分,在浏览器里面发一个试试:
ok啦!数据的问题解决了!注意face
就是我们想要的用户头像信息。
这里有滥用用户信息的嫌疑,有可能被罚80亿🐶,如果有需要,小伙伴们通知我,我会删除这些图片
下面就是通过接口请求所需的数据,我们需要提供DEDEUSERID
,以及分页和排序参数,url大致如下:
const url = "http://api.bilibili.com/x/relation/followers?" +
"vmid=" + DEDEUSERID + "&order=desc&order_type=attention";
这里需要注意,使用ajax请求会受到限制,单页最多50条数据,最多访问20页数据,也就是我们最多可以获得1000个粉丝数据。我这里通过关注时间降序排序可以获得最新关注的用户信息,有点喜新厌旧的感觉,但是请大家相信我,如果可以,我希望把全部2w+关注者都塞进去。
关键代码
下面这部分关键代码实现:
探索题目
这里能不能模拟官网发送jsonp
请求去获取数据,因为用户中心这里是可以获取20页之后的数据的。感兴趣的小伙伴可以探索一下,如果可行,大家一定要给我项目提个PR,那咱们可玩性就更强了,比如我们可以将本月生日的小伙伴全部画出来,又比如我们可以绘制女粉的头像,哈哈。
使用Canvas绘制头图
思路
下面是将获取的粉丝头像绘制到画布上,我们通过canvas
这个库实现(感谢大帅的创意),核心逻辑是:
-
循环获取头像数据:使用
canvas
库提供的loadImage(url)
获取图像数据// 加载图片 const bgImage = await loadImage("bg.jpg");
-
将获取图像绘制到画布:使用canvas提供的
drawImage(img, x, y, width, height)
绘制图片// 绘制图像:ctx是canvas实例提供的上下文 ctx.drawImage(bgImage, 0, 0, canvasSize.w, canvasSize.h);
- 绘制逻辑:画布尺寸2560 * 400,我们打算绘制240个头像(6行40列),那么每个头像尺寸约为64 * 64(2560*400/250,再开方得到64,除以240除不尽,强迫症改成了250,没别的意思哈,就是为了能除尽)
关键代码
上传头图之前我们还可以导出图片确认一下绘制结果:
请求B站接口设置头图
最后是将绘制的图像上传到B站头图,相关接口是https://space.bilibili.com/ajax/topphoto/uploadTopPhotov2
,该接口需要用到前面我们获取的4个用户令牌信息。具体代码如下:
本地在nodejs环境执行代码之后就可以看到更新的效果了!花花绿绿的,还挺好看!
使用GithubAction定时更新头图
虽然前面已经可以做到想要的功能,但是粉丝每天都在变化,每隔一段时间更新一下头图应该会更好。所以我们就需要整一个定时任务来做这个自动更新。GithubAction
就是一个很不错的选项,我们在github项目中定义一个工作流即可,大家可以在项目里创建.github/workflows/schedule.yml
文件:
-
我们定义了
schedule
事件,每天16点跑一次任务 -
jobs
中我们定义执行任务,共分5步:- 迁出代码
- 安装nodejs环境
- 安装所需库
- 安装项目依赖
- 执行脚本
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
#push:
# branches: [ main ]
schedule:
- cron: '0 16 * * *'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Runs a single command using the runners shell
- name: Setup Node.js environment
uses: actions/setup-node@v2.4.0
- 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}}"
注意这里用到了github的秘钥功能,避免我们暴露这些关键信息给其他人,定义方式如下:
相应的,代码中也要获取这些传入参数才行:
const [BILI_JCT, SESSDATA, DEDEUSERID, DEDEUSERID__CKMD5] = process.argv.slice(2);
使用项目
再次感谢大帅创意,原始项目地址,本文相关项目地址如下:
使用该项目时,请按以下步骤走:
- fork项目
- 获取自己的秘钥信息
- 在自己项目settings中设置secrets
- 在actions中手动启动工作流
写在最后
如果大家觉得有帮助的话,给村长点个赞吧!
目前正在卷面试题,大家公众号搜村长学前端
,加入羊村
群,跟我们一起卷吧~