diff --git a/apps/arknights.js b/apps/arknights.js
deleted file mode 100644
index f91cd18..0000000
--- a/apps/arknights.js
+++ /dev/null
@@ -1,32 +0,0 @@
-
-import { segment } from "oicq";
-import puppeteer from "../../../lib/puppeteer/puppeteer.js";
-
-export class arknights extends plugin {
- constructor (e) {
- super({
- name: '明日方舟',
- dsc: '明日方舟信息查询',
- event: 'message',
- priority: 500,
- rule: [
- {
- reg: '^#(明日方舟wiki|arkwiki)(.*)$',
- fnc: 'arkWiki'
- }
- ]
- })
- }
-
- async arkWiki (e) {
- const key = e.msg.replace(/#|明日方舟wiki|arkwiki/g, "").trim();
- const browser = await puppeteer.browserInit()
- const page = await browser.newPage()
- await page.goto(`https://wiki.biligame.com/arknights/${ key }`)
- const wikiImg = await page.screenshot({
- fullPage: true, type: 'jpeg', omitBackground: false, quality: 90
- })
- browser.close()
- await e.reply(segment.image(wikiImg))
- }
-}
\ No newline at end of file
diff --git a/apps/tools.js b/apps/tools.js
index 9869ae1..cb16fca 100644
--- a/apps/tools.js
+++ b/apps/tools.js
@@ -55,6 +55,10 @@ export class tools extends plugin {
{
reg: "(.*)(acfun.cn)",
fnc: "acfun"
+ },
+ {
+ reg: "(.*)(xhslink.com|xiaohongshu.com)",
+ fnc: "redbook"
}
],
});
@@ -64,6 +68,7 @@ export class tools extends plugin {
// redis的key
this.redisKey = `Yz:tools:cache:${ this.group_id }`;
// 代理接口
+ // TODO 填写服务器的内网ID和clash的端口
this.proxyAddr = '10.0.8.10';
this.proxyPort = '7890'
this.myProxy = `http://${this.proxyAddr}:${this.proxyPort}`;
@@ -81,7 +86,8 @@ export class tools extends plugin {
}
const place = msg.replace(language[0], "").trim();
// let url = /[\u4E00-\u9FFF]+/g.test(place)
- let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ transMap[language[1]] }&appid=20210422000794040&salt=542716863&sign=${ md5("20210422000794040" + place + "542716863" + "HooD_ndgwcGH6SAnxGrM") }&q=${ place }`;
+ // TODO 查阅百度文档填写
+ let url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ transMap[language[1]] }&appid=&salt=&sign=${ md5("" + place + "" + "") }&q=${ place }`;
await fetch(url)
.then((resp) => resp.json())
.then((text) => text.trans_result)
@@ -164,9 +170,9 @@ export class tools extends plugin {
// 短号处理
if (url.includes('b23.tv')) {
const bShortUrl = bShortRex.exec(url)[0]
- await this.douyinRequest(bShortUrl).then((res) => {
- url = res.replace("m", "www")
- });
+ await fetch(bShortUrl).then(resp => {
+ url = resp.url;
+ })
} else {
url = urlRex.exec(url)[0];
}
@@ -180,7 +186,7 @@ export class tools extends plugin {
// 视频信息获取例子:http://api.bilibili.com/x/web-interface/view?bvid=BV1hY411m7cB
const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view";
console.log(url);
- const videoId = /video\/(.*)(\/|\?)/g.exec(url)[1];
+ const videoId = /video\/(.*?)(\/|\?)/g.exec(url)[1];
// 获取视频信息,然后发送
fetch(videoId.startsWith("BV") ? `${baseVideoInfo}?bvid=${videoId}` : `${baseVideoInfo}?aid=${videoId}`)
.then(resp => resp.json())
@@ -207,7 +213,7 @@ export class tools extends plugin {
// 百科
async wiki (e) {
const key = e.msg.replace(/#|百科|wiki/g, "").trim();
- const url = `https://xiaoapi.cn/API/bk.php?m=json&type=bd&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'
Promise.all([
// axios.post(url2, {
@@ -258,7 +264,7 @@ export class tools extends plugin {
const twitterUrl = reg.exec(e.msg);
const id = twitterUrl[1];
const httpAgent = new HttpProxyAgent(this.myProxy)
- const twitterClient = new TwitterApi('AAAAAAAAAAAAAAAAAAAAAArXkwEAAAAAhSrZLK61mRibO0BKwRXgVvEnIzU%3DRUtuE2PL9EGsi1fjHPDsM7SLhmR1UWuCJMt4PB8FFdm94uQ5qL', {httpAgent});
+ const twitterClient = new TwitterApi('', {httpAgent});
// Tell typescript it's a readonly app
const readOnlyClient = twitterClient.readOnly;
@@ -417,6 +423,558 @@ export class tools extends plugin {
return true;
}
+ // 小红书解析
+ async redbook(e) {
+ const msgUrl = /(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec(e.msg)[0];
+ const url = `https://dlpanda.com/zh-CN/xhs?url=${msgUrl}`
+
+ await axios.get(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ "Content-Type": "application/json",
+ "Accept-Encoding": "gzip,deflate,compress"
+ },
+ timeout: 10000,
+ proxy: false,
+ }).then((resp) => {
+ const reg = /
resp.json())
+ .then((text) => text.trans_result)
+ .then((res) => this.reply(`${ res[0].dst }`, true))
+ .catch((err) => logger.error(err));
+ return true;
+ }
+
+ // 抖音解析
+ async douyin (e) {
+ const urlRex = /(http:|https:)\/\/v.douyin.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
+ const douUrl = urlRex.exec(e.msg.trim())[0];
+
+ await this.douyinRequest(douUrl).then(async (res) => {
+ const douRex = /.*video\/(\d+)\/(.*?)/g;
+ 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/aweme/v1/web/aweme/detail/?aweme_id=${ douId }&aid=1128&version_name=23.5.0&device_platform=android&os_version=2333`
+ const resp = await fetch(url);
+ const json = await resp.json();
+ const item = json.aweme_detail;
+ e.reply(`识别:抖音, ${item.desc}`);
+ const url_2 = item.video.play_addr.url_list[0];
+ this.downloadVideo(url_2).then(video => {
+ e.reply(segment.video(`${this.defaultPath}${this.e.group_id || this.e.user_id}/temp.mp4`));
+ });
+ });
+ return true;
+ }
+
+ // tiktok解析
+ async tiktok (e) {
+ const urlRex = /(http:|https:)\/\/www.tiktok.com\/[A-Za-z\d._?%&+\-=\/#@]*/g;
+ const urlShortRex = /(http:|https:)\/\/vt.tiktok.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
+ let url = e.msg.trim()
+ // 短号处理
+ if (url.includes('vt.tiktok')) {
+ const temp_url = urlShortRex.exec(url)[0]
+ await fetch(temp_url, {
+ redirect: "follow",
+ follow: 10,
+ timeout: 10000,
+ agent: new HttpProxyAgent(this.myProxy)
+ }).then((resp) => {
+ url = resp.url
+ })
+ } else {
+ url = urlRex.exec(url)[0]
+ }
+ const idVideo = await this.getIdVideo(url)
+ // API链接
+ const API_URL = `https://api19-core-useast5.us.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.get(API_URL, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ "Content-Type": "application/json",
+ "Accept-Encoding": "gzip,deflate,compress"
+ },
+ timeout: 10000,
+ proxy: false,
+ httpAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ httpsAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ }).then(resp => {
+ const data = resp.data.aweme_list[0];
+ e.reply(`识别:tiktok, ${data.desc}`)
+ this.downloadVideo(data.video.play_addr.url_list[0], true).then(video => {
+ e.reply(segment.video(`${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp.mp4`));
+ })
+ })
+ return true
+ }
+
+ // bilibi解析
+ async bili (e) {
+ const urlRex = /(http:|https:)\/\/www.bilibili.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
+ const bShortRex = /(http:|https:)\/\/b23.tv\/[A-Za-z\d._?%&+\-=\/#]*/g;
+ let url = e.msg.trim()
+ // 短号处理
+ if (url.includes('b23.tv')) {
+ const bShortUrl = bShortRex.exec(url)[0]
+ await fetch(bShortUrl).then(resp => {
+ url = resp.url;
+ })
+ } else {
+ url = urlRex.exec(url)[0];
+ }
+
+ const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp`
+ // 待优化
+ if (fs.existsSync(`${ path }.mp4`)) {
+ console.log("视频已存在");
+ fs.unlinkSync(`${ path }.mp4`);
+ }
+ // 视频信息获取例子:http://api.bilibili.com/x/web-interface/view?bvid=BV1hY411m7cB
+ const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view";
+ console.log(url);
+ const videoId = /video\/(.*?)(\/|\?)/g.exec(url)[1];
+ // 获取视频信息,然后发送
+ fetch(videoId.startsWith("BV") ? `${baseVideoInfo}?bvid=${videoId}` : `${baseVideoInfo}?aid=${videoId}`)
+ .then(resp => resp.json())
+ .then(resp => {
+ e.reply(`识别:哔哩哔哩, ${resp.data.title}`)
+ })
+
+ await getDownloadUrl(url)
+ .then(data => {
+ this.downBili(path, data.videoUrl, data.audioUrl)
+ .then(data => {
+ e.reply(segment.video(`${ path }.mp4`))
+ })
+ .catch(data => {
+ e.reply('解析失败,请重试一下')
+ });
+ })
+ .catch(err => {
+ e.reply('解析失败,请重试一下')
+ });
+ return true
+ }
+
+ // 百科
+ async wiki (e) {
+ const key = e.msg.replace(/#|百科|wiki/g, "").trim();
+ const url = `https://xiaoapi.cn/API/bk.php?m=json&type=sg&msg=${ encodeURI(key) }`
+ // const url2 = 'https://api.jikipedia.com/go/auto_complete'
+ Promise.all([
+ // axios.post(url2, {
+ // headers: {
+ // "User-Agent":
+ // "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ // "Content-Type": "application/json",
+ // },
+ // timeout: 10000,
+ // "phrase": key,
+ // })
+ // .then(resp => {
+ // const data = resp.data.data
+ // if (_.isEmpty(data)) {
+ // return data;
+ // }
+ // return data[0].entities[0];
+ // }),
+ axios.get(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ },
+ timeout: 10000,
+ })
+ .then(resp => {
+ return resp.data
+ })
+ ])
+ .then(res => {
+ const data = res[0]
+ // const data2 = res[0]
+ const template = `
+ 解释:${ _.get(data, 'msg') }\n
+ 详情:${ _.get(data, 'more') }\n
+ `;
+ // 小鸡解释:${ _.get(data2, 'content') }
+ e.reply(template)
+ })
+ return true
+ }
+
+ // twitter解析
+ // 例子:https://twitter.com/chonkyanimalx/status/1595834168000204800
+ async twitter (e) {
+ // 配置参数及解析
+ const reg = /https?:\/\/twitter.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/
+ const twitterUrl = reg.exec(e.msg);
+ const id = twitterUrl[1];
+ const httpAgent = new HttpProxyAgent(this.myProxy)
+ // TODO 需要填写Twitter id
+ const twitterClient = new TwitterApi('', {httpAgent});
+
+ // Tell typescript it's a readonly app
+ const readOnlyClient = twitterClient.readOnly;
+
+ readOnlyClient.v2.singleTweet(id, {
+ 'media.fields': 'duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text,variants',
+ expansions: [
+ 'entities.mentions.username',
+ 'attachments.media_keys',
+ ],
+ }).then(resp => {
+ e.reply(`识别:腿忒学习版,${resp.data.text}`)
+ const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
+ // 创建文件夹(如果没有过这个群)
+ if (!fs.existsSync(downloadPath)) {
+ mkdirsSync(downloadPath);
+ }
+ // 开始读取数据
+ if (resp.includes.media[0].type === 'photo') {
+ // 图片
+ resp.includes.media.map(item => {
+ const filePath = `${downloadPath}/${item.url.split('/').pop()}`
+ this.downloadImgs(item.url, downloadPath).then(tmp => {
+ e.reply(segment.image(fs.readFileSync(filePath)))
+ })
+ })
+ } else {
+ // 视频
+ this.downloadVideo(resp.includes.media[0].variants[0].url, true).then(video => {
+ e.reply(segment.video(`${downloadPath}/temp.mp4`));
+ });
+ }
+ });
+ return true;
+ }
+
+ // 视频解析
+ async tx( e ) {
+ const url = e.msg
+ const data = await ( await fetch( `https://xian.txma.cn/API/jx_txjx.php?url=${url}` ) )
+ .json()
+ const k = data.url
+ const name = data.title
+ if( k && name ) {
+ e.reply( name + '\n' + k )
+ let forward = await this.makeForwardMsg( url )
+ e.reply( forward )
+ return true
+ } else {
+ e.reply( '解析腾讯视频失败~\n去浏览器使用拼接接口吧...' )
+ let forward = await this.makeForwardMsg( url )
+ e.reply( forward )
+ return true
+ }
+ }
+
+
+ // 请求参数
+ async douyinRequest (url) {
+ const params = {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ },
+ timeout: 10000,
+ };
+ return new Promise((resolve, reject) => {
+ axios
+ .head(url, params)
+ .then((resp) => {
+ const location = resp.request.res.responseUrl
+ resolve(location);
+ })
+ .catch((err) => {
+ reject(err);
+ });
+ });
+ }
+
+ // 工具:根URL据下载视频 / 音频
+ async downloadVideo (url, isProxy=false) {
+ const groupPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
+ if (!fs.existsSync(groupPath)) {
+ mkdirsSync(groupPath);
+ }
+ const target = `${ groupPath }/temp.mp4`;
+ // 待优化
+ if (fs.existsSync(target)) {
+ console.log(`视频已存在`);
+ fs.unlinkSync(target);
+ }
+ let res;
+ if (!isProxy) {
+ res = await axios.get(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ },
+ responseType: "stream",
+ });
+ } else {
+ res = await axios.get(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ },
+ responseType: "stream",
+ httpAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ httpsAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ });
+ }
+ console.log(`开始下载: ${ url }`);
+ const writer = fs.createWriteStream(target);
+ res.data.pipe(writer);
+
+ return new Promise((resolve, reject) => {
+ writer.on("finish", resolve);
+ writer.on("error", reject);
+ });
+ }
+
+ // 工具:找到tiktok的视频id
+ async getIdVideo (url) {
+ const matching = url.includes("/video/")
+ if (!matching) {
+ this.e.reply("没找到,正在获取随机视频!")
+ return null
+ }
+ const idVideo = url.substring(url.indexOf("/video/") + 7, url.length);
+ return (idVideo.length > 19) ? idVideo.substring(0, idVideo.indexOf("?")) : idVideo;
+ }
+
+ // acfun解析
+ async acfun(e) {
+ const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp/`
+ if (!fs.existsSync(path)) {
+ mkdirsSync(path);
+ }
+
+ let inputMsg = e.msg;
+ // 适配手机分享:https://m.acfun.cn/v/?ac=32838812&sid=d2b0991bd6ad9c09
+ if (inputMsg.includes("m.acfun.cn")) {
+ inputMsg = `https://www.acfun.cn/v/ac${/ac=([^&?]*)/.exec(inputMsg)[1]}`
+ }
+
+ parseUrl(inputMsg).then(res => {
+ e.reply(`识别:猴山,${res.videoName}`)
+ parseM3u8(res.urlM3u8s[res.urlM3u8s.length-1]).then(res2 => {
+ downloadM3u8Videos(res2.m3u8FullUrls, path).then(_ => {
+ mergeAcFileToMp4( res2.tsNames, path, `${path}out.mp4`).then(_ => {
+ e.reply(segment.video(`${path}out.mp4`))
+ })
+ })
+ })
+ })
+ return true;
+ }
+
+ // 小红书解析
+ async redbook(e) {
+ const msgUrl = /(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec(e.msg)[0];
+ const url = `https://dlpanda.com/zh-CN/xhs?url=${msgUrl}`
+
+ await axios.get(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ "Content-Type": "application/json",
+ "Accept-Encoding": "gzip,deflate,compress"
+ },
+ timeout: 10000,
+ proxy: false,
+ }).then((resp) => {
+ const reg = /
0) {
+ e.reply(Bot.makeForwardMsg(images))
+ } else {
+ e.reply("解析失败,重新解析下");
+ }
+ })
+
+ return true;
+ }
+
+ // 工具:下载哔哩哔哩
+ async downBili (title, videoUrl, audioUrl) {
+ return Promise.all([
+ downloadBFile(
+ videoUrl,
+ title + '-video.m4s',
+ _.throttle(
+ value =>
+ console.log('download-progress', {
+ type: 'video',
+ data: value,
+ }),
+ 1000,
+ ),
+ ),
+ downloadBFile(
+ audioUrl,
+ title + '-audio.m4s',
+ _.throttle(
+ value =>
+ console.log('download-progress', {
+ type: 'audio',
+ data: value,
+ }),
+ 1000,
+ ),
+ ),
+ ])
+ .then(data => {
+ return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, title + '.mp4');
+ })
+ }
+
+ // 工具:下载一张网络图片
+ async downloadImgs(img, dir) {
+
+ const filename = img.split('/').pop();
+ const filepath = `${dir}/${filename}`;
+ const writer = fs.createWriteStream(filepath);
+ return axios.get(img, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ },
+ responseType: "stream",
+ httpAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ httpsAgent: tunnel.httpOverHttp({ proxy: { host: this.proxyAddr, port: this.proxyPort } }),
+ }).then(res => {
+ res.data.pipe(writer);
+ return new Promise((resolve, reject) => {
+ writer.on('finish', () => resolve(filepath));
+ writer.on('error', reject);
+ });
+ });
+ }
+ }
+
+ let images = [];
+ while (res = reg.exec(resp.data)) {
+ console.log(`https://ci.xiaohongshu.com${res[2]}`)
+ images.push({
+ message: segment.image(`https://ci.xiaohongshu.com${res[2]}`),
+ nickname: e.sender.card || e.user_id,
+ user_id: e.user_id
+ })
+ }
+ if (images.length > 0) {
+ e.reply(Bot.makeForwardMsg(images))
+ } else {
+ e.reply("解析失败,重新解析下");
+ }
+ })
+
+ return true;
+ }
+
// 工具:下载哔哩哔哩
async downBili (title, videoUrl, audioUrl) {
return Promise.all([