2Sdqc9f9DdCnJn?B`NB}psHA>`EUXJtAmafxOE8-c3VRfCEIS1MF6|B%kYWz( zUIxt?#gOvy5;k^L!Anu%cVXb|kRqKlCmPGn)&Fr|D)q&0fX^$Zn3J5U7H- zt)ELQppWLI>Z;#TEBCJ*fO)gVk#pgK?*7@X%?k)gcn$tSDIkm4R@fF@jc3@y9K$5K z|C98^)!8_}T`rx;AX7zD?MPCw68}OQLj|ou^qX++;Pvmmcz9m)qb8&bCK*dl6Wpti z&Uhw-Nj$+ZOmB{61$>=^=Vu@Zqm6osf6D(FE}Y&0r@q=~s9<{7vql&fbX>#G($bI} ze4R2I)vH(kEl)F7!dbSZLi3re!J2BoV8IcBjv|gkmGxGoBBWcQ`3y(1lQ@Q1=YOlT zc-CxXgM#1)S+Q^`387$)Lt9m)aM}_+2f{(quY^4vR^8umAd63vP=W=N4<3RR)$?sy z!k~WL{b&C?1v_t7)c%Xu4o_{1zfj1%tC=J
5QkOH~Gd?EELl!bvm8I45o;VGoQZpU=@(V+^u*28vGw?e$Bh zfGqTqusu{n$ak|~`s8F%C4&0{RXBLQM#fglEa0JRHEyH`N7h2?XPS_DFWp<JJlo%a6oohut$ig%z%>Jv{`mhXe;RH#XsKrD^<(ExS z+QJ?W*NI$AyTXI)KbU?0mIaWPf{CqNB}Tv2eR&Ig;JyvaSzzu$!?g4OWMLT;iLFd8 zNT_H4l4EhkV($?0?vc{bgW0 >X0Zz0^_>hX?{vM}unMma!N9;iox*BI zM10e!L+c$s+|R { @@ -53,9 +64,7 @@ export async function getDownloadUrl(url) { return axios .get(url, { headers: { - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36', - referer: 'https://www.bilibili.com', + ...biliHeaders }, }) .then(({ data }) => { @@ -127,9 +136,7 @@ export async function m4sToMp3(m4sUrl, path) { .get(m4sUrl, { responseType: 'stream', headers: { - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36', - referer: 'https://www.bilibili.com', + ...biliHeaders }, }).then(async res => { // 如果没有目录就创建一个 @@ -231,9 +238,7 @@ export async function getDynamic(dynamicId, SESSDATA) { const dynamicApi = BILI_DYNAMIC.replace("{}", dynamicId); return axios.get(dynamicApi, { headers: { - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36', - 'referer': 'https://www.bilibili.com', + ...biliHeaders, Cookie: `SESSDATA=${ SESSDATA }` }, }).then(resp => { @@ -254,4 +259,60 @@ export async function getDynamic(dynamicId, SESSDATA) { dynamicDesc } }) +} + +/** + * 扫码 + * @param qrcodeSavePath 【必须】QR保存位置 + * @param detectTime 【可选】检测时间(默认10s检测一次) + * @param hook 【可选】钩子函数,目前只用来人机交互 + * @returns {Promise<{ + * SESSDATA, + * refresh_token + * }>} + */ +export async function getScanCodeData(qrcodeSavePath = 'qrcode.png', detectTime = 10, hook = () => {}) { + try { + const resp = await axios.get(BILI_SCAN_CODE_GENERATE, { ...biliHeaders }); + // 保存扫码的地址、扫码登录秘钥 + const { url: scanUrl, qrcode_key } = resp.data.data; + await qrcode.toFile(qrcodeSavePath, scanUrl); + + let code = 1; + + // 设置最大尝试次数 + let attemptCount = 0; + const maxAttempts = 3; + + let loginResp; + // 检测扫码情况默认 10s 检测一次,并且尝试3次,没扫就拜拜 + while (code !== 0 && attemptCount < maxAttempts) { + // 钩子函数,目前用于发送二维码给用户 + hook(); + loginResp = await axios.get(BILI_SCAN_CODE_DETECT.replace("{}", qrcode_key), { ...biliHeaders }); + code = loginResp.data.data.code; + await new Promise(resolve => setTimeout(resolve, detectTime * 1000)); // Wait for detectTime seconds + } + // 获取刷新令牌 + const { refresh_token } = loginResp.data.data; + + // 获取cookie + const cookies = loginResp.headers['set-cookie']; + const SESSDATA = cookies + .map(cookie => cookie.split(';').find(item => item.trim().startsWith('SESSDATA='))) + .find(item => item !== undefined) + ?.split('=')[1]; + + return { + SESSDATA, + refresh_token + }; + } catch (err) { + logger.error(err); + // 可能需要处理错误或返回一个默认值 + return { + SESSDATA: '', + refresh_token: '' + }; + } } \ No newline at end of file