JavaScript復(fù)原何同學(xué)B站頭圖細(xì)節(jié)示例詳解
前言
在今年初,B站頒布了2021年的百大UP。我很喜歡其中一位UP主 @老師好我叫何同學(xué) ,他的每一個(gè)視頻都非常的有創(chuàng)意。
何同學(xué)也是一個(gè)極其注重細(xì)節(jié)的人,點(diǎn)進(jìn)何同學(xué)的B站個(gè)人空間,細(xì)心的小伙伴肯定能關(guān)注到他個(gè)人空間的頭圖,右邊顯示的數(shù)字其實(shí)是何同學(xué)上次投稿距今的時(shí)間,這個(gè)數(shù)字每天都會(huì)變。
這也太細(xì)節(jié)了吧~
我并不知道何同學(xué)具體是如何實(shí)現(xiàn)的,但大帥
作為一個(gè)熱愛(ài)編程的老
程序猿
,思路很快就在我腦海里浮現(xiàn)出來(lái)了?;艘惶斓臅r(shí)間敲代碼和Debug,我已經(jīng)完全實(shí)現(xiàn)了和何同學(xué)一樣的效果,并且無(wú)需服務(wù)器無(wú)需打開電腦,頭圖每天也會(huì)自動(dòng)更新。
代碼已在github
開源,如果你只是想使用它,并不想知道技術(shù)細(xì)節(jié),請(qǐng)直接跳到最后看使用教學(xué)。
接下來(lái)我會(huì)手把手教你一步步去實(shí)現(xiàn)它,如果你想跟我一起用編程玩轉(zhuǎn)創(chuàng)意,也請(qǐng)點(diǎn)贊收藏分享支持一下吧。
本文配套視頻:www.bilibili.com/video/BV1bS…
手把手實(shí)現(xiàn)它
好的,接下來(lái)你會(huì)學(xué)習(xí)到
- 如何抓取B站的請(qǐng)求
- 在nodejs里生成圖片
- 獲得用戶最新的投稿計(jì)算日子
- GithubAction定時(shí)更新頭圖
如何抓取B站的請(qǐng)求
自動(dòng)的前提是手動(dòng),所以我們要先了解如何手動(dòng)操作才可以更換個(gè)人空間頭圖(此功能需要B站的大會(huì)員),打開B站你的個(gè)人空間,點(diǎn)擊頭圖右上角的這個(gè)區(qū)域更換皮膚
在網(wǎng)頁(yè)底部會(huì)彈出更換頭圖的操作面板,上傳任意圖片作為頭圖的功能只有大會(huì)員才有。
接下來(lái)常規(guī)操作,我們按下F12
打開調(diào)試面板,切換到network
標(biāo)簽,此時(shí)我們上傳一張圖片,就可以抓取到這個(gè)上傳頭圖的接口了
https://space.bilibili.com/ajax/topphoto/uploadTopPhotov2
點(diǎn)擊鼠標(biāo)右鍵,選擇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"});
然后我們新建一個(gè)nodejs
的項(xiàng)目,安裝一下node-fetch
庫(kù)
//如果你的環(huán)境支持ESModule,那么使用importimport fetch from 'node-fetch'; //如果是用require導(dǎo)入 const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
現(xiàn)在你已經(jīng)可以把剛才的上傳圖片的操作通過(guò)代碼完成了,那么這一堆參數(shù)里,我們需要注意哪些呢?
- cookie
用戶身份校驗(yàn)的參數(shù),我們主要會(huì)用到bili_jct
,SESSDATA
,DedeUserID
, DedeUserID__ckMd5
- body
topphoto為圖片base64編碼的數(shù)據(jù),csrf
就是bili_jct
如果是自己用,那么你只需要生成圖片并轉(zhuǎn)為base64編碼后通過(guò)topphoto
參數(shù)提交給B站接口就可以了
在nodejs里生成圖片
在網(wǎng)頁(yè)里生成圖片大概率你知道要用canvas,比如我在碼上掘金里寫的這個(gè)demo。代碼片段
其實(shí)在node環(huán)境里生成圖片,也有一個(gè)canvas的庫(kù)可以用。
npm install canvas
這個(gè)庫(kù)在不同的系統(tǒng)下還需要安裝不同的底層繪制庫(kù)。
# 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`
因?yàn)槲也挥脀indows,所以windows的小伙伴自己去看官方的安裝說(shuō)明吧github.com/Automattic/…
使用這個(gè)庫(kù)繪圖的API設(shè)計(jì)和網(wǎng)頁(yè)canvas基本相同。
//導(dǎo)入canvas庫(kù)里的三個(gè)方法const { createCanvas, loadImage ,registerFont } = require('canvas'); //B站頭圖的建議尺寸是2560x400 const canvasSize = {w:2560,h:400}; //創(chuàng)建畫布const canvas = createCanvas(canvasSize.w, canvasSize.h); //獲得畫布的繪制對(duì)象 const ctx = canvas.getContext('2d'); async function painting(){ //添加背景圖 const bgImage = await loadImage('bg.jpg'); //將圖片繪制到畫布的0,0坐標(biāo),并設(shè)置寬和高 ctx.drawImage(bgImage, 0, 0, canvasSize.w, canvasSize.h); } painting();
有了背景圖,現(xiàn)在我們加入文字
//注冊(cè)字體 registerFont('digit.ttf', { family: 'digit' }); //設(shè)置文字顏色和字號(hào),字體 ctx.fillStyle = "#e6433a"; ctx.font = '97px digit'; let txt = "HELLO" //計(jì)算文字尺寸 let size = ctx.measureText(txt); //將文字繪制到指定坐標(biāo) ctx.fillText(txt, 0, 0);
何同學(xué)頭圖里的文字是有垂直方向上的傾斜的,這個(gè)在canvas
中也可以實(shí)現(xiàn)
//設(shè)置接下來(lái)傾斜的原點(diǎn)為文字的左上角ctx.translate(txt_x, txt_y); /* transform(a,b,c,d,e,f)a 水平縮放繪圖b 水平傾斜繪圖c 垂直傾斜繪圖d 垂直縮放繪圖e 水平移動(dòng)繪圖f 垂直移動(dòng)繪圖 */ ctx.transform(1,-0.3,0,1,0,0);
接下來(lái)使用canvas.toDataURL("image/png")
就可以將畫布轉(zhuǎn)換為base64
編碼的數(shù)據(jù)了,這里需要注意一下,B站頭圖接口中的topphoto
參數(shù)是不需要前面22個(gè)字符的圖片頭信息,所以我們還要截取一下
canvas.toDataURL("image/png").substring(22);
當(dāng)然,你現(xiàn)在并不能確定咱們生成的圖片是否正確,所以你也可以將圖片保存成本地文件先看看是不是對(duì)了
fs.writeFileSync("test.png",canvas.toBuffer());
獲得用戶最新的投稿計(jì)算日子
通過(guò)接口https://api.bilibili.com/x/space/arc/search
可以抓取指定用戶的投稿視頻
//pn為頁(yè)數(shù),ps為每頁(yè)條數(shù),order=pubdate代表按發(fā)布時(shí)間返回?cái)?shù)據(jù) fetch("https://api.bilibili.com/x/space/arc/search?mid="+DEDEUSERID+"&pn=1&ps=1&order=pubdate&jsonp=jsonp");
在每條視頻的信息里,created
屬性代表了發(fā)布時(shí)間(單位:秒),我們需要計(jì)算一下這個(gè)時(shí)間和當(dāng)前系統(tǒng)的時(shí)間差并轉(zhuǎn)換為天為單位
//計(jì)算兩個(gè)日期相差的天數(shù) const diffDays = (date, otherDate) => Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));
這里推薦給大家一個(gè)網(wǎng)站,里面收錄了各種用一行代碼實(shí)現(xiàn)的功能 1loc.dev/
Github Action定時(shí)任務(wù)
Github Action
是Github
提供的虛擬容器服務(wù),通俗點(diǎn)說(shuō)就是免費(fèi)給你一臺(tái)云服務(wù)器,這個(gè)云服務(wù)器的系統(tǒng)是什么,具備哪些代碼運(yùn)行環(huán)境通通都可以根據(jù)配置自定義。我們通過(guò)github的工作流workflow
來(lái)使用它,有趣的是,我們還可以給它設(shè)置定時(shí)任務(wù)來(lái)定期運(yùn)行我們的工作流,執(zhí)行我們寫好的代碼,生成圖片上傳一氣呵成!完全免費(fèi)!
打開終端/命令行,在git項(xiàng)目目錄下新建目錄并創(chuàng)建schedule.yml配置文件
mkdir .github mkdir .github/workflows touch .github/workflows/schedule.yml
schedule.yml
配置
# 這個(gè)工作流的名稱 name: CI # 工作流什么時(shí)候可以運(yùn)行 on: # Schedule就是定時(shí)任務(wù),由于服務(wù)在國(guó)外,所以時(shí)間需要減去8小時(shí)才是北京時(shí)間 schedule: - cron: '0 16 * * *' # 也允許這個(gè)工作流在github aciton面板中手動(dòng)觸發(fā) workflow_dispatch: # 工作流內(nèi)有哪些任務(wù) jobs: # 此工作流包含一個(gè)任務(wù)名為build build: # 安裝最新的ubuntu系統(tǒng) runs-on: ubuntu-latest # 此任務(wù)重包含的子任務(wù)/步驟 steps: # 拉取最新的代碼 - uses: actions/checkout@v2 # 安裝好Nodejs的運(yùn)行環(huán)境 - name: Setup Node.js environment uses: actions/setup-node@v2.4.0 # 安裝好node canvas必備的系統(tǒng)繪圖庫(kù) - name: Setup Basically Packages run: sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev # 安裝好我們自己項(xiàng)目的依賴包 - name: Install NPM dependencies run: npm install # 執(zhí)行我們自己的代碼 - name: Run run: node index.js "${{secrets.BILI_JCT}}" "${{secrets.SESSDATA}}" "${{secrets.DEDEUSERID}}" "${{secrets.DEDEUSERID__CKMD5}}"
配置這樣就結(jié)束了,在北京時(shí)間每天的零點(diǎn)(美國(guó)時(shí)間16點(diǎn)
)就會(huì)自動(dòng)生成頭圖并上傳啦。
配置中的secrets.xxx
是我們代碼運(yùn)行時(shí)攜帶的參數(shù),為了讓大家更方便的fork此開源倉(cāng)庫(kù),所以我將四個(gè)B站用戶身份所對(duì)應(yīng)的參數(shù)設(shè)置成了可自定義的。這種secrets
的參數(shù)在接受自定義的同時(shí)還能保護(hù)其在Github
不被泄露。
使用本項(xiàng)目
如果你只是想要用使用本倉(cāng)庫(kù)實(shí)現(xiàn)一樣的效果,是非常簡(jiǎn)單的,因?yàn)槲叶挤庋b好了,拿來(lái)即用
溫馨提示:只有B站大會(huì)員可以自定義頭圖
https://github.com/ezshine/auto-bilibili-topphoto
步驟1:
fork本倉(cāng)庫(kù)
步驟2:
用Chrome
瀏覽器打開B站,進(jìn)入自己的個(gè)人空間,按下F12,切換到application
標(biāo)簽
在Cookie
中找到這四個(gè)參數(shù),然后打開自己分支倉(cāng)庫(kù),點(diǎn)擊Settings
,進(jìn)入Secrets
,點(diǎn)擊New repository secret
將四個(gè)參數(shù)一一配置好
步驟3:
手動(dòng)執(zhí)行一次工作流,以后就可以自動(dòng)定時(shí)運(yùn)行了!
恭喜,現(xiàn)在你已經(jīng)擁有了和何同學(xué)一樣有趣的全自動(dòng)B站個(gè)人空間頭圖。
以上就是JavaScript復(fù)原何同學(xué)B站頭圖細(xì)節(jié)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript復(fù)原頭圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序 獲取當(dāng)前地理位置和經(jīng)緯度實(shí)例代碼
這篇文章主要介紹了微信小程序 獲取當(dāng)前地理位置和經(jīng)緯度實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-12-12JavaScript前端學(xué)算法題解LeetCode最大重復(fù)子字符串
這篇文章主要為大家介紹了JavaScript前端學(xué)算法題解LeetCode最大重復(fù)子字符串,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09TypeScript 內(nèi)置高級(jí)類型編程示例
這篇文章主要為大家介紹了TypeScript 內(nèi)置高級(jí)類型編程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09微信小程序 圖片寬度自適應(yīng)的實(shí)現(xiàn)
這篇文章主要介紹了微信小程序 圖片寬度自適應(yīng)的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-04-04微信小程序 本地存儲(chǔ)及登錄頁(yè)面處理實(shí)例詳解
這篇文章主要介紹了微信小程序 本地存儲(chǔ)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01