feat(route): 添加 dm_img_list 字段防止被 Bilibili 识别 (#14128)

* feat(route): add dm_img_list parameter

Signed-off-by: NightSpaceC <NightSpaceC@outlook.com>

* feat(route): readd video-all. It is still usable.

* fix(route): use camelCase

* feat(route): generate data of dm_img_list

---------

Signed-off-by: NightSpaceC <NightSpaceC@outlook.com>
This commit is contained in:
Night Space 2024-01-01 00:00:10 +08:00 committed by GitHub
parent 6e244aaee8
commit 64d906fc9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 126 additions and 22 deletions

View File

@ -55,8 +55,8 @@ module.exports = {
return cookie.join('; ');
});
},
getVerifyString: (ctx) => {
const key = 'bili-verify-string';
getWbiVerifyString: (ctx) => {
const key = 'bili-wbi-verify-string';
return ctx.cache.tryGet(key, async () => {
const cookie = await module.exports.getCookie(ctx);
const { data: navResponse } = await got('https://api.bilibili.com/x/web-interface/nav', {
@ -97,14 +97,14 @@ module.exports = {
const key = 'bili-username-from-uid-' + uid;
return ctx.cache.tryGet(key, async () => {
const cookie = await module.exports.getCookie(ctx);
const verifyString = await module.exports.getVerifyString(ctx);
const wbiVerifyString = await module.exports.getWbiVerifyString(ctx);
// await got(`https://space.bilibili.com/${uid}/`, {
// headers: {
// Referer: 'https://www.bilibili.com/',
// Cookie: cookie,
// },
// });
const params = utils.addVerifyInfo(`mid=${uid}&token=&platform=web&web_location=1550101`, verifyString);
const params = utils.addWbiVerifyInfo(`mid=${uid}&token=&platform=web&web_location=1550101`, wbiVerifyString);
const { data: nameResponse } = await got(`https://api.bilibili.com/x/space/wbi/acc/info?${params}`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/`,
@ -121,14 +121,14 @@ module.exports = {
let face = await ctx.cache.get(faceKey);
if (!name || !face) {
const cookie = await module.exports.getCookie(ctx);
const verifyString = await module.exports.getVerifyString(ctx);
const wbiVerifyString = await module.exports.getWbiVerifyString(ctx);
// await got(`https://space.bilibili.com/${uid}/`, {
// headers: {
// Referer: `https://www.bilibili.com/`,
// Cookie: cookie,
// },
// });
const params = utils.addVerifyInfo(`mid=${uid}&token=&platform=web&web_location=1550101`, verifyString);
const params = utils.addWbiVerifyInfo(`mid=${uid}&token=&platform=web&web_location=1550101`, wbiVerifyString);
const { data: nameResponse } = await got(`https://api.bilibili.com/x/space/wbi/acc/info?${params}`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/`,

View File

@ -3,8 +3,8 @@ const cache = require('./cache');
const utils = require('./utils');
module.exports = async (ctx) => {
const verifyString = await cache.getVerifyString(ctx);
const params = utils.addVerifyInfo('limit=10&platform=web', verifyString);
const wbiVerifyString = await cache.getWbiVerifyString(ctx);
const params = utils.addWbiVerifyInfo('limit=10&platform=web', wbiVerifyString);
const url = `https://api.bilibili.com/x/web-interface/wbi/search/square?${params}`;
const response = await got({
method: 'get',

View File

@ -17,9 +17,9 @@ module.exports = async (ctx) => {
orderTitle = '人气直播';
break;
}
const verifyString = await cache.getVerifyString(ctx);
const wbiVerifyString = await cache.getWbiVerifyString(ctx);
let params = `__refresh__=true&_extra=&context=&page=1&page_size=42&order=${order}&duration=&from_source=&from_spmid=333.337&platform=pc&highlight=1&single_column=0&keyword=${urlEncodedKey}&ad_resource=&source_tag=3&gaia_vtoken=&category_id=&search_type=live&dynamic_offset=0&web_location=1430654`;
params = utils.addVerifyInfo(params, verifyString);
params = utils.addWbiVerifyInfo(params, wbiVerifyString);
const response = await got({
method: 'get',

View File

@ -32,6 +32,7 @@ module.exports = (router) => {
router.get('/user/followers/:uid/:loginUid', require('./followers'));
router.get('/user/followings/:uid/:loginUid', require('./followings'));
router.get('/user/video/:uid/:disableEmbed?', require('./video'));
router.get('/user/video-all/:uid/:disableEmbed?', require('./video-all'));
router.get('/video/danmaku/:bvid/:pid?', require('./danmaku'));
router.get('/video/page/:bvid/:disableEmbed?', require('./page'));
router.get('/video/reply/:bvid', require('./reply'));

View File

@ -65,20 +65,54 @@ function hexsign(e) {
return o;
}
function addVerifyInfo(params, verifyString) {
function addWbiVerifyInfo(params, wbiVerifyString) {
const searchParams = new URLSearchParams(params);
searchParams.sort();
const verifyParam = searchParams.toString();
const wts = Math.round(Date.now() / 1000);
const w_rid = md5(`${verifyParam}&wts=${wts}${verifyString}`);
const w_rid = md5(`${verifyParam}&wts=${wts}${wbiVerifyString}`);
return `${params}&w_rid=${w_rid}&wts=${wts}`;
}
// https://github.com/errcw/gaussian/blob/master/lib/box-muller.js
function generateGaussianInteger(mean, std) {
const _2PI = Math.PI * 2;
const u1 = Math.random();
const u2 = Math.random();
const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(_2PI * u2);
return Math.round(z0 * std + mean);
}
function getDmImgList() {
const x = Math.max(generateGaussianInteger(720, 20), 0);
const y = Math.max(generateGaussianInteger(480, 20), 0);
const path = [
{
x: 3 * x + 2 * y,
y: 4 * x - 5 * y,
z: 0,
timestamp: Math.max(generateGaussianInteger(40, 5), 0),
type: 0,
},
];
return JSON.stringify(path);
}
function addDmVerifyInfo(params, dmImgList) {
const dmImgStr = Buffer.from('no webgl').toString('base64').slice(0, -2);
const dmCoverImgStr = Buffer.from('no webgl').toString('base64').slice(0, -2);
return `${params}&dm_img_list=${dmImgList}&dm_img_str=${dmImgStr}&dm_cover_img_str=${dmCoverImgStr}`;
}
module.exports = {
iframe,
lsid,
_uuid,
hexsign,
addVerifyInfo,
addWbiVerifyInfo,
getDmImgList,
addDmVerifyInfo,
bvidTime: 1589990400,
};

View File

@ -0,0 +1,75 @@
const got = require('@/utils/got');
const cache = require('./cache');
const utils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const uid = ctx.params.uid;
const disableEmbed = ctx.params.disableEmbed;
const cookie = await cache.getCookie(ctx);
const wbiVerifyString = await cache.getWbiVerifyString(ctx);
const dmImgList = utils.getDmImgList();
const [name, face] = await cache.getUsernameAndFaceFromUID(ctx, uid);
await got(`https://space.bilibili.com/${uid}/video?tid=0&page=1&keyword=&order=pubdate`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/`,
Cookie: cookie,
},
});
const params = utils.addWbiVerifyInfo(utils.addDmVerifyInfo(`mid=${uid}&ps=30&tid=0&pn=1&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true`, dmImgList), wbiVerifyString);
const response = await got(`https://api.bilibili.com/x/space/wbi/arc/search?${params}`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/video?tid=0&page=1&keyword=&order=pubdate`,
Cookie: cookie,
},
});
const vlist = [...response.data.data.list.vlist];
const pageTotal = Math.ceil(response.data.data.page.count / response.data.data.page.ps);
const getPage = async (pageId) => {
const cookie = await cache.getCookie(ctx);
await got(`https://space.bilibili.com/${uid}/video?tid=0&page=${pageId}&keyword=&order=pubdate`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/`,
Cookie: cookie,
},
});
const params = utils.addWbiVerifyInfo(utils.addDmVerifyInfo(`mid=${uid}&ps=30&tid=0&pn=${pageId}&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true`, dmImgList), wbiVerifyString);
return got(`https://api.bilibili.com/x/space/wbi/arc/search?${params}`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/video?tid=0&page=${pageId}&keyword=&order=pubdate`,
Cookie: cookie,
},
});
};
const promises = [];
if (pageTotal > 1) {
for (let i = 2; i <= pageTotal; i++) {
promises.push(getPage(i));
}
const rets = await Promise.all(promises);
rets.forEach((ret) => {
vlist.push(...ret.data.data.list.vlist);
});
}
ctx.state.data = {
title: name,
link: `https://space.bilibili.com/${uid}/video`,
description: `${name} 的 bilibili 所有视频`,
logo: face,
icon: face,
item: vlist.map((item) => ({
title: item.title,
description: `${item.description}${!disableEmbed ? `<br><br>${utils.iframe(item.aid)}` : ''}<br><img src="${item.pic}">`,
pubDate: parseDate(item.created, 'X'),
link: item.created > utils.bvidTime && item.bvid ? `https://www.bilibili.com/video/${item.bvid}` : `https://www.bilibili.com/video/av${item.aid}`,
author: name,
comments: item.comment,
})),
};
};

View File

@ -7,7 +7,8 @@ module.exports = async (ctx) => {
const uid = ctx.params.uid;
const disableEmbed = ctx.params.disableEmbed;
const cookie = await cache.getCookie(ctx);
const verifyString = await cache.getVerifyString(ctx);
const wbiVerifyString = await cache.getWbiVerifyString(ctx);
const dmImgList = utils.getDmImgList();
const [name, face] = await cache.getUsernameAndFaceFromUID(ctx, uid);
// await got(`https://space.bilibili.com/${uid}/video?tid=0&page=1&keyword=&order=pubdate`, {
@ -16,14 +17,7 @@ module.exports = async (ctx) => {
// Cookie: cookie,
// },
// });
const params = utils.addVerifyInfo(
`mid=${uid}&ps=30&tid=0&pn=1&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true&dm_img_list=[]&dm_img_str=${Buffer.from('no webgl').toString('base64').slice(0, -2)}&dm_cover_img_str=${Buffer.from(
'no webgl'
)
.toString('base64')
.slice(0, -2)}`,
verifyString
);
const params = utils.addWbiVerifyInfo(utils.addDmVerifyInfo(`mid=${uid}&ps=30&tid=0&pn=1&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true`, dmImgList), wbiVerifyString);
const response = await got(`https://api.bilibili.com/x/space/wbi/arc/search?${params}`, {
headers: {
Referer: `https://space.bilibili.com/${uid}/video?tid=0&page=1&keyword=&order=pubdate`,