feat: 添加tiktok新短号支持

This commit is contained in:
zhiyu1998 2023-02-25 17:35:11 +08:00
parent c1a1a65507
commit 97684297d7

View File

@ -17,7 +17,7 @@ import { retry } from "../utils/common.js";
import config from "../model/index.js"; import config from "../model/index.js";
export class tools extends plugin { export class tools extends plugin {
constructor() { constructor () {
super({ super({
name: "工具和学习类", name: "工具和学习类",
dsc: "工具相关指令", dsc: "工具相关指令",
@ -33,7 +33,7 @@ export class tools extends plugin {
fnc: "douyin", fnc: "douyin",
}, },
{ {
reg: "(.*)(www.tiktok.com)|(vt.tiktok.com)", reg: "(.*)(www.tiktok.com)|(vt.tiktok.com)|(vm.tiktok.com)",
fnc: "tiktok", fnc: "tiktok",
}, },
{ {
@ -72,12 +72,12 @@ export class tools extends plugin {
// 视频保存路径 // 视频保存路径
this.defaultPath = this.toolsConfig.defaultPath; this.defaultPath = this.toolsConfig.defaultPath;
// redis的key // redis的key
this.redisKey = `Yz:tools:cache:${this.group_id}`; this.redisKey = `Yz:tools:cache:${ this.group_id }`;
// 代理接口 // 代理接口
// TODO 填写服务器的内网ID和clash的端口 // TODO 填写服务器的内网ID和clash的端口
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 }`;
// console.log(this.myProxy) // console.log(this.myProxy)
// 加载百度翻译配置 // 加载百度翻译配置
this.translateAppId = this.toolsConfig.translateAppId; this.translateAppId = this.toolsConfig.translateAppId;
@ -87,7 +87,7 @@ export class tools extends plugin {
} }
// 翻译插件 // 翻译插件
async trans(e) { async trans (e) {
const languageReg = /翻(.)/g; const languageReg = /翻(.)/g;
const msg = e.msg.trim(); const msg = e.msg.trim();
const language = languageReg.exec(msg); const language = languageReg.exec(msg);
@ -102,20 +102,20 @@ export class tools extends plugin {
// let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ transMap[language[1]] }&appid=APP ID&salt=自定义&sign=${ md5("APP ID" + place + "自定义" + "密钥") }&q=${ place }`; // let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ transMap[language[1]] }&appid=APP ID&salt=自定义&sign=${ md5("APP ID" + place + "自定义" + "密钥") }&q=${ place }`;
let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${
transMap[language[1]] transMap[language[1]]
}&appid=${this.translateAppId}&salt=rconsole&sign=${md5( }&appid=${ this.translateAppId }&salt=rconsole&sign=${ md5(
this.translateAppId + place + "rconsole" + this.translateSecret this.translateAppId + place + "rconsole" + this.translateSecret
)}&q=${place}`; ) }&q=${ place }`;
// console.log(url) // console.log(url)
await fetch(url) await fetch(url)
.then(resp => resp.json()) .then(resp => resp.json())
.then(text => text.trans_result) .then(text => text.trans_result)
.then(res => this.reply(`${res[0].dst}`, true)) .then(res => this.reply(`${ res[0].dst }`, true))
.catch(err => logger.error(err)); .catch(err => logger.error(err));
return true; return true;
} }
// 抖音解析 // 抖音解析
async douyin(e) { async douyin (e) {
const urlRex = /(http:|https:)\/\/v.douyin.com\/[A-Za-z\d._?%&+\-=\/#]*/g; const urlRex = /(http:|https:)\/\/v.douyin.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
const douUrl = urlRex.exec(e.msg.trim())[0]; const douUrl = urlRex.exec(e.msg.trim())[0];
@ -123,7 +123,7 @@ export class tools extends plugin {
const douRex = /.*video\/(\d+)\/(.*?)/g; const douRex = /.*video\/(\d+)\/(.*?)/g;
const douId = douRex.exec(res)[1]; const douId = douRex.exec(res)[1];
// const url = `https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=${ douId }`; // const url = `https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=${ douId }`;
const url = `https://www.iesdouyin.com/aweme/v1/web/aweme/detail/?aweme_id=${douId}&aid=1128&version_name=23.5.0&device_platform=android&os_version=2333`; const url = `https://www.iesdouyin.com/aweme/v1/web/aweme/detail/?aweme_id=${ douId }&aid=1128&version_name=23.5.0&device_platform=android&os_version=2333`;
// 默认重试3次每次间隔1s (防止SyntaxError: Unexpected token b in JSON at position 0) // 默认重试3次每次间隔1s (防止SyntaxError: Unexpected token b in JSON at position 0)
retry( retry(
await function () { await function () {
@ -131,7 +131,7 @@ export class tools extends plugin {
} }
).then(async resp_json => { ).then(async resp_json => {
const item = resp_json.aweme_detail; const item = resp_json.aweme_detail;
e.reply(`识别:抖音, ${item.desc}`); e.reply(`识别:抖音, ${ item.desc }`);
const url_type_code = item.aweme_type; const url_type_code = item.aweme_type;
const url_type = douyinTypeMap[url_type_code]; const url_type = douyinTypeMap[url_type_code];
if (url_type === "video") { if (url_type === "video") {
@ -139,7 +139,7 @@ export class tools extends plugin {
this.downloadVideo(url_2).then(video => { this.downloadVideo(url_2).then(video => {
e.reply( e.reply(
segment.video( segment.video(
`${this.defaultPath}${this.e.group_id || this.e.user_id}/temp.mp4` `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp.mp4`
) )
); );
}); });
@ -168,9 +168,10 @@ export class tools extends plugin {
} }
// tiktok解析 // tiktok解析
async tiktok(e) { async tiktok (e) {
const urlRex = /(http:|https:)\/\/www.tiktok.com\/[A-Za-z\d._?%&+\-=\/#@]*/g; const urlRex = /(http:|https:)\/\/www.tiktok.com\/[A-Za-z\d._?%&+\-=\/#@]*/g;
const urlShortRex = /(http:|https:)\/\/vt.tiktok.com\/[A-Za-z\d._?%&+\-=\/#]*/g; const urlShortRex = /(http:|https:)\/\/vt.tiktok.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
const urlShortRex2 = /(http:|https:)\/\/vm.tiktok.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
let url = e.msg.trim(); let url = e.msg.trim();
// 短号处理 // 短号处理
if (url.includes("vt.tiktok")) { if (url.includes("vt.tiktok")) {
@ -183,12 +184,23 @@ export class tools extends plugin {
}).then(resp => { }).then(resp => {
url = resp.url; url = resp.url;
}); });
} else if (url.includes("vm.tiktok")) {
const temp_url = urlShortRex2.exec(url)[0];
await fetch(temp_url, {
headers: { "User-Agent": "facebookexternalhit/1.1" },
redirect: "follow",
follow: 10,
timeout: 10000,
agent: new HttpProxyAgent(this.myProxy),
}).then(resp => {
url = resp.url;
});
} else { } else {
url = urlRex.exec(url)[0]; url = urlRex.exec(url)[0];
} }
const idVideo = await this.getIdVideo(url); const idVideo = await this.getIdVideo(url);
// API链接 // API链接
const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${idVideo}&version_code=262&app_name=musical_ly&channel=App&device_id=null&os_version=14.4.2&device_platform=iphone&device_type=iPhone9`; const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${ idVideo }&version_code=262&app_name=musical_ly&channel=App&device_id=null&os_version=14.4.2&device_platform=iphone&device_type=iPhone9`;
await axios await axios
.get(API_URL, { .get(API_URL, {
@ -209,11 +221,11 @@ export class tools extends plugin {
}) })
.then(resp => { .then(resp => {
const data = resp.data.aweme_list[0]; const data = resp.data.aweme_list[0];
e.reply(`识别tiktok, ${data.desc}`); e.reply(`识别tiktok, ${ data.desc }`);
this.downloadVideo(data.video.play_addr.url_list[0], true).then(video => { this.downloadVideo(data.video.play_addr.url_list[0], true).then(video => {
e.reply( e.reply(
segment.video( segment.video(
`${this.defaultPath}${this.e.group_id || this.e.user_id}/temp.mp4` `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp.mp4`
) )
); );
}); });
@ -222,7 +234,7 @@ export class tools extends plugin {
} }
// bilibi解析 // bilibi解析
async bili(e) { async bili (e) {
const urlRex = /(http:|https:)\/\/www.bilibili.com\/[A-Za-z\d._?%&+\-=\/#]*/g; const urlRex = /(http:|https:)\/\/www.bilibili.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
const bShortRex = /(http:|https:)\/\/b23.tv\/[A-Za-z\d._?%&+\-=\/#]*/g; const bShortRex = /(http:|https:)\/\/b23.tv\/[A-Za-z\d._?%&+\-=\/#]*/g;
let url = e.msg.trim(); let url = e.msg.trim();
@ -246,7 +258,7 @@ export class tools extends plugin {
// console.log(dynamicId) // console.log(dynamicId)
getDynamic(dynamicId).then(resp => { getDynamic(dynamicId).then(resp => {
if (resp.dynamicSrc.length > 0) { if (resp.dynamicSrc.length > 0) {
e.reply(`识别:哔哩哔哩动态, ${resp.dynamicDesc}`); e.reply(`识别:哔哩哔哩动态, ${ resp.dynamicDesc }`);
// let dynamicSrcMsg = [] // let dynamicSrcMsg = []
// resp.dynamicSrc.forEach(item => { // resp.dynamicSrc.forEach(item => {
// dynamicSrcMsg.push({ // dynamicSrcMsg.push({
@ -265,7 +277,7 @@ export class tools extends plugin {
return true; return true;
} }
const path = `${this.defaultPath}${this.e.group_id || this.e.user_id}/`; const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/`;
if (!fs.existsSync(path)) { if (!fs.existsSync(path)) {
mkdirsSync(path); mkdirsSync(path);
} }
@ -277,12 +289,12 @@ export class tools extends plugin {
// 获取视频信息,然后发送 // 获取视频信息,然后发送
fetch( fetch(
videoId.startsWith("BV") videoId.startsWith("BV")
? `${baseVideoInfo}?bvid=${videoId}` ? `${ baseVideoInfo }?bvid=${ videoId }`
: `${baseVideoInfo}?aid=${videoId}` : `${ baseVideoInfo }?aid=${ videoId }`
) )
.then(resp => resp.json()) .then(resp => resp.json())
.then(resp => { .then(resp => {
e.reply(`识别:哔哩哔哩, ${resp.data.title}`).catch(err => { e.reply(`识别:哔哩哔哩, ${ resp.data.title }`).catch(err => {
e.reply("解析失败,重试一下"); e.reply("解析失败,重试一下");
console.log(err); console.log(err);
}); });
@ -291,9 +303,9 @@ export class tools extends plugin {
await getDownloadUrl(url) await getDownloadUrl(url)
.then(data => { .then(data => {
this.downBili(`${path}temp`, data.videoUrl, data.audioUrl) this.downBili(`${ path }temp`, data.videoUrl, data.audioUrl)
.then(data => { .then(data => {
e.reply(segment.video(`${path}temp.mp4`)); e.reply(segment.video(`${ path }temp.mp4`));
}) })
.catch(err => { .catch(err => {
console.log(err); console.log(err);
@ -308,9 +320,9 @@ export class tools extends plugin {
} }
// 百科 // 百科
async wiki(e) { async wiki (e) {
const key = e.msg.replace(/#|百科|wiki/g, "").trim(); const key = e.msg.replace(/#|百科|wiki/g, "").trim();
const url = `https://xiaoapi.cn/API/bk.php?m=json&type=sg&msg=${encodeURI(key)}`; const url = `https://xiaoapi.cn/API/bk.php?m=json&type=sg&msg=${ encodeURI(key) }`;
// const url2 = 'https://api.jikipedia.com/go/auto_complete' // const url2 = 'https://api.jikipedia.com/go/auto_complete'
Promise.all([ Promise.all([
// axios.post(url2, { // axios.post(url2, {
@ -344,8 +356,8 @@ export class tools extends plugin {
const data = res[0]; const data = res[0];
// const data2 = res[0] // const data2 = res[0]
const template = ` const template = `
解释${_.get(data, "msg")}\n 解释${ _.get(data, "msg") }\n
详情${_.get(data, "more")}\n 详情${ _.get(data, "more") }\n
`; `;
// 小鸡解释:${ _.get(data2, 'content') } // 小鸡解释:${ _.get(data2, 'content') }
e.reply(template); e.reply(template);
@ -355,7 +367,7 @@ export class tools extends plugin {
// 小蓝鸟解析 // 小蓝鸟解析
// 例子https://twitter.com/chonkyanimalx/status/1595834168000204800 // 例子https://twitter.com/chonkyanimalx/status/1595834168000204800
async twitter(e) { async twitter (e) {
// 配置参数及解析 // 配置参数及解析
const reg = /https?:\/\/twitter.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/; const reg = /https?:\/\/twitter.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/;
const twitterUrl = reg.exec(e.msg); const twitterUrl = reg.exec(e.msg);
@ -370,11 +382,11 @@ export class tools extends plugin {
.singleTweet(id, { .singleTweet(id, {
"media.fields": "media.fields":
"duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text,variants", "duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text,variants",
expansions: ["entities.mentions.username", "attachments.media_keys"], expansions: [ "entities.mentions.username", "attachments.media_keys" ],
}) })
.then(resp => { .then(resp => {
e.reply(`识别:小蓝鸟学习版,${resp.data.text}`); e.reply(`识别:小蓝鸟学习版,${ resp.data.text }`);
const downloadPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`; const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 创建文件夹(如果没有过这个群) // 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) { if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath); mkdirsSync(downloadPath);
@ -383,7 +395,7 @@ export class tools extends plugin {
for (let item of resp.includes.media) { for (let item of resp.includes.media) {
if (item.type === "photo") { if (item.type === "photo") {
// 图片 // 图片
const filePath = `${downloadPath}/${item.url.split("/").pop()}`; const filePath = `${ downloadPath }/${ item.url.split("/").pop() }`;
this.downloadImg(item.url, downloadPath).then(_ => { this.downloadImg(item.url, downloadPath).then(_ => {
e.reply(segment.image(fs.readFileSync(filePath))); e.reply(segment.image(fs.readFileSync(filePath)));
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
@ -391,7 +403,7 @@ export class tools extends plugin {
} else if (item.type === "video") { } else if (item.type === "video") {
// 视频 // 视频
this.downloadVideo(resp.includes.media[0].variants[0].url, true).then(_ => { 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`));
}); });
} }
} }
@ -400,9 +412,9 @@ export class tools extends plugin {
} }
// 视频解析 // 视频解析
async tx(e) { async tx (e) {
const url = e.msg; const url = e.msg;
const data = await (await fetch(`https://xian.txma.cn/API/jx_txjx.php?url=${url}`)).json(); const data = await (await fetch(`https://xian.txma.cn/API/jx_txjx.php?url=${ url }`)).json();
const k = data.url; const k = data.url;
const name = data.title; const name = data.title;
if (k && name) { if (k && name) {
@ -419,7 +431,7 @@ export class tools extends plugin {
} }
// 请求参数 // 请求参数
async douyinRequest(url) { async douyinRequest (url) {
const params = { const params = {
headers: { headers: {
"User-Agent": "User-Agent":
@ -441,12 +453,12 @@ export class tools extends plugin {
} }
// 工具根URL据下载视频 / 音频 // 工具根URL据下载视频 / 音频
async downloadVideo(url, isProxy = false) { async downloadVideo (url, isProxy = false) {
const groupPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`; const groupPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
if (!fs.existsSync(groupPath)) { if (!fs.existsSync(groupPath)) {
mkdirsSync(groupPath); mkdirsSync(groupPath);
} }
const target = `${groupPath}/temp.mp4`; const target = `${ groupPath }/temp.mp4`;
// 待优化 // 待优化
if (fs.existsSync(target)) { if (fs.existsSync(target)) {
console.log(`视频已存在`); console.log(`视频已存在`);
@ -476,7 +488,7 @@ export class tools extends plugin {
}), }),
}); });
} }
console.log(`开始下载: ${url}`); console.log(`开始下载: ${ url }`);
const writer = fs.createWriteStream(target); const writer = fs.createWriteStream(target);
res.data.pipe(writer); res.data.pipe(writer);
@ -487,7 +499,7 @@ export class tools extends plugin {
} }
// 工具找到tiktok的视频id // 工具找到tiktok的视频id
async getIdVideo(url) { async getIdVideo (url) {
const matching = url.includes("/video/"); const matching = url.includes("/video/");
if (!matching) { if (!matching) {
this.e.reply("没找到,正在获取随机视频!"); this.e.reply("没找到,正在获取随机视频!");
@ -498,8 +510,8 @@ export class tools extends plugin {
} }
// acfun解析 // acfun解析
async acfun(e) { async acfun (e) {
const path = `${this.defaultPath}${this.e.group_id || this.e.user_id}/temp/`; const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp/`;
if (!fs.existsSync(path)) { if (!fs.existsSync(path)) {
mkdirsSync(path); mkdirsSync(path);
} }
@ -507,15 +519,15 @@ export class tools extends plugin {
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] }`;
} }
parseUrl(inputMsg).then(res => { parseUrl(inputMsg).then(res => {
e.reply(`识别:猴山,${res.videoName}`); e.reply(`识别:猴山,${ 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(_ => {
e.reply(segment.video(`${path}out.mp4`)); e.reply(segment.video(`${ path }out.mp4`));
}); });
}); });
}); });
@ -524,11 +536,11 @@ export class tools extends plugin {
} }
// 小红书解析 // 小红书解析
async redbook(e) { async redbook (e) {
const msgUrl = /(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec( const msgUrl = /(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec(
e.msg e.msg
)[0]; )[0];
const url = `https://dlpanda.com/zh-CN/xhs?url=${msgUrl}`; const url = `https://dlpanda.com/zh-CN/xhs?url=${ msgUrl }`;
await axios await axios
.get(url, { .get(url, {
@ -545,13 +557,13 @@ export class tools extends plugin {
const reg = /<img(.*)src="\/\/ci\.xiaohongshu\.com(.*?)"/g; const reg = /<img(.*)src="\/\/ci\.xiaohongshu\.com(.*?)"/g;
let res = ""; let res = "";
const downloadPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`; const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 创建文件夹(如果没有过这个群) // 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) { if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath); mkdirsSync(downloadPath);
} }
while ((res = reg.exec(resp.data))) { while ((res = reg.exec(resp.data))) {
const addr = `https://ci.xiaohongshu.com${res[2]}`; const addr = `https://ci.xiaohongshu.com${ res[2] }`;
axios axios
.get(addr, { .get(addr, {
headers: { headers: {
@ -561,7 +573,7 @@ export class tools extends plugin {
responseType: "stream", responseType: "stream",
}) })
.then(resp => { .then(resp => {
const filepath = `${downloadPath}/${/com\/(.*)\?/.exec(addr)[1]}.jpg`; const filepath = `${ downloadPath }/${ /com\/(.*)\?/.exec(addr)[1] }.jpg`;
const writer = fs.createWriteStream(filepath); const writer = fs.createWriteStream(filepath);
resp.data.pipe(writer); resp.data.pipe(writer);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -580,7 +592,7 @@ export class tools extends plugin {
} }
// 文献解析 // 文献解析
async literature(e) { async literature (e) {
const litReg = /(http:|https:)\/\/doi.org\/[A-Za-z\d._?%&+\-=\/#@]*/; const litReg = /(http:|https:)\/\/doi.org\/[A-Za-z\d._?%&+\-=\/#@]*/;
const url = litReg.exec(e.msg.trim())[0]; const url = litReg.exec(e.msg.trim())[0];
const waitList = [ const waitList = [
@ -601,7 +613,7 @@ export class tools extends plugin {
}); });
} }
async downBili(title, videoUrl, audioUrl) { async downBili (title, videoUrl, audioUrl) {
return Promise.all([ return Promise.all([
downloadBFile( downloadBFile(
videoUrl, videoUrl,
@ -633,9 +645,9 @@ export class tools extends plugin {
} }
// 工具:下载一张网络图片 // 工具:下载一张网络图片
async downloadImg(img, dir) { async downloadImg (img, dir) {
const filename = img.split("/").pop(); const filename = img.split("/").pop();
const filepath = `${dir}/${filename}`; const filepath = `${ dir }/${ filename }`;
const writer = fs.createWriteStream(filepath); const writer = fs.createWriteStream(filepath);
return axios return axios
.get(img, { .get(img, {
@ -669,7 +681,7 @@ export class tools extends plugin {
} }
// 工具下载pdf文件 // 工具下载pdf文件
async downloadPDF(url, filename) { async downloadPDF (url, filename) {
return axios({ return axios({
url: url, url: url,
responseType: "stream", responseType: "stream",