From b7a9e031f48d763719fe45c6e61c5a2e0aace45c Mon Sep 17 00:00:00 2001 From: zhiyu1998 <542716863@qq.com> Date: Wed, 14 Aug 2024 11:20:29 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=9F=20feat:=20=E9=99=A4=E4=BA=86?= =?UTF-8?q?=E5=93=94=E5=93=A9=E5=93=94=E5=93=A9=E4=B8=8B=E8=BD=BD=E5=A4=96?= =?UTF-8?q?=E7=9A=84=E5=85=B6=E4=BB=96=E6=94=AF=E6=8C=81Aria2=E5=92=8Caxel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 150 +++++++++++++++++++++++++++++++++++++++++- constants/constant.js | 8 ++- utils/bbdown-util.js | 2 +- 3 files changed, 156 insertions(+), 4 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index d483f1c..d878cc8 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -13,7 +13,7 @@ import { BILI_DEFAULT_INTRO_LEN_LIMIT, COMMON_USER_AGENT, DIVIDING_LINE, - douyinTypeMap, + douyinTypeMap, DOWNLOAD_WAIT_DETECT_FILE_TIME, HELP_DOC, MESSAGE_RECALL_TIME, REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_LAGRANGE, REDOS_YUNZAI_WHITELIST, @@ -1939,6 +1939,10 @@ export class tools extends plugin { // 如果是用户设置了单线程,则不分片下载 if (numThreads === 1) { return await this.downloadVideoWithSingleThread(downloadVideoParams); + } else if (numThreads !== 1 && this.biliDownloadMethod === 1) { + return await this.downloadVideoWithAria2(downloadVideoParams, numThreads); + } else if (numThreads !== 1 && this.biliDownloadMethod === 2) { + return await this.downloadVideoUseAxel(downloadVideoParams, numThreads); } else { return await this.downloadVideoWithMultiThread(downloadVideoParams, numThreads); } @@ -2026,6 +2030,148 @@ export class tools extends plugin { } } + /** + * 使用Aria2进行多线程下载 + * @param downloadVideoParams + * @param numThreads + * @returns {Promise} + */ + async downloadVideoWithAria2(downloadVideoParams, numThreads) { + const { url, headers, userAgent, proxyOption, target, groupPath } = downloadVideoParams; + + // 构造aria2c命令参数 + const aria2cArgs = [ + `"${url}"`, + `--out="temp.mp4"`, + `--dir="${groupPath}"`, + `--user-agent="${userAgent}"`, + `--max-connection-per-server=${ numThreads }`, // 每个服务器的最大连接数 + `--split=${ numThreads }`, // 分成 6 个部分进行下载 + ]; + + // 如果有自定义头信息 + if (headers) { + for (const [key, value] of Object.entries(headers)) { + aria2cArgs.push(`--header="${key}: ${value}"`); + } + } + + // 如果使用代理 + if (proxyOption && proxyOption.httpAgent) { + const proxyUrl = proxyOption.httpAgent.proxy.href; + aria2cArgs.push(`--all-proxy="${proxyUrl}"`); + } + + try { + await checkAndRemoveFile(target); + logger.mark(`开始下载: ${url}`); + + // 执行aria2c命令 + const command = `aria2c ${aria2cArgs.join(' ')}`; + exec(command, (error, stdout, stderr) => { + if (error) { + logger.error(`下载视频发生错误!\ninfo:${stderr}`); + throw error; + } else { + logger.mark(`下载完成: ${url}`); + } + }); + + // 监听文件生成完成 + let count = 0; + return new Promise((resolve, reject) => { + const checkInterval = setInterval(() => { + logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${ count + 1 }次`)); + count += 1; + if (fs.existsSync(target)) { + logger.info("[R插件][Aria2] 检测到文件!"); + clearInterval(checkInterval); + resolve(groupPath); + } + if (count === 6) { + logger.error(`[R插件][Aria2] 下载视频发生错误!`); + clearInterval(checkInterval); + reject(); + } + }, DOWNLOAD_WAIT_DETECT_FILE_TIME); + }); + } catch (err) { + logger.error(`下载视频发生错误!\ninfo:${err}`); + throw err; + } + } + + /** + * 使用Axel进行多线程下载 + * @param downloadVideoParams + * @param numThreads + * @returns {Promise} + */ + async downloadVideoUseAxel(downloadVideoParams, numThreads) { + const { url, headers, userAgent, proxyOption, target, groupPath } = downloadVideoParams; + + // 构造axel命令参数 + const axelArgs = [ + `-n ${numThreads}`, + `-o "${target}"`, + `-U "${userAgent}"`, + url + ]; + + // 如果有自定义头信息 + if (headers) { + for (const [key, value] of Object.entries(headers)) { + axelArgs.push(`-H "${key}: ${value}"`); + } + } + + // 如果使用代理 + if (proxyOption && proxyOption.httpAgent) { + const proxyUrl = proxyOption.httpAgent.proxy.href; + axelArgs.push(`--proxy="${proxyUrl}"`); + } + + try { + await checkAndRemoveFile(target); + logger.mark(`开始下载: ${url}`); + + + // 执行axel命令 + const command = `axel ${axelArgs.join(' ')}`; + exec(command, (error, stdout, stderr) => { + if (error) { + logger.error(`下载视频发生错误!\ninfo:${stderr}`); + throw error; + } else { + logger.mark(`下载完成: ${url}`); + } + }); + + let count = 0; + // 监听文件生成完成 + return new Promise((resolve, reject) => { + const checkInterval = setInterval(() => { + logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${ count + 1 }次`)); + count += 1; + if (fs.existsSync(target)) { + logger.info("[R插件][Axel] 检测到文件!"); + clearInterval(checkInterval); + logger.info(`[R插件][Axel] 下载到${groupPath}`); + resolve(groupPath); + } + if (count === 6) { + logger.error(`[R插件][Axel] 下载视频发生错误!`); + clearInterval(checkInterval); + reject(); + } + }, DOWNLOAD_WAIT_DETECT_FILE_TIME); + }); + } catch (err) { + logger.error(`下载视频发生错误!\ninfo:${err}`); + throw err; + } + } + /** * 单线程下载视频 * @link {downloadVideo} @@ -2100,7 +2246,7 @@ export class tools extends plugin { return false; } const whiteList = await redisGetKey(REDOS_YUNZAI_WHITELIST); - return whiteList.includes(userId) || whiteList.includes(userId.toString()); + return whiteList.includes(userId.toString()) || whiteList.includes(userId); } /** diff --git a/constants/constant.js b/constants/constant.js index b3e9ca0..f3f043b 100644 --- a/constants/constant.js +++ b/constants/constant.js @@ -144,4 +144,10 @@ export const BILI_DOWNLOAD_METHOD = Object.freeze([ * 消息撤回时间 * @type {number} */ -export const MESSAGE_RECALL_TIME = 60; \ No newline at end of file +export const MESSAGE_RECALL_TIME = 60; + +/** + * 针对 Aria2 和 Alex 的下载检测文件时间 + * @type {number} + */ +export const DOWNLOAD_WAIT_DETECT_FILE_TIME = 2000; \ No newline at end of file diff --git a/utils/bbdown-util.js b/utils/bbdown-util.js index ac1a34a..d3ca211 100644 --- a/utils/bbdown-util.js +++ b/utils/bbdown-util.js @@ -24,7 +24,7 @@ export function startBBDown(videoUrl, downloadDir, BBDownOptions) { urlObj.search = newParams.toString(); videoUrl = urlObj.toString(); // 说明:-F 自定义名称,-c 自定义Cookie, --work-dir 设置下载目录,-M 多p下载的时候命名 - const command = `BBDown ${videoUrl} --work-dir ${downloadDir} ${biliSessData ? '-c SESSDATA=\"' + biliSessData + '\"' : ''} ${pageParam ? '-p ' + pageParam + ' -M \"temp\"' : '-p 1' + ' -M \"temp\"'} -F temp --skip-subtitle --skip-cover ${biliUseAria2 ? '--use-aria2c' : ''} ${biliCDN ? '--upos-host ' + biliCDN : ''}`; + const command = `BBDown ${videoUrl} --work-dir ${downloadDir} ${biliSessData ? '-c SESSDATA=' + biliSessData : ''} ${pageParam ? '-p ' + pageParam + ' -M \"temp\"' : '-p 1' + ' -M \"temp\"'} -F temp --skip-subtitle --skip-cover ${biliUseAria2 ? '--use-aria2c' : ''} ${biliCDN ? '--upos-host ' + biliCDN : ''}`; logger.info(command); // logger.info(command); // 直接调用BBDown,因为它已经在系统路径中