🌟 feat: 添加主人不用设置权限

This commit is contained in:
zhiyu1998 2024-09-30 11:09:19 +08:00
parent b5a777e499
commit b9bb9bd934

View File

@ -124,7 +124,7 @@ export class tools extends plugin {
priority: 300, priority: 300,
rule: [ rule: [
{ {
reg: `^(翻|trans)[${ tools.Constants.existsTransKey }]`, reg: `^(翻|trans)[${tools.Constants.existsTransKey}]`,
fnc: "trans", fnc: "trans",
}, },
{ {
@ -227,7 +227,7 @@ export class tools extends plugin {
// 魔法接口 // 魔法接口
this.proxyAddr = this.toolsConfig.proxyAddr; this.proxyAddr = this.toolsConfig.proxyAddr;
this.proxyPort = this.toolsConfig.proxyPort; this.proxyPort = this.toolsConfig.proxyPort;
this.myProxy = `http://${ this.proxyAddr }:${ this.proxyPort }`; this.myProxy = `http://${this.proxyAddr}:${this.proxyPort}`;
// 加载识别前缀 // 加载识别前缀
this.identifyPrefix = this.toolsConfig.identifyPrefix; this.identifyPrefix = this.toolsConfig.identifyPrefix;
// 加载哔哩哔哩配置 // 加载哔哩哔哩配置
@ -311,7 +311,7 @@ export class tools extends plugin {
const res = await this.douyinRequest(douUrl); const res = await this.douyinRequest(douUrl);
// 当前版本需要填入cookie // 当前版本需要填入cookie
if (_.isEmpty(this.douyinCookie)) { if (_.isEmpty(this.douyinCookie)) {
e.reply(`检测到没有Cookie无法解析抖音${ HELP_DOC }`); e.reply(`检测到没有Cookie无法解析抖音${HELP_DOC}`);
return; return;
} }
const douId = /note\/(\d+)/g.exec(res)?.[1] || /video\/(\d+)/g.exec(res)?.[1]; const douId = /note\/(\d+)/g.exec(res)?.[1] || /video\/(\d+)/g.exec(res)?.[1];
@ -332,8 +332,8 @@ export class tools extends plugin {
headers["User-Agent"], headers["User-Agent"],
); );
// const param = resp.data.result[0].paramsencode; // const param = resp.data.result[0].paramsencode;
const resDyApi = `${ dyApi }&a_bogus=${ abParam }`; const resDyApi = `${dyApi}&a_bogus=${abParam}`;
headers['Referer'] = `https://www.douyin.com/video/${ douId }` headers['Referer'] = `https://www.douyin.com/video/${douId}`
// 定义一个dy请求 // 定义一个dy请求
const dyResponse = () => axios.get(resDyApi, { const dyResponse = () => axios.get(resDyApi, {
headers, headers,
@ -360,20 +360,20 @@ export class tools extends plugin {
const dyDuration = Math.trunc(duration / 1000); const dyDuration = Math.trunc(duration / 1000);
const durationThreshold = this.biliDuration; const durationThreshold = this.biliDuration;
// 一些共同发送内容 // 一些共同发送内容
let dySendContent = `${ this.identifyPrefix }识别:抖音,${ item.author.nickname }\n📝 简介:${ item.desc }`; let dySendContent = `${this.identifyPrefix}识别:抖音,${item.author.nickname}\n📝 简介:${item.desc}`;
if (dyDuration >= durationThreshold) { if (dyDuration >= durationThreshold) {
// 超过阈值,不发送的情况 // 超过阈值,不发送的情况
// 封面 // 封面
const dyCover = cover.url_list?.pop(); const dyCover = cover.url_list?.pop();
// logger.info(cover.url_list); // logger.info(cover.url_list);
dySendContent += `\n dySendContent += `\n
${ DIVIDING_LINE.replace('{}', '限制说明') }\n当前视频时长约${ Math.trunc(dyDuration / 60) }分钟\n大于管理员设置的最大时长 ${ durationThreshold / 60 } 分钟`; ${DIVIDING_LINE.replace('{}', '限制说明')}\n当前视频时长约${Math.trunc(dyDuration / 60)}分钟\n大于管理员设置的最大时长 ${durationThreshold / 60} 分钟`;
e.reply([segment.image(dyCover), dySendContent]); e.reply([segment.image(dyCover), dySendContent]);
// 如果开启评论的就调用 // 如果开启评论的就调用
await this.douyinComment(e, douId, headers); await this.douyinComment(e, douId, headers);
return; return;
} }
e.reply(`${ dySendContent }`); e.reply(`${dySendContent}`);
// 分辨率判断是否压缩 // 分辨率判断是否压缩
const resolution = this.douyinCompression ? "720p" : "1080p"; const resolution = this.douyinCompression ? "720p" : "1080p";
// 使用今日头条 CDN 进一步加快解析速度 // 使用今日头条 CDN 进一步加快解析速度
@ -392,14 +392,14 @@ export class tools extends plugin {
}*/ }*/
// logger.info(resUrl); // logger.info(resUrl);
const path = `${ this.getCurDownloadPath(e) }/temp.mp4`; const path = `${this.getCurDownloadPath(e)}/temp.mp4`;
// 加入队列 // 加入队列
await this.downloadVideo(resUrl).then(() => { await this.downloadVideo(resUrl).then(() => {
this.sendVideoToUpload(e, path) this.sendVideoToUpload(e, path)
}); });
} else if (urlType === "image") { } else if (urlType === "image") {
// 发送描述 // 发送描述
e.reply(`${ this.identifyPrefix }识别:抖音, ${ item.desc }`); e.reply(`${this.identifyPrefix}识别:抖音, ${item.desc}`);
// 无水印图片列表 // 无水印图片列表
let no_watermark_image_list = []; let no_watermark_image_list = [];
// 有水印图片列表 // 有水印图片列表
@ -422,7 +422,7 @@ export class tools extends plugin {
await this.douyinComment(e, douId, headers); await this.douyinComment(e, douId, headers);
} catch (err) { } catch (err) {
logger.error(err); logger.error(err);
logger.mark(`Cookie 过期或者 Cookie 没有填写,请参考\n${ HELP_DOC }\n尝试无效后可以到官方QQ群[575663150]提出 bug 等待解决`) logger.mark(`Cookie 过期或者 Cookie 没有填写,请参考\n${HELP_DOC}\n尝试无效后可以到官方QQ群[575663150]提出 bug 等待解决`)
} }
return true; return true;
} }
@ -442,7 +442,7 @@ export class tools extends plugin {
new URLSearchParams(new URL(dyCommentUrl).search).toString(), new URLSearchParams(new URL(dyCommentUrl).search).toString(),
headers["User-Agent"], headers["User-Agent"],
); );
const commentsResp = await axios.get(`${ dyCommentUrl }&a_bogus=${ abParam }`, { const commentsResp = await axios.get(`${dyCommentUrl}&a_bogus=${abParam}`, {
headers headers
}) })
// logger.info(headers) // logger.info(headers)
@ -477,9 +477,9 @@ export class tools extends plugin {
const path = this.getCurDownloadPath(e); const path = this.getCurDownloadPath(e);
await checkAndRemoveFile(path + "/temp.mp4"); await checkAndRemoveFile(path + "/temp.mp4");
const title = ytDlpGetTilt(url, isOversea, this.myProxy); const title = ytDlpGetTilt(url, isOversea, this.myProxy);
e.reply(`${ this.identifyPrefix }识别TikTok视频下载中请耐心等待 \n${ title }`); e.reply(`${this.identifyPrefix}识别TikTok视频下载中请耐心等待 \n${title}`);
await ytDlpHelper(path, cleanedTiktokUrl, isOversea, this.myProxy); await ytDlpHelper(path, cleanedTiktokUrl, isOversea, this.myProxy);
await this.sendVideoToUpload(e, `${ path }/temp.mp4`); await this.sendVideoToUpload(e, `${path}/temp.mp4`);
return true; return true;
} }
@ -494,7 +494,7 @@ export class tools extends plugin {
// 检查路径是否存在文件夹 // 检查路径是否存在文件夹
await mkdirIfNotExists(this.defaultPath); await mkdirIfNotExists(this.defaultPath);
// 发送请求 // 发送请求
const saveCodePath = `${ this.defaultPath }qrcode.png`; const saveCodePath = `${this.defaultPath}qrcode.png`;
const { SESSDATA, refresh_token } = await getScanCodeData(saveCodePath, 8, () => imgSendHook(e, saveCodePath)) const { SESSDATA, refresh_token } = await getScanCodeData(saveCodePath, 8, () => imgSendHook(e, saveCodePath))
@ -511,7 +511,7 @@ export class tools extends plugin {
let url = e.msg === undefined ? e.message.shift().data.replaceAll("\\", "") : e.msg.trim().replaceAll("\\", ""); let url = e.msg === undefined ? e.message.shift().data.replaceAll("\\", "") : e.msg.trim().replaceAll("\\", "");
// 直接发送BV号的处理 // 直接发送BV号的处理
if (/^BV[1-9a-zA-Z]{10}$/.exec(url)?.[0]) { if (/^BV[1-9a-zA-Z]{10}$/.exec(url)?.[0]) {
url = `https://www.bilibili.com/video/${ url }`; url = `https://www.bilibili.com/video/${url}`;
logger.info(url) logger.info(url)
} }
// 短号处理 // 短号处理
@ -547,7 +547,7 @@ export class tools extends plugin {
e.reply([ e.reply([
segment.image(user_cover), segment.image(user_cover),
segment.image(keyframe), segment.image(keyframe),
`${ this.identifyPrefix }识别:哔哩哔哩直播,${ title }${ description ? `\n\n简述:${ description }\n` : '' }${ tags ? `标签:${ tags }\n` : '' }` `${this.identifyPrefix}识别:哔哩哔哩直播,${title}${description ? `\n\n简述:${description}\n` : ''}${tags ? `标签:${tags}\n` : ''}`
]); ]);
return true; return true;
} }
@ -566,7 +566,7 @@ export class tools extends plugin {
return true; return true;
} }
// 创建文件,如果不存在, // 创建文件,如果不存在,
const path = `${ this.getCurDownloadPath(e) }/`; const path = `${this.getCurDownloadPath(e)}/`;
await mkdirIfNotExists(path); await mkdirIfNotExists(path);
// 处理番剧 // 处理番剧
if (url.includes("play\/ep") || url.includes("play\/ss")) { if (url.includes("play\/ep") || url.includes("play\/ss")) {
@ -574,7 +574,7 @@ export class tools extends plugin {
// 如果使用了BBDown && 没有填写session 就放开下载 // 如果使用了BBDown && 没有填写session 就放开下载
if (this.biliUseBBDown) { if (this.biliUseBBDown) {
// 下载文件 // 下载文件
await this.biliDownloadStrategy(e, `https://www.bilibili.com/bangumi/play/ep${ ep }`, path); await this.biliDownloadStrategy(e, `https://www.bilibili.com/bangumi/play/ep${ep}`, path);
} }
return true; return true;
} }
@ -598,7 +598,7 @@ export class tools extends plugin {
// 限制视频解析 // 限制视频解析
if (isLimitDuration) { if (isLimitDuration) {
const durationInMinutes = (curDuration / 60).toFixed(0); const durationInMinutes = (curDuration / 60).toFixed(0);
biliInfo.push(`${ DIVIDING_LINE.replace('{}', '限制说明') }\n当前视频时长约:${ durationInMinutes }分钟,\n大于管理员设置的最大时长 ${ this.biliDuration / 60 } 分钟!`); biliInfo.push(`${DIVIDING_LINE.replace('{}', '限制说明')}\n当前视频时长约:${durationInMinutes}分钟,\n大于管理员设置的最大时长 ${this.biliDuration / 60} 分钟!`);
e.reply(biliInfo); e.reply(biliInfo);
return true; return true;
} else { } else {
@ -636,21 +636,21 @@ export class tools extends plugin {
"弹幕数量": danmaku, "弹幕数量": danmaku,
"评论": reply "评论": reply
}; };
combineContent += `\n${ formatBiliInfo(dataProcessMap) }`; combineContent += `\n${formatBiliInfo(dataProcessMap)}`;
} }
// 是否显示简介 // 是否显示简介
if (this.biliDisplayIntro) { if (this.biliDisplayIntro) {
// 过滤简介中的一些链接 // 过滤简介中的一些链接
const filteredDesc = await filterBiliDescLink(desc); const filteredDesc = await filterBiliDescLink(desc);
combineContent += `\n📝 简介:${ truncateString(filteredDesc, this.toolsConfig.biliIntroLenLimit || BILI_DEFAULT_INTRO_LEN_LIMIT) }`; combineContent += `\n📝 简介:${truncateString(filteredDesc, this.toolsConfig.biliIntroLenLimit || BILI_DEFAULT_INTRO_LEN_LIMIT)}`;
} }
// 是否显示在线人数 // 是否显示在线人数
if (this.biliDisplayOnline) { if (this.biliDisplayOnline) {
// 拼接在线人数 // 拼接在线人数
const onlineTotal = await this.biliOnlineTotal(bvid, cid); const onlineTotal = await this.biliOnlineTotal(bvid, cid);
combineContent += `\n🏄‍♂️️ 当前视频有 ${ onlineTotal.total } 人在观看,其中 ${ onlineTotal.count } 人在网页端观看`; combineContent += `\n🏄‍♂️️ 当前视频有 ${onlineTotal.total} 人在观看,其中 ${onlineTotal.count} 人在网页端观看`;
} }
let biliInfo = [`${ this.identifyPrefix }识别:哔哩哔哩:${ title }`, combineContent] let biliInfo = [`${this.identifyPrefix}识别:哔哩哔哩:${title}`, combineContent]
// 是否显示封面 // 是否显示封面
if (this.biliDisplayCover) { if (this.biliDisplayCover) {
// 加入图片 // 加入图片
@ -697,10 +697,10 @@ export class tools extends plugin {
const title = result.title; const title = result.title;
e.reply([ e.reply([
segment.image(resp.result.cover), segment.image(resp.result.cover),
`${ this.identifyPrefix }识别:哔哩哔哩番剧,${ title }\n🎯 评分: ${ result?.rating?.score ?? '-' } / ${ result?.rating?.count ?? '-' }\n📺 ${ result.new_ep.desc }, ${ result.seasons[0].new_ep.index_show }\n`, `${this.identifyPrefix}识别:哔哩哔哩番剧,${title}\n🎯 评分: ${result?.rating?.score ?? '-'} / ${result?.rating?.count ?? '-'}\n📺 ${result.new_ep.desc}, ${result.seasons[0].new_ep.index_show}\n`,
`${ formatBiliInfo(dataProcessMap) }`, `${formatBiliInfo(dataProcessMap)}`,
`\n\n🪶 在线观看: ${ await urlTransformShortLink(ANIME_SERIES_SEARCH_LINK + title) }`, `\n\n🪶 在线观看: ${await urlTransformShortLink(ANIME_SERIES_SEARCH_LINK + title)}`,
`\n🌸 在线观看: ${ await urlTransformShortLink(ANIME_SERIES_SEARCH_LINK2 + title) }` `\n🌸 在线观看: ${await urlTransformShortLink(ANIME_SERIES_SEARCH_LINK2 + title)}`
], true); ], true);
return ep; return ep;
} }
@ -716,7 +716,7 @@ export class tools extends plugin {
return this.queue.add(async () => { return this.queue.add(async () => {
// =================以下是调用BBDown的逻辑===================== // =================以下是调用BBDown的逻辑=====================
// 下载视频和音频 // 下载视频和音频
const tempPath = `${ path }temp`; const tempPath = `${path}temp`;
// 检测是否开启BBDown // 检测是否开启BBDown
if (this.biliUseBBDown) { if (this.biliUseBBDown) {
// 检测环境的 BBDown // 检测环境的 BBDown
@ -724,7 +724,7 @@ export class tools extends plugin {
// 存在 BBDown // 存在 BBDown
if (isExistBBDown) { if (isExistBBDown) {
// 删除之前的文件 // 删除之前的文件
await checkAndRemoveFile(`${ tempPath }.mp4`); await checkAndRemoveFile(`${tempPath}.mp4`);
// 下载视频 // 下载视频
await startBBDown(url, path, { await startBBDown(url, path, {
biliSessData: this.biliSessData, biliSessData: this.biliSessData,
@ -733,7 +733,7 @@ export class tools extends plugin {
biliResolution: this.biliResolution, biliResolution: this.biliResolution,
}); });
// 发送视频 // 发送视频
return this.sendVideoToUpload(e, `${ tempPath }.mp4`); return this.sendVideoToUpload(e, `${tempPath}.mp4`);
} }
e.reply("🚧 R插件提醒你开启但未检测到当前环境有【BBDown】即将使用默认下载方式 ( ◡̀_◡́)ᕤ"); e.reply("🚧 R插件提醒你开启但未检测到当前环境有【BBDown】即将使用默认下载方式 ( ◡̀_◡́)ᕤ");
} }
@ -745,7 +745,7 @@ export class tools extends plugin {
await this.downBili(tempPath, data.videoUrl, data.audioUrl); await this.downBili(tempPath, data.videoUrl, data.audioUrl);
// 上传视频 // 上传视频
return this.sendVideoToUpload(e, `${ tempPath }.mp4`); return this.sendVideoToUpload(e, `${tempPath}.mp4`);
} catch (err) { } catch (err) {
// 错误处理 // 错误处理
logger.error('[R插件][哔哩哔哩视频发送]下载错误,具体原因为:', err); logger.error('[R插件][哔哩哔哩视频发送]下载错误,具体原因为:', err);
@ -794,7 +794,7 @@ export class tools extends plugin {
const dynamicId = /[^/]+(?!.*\/)/.exec(url)[0]; const dynamicId = /[^/]+(?!.*\/)/.exec(url)[0];
getDynamic(dynamicId, session).then(async resp => { getDynamic(dynamicId, session).then(async resp => {
if (resp.dynamicSrc.length > 0) { if (resp.dynamicSrc.length > 0) {
e.reply(`${ this.identifyPrefix }识别:哔哩哔哩动态, ${ resp.dynamicDesc }`); e.reply(`${this.identifyPrefix}识别:哔哩哔哩动态, ${resp.dynamicDesc}`);
let dynamicSrcMsg = []; let dynamicSrcMsg = [];
resp.dynamicSrc.forEach(item => { resp.dynamicSrc.forEach(item => {
dynamicSrcMsg.push({ dynamicSrcMsg.push({
@ -827,7 +827,7 @@ export class tools extends plugin {
wbi = await getWbi({ bvid, cid, up_mid }, this.biliSessData); wbi = await getWbi({ bvid, cid, up_mid }, this.biliSessData);
} }
// 构造API // 构造API
const summaryUrl = `${ BILI_SUMMARY }?${ wbi }`; const summaryUrl = `${BILI_SUMMARY}?${wbi}`;
logger.info(summaryUrl) logger.info(summaryUrl)
// 构造结果https://api.bilibili.com/x/web-interface/view/conclusion/get?bvid=BV1L94y1H7CV&cid=1335073288&up_mid=297242063&wts=1701546363&w_rid=1073871926b3ccd99bd790f0162af634 // 构造结果https://api.bilibili.com/x/web-interface/view/conclusion/get?bvid=BV1L94y1H7CV&cid=1335073288&up_mid=297242063&wts=1701546363&w_rid=1073871926b3ccd99bd790f0162af634
return axios.get(summaryUrl) return axios.get(summaryUrl)
@ -839,7 +839,7 @@ export class tools extends plugin {
let resReply = ""; let resReply = "";
// 总体总结 // 总体总结
if (summary) { if (summary) {
resReply = `\n摘要:${ summary }\n` resReply = `\n摘要:${summary}\n`
} }
// 分段总结 // 分段总结
if (outline) { if (outline) {
@ -850,9 +850,9 @@ export class tools extends plugin {
const specificContent = keyPoint.map(point => { const specificContent = keyPoint.map(point => {
const { timestamp, content } = point const { timestamp, content } = point
const specificTime = secondsToTime(timestamp) const specificTime = secondsToTime(timestamp)
return `${ specificTime } ${ content }\n`; return `${specificTime} ${content}\n`;
}).join(""); }).join("");
return `- ${ smallTitle }\n${ specificContent }\n`; return `- ${smallTitle}\n${specificContent}\n`;
}); });
resReply += specificTimeSummary.join(""); resReply += specificTimeSummary.join("");
} }
@ -866,7 +866,7 @@ export class tools extends plugin {
* @returns {Promise<*>} * @returns {Promise<*>}
*/ */
async getBiliStream(liveId) { async getBiliStream(liveId) {
return axios.get(`${ BILI_STREAM_INFO }?room_id=${ liveId }`, { return axios.get(`${BILI_STREAM_INFO}?room_id=${liveId}`, {
headers: { headers: {
'User-Agent': COMMON_USER_AGENT, 'User-Agent': COMMON_USER_AGENT,
} }
@ -895,14 +895,14 @@ export class tools extends plugin {
await fetch(TWITTER_TWEET_INFO.replace("{}", id), { await fetch(TWITTER_TWEET_INFO.replace("{}", id), {
headers: { headers: {
"User-Agent": "v2TweetLookupJS", "User-Agent": "v2TweetLookupJS",
"authorization": `Bearer ${ Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString() }` "authorization": `Bearer ${Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString()}`
}, },
...params, ...params,
agent: !isOversea ? '' : new HttpsProxyAgent(this.myProxy), agent: !isOversea ? '' : new HttpsProxyAgent(this.myProxy),
}).then(async resp => { }).then(async resp => {
logger.info(resp) logger.info(resp)
e.reply(`${ this.identifyPrefix }识别:小蓝鸟学习版,${ resp.data.text }`); e.reply(`${this.identifyPrefix}识别:小蓝鸟学习版,${resp.data.text}`);
const downloadPath = `${ this.getCurDownloadPath(e) }`; const downloadPath = `${this.getCurDownloadPath(e)}`;
// 创建文件夹(如果没有过这个群) // 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) { if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath); mkdirsSync(downloadPath);
@ -917,7 +917,7 @@ export class tools extends plugin {
// 视频 // 视频
await this.downloadVideo(resp.includes.media[0].variants[0].url, true).then( await this.downloadVideo(resp.includes.media[0].variants[0].url, true).then(
_ => { _ => {
e.reply(segment.video(`${ downloadPath }/temp.mp4`)); e.reply(segment.video(`${downloadPath}/temp.mp4`));
}, },
); );
} }
@ -967,7 +967,7 @@ export class tools extends plugin {
} }
// 提取视频 // 提取视频
let videoUrl = GENERAL_REQ_LINK.link.replace("{}", twitterUrl); let videoUrl = GENERAL_REQ_LINK.link.replace("{}", twitterUrl);
e.reply(`${ this.identifyPrefix }识别:小蓝鸟学习版`); e.reply(`${this.identifyPrefix}识别:小蓝鸟学习版`);
const config = { const config = {
headers: { headers: {
'Accept': 'ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Accept': 'ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
@ -1017,24 +1017,24 @@ export class tools extends plugin {
// acfun解析 // acfun解析
async acfun(e) { async acfun(e) {
const path = `${ this.getCurDownloadPath(e) }/temp/`; const path = `${this.getCurDownloadPath(e)}/temp/`;
await mkdirIfNotExists(path); await mkdirIfNotExists(path);
let inputMsg = e.msg; let inputMsg = e.msg;
// 适配手机分享https://m.acfun.cn/v/?ac=32838812&sid=d2b0991bd6ad9c09 // 适配手机分享https://m.acfun.cn/v/?ac=32838812&sid=d2b0991bd6ad9c09
if (inputMsg.includes("m.acfun.cn")) { if (inputMsg.includes("m.acfun.cn")) {
inputMsg = `https://www.acfun.cn/v/ac${ /ac=([^&?]*)/.exec(inputMsg)[1] }`; inputMsg = `https://www.acfun.cn/v/ac${/ac=([^&?]*)/.exec(inputMsg)[1]}`;
} else if (inputMsg.includes("ac")) { } else if (inputMsg.includes("ac")) {
// 如果是 // 如果是
inputMsg = "https://www.acfun.cn/v/" + /ac\d+/.exec(inputMsg)[0]; inputMsg = "https://www.acfun.cn/v/" + /ac\d+/.exec(inputMsg)[0];
} }
parseUrl(inputMsg).then(res => { parseUrl(inputMsg).then(res => {
e.reply(`${ this.identifyPrefix }识别:猴山,${ res.videoName }`); e.reply(`${this.identifyPrefix}识别:猴山,${res.videoName}`);
parseM3u8(res.urlM3u8s[res.urlM3u8s.length - 1]).then(res2 => { parseM3u8(res.urlM3u8s[res.urlM3u8s.length - 1]).then(res2 => {
downloadM3u8Videos(res2.m3u8FullUrls, path).then(_ => { downloadM3u8Videos(res2.m3u8FullUrls, path).then(_ => {
mergeAcFileToMp4(res2.tsNames, path, `${ path }out.mp4`).then(_ => { mergeAcFileToMp4(res2.tsNames, path, `${path}out.mp4`).then(_ => {
this.sendVideoToUpload(e, `${ path }out.mp4`) this.sendVideoToUpload(e, `${path}out.mp4`)
}); });
}); });
}); });
@ -1076,14 +1076,14 @@ export class tools extends plugin {
} else { } else {
id = /explore\/(\w+)/.exec(msgUrl)?.[1] || /discovery\/item\/(\w+)/.exec(msgUrl)?.[1]; id = /explore\/(\w+)/.exec(msgUrl)?.[1] || /discovery\/item\/(\w+)/.exec(msgUrl)?.[1];
} }
const downloadPath = `${ this.getCurDownloadPath(e) }`; const downloadPath = `${this.getCurDownloadPath(e)}`;
// 检测没有 cookie 则退出 // 检测没有 cookie 则退出
if (_.isEmpty(this.xiaohongshuCookie)) { if (_.isEmpty(this.xiaohongshuCookie)) {
e.reply(`2024-8-2后反馈必须使用ck不然无法解析请填写相关ck\n${ HELP_DOC }`); e.reply(`2024-8-2后反馈必须使用ck不然无法解析请填写相关ck\n${HELP_DOC}`);
return; return;
} }
// 获取信息 // 获取信息
fetch(`${ XHS_REQ_LINK }${ id }`, { fetch(`${XHS_REQ_LINK}${id}`, {
headers: XHS_NO_WATERMARK_HEADER, headers: XHS_NO_WATERMARK_HEADER,
}).then(async resp => { }).then(async resp => {
const xhsHtml = await resp.text(); const xhsHtml = await resp.text();
@ -1095,7 +1095,7 @@ export class tools extends plugin {
if (type === "video") { if (type === "video") {
// 封面 // 封面
const cover = noteData.imageList?.[0].urlDefault; const cover = noteData.imageList?.[0].urlDefault;
e.reply([segment.image(cover), `${ this.identifyPrefix }识别:小红书, ${ title }\n${ desc }`]); e.reply([segment.image(cover), `${this.identifyPrefix}识别:小红书, ${title}\n${desc}`]);
// ⚠️ 暂时废弃构造xhs视频链接有水印 // ⚠️ 暂时废弃构造xhs视频链接有水印
const xhsVideoUrl = noteData.video.media.stream.h264?.[0]?.masterUrl; const xhsVideoUrl = noteData.video.media.stream.h264?.[0]?.masterUrl;
@ -1105,20 +1105,20 @@ export class tools extends plugin {
this.downloadVideo(xhsVideoUrl).then(path => { this.downloadVideo(xhsVideoUrl).then(path => {
if (path === undefined) { if (path === undefined) {
// 创建文件,如果不存在 // 创建文件,如果不存在
path = `${ this.getCurDownloadPath(e) }/`; path = `${this.getCurDownloadPath(e)}/`;
} }
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
return true; return true;
} else if (type === "normal") { } else if (type === "normal") {
e.reply(`${ this.identifyPrefix }识别:小红书, ${ title }\n${ desc }`); e.reply(`${this.identifyPrefix}识别:小红书, ${title}\n${desc}`);
const imagePromises = []; const imagePromises = [];
// 使用 for..of 循环处理异步下载操作 // 使用 for..of 循环处理异步下载操作
for (let [index, item] of noteData.imageList.entries()) { for (let [index, item] of noteData.imageList.entries()) {
imagePromises.push(downloadImg({ imagePromises.push(downloadImg({
img: item.urlDefault, img: item.urlDefault,
dir: downloadPath, dir: downloadPath,
fileName: `${ index }.png`, fileName: `${index}.png`,
downloadMethod: this.biliDownloadMethod, downloadMethod: this.biliDownloadMethod,
})); }));
} }
@ -1153,14 +1153,14 @@ export class tools extends plugin {
/(?=mvId).*?(?=&)/.exec(e.msg.trim())?.[0].replace("mvId=", ""); /(?=mvId).*?(?=&)/.exec(e.msg.trim())?.[0].replace("mvId=", "");
const { name, album, artist, albumPic120, categorys } = await getBodianMusicInfo(id); const { name, album, artist, albumPic120, categorys } = await getBodianMusicInfo(id);
e.reply([ e.reply([
`${ this.identifyPrefix }识别:波点音乐,${ name }-${ album }-${ artist }\n标签:${ categorys `${this.identifyPrefix}识别:波点音乐,${name}-${album}-${artist}\n标签:${categorys
.map(item => item.name) .map(item => item.name)
.join(" | ") }`, .join(" | ")}`,
segment.image(albumPic120), segment.image(albumPic120),
]); ]);
if (e.msg.includes("musicId")) { if (e.msg.includes("musicId")) {
const path = `${ this.getCurDownloadPath(e) }`; const path = `${this.getCurDownloadPath(e)}`;
await getBodianAudio(id, path, `${ name }-${ artist }`).then(sendPath => { await getBodianAudio(id, path, `${name}-${artist}`).then(sendPath => {
// 发送语音 // 发送语音
e.reply(segment.record(sendPath)); e.reply(segment.record(sendPath));
// 上传群文件 // 上传群文件
@ -1228,11 +1228,11 @@ export class tools extends plugin {
}) })
]); ]);
const { name: mvName, artistName: mvArtist, cover: mvCover } = mvDetailData.data?.data; const { name: mvName, artistName: mvArtist, cover: mvCover } = mvDetailData.data?.data;
e.reply([segment.image(mvCover), `${ this.identifyPrefix }识别网易云MV${ mvName } - ${ mvArtist }`]); e.reply([segment.image(mvCover), `${this.identifyPrefix}识别网易云MV${mvName} - ${mvArtist}`]);
// logger.info(mvUrlData.data) // logger.info(mvUrlData.data)
const { url: mvUrl } = mvUrlData.data?.data; const { url: mvUrl } = mvUrlData.data?.data;
this.downloadVideo(mvUrl).then(path => { this.downloadVideo(mvUrl).then(path => {
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
return; return;
} }
@ -1251,14 +1251,14 @@ export class tools extends plugin {
// 获取歌曲信息 // 获取歌曲信息
let title = await axios.get(AUTO_NETEASE_SONG_DETAIL.replace("{}", id)).then(res => { let title = await axios.get(AUTO_NETEASE_SONG_DETAIL.replace("{}", id)).then(res => {
const song = res.data.songs[0]; const song = res.data.songs[0];
return cleanFilename(`${ song?.name }-${ song?.ar?.[0].name }`); return cleanFilename(`${song?.name}-${song?.ar?.[0].name}`);
}); });
// 一般这个情况是VIP歌曲 (如果没有url或者是国内, 国内全走临时接口,后续如果不要删除逻辑'!isOversea ||') // 一般这个情况是VIP歌曲 (如果没有url或者是国内, 国内全走临时接口,后续如果不要删除逻辑'!isOversea ||')
if (!isOversea || url == null) { if (!isOversea || url == null) {
url = await this.musicTempApi(e, title, "网易云音乐"); url = await this.musicTempApi(e, title, "网易云音乐");
} else { } else {
// 不是VIP歌曲直接识别完就下一步 // 不是VIP歌曲直接识别完就下一步
e.reply(`${ this.identifyPrefix }识别:网易云音乐,${ title }`); e.reply(`${this.identifyPrefix}识别:网易云音乐,${title}`);
} }
// 动态判断后缀名 // 动态判断后缀名
const extensionPattern = /\.([a-zA-Z0-9]+)$/; const extensionPattern = /\.([a-zA-Z0-9]+)$/;
@ -1272,7 +1272,7 @@ export class tools extends plugin {
// 删除文件 // 删除文件
await checkAndRemoveFile(path); await checkAndRemoveFile(path);
}).catch(err => { }).catch(err => {
logger.error(`下载音乐失败,错误信息为: ${ err.message }`); logger.error(`下载音乐失败,错误信息为: ${err.message}`);
}); });
}); });
return true; return true;
@ -1296,7 +1296,7 @@ export class tools extends plugin {
// ??后的内容是适配`QQ_MUSIC_TEMP_API`、最后是汽水 // ??后的内容是适配`QQ_MUSIC_TEMP_API`、最后是汽水
const url = vipMusicData.data?.music_url ?? vipMusicData.data?.data?.music_url ?? vipMusicData.data?.music; const url = vipMusicData.data?.music_url ?? vipMusicData.data?.data?.music_url ?? vipMusicData.data?.music;
const cover = vipMusicData.data?.cover ?? vipMusicData.data?.data?.cover ?? vipMusicData.data?.cover; const cover = vipMusicData.data?.cover ?? vipMusicData.data?.data?.cover ?? vipMusicData.data?.cover;
await e.reply([segment.image(cover), `${ this.identifyPrefix }识别:${ musicType }${ messageTitle }`]); await e.reply([segment.image(cover), `${this.identifyPrefix}识别:${musicType}${messageTitle}`]);
return url; return url;
} }
@ -1328,13 +1328,13 @@ export class tools extends plugin {
"User-Agent": COMMON_USER_AGENT, "User-Agent": COMMON_USER_AGENT,
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"cookie": "_T_WM=40835919903; WEIBOCN_FROM=1110006030; MLOGIN=0; XSRF-TOKEN=4399c8", "cookie": "_T_WM=40835919903; WEIBOCN_FROM=1110006030; MLOGIN=0; XSRF-TOKEN=4399c8",
"Referer": `https://m.weibo.cn/detail/${ id }`, "Referer": `https://m.weibo.cn/detail/${id}`,
} }
}) })
.then(async resp => { .then(async resp => {
const wbData = resp.data.data; const wbData = resp.data.data;
const { text, status_title, source, region_name, pics, page_info } = wbData; const { text, status_title, source, region_name, pics, page_info } = wbData;
e.reply(`${ this.identifyPrefix }识别:微博,${ text.replace(/<[^>]+>/g, '') }\n${ status_title }\n${ source }\t${ region_name ?? '' }`); e.reply(`${this.identifyPrefix}识别:微博,${text.replace(/<[^>]+>/g, '')}\n${status_title}\n${source}\t${region_name ?? ''}`);
if (pics) { if (pics) {
// 下载图片并格式化消息 // 下载图片并格式化消息
const imagesPromise = pics.map(item => { const imagesPromise = pics.map(item => {
@ -1378,7 +1378,7 @@ export class tools extends plugin {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"referer": "https://weibo.com/", "referer": "https://weibo.com/",
}, 1).then(path => { }, 1).then(path => {
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
} catch (err) { } catch (err) {
e.reply("视频资源获取失败"); e.reply("视频资源获取失败");
@ -1397,7 +1397,7 @@ export class tools extends plugin {
async general(e) { async general(e) {
try { try {
const adapter = await GeneralLinkAdapter.create(e.msg); const adapter = await GeneralLinkAdapter.create(e.msg);
e.reply(`${ this.identifyPrefix }识别:${ adapter.name }${ adapter.desc ? `, ${ adapter.desc }` : '' }`); e.reply(`${this.identifyPrefix}识别:${adapter.name}${adapter.desc ? `, ${adapter.desc}` : ''}`);
logger.mark(adapter); logger.mark(adapter);
if (adapter.images && adapter.images.length > 0) { if (adapter.images && adapter.images.length > 0) {
const images = adapter.images.map(item => { const images = adapter.images.map(item => {
@ -1413,7 +1413,7 @@ export class tools extends plugin {
const url = adapter.video; const url = adapter.video;
this.downloadVideo(url).then(path => { this.downloadVideo(url).then(path => {
logger.info(path); logger.info(path);
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
} else { } else {
e.reply("解析失败:无法获取到资源"); e.reply("解析失败:无法获取到资源");
@ -1449,9 +1449,9 @@ export class tools extends plugin {
const path = this.getCurDownloadPath(e); const path = this.getCurDownloadPath(e);
await checkAndRemoveFile(path + "/temp.mp4") await checkAndRemoveFile(path + "/temp.mp4")
const title = await ytDlpGetTilt(url, isOversea, this.myProxy); const title = await ytDlpGetTilt(url, isOversea, this.myProxy);
e.reply(`${ this.identifyPrefix }识别:油管,视频下载中请耐心等待 \n${ title }`); e.reply(`${this.identifyPrefix}识别:油管,视频下载中请耐心等待 \n${title}`);
await ytDlpHelper(path, url, isOversea, this.myProxy, true); await ytDlpHelper(path, url, isOversea, this.myProxy, true);
this.sendVideoToUpload(e, `${ path }/temp.mp4`); this.sendVideoToUpload(e, `${path}/temp.mp4`);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
throw error; // Rethrow the error so it can be handled by the caller throw error; // Rethrow the error so it can be handled by the caller
@ -1497,7 +1497,7 @@ export class tools extends plugin {
} catch (e) { } catch (e) {
realContent = content; realContent = content;
} }
const normalMsg = `${ this.identifyPrefix }识别:米游社,${ subject }\n${ realContent?.describe || "" }`; const normalMsg = `${this.identifyPrefix}识别:米游社,${subject}\n${realContent?.describe || ""}`;
const replyMsg = cover ? [segment.image(cover), normalMsg] : normalMsg; const replyMsg = cover ? [segment.image(cover), normalMsg] : normalMsg;
e.reply(replyMsg); e.reply(replyMsg);
// 图片 // 图片
@ -1521,7 +1521,7 @@ export class tools extends plugin {
// 暂时选取分辨率较低的video进行解析 // 暂时选取分辨率较低的video进行解析
const videoUrl = resolutions[i].url; const videoUrl = resolutions[i].url;
this.downloadVideo(videoUrl).then(path => { this.downloadVideo(videoUrl).then(path => {
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
break; break;
} }
@ -1566,10 +1566,10 @@ export class tools extends plugin {
const cover = firstFeed.images[0].url; const cover = firstFeed.images[0].url;
const noWatermarkDownloadUrl = firstFeed.video_url; const noWatermarkDownloadUrl = firstFeed.video_url;
e.reply([segment.image(cover), `${ this.identifyPrefix }识别:微视,${ title }`]); e.reply([segment.image(cover), `${this.identifyPrefix}识别:微视,${title}`]);
this.downloadVideo(noWatermarkDownloadUrl).then(path => { this.downloadVideo(noWatermarkDownloadUrl).then(path => {
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
} catch (err) { } catch (err) {
logger.error(err); logger.error(err);
@ -1618,7 +1618,7 @@ export class tools extends plugin {
images, images,
}; };
e.reply(`${ this.identifyPrefix }识别:最右,${ shortVideoInfo.authorName }\n${ shortVideoInfo.title }`) e.reply(`${this.identifyPrefix}识别:最右,${shortVideoInfo.authorName}\n${shortVideoInfo.title}`)
if (shortVideoInfo.images.length > 0) { if (shortVideoInfo.images.length > 0) {
const replyImages = shortVideoInfo.images.map(item => { const replyImages = shortVideoInfo.images.map(item => {
@ -1632,7 +1632,7 @@ export class tools extends plugin {
} }
if (shortVideoInfo.noWatermarkDownloadUrl) { if (shortVideoInfo.noWatermarkDownloadUrl) {
this.downloadVideo(shortVideoInfo.noWatermarkDownloadUrl).then(path => { this.downloadVideo(shortVideoInfo.noWatermarkDownloadUrl).then(path => {
this.sendVideoToUpload(e, `${ path }/temp.mp4`) this.sendVideoToUpload(e, `${path}/temp.mp4`)
}); });
} }
} catch (error) { } catch (error) {
@ -1654,17 +1654,17 @@ export class tools extends plugin {
// 检测是否存在框架 // 检测是否存在框架
const isExistFreyr = await checkToolInCurEnv("freyr"); const isExistFreyr = await checkToolInCurEnv("freyr");
if (!isExistFreyr) { if (!isExistFreyr) {
e.reply(`检测到没有${ freyrName }需要的环境,无法解析!${ HELP_DOC }`); e.reply(`检测到没有${freyrName}需要的环境,无法解析!${HELP_DOC}`);
return; return;
} }
// 执行命令 // 执行命令
const result = await execSync(`freyr -d ${ currentWorkingDirectory + "/am/" } get ${ message }`); const result = await execSync(`freyr -d ${currentWorkingDirectory + "/am/"} get ${message}`);
logger.info(result.toString()); logger.info(result.toString());
// 获取信息 // 获取信息
let { title, album, artist } = await this.parseFreyrLog(result.toString()); let { title, album, artist } = await this.parseFreyrLog(result.toString());
// 兜底策略 // 兜底策略
if (freyrName === "Apple Music" && (title === "N/A" || album === "N/A" || artist === "N/A")) { if (freyrName === "Apple Music" && (title === "N/A" || album === "N/A" || artist === "N/A")) {
const data = await axios.get(`https://api.fabdl.com/apple-music/get?url=${ message }`, { const data = await axios.get(`https://api.fabdl.com/apple-music/get?url=${message}`, {
headers: { headers: {
"User-Agent": COMMON_USER_AGENT, "User-Agent": COMMON_USER_AGENT,
"Referer": "https://apple-music-downloader.com/", "Referer": "https://apple-music-downloader.com/",
@ -1681,7 +1681,7 @@ export class tools extends plugin {
// 国内服务器解决方案 // 国内服务器解决方案
if (!isOversea) { if (!isOversea) {
// 临时接口 // 临时接口
const url = await this.musicTempApi(e, `${ title } ${ artist }`, freyrName); const url = await this.musicTempApi(e, `${title} ${artist}`, freyrName);
// 下载音乐 // 下载音乐
downloadAudio(url, this.getCurDownloadPath(e), title, 'follow').then(async path => { downloadAudio(url, this.getCurDownloadPath(e), title, 'follow').then(async path => {
// 发送语音 // 发送语音
@ -1690,22 +1690,22 @@ export class tools extends plugin {
await this.uploadGroupFile(e, path); await this.uploadGroupFile(e, path);
await checkAndRemoveFile(path); await checkAndRemoveFile(path);
}).catch(err => { }).catch(err => {
logger.error(`下载音乐失败,错误信息为: ${ err.message }`); logger.error(`下载音乐失败,错误信息为: ${err.message}`);
}); });
} else { } else {
// freyr 逻辑 // freyr 逻辑
e.reply(`${ this.identifyPrefix }识别:${ freyrName }${ title }--${ artist }`); e.reply(`${this.identifyPrefix}识别:${freyrName}${title}--${artist}`);
// 检查目录是否存在 // 检查目录是否存在
const musicPath = currentWorkingDirectory + "/am/" + artist + "/" + album; const musicPath = currentWorkingDirectory + "/am/" + artist + "/" + album;
// 找到音频文件 // 找到音频文件
const mediaFiles = await getMediaFilesAndOthers(musicPath); const mediaFiles = await getMediaFilesAndOthers(musicPath);
for (let other of mediaFiles.others) { for (let other of mediaFiles.others) {
await this.uploadGroupFile(e, `${ musicPath }/${ other }`); await this.uploadGroupFile(e, `${musicPath}/${other}`);
} }
} }
// 计数 // 计数
tools.#amCount += 1; tools.#amCount += 1;
logger.info(`当前${ freyrName }已经下载了:${ tools.#amCount }`); logger.info(`当前${freyrName}已经下载了:${tools.#amCount}`);
// 定时清理 // 定时清理
if (tools.#amCount >= 5) { if (tools.#amCount >= 5) {
await deleteFolderRecursive(currentWorkingDirectory + "/am"); await deleteFolderRecursive(currentWorkingDirectory + "/am");
@ -1756,13 +1756,13 @@ export class tools extends plugin {
.setModel(this.aiModel) .setModel(this.aiModel)
.setPrompt(SUMMARY_PROMPT) .setPrompt(SUMMARY_PROMPT)
.build(); .build();
e.reply(`${ this.identifyPrefix }识别:${ name },正在为您总结,请稍等...`, true, { recallMsg: MESSAGE_RECALL_TIME }); e.reply(`${this.identifyPrefix}识别:${name},正在为您总结,请稍等...`, true, { recallMsg: MESSAGE_RECALL_TIME });
const { ans: kimiAns, model } = await builder.kimi(summaryLink); const { ans: kimiAns, model } = await builder.kimi(summaryLink);
// 计算阅读时间 // 计算阅读时间
const stats = estimateReadingTime(kimiAns); const stats = estimateReadingTime(kimiAns);
const titleMatch = kimiAns.match(/(Title|标题)([:])\s*(.*?)\n/)?.[3]; const titleMatch = kimiAns.match(/(Title|标题)([:])\s*(.*?)\n/)?.[3];
e.reply(`${ titleMatch }》 预计阅读时间: ${ stats.minutes } 分钟,总字数: ${ stats.words }`) e.reply(`${titleMatch}》 预计阅读时间: ${stats.minutes} 分钟,总字数: ${stats.words}`)
const Msg = await Bot.makeForwardMsg(textArrayToMakeForward(e, [`「R插件 x ${ model }」联合为您总结内容:`, kimiAns])); const Msg = await Bot.makeForwardMsg(textArrayToMakeForward(e, [`「R插件 x ${model}」联合为您总结内容:`, kimiAns]));
await e.reply(Msg); await e.reply(Msg);
return true; return true;
} }
@ -1777,7 +1777,7 @@ export class tools extends plugin {
async tempSummary(name, summaryLink, e) { async tempSummary(name, summaryLink, e) {
const content = await llmRead(summaryLink); const content = await llmRead(summaryLink);
const titleMatch = content.match(/Title:\s*(.*?)\n/)?.[1]; const titleMatch = content.match(/Title:\s*(.*?)\n/)?.[1];
e.reply(`${ this.identifyPrefix }识别:${ name } - ${ titleMatch },正在为您总结,请稍等...`, true); e.reply(`${this.identifyPrefix}识别:${name} - ${titleMatch},正在为您总结,请稍等...`, true);
const summary = await deepSeekChat(content, SUMMARY_PROMPT); const summary = await deepSeekChat(content, SUMMARY_PROMPT);
const Msg = await Bot.makeForwardMsg(textArrayToMakeForward(e, [`「R插件 x DeepSeek」联合为您总结内容`, summary])); const Msg = await Bot.makeForwardMsg(textArrayToMakeForward(e, [`「R插件 x DeepSeek」联合为您总结内容`, summary]));
await e.reply(Msg); await e.reply(Msg);
@ -1801,7 +1801,7 @@ export class tools extends plugin {
musicInfo = prompt + "-" + desc; musicInfo = prompt + "-" + desc;
// 空判定 // 空判定
if (musicInfo.trim() === "-" || prompt === undefined || desc === undefined) { if (musicInfo.trim() === "-" || prompt === undefined || desc === undefined) {
logger.info(`没有识别到QQ音乐小程序帮助文档如下${ HELP_DOC }`) logger.info(`没有识别到QQ音乐小程序帮助文档如下${HELP_DOC}`)
return true; return true;
} }
} else { } else {
@ -1811,7 +1811,7 @@ export class tools extends plugin {
} }
// 删除特殊字符 // 删除特殊字符
musicInfo = cleanFilename(musicInfo); musicInfo = cleanFilename(musicInfo);
logger.info(`[R插件][qqMusic] 识别音乐为:${ musicInfo }`); logger.info(`[R插件][qqMusic] 识别音乐为:${musicInfo}`);
// 使用临时接口下载 // 使用临时接口下载
const url = await this.musicTempApi(e, musicInfo, "QQ音乐"); const url = await this.musicTempApi(e, musicInfo, "QQ音乐");
// 下载音乐 // 下载音乐
@ -1822,7 +1822,7 @@ export class tools extends plugin {
await this.uploadGroupFile(e, path); await this.uploadGroupFile(e, path);
await checkAndRemoveFile(path); await checkAndRemoveFile(path);
}).catch(err => { }).catch(err => {
logger.error(`下载音乐失败,错误信息为: ${ err.message }`); logger.error(`下载音乐失败,错误信息为: ${err.message}`);
}); });
return true; return true;
} }
@ -1831,7 +1831,7 @@ export class tools extends plugin {
async qishuiMusic(e) { async qishuiMusic(e) {
const normalRegex = /^(.*?)\s*https?:\/\//; const normalRegex = /^(.*?)\s*https?:\/\//;
const musicInfo = normalRegex.exec(e.msg)?.[1].trim().replace("@汽水音乐", ""); const musicInfo = normalRegex.exec(e.msg)?.[1].trim().replace("@汽水音乐", "");
logger.info(`[R插件][qishuiMusic] 识别音乐为:${ musicInfo }`); logger.info(`[R插件][qishuiMusic] 识别音乐为:${musicInfo}`);
// 使用临时接口下载 // 使用临时接口下载
const url = await this.musicTempApi(e, musicInfo, "汽水音乐"); const url = await this.musicTempApi(e, musicInfo, "汽水音乐");
// 下载音乐 // 下载音乐
@ -1842,7 +1842,7 @@ export class tools extends plugin {
await this.uploadGroupFile(e, path); await this.uploadGroupFile(e, path);
await checkAndRemoveFile(path); await checkAndRemoveFile(path);
}).catch(err => { }).catch(err => {
logger.error(`下载音乐失败,错误信息为: ${ err.message }`); logger.error(`下载音乐失败,错误信息为: ${err.message}`);
}); });
return true; return true;
} }
@ -1862,7 +1862,7 @@ export class tools extends plugin {
// 检查当前环境 // 检查当前环境
const isExistTdl = await checkToolInCurEnv("tdl"); const isExistTdl = await checkToolInCurEnv("tdl");
if (!isExistTdl) { if (!isExistTdl) {
e.reply(`未检测到必要的环境,无法解析小飞机${ HELP_DOC }`); e.reply(`未检测到必要的环境,无法解析小飞机${HELP_DOC}`);
return; return;
} }
const url = urlRex.exec(e.msg)[0]; const url = urlRex.exec(e.msg)[0];
@ -1872,8 +1872,8 @@ export class tools extends plugin {
e.reply("文件已保存到 Save Messages"); e.reply("文件已保存到 Save Messages");
return true; return true;
} }
e.reply(`${ this.identifyPrefix }识别:小飞机(学习版)`); e.reply(`${this.identifyPrefix}识别:小飞机(学习版)`);
const tgSavePath = `${ this.getCurDownloadPath(e) }/tg`; const tgSavePath = `${this.getCurDownloadPath(e)}/tg`;
// 如果没有文件夹则创建 // 如果没有文件夹则创建
await mkdirIfNotExists(tgSavePath); await mkdirIfNotExists(tgSavePath);
// 删除之前的文件 // 删除之前的文件
@ -1883,7 +1883,7 @@ export class tools extends plugin {
const mediaFiles = await getMediaFilesAndOthers(tgSavePath); const mediaFiles = await getMediaFilesAndOthers(tgSavePath);
if (mediaFiles.images.length > 0) { if (mediaFiles.images.length > 0) {
const imagesData = mediaFiles.images.map(item => { const imagesData = mediaFiles.images.map(item => {
const fileContent = fs.readFileSync(`${ tgSavePath }/${ item }`); const fileContent = fs.readFileSync(`${tgSavePath}/${item}`);
return { return {
message: segment.image(fileContent), message: segment.image(fileContent),
nickname: e.sender.card || e.user_id, nickname: e.sender.card || e.user_id,
@ -1893,11 +1893,11 @@ export class tools extends plugin {
e.reply(await Bot.makeForwardMsg(imagesData), true, { recallMsg: MESSAGE_RECALL_TIME }); e.reply(await Bot.makeForwardMsg(imagesData), true, { recallMsg: MESSAGE_RECALL_TIME });
} else if (mediaFiles.videos.length > 0) { } else if (mediaFiles.videos.length > 0) {
for (const item of mediaFiles.videos) { for (const item of mediaFiles.videos) {
await this.sendVideoToUpload(e, `${ tgSavePath }/${ item }`); await this.sendVideoToUpload(e, `${tgSavePath}/${item}`);
} }
} else { } else {
for (let other of mediaFiles.others) { for (let other of mediaFiles.others) {
await this.uploadGroupFile(e, `${ tgSavePath }/${ other }`); await this.uploadGroupFile(e, `${tgSavePath}/${other}`);
} }
} }
return true; return true;
@ -1909,7 +1909,7 @@ export class tools extends plugin {
const msg = /https:\/\/tieba\.baidu\.com\/p\/[A-Za-z0-9]+/.exec(e.msg)?.[0]; const msg = /https:\/\/tieba\.baidu\.com\/p\/[A-Za-z0-9]+/.exec(e.msg)?.[0];
const id = /\/p\/([A-Za-z0-9]+)/.exec(msg)?.[1]; const id = /\/p\/([A-Za-z0-9]+)/.exec(msg)?.[1];
// 获取帖子详情 // 获取帖子详情
const hibi = HIBI_API_SERVICE + `/tieba/post_detail?tid=${ id }`; const hibi = HIBI_API_SERVICE + `/tieba/post_detail?tid=${id}`;
const hibiResp = await fetch(hibi, { const hibiResp = await fetch(hibi, {
headers: { headers: {
"User-Agent": COMMON_USER_AGENT, "User-Agent": COMMON_USER_AGENT,
@ -1920,7 +1920,7 @@ export class tools extends plugin {
const top = postList[0]; const top = postList[0];
// 提取标题和内容 // 提取标题和内容
const { title, content } = top; const { title, content } = top;
let sendContent = `${ this.identifyPrefix }识别:贴吧,${ title }` let sendContent = `${this.identifyPrefix}识别:贴吧,${title}`
let extractImages = []; let extractImages = [];
// 如果内容中有图片、文本或视频,它会将它们添加到 sendContent 消息中 // 如果内容中有图片、文本或视频,它会将它们添加到 sendContent 消息中
if (content && content.length > 0) { if (content && content.length > 0) {
@ -1932,12 +1932,12 @@ export class tools extends plugin {
if (cdn_src) extractImages.push(segment.image(cdn_src)); if (cdn_src) extractImages.push(segment.image(cdn_src));
// 处理文本 // 处理文本
if (text) sendContent.push(`\n\n📝 简介:${ text }`); if (text) sendContent.push(`\n\n📝 简介:${text}`);
// 处理视频 // 处理视频
if (link) { if (link) {
const filePath = await this.downloadVideo(link); const filePath = await this.downloadVideo(link);
this.sendVideoToUpload(e, `${ filePath }/temp.mp4`); this.sendVideoToUpload(e, `${filePath}/temp.mp4`);
} }
} }
} }
@ -1987,7 +1987,7 @@ export class tools extends plugin {
const tag = e.msg.replace(/#验车/g, ""); const tag = e.msg.replace(/#验车/g, "");
const reqUrl = `https://whatslink.info/api/v1/link?url=${ tag }`; const reqUrl = `https://whatslink.info/api/v1/link?url=${tag}`;
const resp = await axios.get(reqUrl, { const resp = await axios.get(reqUrl, {
headers: { headers: {
"User-Agent": COMMON_USER_AGENT, "User-Agent": COMMON_USER_AGENT,
@ -1997,7 +1997,7 @@ export class tools extends plugin {
e.reply("没有找到相关磁力"); e.reply("没有找到相关磁力");
return; return;
} }
await e.reply(`🧲 [R插件 x Mix] 联合为您验车:\n${ resp.data.name }`, false, { recallMsg: MESSAGE_RECALL_TIME }); await e.reply(`🧲 [R插件 x Mix] 联合为您验车:\n${resp.data.name}`, false, { recallMsg: MESSAGE_RECALL_TIME });
if (resp.data?.screenshots === null) { if (resp.data?.screenshots === null) {
e.reply("没有找到相关媒体"); e.reply("没有找到相关媒体");
return; return;
@ -2049,7 +2049,7 @@ export class tools extends plugin {
this.videoDownloadConcurrency this.videoDownloadConcurrency
), ),
]).then(data => { ]).then(data => {
return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, `${ title }.mp4`); return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, `${title}.mp4`);
}); });
} }
@ -2087,7 +2087,7 @@ export class tools extends plugin {
* @returns {string} * @returns {string}
*/ */
getCurDownloadPath(e) { getCurDownloadPath(e) {
return `${ this.defaultPath }${ e.group_id || e.user_id }` return `${this.defaultPath}${e.group_id || e.user_id}`
} }
/** /**
@ -2095,8 +2095,8 @@ export class tools extends plugin {
* @returns {{groupPath: string, target: string}} * @returns {{groupPath: string, target: string}}
*/ */
getGroupPathAndTarget() { getGroupPathAndTarget() {
const groupPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; const groupPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`;
const target = `${ groupPath }/temp.mp4`; const target = `${groupPath}/temp.mp4`;
return { groupPath, target }; return { groupPath, target };
} }
@ -2118,7 +2118,7 @@ export class tools extends plugin {
// 构造代理参数 // 构造代理参数
const proxyOption = { const proxyOption = {
...(isProxy && { ...(isProxy && {
httpAgent: new HttpsProxyAgent(`http://${ this.proxyAddr }:${ this.proxyPort }`), httpAgent: new HttpsProxyAgent(`http://${this.proxyAddr}:${this.proxyPort}`),
}), }),
} }
@ -2135,7 +2135,7 @@ export class tools extends plugin {
target, target,
groupPath, groupPath,
} }
logger.info(`[R插件][视频下载]:当前队列长度为 ${ this.queue.size + 1 }`); logger.info(`[R插件][视频下载]:当前队列长度为 ${this.queue.size + 1}`);
return await this.queue.add(async () => { return await this.queue.add(async () => {
// 如果是用户设置了单线程,则不分片下载 // 如果是用户设置了单线程,则不分片下载
if (numThreads === 1) { if (numThreads === 1) {
@ -2185,7 +2185,7 @@ export class tools extends plugin {
const partAxiosConfig = { const partAxiosConfig = {
headers: { headers: {
"User-Agent": userAgent, "User-Agent": userAgent,
"Range": `bytes=${ start }-${ end }` "Range": `bytes=${start}-${end}`
}, },
responseType: "stream", responseType: "stream",
...proxyOption ...proxyOption
@ -2193,12 +2193,12 @@ export class tools extends plugin {
promises.push(axios.get(url, partAxiosConfig).then(res => { promises.push(axios.get(url, partAxiosConfig).then(res => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const partPath = `${ target }.part${ i }`; const partPath = `${target}.part${i}`;
logger.mark(`[R插件][视频下载引擎] 正在下载 part${ i }`) logger.mark(`[R插件][视频下载引擎] 正在下载 part${i}`)
const writer = fs.createWriteStream(partPath); const writer = fs.createWriteStream(partPath);
res.data.pipe(writer); res.data.pipe(writer);
writer.on("finish", () => { writer.on("finish", () => {
logger.mark(`[R插件][视频下载引擎] part${ i + 1 } 下载完成`); // 记录线程下载完成 logger.mark(`[R插件][视频下载引擎] part${i + 1} 下载完成`); // 记录线程下载完成
resolve(partPath); resolve(partPath);
}); });
writer.on("error", reject); writer.on("error", reject);
@ -2228,7 +2228,7 @@ export class tools extends plugin {
return groupPath; return groupPath;
} catch (err) { } catch (err) {
logger.error(`下载视频发生错误!\ninfo:${ err }`); logger.error(`下载视频发生错误!\ninfo:${err}`);
} }
} }
@ -2243,39 +2243,39 @@ export class tools extends plugin {
// 构造aria2c命令参数 // 构造aria2c命令参数
const aria2cArgs = [ const aria2cArgs = [
`"${ url }"`, `"${url}"`,
`--out="temp.mp4"`, `--out="temp.mp4"`,
`--dir="${ groupPath }"`, `--dir="${groupPath}"`,
`--user-agent="${ userAgent }"`, `--user-agent="${userAgent}"`,
`--max-connection-per-server=${ numThreads }`, // 每个服务器的最大连接数 `--max-connection-per-server=${numThreads}`, // 每个服务器的最大连接数
`--split=${ numThreads }`, // 分成 6 个部分进行下载 `--split=${numThreads}`, // 分成 6 个部分进行下载
]; ];
// 如果有自定义头信息 // 如果有自定义头信息
if (headers) { if (headers) {
for (const [key, value] of Object.entries(headers)) { for (const [key, value] of Object.entries(headers)) {
aria2cArgs.push(`--header="${ key }: ${ value }"`); aria2cArgs.push(`--header="${key}: ${value}"`);
} }
} }
// 如果使用代理 // 如果使用代理
if (proxyOption && proxyOption.httpAgent) { if (proxyOption && proxyOption.httpAgent) {
const proxyUrl = proxyOption.httpAgent.proxy.href; const proxyUrl = proxyOption.httpAgent.proxy.href;
aria2cArgs.push(`--all-proxy="${ proxyUrl }"`); aria2cArgs.push(`--all-proxy="${proxyUrl}"`);
} }
try { try {
await checkAndRemoveFile(target); await checkAndRemoveFile(target);
logger.mark(`开始下载: ${ url }`); logger.mark(`开始下载: ${url}`);
// 执行aria2c命令 // 执行aria2c命令
const command = `aria2c ${ aria2cArgs.join(' ') }`; const command = `aria2c ${aria2cArgs.join(' ')}`;
exec(command, (error, stdout, stderr) => { exec(command, (error, stdout, stderr) => {
if (error) { if (error) {
logger.error(`下载视频发生错误!\ninfo:${ stderr }`); logger.error(`下载视频发生错误!\ninfo:${stderr}`);
throw error; throw error;
} else { } else {
logger.mark(`下载完成: ${ url }`); logger.mark(`下载完成: ${url}`);
} }
}); });
@ -2283,7 +2283,7 @@ export class tools extends plugin {
let count = 0; let count = 0;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const checkInterval = setInterval(() => { const checkInterval = setInterval(() => {
logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${ count + 1 }`)); logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${count + 1}`));
count += 1; count += 1;
if (fs.existsSync(target)) { if (fs.existsSync(target)) {
logger.info("[R插件][Aria2] 检测到文件!"); logger.info("[R插件][Aria2] 检测到文件!");
@ -2298,7 +2298,7 @@ export class tools extends plugin {
}, DOWNLOAD_WAIT_DETECT_FILE_TIME); }, DOWNLOAD_WAIT_DETECT_FILE_TIME);
}); });
} catch (err) { } catch (err) {
logger.error(`下载视频发生错误!\ninfo:${ err }`); logger.error(`下载视频发生错误!\ninfo:${err}`);
throw err; throw err;
} }
} }
@ -2314,38 +2314,38 @@ export class tools extends plugin {
// 构造axel命令参数 // 构造axel命令参数
const axelArgs = [ const axelArgs = [
`-n ${ numThreads }`, `-n ${numThreads}`,
`-o "${ target }"`, `-o "${target}"`,
`-U "${ userAgent }"`, `-U "${userAgent}"`,
url url
]; ];
// 如果有自定义头信息 // 如果有自定义头信息
if (headers) { if (headers) {
for (const [key, value] of Object.entries(headers)) { for (const [key, value] of Object.entries(headers)) {
axelArgs.push(`-H "${ key }: ${ value }"`); axelArgs.push(`-H "${key}: ${value}"`);
} }
} }
// 如果使用代理 // 如果使用代理
if (proxyOption && proxyOption.httpAgent) { if (proxyOption && proxyOption.httpAgent) {
const proxyUrl = proxyOption.httpAgent.proxy.href; const proxyUrl = proxyOption.httpAgent.proxy.href;
axelArgs.push(`--proxy="${ proxyUrl }"`); axelArgs.push(`--proxy="${proxyUrl}"`);
} }
try { try {
await checkAndRemoveFile(target); await checkAndRemoveFile(target);
logger.mark(`开始下载: ${ url }`); logger.mark(`开始下载: ${url}`);
// 执行axel命令 // 执行axel命令
const command = `axel ${ axelArgs.join(' ') }`; const command = `axel ${axelArgs.join(' ')}`;
exec(command, (error, stdout, stderr) => { exec(command, (error, stdout, stderr) => {
if (error) { if (error) {
logger.error(`下载视频发生错误!\ninfo:${ stderr }`); logger.error(`下载视频发生错误!\ninfo:${stderr}`);
throw error; throw error;
} else { } else {
logger.mark(`下载完成: ${ url }`); logger.mark(`下载完成: ${url}`);
} }
}); });
@ -2353,12 +2353,12 @@ export class tools extends plugin {
// 监听文件生成完成 // 监听文件生成完成
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const checkInterval = setInterval(() => { const checkInterval = setInterval(() => {
logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${ count + 1 }`)); logger.info(logger.red(`[R插件][Aria2] 没有检测到文件!重试第${count + 1}`));
count += 1; count += 1;
if (fs.existsSync(target)) { if (fs.existsSync(target)) {
logger.info("[R插件][Axel] 检测到文件!"); logger.info("[R插件][Axel] 检测到文件!");
clearInterval(checkInterval); clearInterval(checkInterval);
logger.info(`[R插件][Axel] 下载到${ groupPath }`); logger.info(`[R插件][Axel] 下载到${groupPath}`);
resolve(groupPath); resolve(groupPath);
} }
if (count === 6) { if (count === 6) {
@ -2369,7 +2369,7 @@ export class tools extends plugin {
}, DOWNLOAD_WAIT_DETECT_FILE_TIME); }, DOWNLOAD_WAIT_DETECT_FILE_TIME);
}); });
} catch (err) { } catch (err) {
logger.error(`下载视频发生错误!\ninfo:${ err }`); logger.error(`下载视频发生错误!\ninfo:${err}`);
throw err; throw err;
} }
} }
@ -2392,7 +2392,7 @@ export class tools extends plugin {
await checkAndRemoveFile(target); await checkAndRemoveFile(target);
const res = await axios.get(url, axiosConfig); const res = await axios.get(url, axiosConfig);
logger.mark(`开始下载: ${ url }`); logger.mark(`开始下载: ${url}`);
const writer = fs.createWriteStream(target); const writer = fs.createWriteStream(target);
res.data.pipe(writer); res.data.pipe(writer);
@ -2401,7 +2401,7 @@ export class tools extends plugin {
writer.on("error", reject); writer.on("error", reject);
}); });
} catch (err) { } catch (err) {
logger.error(`下载视频发生错误!\ninfo:${ err }`); logger.error(`下载视频发生错误!\ninfo:${err}`);
} }
} }
@ -2443,6 +2443,10 @@ export class tools extends plugin {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
async isTrustUser(userId) { async isTrustUser(userId) {
// 如果当前用户是机器人主人
if (this.e.isMaster) {
return true;
}
// 如果不存在则返回 // 如果不存在则返回
if (!(await redisExistKey(REDIS_YUNZAI_WHITELIST))) { if (!(await redisExistKey(REDIS_YUNZAI_WHITELIST))) {
return false; return false;
@ -2494,13 +2498,13 @@ export class tools extends plugin {
} }
// 正常发送视频 // 正常发送视频
if (videoSize > videoSizeLimit) { if (videoSize > videoSizeLimit) {
e.reply(`当前视频大小:${ videoSize }MB\n大于设置的最大限制:${ videoSizeLimit }MB\n改为上传群文件`); e.reply(`当前视频大小:${videoSize}MB\n大于设置的最大限制:${videoSizeLimit}MB\n改为上传群文件`);
await this.uploadGroupFile(e, path); await this.uploadGroupFile(e, path);
} else { } else {
e.reply(segment.video(path)); e.reply(segment.video(path));
} }
} catch (err) { } catch (err) {
logger.error(`[R插件][发送视频判断是否需要上传] 发生错误:\n ${ err }`); logger.error(`[R插件][发送视频判断是否需要上传] 发生错误:\n ${err}`);
// logger.info(logger.yellow(`上传发生错误R插件正在为你采用备用策略请稍等如果发不出来请再次尝试`)); // logger.info(logger.yellow(`上传发生错误R插件正在为你采用备用策略请稍等如果发不出来请再次尝试`));
// e.reply(segment.video(path)); // e.reply(segment.video(path));
} }