From ceb242dfa87d23378ad3bda3d35b1d2207cf3974 Mon Sep 17 00:00:00 2001 From: zhiyu1998 <542716863@qq.com> Date: Tue, 13 Aug 2024 16:20:09 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=201.8.0-beta=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新内容如下: 1. 添加小飞机解析 2. 添加信任用户 --- apps/switchers.js | 139 +++++++++++++++++++++++++++----- apps/tools.js | 130 ++++++++++++++++++----------- config/help.yaml | 3 + config/version.yaml | 4 +- constants/constant.js | 14 +++- resources/img/icon/telegram.png | Bin 0 -> 4293 bytes utils/bbdown-util.js | 21 ----- utils/common.js | 35 ++++++-- utils/file.js | 37 +++++++++ utils/redis-util.js | 42 ++++++++++ utils/tdl-util.js | 29 +++++++ utils/y2b.js | 27 ------- utils/yt-dlp-util.js | 21 +++++ 13 files changed, 378 insertions(+), 124 deletions(-) create mode 100644 resources/img/icon/telegram.png create mode 100644 utils/redis-util.js create mode 100644 utils/tdl-util.js delete mode 100644 utils/y2b.js create mode 100644 utils/yt-dlp-util.js diff --git a/apps/switchers.js b/apps/switchers.js index acfe8c2..7b353dc 100644 --- a/apps/switchers.js +++ b/apps/switchers.js @@ -1,7 +1,8 @@ import config from "../model/config.js"; import schedule from 'node-schedule'; -import { REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_LAGRANGE } from "../constants/constant.js"; +import { REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_LAGRANGE, REDOS_YUNZAI_WHITELIST } from "../constants/constant.js"; import { deleteFolderRecursive, readCurrentDir } from "../utils/file.js"; +import { redisExistAndGetKey, redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js"; //自动清理定时 const autotime = config.getConfig("tools").autoclearTrashtime @@ -30,6 +31,21 @@ export class switchers extends plugin { fnc: "clearTrash", permission: "master", }, + { + reg: "^#设置R信任用户(.*)", + fnc: "setWhiteList", + permission: "master", + }, + { + reg: "^#R信任用户$", + fnc: "getWhiteList", + permission: "master", + }, + { + reg: "^#查询R信任用户(.*)", + fnc: "searchWhiteList", + permission: "master", + } ] }); } @@ -41,45 +57,42 @@ export class switchers extends plugin { */ async setOversea(e) { // 查看当前设置 - let os; - if ((await redis.exists(REDIS_YUNZAI_ISOVERSEA))) { - os = JSON.parse(await redis.get(REDIS_YUNZAI_ISOVERSEA)).os; - } + let os = (await redisExistAndGetKey(REDIS_YUNZAI_ISOVERSEA)).os; // 设置 os = ~os - await redis.set( - REDIS_YUNZAI_ISOVERSEA, - JSON.stringify({ - os: os, - }), - ); + await redisSetKey(REDIS_YUNZAI_ISOVERSEA, { + os: os, + }); e.reply(`当前服务器:${ os ? '海外服务器' : '国内服务器' }`) return true; } + /** + * 设置拉格朗日 + * @param e + * @returns {Promise} + */ async setLagrange(e) { // 查看当前设置 - let driver; - if ((await redis.exists(REDIS_YUNZAI_LAGRANGE))) { - driver = JSON.parse(await redis.get(REDIS_YUNZAI_LAGRANGE)).driver; - } + let driver = (await redisExistAndGetKey(REDIS_YUNZAI_LAGRANGE)).driver; // 异常检测,之前算法出现问题,如果出现异常就检测纠正 if (driver === -1) { driver = 1; } // 设置 driver ^= 1; - await redis.set( - REDIS_YUNZAI_LAGRANGE, - JSON.stringify({ - driver: driver, - }), - ); + await redisSetKey({ + driver: driver, + }) e.reply(`当前驱动:${ driver ? '拉格朗日' : '其他驱动' }`) return true; } - //手动清理垃圾 + /** + * 手动清理垃圾 + * @param e + * @returns {Promise} + */ async clearTrash(e) { try { const { dataClearFileLen, rTempFileLen } = await autoclearTrash(); @@ -90,6 +103,88 @@ export class switchers extends plugin { e.reply(`手动清理垃圾时发生错误: ${ err.message }`); } } + + /** + * 设置解析信任用户 + * @param e + * @returns {Promise} + */ + async setWhiteList(e) { + let trustUserId; + // 判断是不是回复用户命令 + if (e?.reply_id !== undefined) { + trustUserId = (await e.getReply()).user_id; + } else { + // 如果不是回复就看发送内容 + trustUserId = e.msg.replace("#设置R信任用户", ""); + } + // 用户ID检测 + if (trustUserId == null || trustUserId === "") { + e.reply("无效的R信任用户"); + return; + } + let whiteList = await redisExistAndGetKey(REDOS_YUNZAI_WHITELIST); + // 不存在就创建 + if (whiteList == null) { + whiteList = []; + } + // 重复检测 + if (whiteList.includes(trustUserId)) { + e.reply("R信任用户已存在,无须添加!"); + return; + } + whiteList = [...whiteList, trustUserId]; + // 放置到Redis里 + await redisSetKey(REDOS_YUNZAI_WHITELIST, whiteList); + e.reply(`成功添加R信任用户:${ trustUserId }`); + } + + /** + * 获取信任用户名单 + * @param e + * @returns {Promise} + */ + async getWhiteList(e) { + let whiteList = await redisExistAndGetKey(REDOS_YUNZAI_WHITELIST); + if (whiteList == null) { + whiteList = []; + } + const message = `R信任用户列表:${ whiteList.join(",\n") }`; + if (this.e.isGroup) { + await Bot.pickUser(this.e.user_id).sendMsg(await this.e.runtime.common.makeForwardMsg(this.e, message)); + await this.reply('R插件的信任用户名单已发送至您的私信了~'); + } else { + await e.reply(await makeForwardMsg(this.e, message)); + } + } + + /** + * 查询某个用户是否是信任用户 + * @param e + * @returns {Promise} + */ + async searchWhiteList(e) { + let trustUserId; + // 判断是不是回复用户命令 + if (e?.reply_id !== undefined) { + trustUserId = (await e.getReply()).user_id; + } else { + // 如果不是回复就看发送内容 + trustUserId = e.msg.replace("#设置R信任用户", ""); + } + let whiteList = await redisExistAndGetKey(REDOS_YUNZAI_WHITELIST); + if (whiteList == null) { + e.reply("R插件当前没有任何信任用户!"); + return; + } + const isInWhiteList = whiteList.includes(trustUserId); + if (isInWhiteList) { + e.reply(`✅ ${trustUserId}已经是R插件的信任用户哦~`); + } else { + e.reply(`⚠️ ${trustUserId}不是R插件的信任用户哦~`); + } + return true; + } } diff --git a/apps/tools.js b/apps/tools.js index 5c8c114..322e7c8 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -14,9 +14,9 @@ import { COMMON_USER_AGENT, DIVIDING_LINE, douyinTypeMap, - HELP_DOC, + HELP_DOC, MESSAGE_RECALL_TIME, REDIS_YUNZAI_ISOVERSEA, - REDIS_YUNZAI_LAGRANGE, + REDIS_YUNZAI_LAGRANGE, REDOS_YUNZAI_WHITELIST, SUMMARY_PROMPT, transMap, TWITTER_BEARER_TOKEN, @@ -43,7 +43,7 @@ import { import config from "../model/config.js"; import * as aBogus from "../utils/a-bogus.cjs"; import { downloadM3u8Videos, mergeAcFileToMp4, parseM3u8, parseUrl } from "../utils/acfun.js"; -import { checkBBDown, startBBDown } from "../utils/bbdown-util.js"; +import { startBBDown } from "../utils/bbdown-util.js"; import { av2BV } from "../utils/bilibili-bv-av-convert.js"; import { downloadBFile, @@ -61,6 +61,7 @@ import { getWbi } from "../utils/biliWbi.js"; import { getBodianAudio, getBodianMusicInfo, getBodianMv } from "../utils/bodian.js"; import { checkCommandExists, + checkToolInCurEnv, cleanFilename, downloadAudio, downloadImg, @@ -71,14 +72,17 @@ import { testProxy, truncateString } from "../utils/common.js"; -import { checkAndRemoveFile, deleteFolderRecursive, mkdirIfNotExists } from "../utils/file.js"; +import { checkAndRemoveFile, deleteFolderRecursive, getMediaFiles, mkdirIfNotExists } from "../utils/file.js"; import GeneralLinkAdapter from "../utils/general-link-adapter.js"; import { LagrangeAdapter } from "../utils/lagrange-adapter.js"; import { contentEstimator } from "../utils/link-share-summary-util.js"; import { getDS } from "../utils/mihoyo.js"; import { OpenaiBuilder } from "../utils/openai-builder.js"; +import { redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js"; +import { startTDL } from "../utils/tdl-util.js"; import Translate from "../utils/trans-strategy.js"; import { mid2id } from "../utils/weibo.js"; +import { dy2b } from "../utils/yt-dlp-util.js"; import { textArrayToMakeForward } from "../utils/yunzai-util.js"; export class tools extends plugin { @@ -186,6 +190,10 @@ export class tools extends plugin { { reg: "(qishui.douyin.com)", fnc: "qishuiMusic" + }, + { + reg: "(t.me)", + fnc: "aircraft" } ], }); @@ -626,7 +634,7 @@ export class tools extends plugin { // 检测是否开启BBDown if (this.biliUseBBDown) { // 检测环境的 BBDown - const isExistBBDown = await checkBBDown(); + const isExistBBDown = await checkToolInCurEnv("BBDown"); // 存在 BBDown if (isExistBBDown) { // 删除之前的文件 @@ -897,6 +905,10 @@ export class tools extends plugin { // 使用现有api解析小蓝鸟 async twitter_x(e) { + if (!(await this.isTrustUser(e.user_id))) { + e.reply("你没有权限使用此命令"); + return; + } // 配置参数及解析 const reg = /https?:\/\/x.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/; const twitterUrl = reg.exec(e.msg)[0]; @@ -1340,28 +1352,6 @@ export class tools extends plugin { return true } - /** - * yt-dlp工具类 - * @returns {Promise} - * @param path 下载路径 - * @param url 下载链接 - * @param isOversea 是否是海外用户 - */ - async dy2b(path, url, isOversea) { - return new Promise((resolve, reject) => { - const command = `yt-dlp ${ isOversea ? "" : `--proxy ${ this.myProxy }` } -P ${ path } -o "temp.%(ext)s" --merge-output-format "mp4" ${ url }`; - exec(command, (error, stdout) => { - if (error) { - console.error(`Error executing command: ${ error }`); - reject(error); - } else { - console.log(`Command output: ${ stdout }`); - resolve(stdout); - } - }); - }); - } - // 油管解析 async sy2b(e) { const isOversea = await this.isOverseasServer(); @@ -1382,7 +1372,7 @@ export class tools extends plugin { await checkAndRemoveFile(path + "/temp.mp4") const title = execSync(`yt-dlp --get-title ${ url } ${ isOversea ? "" : `--proxy ${ this.myProxy }` }`) e.reply(`识别:油管,视频下载中请耐心等待 \n${ title }`); - await this.dy2b(path, url, isOversea); + await dy2b(path, url, isOversea); this.sendVideoToUpload(e, `${ path }/temp.mp4`); } catch (error) { console.error(error); @@ -1697,7 +1687,7 @@ export class tools extends plugin { .setModel(this.aiModel) .setPrompt(SUMMARY_PROMPT) .build(); - e.reply(`识别:${ name },正在为您总结,请稍等...`, true, { recallMsg: 60 }); + e.reply(`识别:${ name },正在为您总结,请稍等...`, true, { recallMsg: MESSAGE_RECALL_TIME }); const { ans: kimiAns, model } = await builder.kimi(summaryLink); // 计算阅读时间 const stats = estimateReadingTime(kimiAns); @@ -1771,6 +1761,48 @@ export class tools extends plugin { return true; } + // TG下载 + async aircraft(e) { + if (!(await this.isTrustUser(e.user_id))) { + e.reply("你没有权限使用此命令"); + return; + } + const isOversea = await this.isOverseasServer(); + if (!isOversea && !(await testProxy(this.proxyAddr, this.proxyPort))) { + e.reply("检测到没有梯子,无法解析小飞机"); + return false; + } + const urlRex = /(?:https?:\/\/)?t\.me\/[A-Za-z\d._?%&+\-=\/#]*/g; + // 检查当前环境 + const isExistTdl = await checkToolInCurEnv("tdl"); + if (!isExistTdl) { + e.reply(`未检测到必要的环境,无法解析小飞机${HELP_DOC}`); + return; + } + const url = urlRex.exec(e.msg)[0]; + const tgSavePath = this.getCurDownloadPath(e); + await startTDL(url, tgSavePath, isOversea, this.myProxy); + e.reply(`识别:小飞机(学习版)`); + const mediaFiles = await getMediaFiles(tgSavePath); + if (mediaFiles.images.length > 0) { + const imagesData = mediaFiles.images.map(item => { + const fileContent = fs.readFileSync(`${tgSavePath}/${item}`); + return { + message: segment.image(fileContent), + nickname: e.sender.card || e.user_id, + user_id: e.user_id, + }; + }) + e.reply(await Bot.makeForwardMsg(imagesData), true, { recallMsg: MESSAGE_RECALL_TIME }); + } else if (mediaFiles.videos.length > 0) { + for (const item of mediaFiles.videos) { + await this.sendVideoToUpload(e, `${tgSavePath}/${item}`); + } + } + await deleteFolderRecursive(tgSavePath); + return true; + } + /** * 哔哩哔哩下载 * @param title @@ -2021,17 +2053,14 @@ export class tools extends plugin { */ async isOverseasServer() { // 如果第一次使用没有值就设置 - if (!(await redis.exists(REDIS_YUNZAI_ISOVERSEA))) { - await redis.set( - REDIS_YUNZAI_ISOVERSEA, - JSON.stringify({ - os: false, - }), - ); + if (!(await redisExistKey(REDIS_YUNZAI_ISOVERSEA))) { + await redisSetKey(REDIS_YUNZAI_ISOVERSEA, { + os: false, + }) return true; } // 如果有就取出来 - return JSON.parse((await redis.get(REDIS_YUNZAI_ISOVERSEA))).os; + return (await redis.get(REDIS_YUNZAI_ISOVERSEA)).os; } /** @@ -2040,17 +2069,28 @@ export class tools extends plugin { */ async isLagRangeDriver() { // 如果第一次使用没有值就设置 - if (!(await redis.exists(REDIS_YUNZAI_LAGRANGE))) { - await redis.set( - REDIS_YUNZAI_LAGRANGE, - JSON.stringify({ - driver: 0, - }), - ); + if (!(await redisExistKey(REDIS_YUNZAI_LAGRANGE))) { + await redisSetKey(REDIS_YUNZAI_LAGRANGE, { + driver: 0, + }); return true; } // 如果有就取出来 - return JSON.parse((await redis.get(REDIS_YUNZAI_LAGRANGE))).driver; + return (await redisGetKey(REDIS_YUNZAI_LAGRANGE)).driver; + } + + /** + * 判断当前用户是否是信任用户 + * @param userId + * @returns {Promise} + */ + async isTrustUser(userId) { + // 如果不存在则返回 + if (!(await redisExistKey(REDOS_YUNZAI_WHITELIST))) { + return false; + } + const whiteList = await redisGetKey(REDOS_YUNZAI_WHITELIST); + return whiteList.includes(userId); } /** diff --git a/config/help.yaml b/config/help.yaml index bcdebbe..47db1e3 100644 --- a/config/help.yaml +++ b/config/help.yaml @@ -80,6 +80,9 @@ - icon: spotify title: "Spotify" desc: 解析Spotify音乐 + - icon: telegram + title: "小飞机(学习版)" + desc: 解析小飞机 - group: 其他指令 list: - icon: update diff --git a/config/version.yaml b/config/version.yaml index 52b3113..c585ea0 100644 --- a/config/version.yaml +++ b/config/version.yaml @@ -1,10 +1,10 @@ - { - version: 1.7.4, + version: 1.8.0-beta, data: [ + 新增小飞机解析 Beta功能, 新增BBDown更换CDN功能, 新增Aria2下载选项功能, - 新增最大上传限制选项功能, 支持锅巴插件,方便查看和修改配置, 输入#R帮助获取插件帮助, 输入#R更新更新插件, diff --git a/constants/constant.js b/constants/constant.js index 72d9c83..b3e9ca0 100644 --- a/constants/constant.js +++ b/constants/constant.js @@ -80,6 +80,12 @@ export const REDIS_YUNZAI_ISOVERSEA = "Yz:rconsole:tools:oversea"; */ export const REDIS_YUNZAI_LAGRANGE = "Yz:rconsole:tools:lagrange"; +/** + * 某些功能的解析白名单 + * @type {string} + */ +export const REDOS_YUNZAI_WHITELIST = "Yz:rconsole:tools:whitelist"; + export const TWITTER_BEARER_TOKEN = ""; /** @@ -132,4 +138,10 @@ export const BILI_DOWNLOAD_METHOD = Object.freeze([ { label: '稳定(原生)', value: 0 }, { label: '性能(Aria2)', value: 1 }, { label: '轻量(axel/wget)', value: 2 } -]); \ No newline at end of file +]); + +/** + * 消息撤回时间 + * @type {number} + */ +export const MESSAGE_RECALL_TIME = 60; \ No newline at end of file diff --git a/resources/img/icon/telegram.png b/resources/img/icon/telegram.png new file mode 100644 index 0000000000000000000000000000000000000000..90b5654032c5585e805bacfdaeb568b00c42f55f GIT binary patch literal 4293 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 { - const command = os.platform() === 'win32' ? 'where BBDown' : 'which BBDown'; - - exec(command, (error, stdout, stderr) => { - if (error) { - logger.error(`[R插件][BBDown]未找到: ${stderr || error.message}`); - resolve(false); - return; - } - logger.info(`[R插件][BBDown]找到: ${stdout.trim()}`); - resolve(true); - }); - }); -} /** * 使用BBDown下载 diff --git a/utils/common.js b/utils/common.js index edc56ac..8dec678 100644 --- a/utils/common.js +++ b/utils/common.js @@ -1,12 +1,13 @@ -import schedule from "node-schedule"; -import common from "../../../lib/common/common.js"; import axios from "axios"; -import fs from "node:fs"; -import fetch from "node-fetch"; -import { mkdirIfNotExists } from "./file.js"; -import { TEN_THOUSAND } from "../constants/constant.js"; import { exec } from "child_process"; import { HttpsProxyAgent } from 'https-proxy-agent'; +import fetch from "node-fetch"; +import schedule from "node-schedule"; +import fs from "node:fs"; +import os from "os"; +import common from "../../../lib/common/common.js"; +import { TEN_THOUSAND } from "../constants/constant.js"; +import { mkdirIfNotExists } from "./file.js"; /** * 请求模板 @@ -454,4 +455,26 @@ export function cleanFilename(filename) { filename = filename.trim(); return filename; +} + +/** + * 检测当前环境是否存在某个命令 + * @param someCommand + * @returns {Promise} + */ +export function checkToolInCurEnv(someCommand) { + // 根据操作系统选择命令 + return new Promise((resolve, reject) => { + const command = os.platform() === 'win32' ? `where ${someCommand}` : `which ${someCommand}`; + + exec(command, (error, stdout, stderr) => { + if (error) { + logger.error(`[R插件][checkTool]未找到${someCommand}: ${stderr || error.message}`); + resolve(false); + return; + } + logger.info(`[R插件][checkTool]找到${someCommand}: ${stdout.trim()}`); + resolve(true); + }); + }); } \ No newline at end of file diff --git a/utils/file.js b/utils/file.js index 6db261b..c0f1f01 100644 --- a/utils/file.js +++ b/utils/file.js @@ -139,3 +139,40 @@ function getMimeType(filePath) { const ext = filePath.substring(filePath.lastIndexOf('.')).toLowerCase(); return mimeTypes[ext] || 'application/octet-stream'; } + +/** + * 获取文件夹中的图片和视频文件 + * @param {string} folderPath - 要检测的文件夹路径 + * @returns {Promise} 包含图片和视频文件名的对象 + */ +export async function getMediaFiles(folderPath) { + return new Promise((resolve, reject) => { + // 定义图片和视频的扩展名 + const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']; + const videoExtensions = ['.mp4', '.mkv', '.avi', '.mov', '.wmv', '.flv', '.webm']; + + // 初始化存储图片和视频的数组 + const images = []; + const videos = []; + + // 读取文件夹中的所有文件 + fs.readdir(folderPath, (err, files) => { + if (err) { + return reject('无法读取文件夹: ' + err); + } + + files.forEach(file => { + const ext = path.extname(file).toLowerCase(); + + if (imageExtensions.includes(ext)) { + images.push(file); + } else if (videoExtensions.includes(ext)) { + videos.push(file); + } + }); + + // 返回包含图片和视频的对象 + resolve({ images, videos }); + }); + }); +} \ No newline at end of file diff --git a/utils/redis-util.js b/utils/redis-util.js new file mode 100644 index 0000000..34427a5 --- /dev/null +++ b/utils/redis-util.js @@ -0,0 +1,42 @@ +/** + * 判断某个key是否存在 + * @param key + * @returns {Promise} + */ +export async function redisExistKey(key) { + return redis.exists(key); +} + +/** + * 获取某个key的值 + * @param key + * @returns {Promise} + */ +export async function redisGetKey(key) { + return JSON.parse(await redis.get(key)); +} + +/** + * 为某个key设置值,value必须是个键值对 + * @param key + * @param value + * @returns {Promise<*>} + */ +export async function redisSetKey(key, value = {}) { + return redis.set( + key, + JSON.stringify(value), + ); +} + +/** + * 判断是否存在这个key然后再取值,如果没有就返回null + * @param key + * @returns {Promise} + */ +export async function redisExistAndGetKey(key) { + if (await redisExistKey(key)) { + return redisGetKey(key); + } + return null; +} \ No newline at end of file diff --git a/utils/tdl-util.js b/utils/tdl-util.js new file mode 100644 index 0000000..b1e167c --- /dev/null +++ b/utils/tdl-util.js @@ -0,0 +1,29 @@ +import { exec } from 'child_process'; +import path from 'path' + +/** + * 执行 TDL 进行下载 + * @param url + * @param curPath + * @param isOversea + * @param proxyAddr + * @returns {Promise} + */ +export async function startTDL(url, curPath, isOversea, proxyAddr) { + return new Promise((resolve, reject) => { + curPath = path.resolve(curPath); + const proxyStr = isOversea ? `` : `--proxy ${ proxyAddr }`; + const command = `tdl dl -u ${url} -d ${curPath} ${proxyStr}` + exec(command, (error, stdout, stderr) => { + if (error) { + reject(`[R插件][TDL]执行出错: ${error.message}`); + return; + } + if (stderr) { + reject(`[R插件][TDL]错误信息: ${stderr}`); + return; + } + resolve(stdout); + }) + }) +} \ No newline at end of file diff --git a/utils/y2b.js b/utils/y2b.js deleted file mode 100644 index b4c1e60..0000000 --- a/utils/y2b.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * y2b 音频信息 - * @param id - * @param format - * @param rate - * @param info - * @param size - * @returns {{size: (string|*), rate: (string|*), format, id, info}} - */ -export function getAudio(id, format, rate, info, size) { - return { id, format, rate: rate == 0 ? '未知' : rate, info, size: size == 0 ? '未知' : size }; -} - -/** - * y2b 视频信息 - * @param id - * @param format - * @param scale - * @param frame - * @param rate - * @param info - * @param size - * @returns {{size: (string|*), rate: (string|*), format, scale, id, frame, info}} - */ -export function getVideo(id, format, scale, frame, rate, info, size) { - return { id, format, scale, frame, rate: rate == 0 ? '未知' : rate, info, size: size == 0 ? '未知' : size }; -} \ No newline at end of file diff --git a/utils/yt-dlp-util.js b/utils/yt-dlp-util.js new file mode 100644 index 0000000..cc2a748 --- /dev/null +++ b/utils/yt-dlp-util.js @@ -0,0 +1,21 @@ +/** + * yt-dlp工具类 + * @returns {Promise} + * @param path 下载路径 + * @param url 下载链接 + * @param isOversea 是否是海外用户 + */ +export async function dy2b(path, url, isOversea) { + return new Promise((resolve, reject) => { + const command = `yt-dlp ${ isOversea ? "" : `--proxy ${ this.myProxy }` } -P ${ path } -o "temp.%(ext)s" --merge-output-format "mp4" ${ url }`; + exec(command, (error, stdout) => { + if (error) { + console.error(`Error executing command: ${ error }`); + reject(error); + } else { + console.log(`Command output: ${ stdout }`); + resolve(stdout); + } + }); + }); +} \ No newline at end of file