diff --git a/.gitignore b/.gitignore index 8228d65..6bff9a5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,8 @@ node_modules/ ehthumbs.db Thumbs.db .idea +.history +package.json package-lock.json +yarn.lock +.prettierrc.json \ No newline at end of file diff --git a/apps/daily.js b/apps/daily.js index 3112cd6..9727494 100644 --- a/apps/daily.js +++ b/apps/daily.js @@ -1,67 +1,67 @@ -import common from '../../../lib/common/common.js' -import fetch from 'node-fetch' -import schedule from 'node-schedule' -import { Group, segment } from 'oicq' +import common from "../../../lib/common/common.js"; +import fetch from "node-fetch"; +import schedule from "node-schedule"; +import { Group, segment } from "oicq"; // 指定定时发送的群号 -const groupList = [ '169721415' ] +const groupList = ["169721415"]; // 是否开启定时推送,默认为 true -let isAutoPush = true -function autoTask (func, time) { +let isAutoPush = true; +function autoTask(func, time) { if (isAutoPush) { schedule.scheduleJob(time, () => { for (let i = 0; i < groupList.length; i++) { - let group = Bot.pickGroup(groupList[i]) - func(group) - common.sleep(1000) + let group = Bot.pickGroup(groupList[i]); + func(group); + common.sleep(1000); } - }) + }); } } // 定时任务合集 -autoTask(pushDailyWorld, '0 30 8 * * ?') -autoTask(pushTouchFish, '0 31 8 * * ?') +autoTask(pushDailyWorld, "0 30 8 * * ?"); +autoTask(pushTouchFish, "0 31 8 * * ?"); export class daily extends plugin { - constructor (e) { + constructor(e) { super({ - name: 'rconsole插件帮助', - dsc: 'rconsole插件帮助插件帮助', - event: 'message', + name: "rconsole插件帮助", + dsc: "rconsole插件帮助插件帮助", + event: "message", priority: 500, rule: [ { - reg: '^#每天60秒$', - fnc: 'dailyWorld' + reg: "^#每天60秒$", + fnc: "dailyWorld", }, { - reg: '^#摸鱼人日历$', - fnc: 'touchFish' + reg: "^#摸鱼人日历$", + fnc: "touchFish", }, { - reg: '^#开关每日推送$', - fnc: 'shutdown' + reg: "^#开关每日推送$", + fnc: "shutdown", }, - ] - }) + ], + }); } - async dailyWorld (e) { + async dailyWorld(e) { // 定时发送时间,采用 Cron 表达式,当前默认为每日 8:30 分推送 await pushDailyWorld(e); return true; } - async touchFish (e) { + async touchFish(e) { await pushTouchFish(e); return true; } - async shutdown (e) { - isAutoPush = !isAutoPush - e.reply(`【当前推送状态】:${ isAutoPush ? '开启' : '关闭' }`) + async shutdown(e) { + isAutoPush = !isAutoPush; + e.reply(`【当前推送状态】:${isAutoPush ? "开启" : "关闭"}`); } } @@ -69,41 +69,43 @@ export class daily extends plugin { * 推送每天60秒读懂世界 * @param e oicq传递的事件参数e */ -async function pushDailyWorld (e) { +async function pushDailyWorld(e) { // 每天60秒读懂世界接口地址 - const url = await fetch('https://api.vvhan.com/api/60s?type=json') - .catch(err => logger.error(err)) - const imgUrl = await url.json() - const res = await imgUrl.imgUrl + const url = await fetch("https://api.vvhan.com/api/60s?type=json").catch(err => + logger.error(err) + ); + const imgUrl = await url.json(); + const res = await imgUrl.imgUrl; // 判断接口是否请求成功 if (!res) { - e.reply('[60秒读懂世界] 接口请求失败') + e.reply("[60秒读懂世界] 接口请求失败"); } // 回复消息 if (e instanceof Group) { - e.sendMsg(segment.image(res)) + e.sendMsg(segment.image(res)); } else { - e.reply(segment.image(res)) + e.reply(segment.image(res)); } } -async function pushTouchFish (e) { - const url = await fetch('https://api.vvhan.com/api/moyu?type=json') - .catch(err => logger.error(err)) - const imgUrl = await url.json() - const res = await imgUrl.url +async function pushTouchFish(e) { + const url = await fetch("https://api.vvhan.com/api/moyu?type=json").catch(err => + logger.error(err) + ); + const imgUrl = await url.json(); + const res = await imgUrl.url; // 判断接口是否请求成功 if (!res) { - e.reply('[摸鱼人日历] 接口请求失败') + e.reply("[摸鱼人日历] 接口请求失败"); } // 回复消息 if (e instanceof Group) { - e.sendMsg(segment.image(res)) + e.sendMsg(segment.image(res)); } else { - e.reply(segment.image(res)) + e.reply(segment.image(res)); } -} \ No newline at end of file +} diff --git a/apps/help.js b/apps/help.js index a273e43..a2b13aa 100644 --- a/apps/help.js +++ b/apps/help.js @@ -1,42 +1,42 @@ -import Help from '../model/help.js' -import puppeteer from '../../../lib/puppeteer/puppeteer.js' -import md5 from 'md5' +import Help from "../model/help.js"; +import puppeteer from "../../../lib/puppeteer/puppeteer.js"; +import md5 from "md5"; let helpData = { - md5: '', - img: '' -} + md5: "", + img: "", +}; export class help extends plugin { - constructor (e) { + constructor(e) { super({ - name: 'rconsole插件帮助', - dsc: 'rconsole插件帮助插件帮助', - event: 'message', + name: "rconsole插件帮助", + dsc: "rconsole插件帮助插件帮助", + event: "message", priority: 500, rule: [ { - reg: '^#*(R|r)(插件)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$', - fnc: 'help' - } - ] - }) + reg: "^#*(R|r)(插件)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$", + fnc: "help", + }, + ], + }); } - async help () { - let data = await Help.get(this.e) - if (!data) return - let img = await this.cache(data) - await this.reply(img) + async help() { + let data = await Help.get(this.e); + if (!data) return; + let img = await this.cache(data); + await this.reply(img); } - async cache (data) { - let tmp = md5(JSON.stringify(data)) - if (helpData.md5 == tmp) return helpData.img + async cache(data) { + let tmp = md5(JSON.stringify(data)); + if (helpData.md5 == tmp) return helpData.img; - helpData.img = await puppeteer.screenshot('help', data) - helpData.md5 = tmp + helpData.img = await puppeteer.screenshot("help", data); + helpData.md5 = tmp; - return helpData.img + return helpData.img; } } diff --git a/apps/mystery.js b/apps/mystery.js index 0348b21..f4841e3 100644 --- a/apps/mystery.js +++ b/apps/mystery.js @@ -1,11 +1,11 @@ // 主库 -import { segment } from 'oicq' -import common from '../../../lib/common/common.js' -import fetch from 'node-fetch' +import { segment } from "oicq"; +import common from "../../../lib/common/common.js"; +import fetch from "node-fetch"; // 配置文件 -import config from '../model/index.js' +import config from "../model/index.js"; // 其他库 -import _ from 'lodash' +import _ from "lodash"; // import mongodb from 'mongodb' // Mongodb初始化 @@ -26,42 +26,47 @@ import _ from 'lodash' // // const mongo = initMongo() // 60s后撤回 -const recallTime = 109 +const recallTime = 109; export class mystery extends plugin { - constructor () { + constructor() { super({ - name: '神秘区域', - dsc: '神秘指令', - event: 'message.group', + name: "神秘区域", + dsc: "神秘指令", + event: "message.group", priority: 500, rule: [ { - reg: '^#(雀食|确实)$', fnc: 'mystery' + reg: "^#(雀食|确实)$", + fnc: "mystery", }, { - reg: '^#*来份涩图 (.*)$', fnc: 'setu' + reg: "^#*来份涩图 (.*)$", + fnc: "setu", }, { - reg: '^#(累了)$', fnc: 'cospro' + reg: "^#(累了)$", + fnc: "cospro", }, { - reg: '^#(啊?|啊?)$', fnc: 'aaa' - } + reg: "^#(啊?|啊?)$", + fnc: "aaa", + }, // { // reg: '^#我靠', fnc: 'tuiimg' // } - ] - }) - this.mysteryConfig = config.getConfig('mystery') + ], + }); + this.mysteryConfig = config.getConfig("mystery"); } /** 接受到消息都会先执行一次 */ async accept() { if (this.e.isGroup) { let group = this.e.group; - if (!group.is_owner && (group.is_admin && group.mute_left > 0)) return; - if (!(group.is_owner || group.is_admin) && (group.all_muted || group.mute_left > 0)) return; + if (!group.is_owner && group.is_admin && group.mute_left > 0) return; + if (!(group.is_owner || group.is_admin) && (group.all_muted || group.mute_left > 0)) + return; } let old_reply = this.e.reply; @@ -75,8 +80,11 @@ export class mystery extends plugin { let isxml = false; for (let msg of msgs) { - if (msg && msg?.type == 'xml' && msg?.data) { - msg.data = msg.data.replace(/^<\?xml.*version=.*?>/g, ''); + if (msg && msg?.type == "xml" && msg?.data) { + msg.data = msg.data.replace( + /^<\?xml.*version=.*?>/g, + '' + ); isxml = true; } } @@ -84,172 +92,183 @@ export class mystery extends plugin { if (isxml) { result = await old_reply(msgs, quote, data); } else { - let MsgList = [{ - message: msgs, - nickname: Bot.nickname, - user_id: Bot.uin - }]; + let MsgList = [ + { + message: msgs, + nickname: Bot.nickname, + user_id: Bot.uin, + }, + ]; let forwardMsg = await Bot.makeForwardMsg(MsgList); forwardMsg.data = forwardMsg.data - .replace('', '') - .replace(/\n/g, '') - .replace(/(.+?)<\/title>/g, '___') + .replace( + '<?xml version="1.0" encoding="utf-8"?>', + '<?xml version="1.0" encoding="utf-8" ?>' + ) + .replace(/\n/g, "") + .replace(/<title color="#777777" size="26">(.+?)<\/title>/g, "___") .replace(/___+/, '<title color="#777777" size="26">请点击查看内容'); msgs = forwardMsg; result = await old_reply(msgs, quote, data); } if (!result || !result.message_id) { - logger.error('风控消息处理失败,请登录手机QQ查看是否可手动解除风控!'); + logger.error("风控消息处理失败,请登录手机QQ查看是否可手动解除风控!"); } } return result; - } + }; } - async mystery (e) { + async mystery(e) { // 最大页数 - const maxPage = this.mysteryConfig.mystery.maxPage - const maxPigObj = this.mysteryConfig.mystery.maxPigObj + const maxPage = this.mysteryConfig.mystery.maxPage; + const maxPigObj = this.mysteryConfig.mystery.maxPigObj; // 限制最大图片数量 - const imageCountLimit = this.mysteryConfig.mystery.imageCountLimit + const imageCountLimit = this.mysteryConfig.mystery.imageCountLimit; // 随机算法 - const page = _.random(1, maxPage) - const randomIndex = _.random(0, maxPigObj - 1) + const page = _.random(1, maxPage); + const randomIndex = _.random(0, maxPigObj - 1); // 回复 - this.reply('确实是吧, 正在探索...') + this.reply("确实是吧, 正在探索..."); // 请求 - let url = `https://www.cos6.net/wp-json/wp/v2/posts?page=${ page }` - let images = [] + let url = `https://www.cos6.net/wp-json/wp/v2/posts?page=${page}`; + let images = []; await fetch(url) - .then((resp) => { - return resp.json() + .then(resp => { + return resp.json(); }) - .then((json) => { + .then(json => { const template = { nickname: this.e.sender.card || this.e.user_id, - user_id: this.e.user_id - } + user_id: this.e.user_id, + }; - const content = json[randomIndex].content - images = this.getCos6Img(content.rendered) + const content = json[randomIndex].content; + images = this.getCos6Img(content.rendered); // 洗牌 - images = _.shuffle(images) + images = _.shuffle(images); // 限制长度 if (images.length > imageCountLimit) { - images = images.slice(1, imageCountLimit + 1) + images = images.slice(1, imageCountLimit + 1); } // 循环队列 for (let i = 0; i < images.length; i++) { images[i] = { message: segment.image(images[i]), - ...template - } + ...template, + }; } }) - .catch((err) => { - this.e.reply('探索失败,你再我去一次吧') - logger.error(err) - return false - }) - return !!(await this.reply(await Bot.makeForwardMsg(images))) + .catch(err => { + this.e.reply("探索失败,你再我去一次吧"); + logger.error(err); + return false; + }); + return !!(await this.reply(await Bot.makeForwardMsg(images))); } - async cospro (e) { - let req = [ ...await fetch('https://imgapi.cn/cos2.php?return=jsonpro').then((resp) => resp.json()).then((json) => json.imgurls), ...await fetch('https://imgapi.cn/cos.php?return=jsonpro').then((resp) => resp.json()).then((json) => json.imgurls) ] - e.reply('哪天克火掉一定是在这个群里面...') - let images = [] + async cospro(e) { + let req = [ + ...(await fetch("https://imgapi.cn/cos2.php?return=jsonpro") + .then(resp => resp.json()) + .then(json => json.imgurls)), + ...(await fetch("https://imgapi.cn/cos.php?return=jsonpro") + .then(resp => resp.json()) + .then(json => json.imgurls)), + ]; + e.reply("哪天克火掉一定是在这个群里面..."); + let images = []; req.forEach(item => { images.push({ message: segment.image(encodeURI(item)), nickname: this.e.sender.card || this.e.user_id, - user_id: this.e.user_id - }) - }) - return !!(await this.reply(await Bot.makeForwardMsg(images))) + user_id: this.e.user_id, + }); + }); + return !!(await this.reply(await Bot.makeForwardMsg(images))); } - async aaa (e) { + async aaa(e) { // https://yingtall.com/wp-json/wp/v2/posts?page=64 // 最大页数 - const maxPage = this.mysteryConfig.aaa.maxPage - const maxPigObj = this.mysteryConfig.aaa.maxPigObj + const maxPage = this.mysteryConfig.aaa.maxPage; + const maxPigObj = this.mysteryConfig.aaa.maxPigObj; // 限制最大图片数量 - const imageCountLimit = this.mysteryConfig.aaa.imageCountLimit + const imageCountLimit = this.mysteryConfig.aaa.imageCountLimit; // 随机算法 - const page = _.random(1, maxPage) - const randomIndex = _.random(0, maxPigObj - 1) + const page = _.random(1, maxPage); + const randomIndex = _.random(0, maxPigObj - 1); // 回复 - this.reply('真变态啊...') + this.reply("真变态啊..."); // 请求 - let images = [] - let imgData = [] - let url = `https://yingtall.com/wp-json/wp/v2/posts?page=${ page }` + let images = []; + let imgData = []; + let url = `https://yingtall.com/wp-json/wp/v2/posts?page=${page}`; await fetch(url) - .then((resp) => { - return resp.json() + .then(resp => { + return resp.json(); }) - .then((json) => { + .then(json => { if (!json.length) { - e.reply('探索失败,你再我去一次吧') - return false + e.reply("探索失败,你再我去一次吧"); + return false; } - const content = json[randomIndex].content - images = this.getImages2(content.rendered) + const content = json[randomIndex].content; + images = this.getImages2(content.rendered); // 如果图片为空直接返回 if (images.length === 0) { - e.reply('探索失败,你再我去一次吧') - return false + e.reply("探索失败,你再我去一次吧"); + return false; } // 洗牌 - images = _.shuffle(images) + images = _.shuffle(images); // 限制长度 if (images.length > imageCountLimit) { - images = images.slice(1, imageCountLimit + 1) + images = images.slice(1, imageCountLimit + 1); } // 循环队列 - images.forEach((item) => { + images.forEach(item => { imgData.push({ message: segment.image(item), nickname: e.sender.card || e.user_id, - user_id: e.user_id - }) - }) + user_id: e.user_id, + }); + }); }) - .catch((err) => logger.error(err)) - return !!(await this.reply(await Bot.makeForwardMsg(imgData))) + .catch(err => logger.error(err)); + return !!(await this.reply(await Bot.makeForwardMsg(imgData))); } - async setu (e) { - const keyword = e.msg.split(' ')[1] - const numb = this.mysteryConfig.setu.count - await e.reply('正在给你找图片啦~', true, { recallMsg: 7 }); + async setu(e) { + const keyword = e.msg.split(" ")[1]; + const numb = this.mysteryConfig.setu.count; + await e.reply("正在给你找图片啦~", true, { recallMsg: 7 }); - let url = `https://api.lolicon.app/setu/v2?r18=${ keyword }&num=${ numb }`;//←此处修改图片类型,0为非18,1为18,2为18非18混合 + let url = `https://api.lolicon.app/setu/v2?r18=${keyword}&num=${numb}`; //←此处修改图片类型,0为非18,1为18,2为18非18混合 const response = await fetch(url); const imgJson = await response.json(); - const images = [] + const images = []; for (let image of imgJson.data) { images.push({ message: segment.image(image.urls.original), nickname: e.sender.card || e.user_id, - user_id: e.user_id - }) + user_id: e.user_id, + }); } - const res = await this.reply( - await Bot.makeForwardMsg(images), - false, - { recallMsg: 60 }) + const res = await this.reply(await Bot.makeForwardMsg(images), false, { recallMsg: 60 }); if (!res) { - return e.reply('好、好涩(//// ^ ////)……不、不行啦……被、被吞啦o(≧口≦)o',true,{recallMsg:60}); + return e.reply("好、好涩(//// ^ ////)……不、不行啦……被、被吞啦o(≧口≦)o", true, { + recallMsg: 60, + }); } - return true + return true; } // async tuiimg (e) { @@ -274,24 +293,24 @@ export class mystery extends plugin { // } // 正则:获取图片 - getCos6Img (string) { - const imgRex = /\/([\w].*?).(jpg|JPG|png|PNG|gif|GIF|jpeg|JPEG|svg)/g - const images = [] - let img + getCos6Img(string) { + const imgRex = /\/([\w].*?).(jpg|JPG|png|PNG|gif|GIF|jpeg|JPEG|svg)/g; + const images = []; + let img; while ((img = imgRex.exec(string))) { - images.push(`https://www.cos6.net/${ img[1] }.jpg`) + images.push(`https://www.cos6.net/${img[1]}.jpg`); } - return images + return images; } // 正则:获取图片 - getImages2 (string) { - const imgRex = /]+>/g - const images = [] - let img + getImages2(string) { + const imgRex = /]+>/g; + const images = []; + let img; while ((img = imgRex.exec(string))) { - images.push(img[1]) + images.push(img[1]); } - return images + return images; } } diff --git a/apps/query.js b/apps/query.js index 29f4c82..5e77e3c 100644 --- a/apps/query.js +++ b/apps/query.js @@ -1,88 +1,93 @@ // 主库 -import { segment } from 'oicq' -import fetch from 'node-fetch' +import { segment } from "oicq"; +import fetch from "node-fetch"; // 配置文件 -import config from '../model/index.js' +import config from "../model/index.js"; // 爬虫库 -import puppeteer from '../../../lib/puppeteer/puppeteer.js' -import _ from 'lodash' +import puppeteer from "../../../lib/puppeteer/puppeteer.js"; +import _ from "lodash"; export class query extends plugin { - constructor () { + constructor() { super({ - name: '查询类', - dsc: '查询相关指令', - event: 'message.group', + name: "查询类", + dsc: "查询相关指令", + event: "message.group", priority: 500, rule: [ { - reg: '^#*医药查询 (.*)$', - fnc: 'doctor' + reg: "^#*医药查询 (.*)$", + fnc: "doctor", }, { - reg: '^#*评分 (.*)', - fnc: 'videoScore' + reg: "^#*评分 (.*)", + fnc: "videoScore", }, { - reg: '^#(cat)$', - fnc: 'cat' + reg: "^#(cat)$", + fnc: "cat", }, { - reg: '^#电脑软件推荐$', /** 执行方法 */ - fnc: 'computerRecommended' + reg: "^#电脑软件推荐$" /** 执行方法 */, + fnc: "computerRecommended", }, { - reg: '^#安卓软件推荐$', /** 执行方法 */ - fnc: 'androidRecommended' + reg: "^#安卓软件推荐$" /** 执行方法 */, + fnc: "androidRecommended", }, { - reg: '^#(热搜)(.*)$', - fnc: 'hotSearch' + reg: "^#(热搜)(.*)$", + fnc: "hotSearch", }, { - reg: '#买家秀', - fnc: 'buyerShow' - } - ] - }) - this.catConfig = config.getConfig('query') + reg: "#买家秀", + fnc: "buyerShow", + }, + ], + }); + this.catConfig = config.getConfig("query"); } - async doctor (e) { - let keyword = e.msg.split(' ')[1] - const url = `https://api2.dayi.org.cn/api/search2?keyword=${ keyword }&pageNo=1&pageSize=10` + async doctor(e) { + let keyword = e.msg.split(" ")[1]; + const url = `https://api2.dayi.org.cn/api/search2?keyword=${keyword}&pageNo=1&pageSize=10`; let res = await fetch(url) - .then((resp) => resp.json()) - .then((resp) => resp.list) - let msg = [] + .then(resp => resp.json()) + .then(resp => resp.list); + let msg = []; for (const element of res) { - const title = this.removeTag(element.title) + const title = this.removeTag(element.title); const template = ` - ${ title }\n - 标签:${ element.secondTitle }\n - 介绍:${ element.introduction } - ` + ${title}\n + 标签:${element.secondTitle}\n + 介绍:${element.introduction} + `; // 如果完全匹配,直接响应页面 if (title === keyword) { - const browser = await puppeteer.browserInit() - const page = await browser.newPage() - await page.goto(`https://www.dayi.org.cn/drug/${ element.id }`) + const browser = await puppeteer.browserInit(); + const page = await browser.newPage(); + await page.goto(`https://www.dayi.org.cn/drug/${element.id}`); let buff = await page.screenshot({ - fullPage: true, type: 'jpeg', omitBackground: false, quality: 90 - }) - browser.close() - await e.reply(segment.image(buff)) + fullPage: true, + type: "jpeg", + omitBackground: false, + quality: 90, + }); + browser.close(); + await e.reply(segment.image(buff)); } msg.push({ - message: { type: 'text', text: `${ template }` }, nickname: Bot.nickname, user_id: Bot.user_id - }) + message: { type: "text", text: `${template}` }, + nickname: Bot.nickname, + user_id: Bot.user_id, + }); } /** 最后回复消息 */ - return !!this.reply(await Bot.makeForwardMsg(msg)) + return !!this.reply(await Bot.makeForwardMsg(msg)); } async videoScore(e) { - let keyword = e.msg.split(' ')[1] + let keyword = e.msg.split(" ")[1]; const api = `https://movie.douban.com/j/subject_suggest?q=${encodeURI(keyword)}`; let movieId = 30433417; @@ -91,182 +96,207 @@ export class query extends plugin { "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", - } - }).then(resp => resp.json()).then(resp => { - if (resp.length === 0 || resp === "") { - e.reply("没找到!"); - return true; - } - movieId = resp[0].id; - const doubanApi = `https://movie.querydata.org/api?id=${movieId}`; - fetch(doubanApi, { - 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", - } - }).then(resp => resp.json()).then(resp => { + }, + }) + .then(resp => resp.json()) + .then(resp => { if (resp.length === 0 || resp === "") { e.reply("没找到!"); return true; } - e.reply(`识别:${resp.data[0].name}\n烂番茄评分:${resp.imdbRating}\n豆瓣评分:${resp.doubanRating}\n评分:${resp.imdbRating}`); - }) - }) + movieId = resp[0].id; + const doubanApi = `https://movie.querydata.org/api?id=${movieId}`; + fetch(doubanApi, { + 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", + }, + }) + .then(resp => resp.json()) + .then(resp => { + if (resp.length === 0 || resp === "") { + e.reply("没找到!"); + return true; + } + e.reply( + `识别:${resp.data[0].name}\n烂番茄评分:${resp.imdbRating}\n豆瓣评分:${resp.doubanRating}\n评分:${resp.imdbRating}` + ); + }); + }); return true; } - async cat (e) { - const numb = this.catConfig.count - let images = [] - let reqRes = [ ...await fetch(`https://shibe.online/api/cats?count=${ numb }`).then(data => data.json()), ...await fetch(`https://api.thecatapi.com/v1/images/search?limit=${ numb }`).then(data => data.json()).then(json => json.map(item => item.url)) ] - e.reply('涩图也不看了,就看猫是吧, 探索中...') + async cat(e) { + const numb = this.catConfig.count; + let images = []; + let reqRes = [ + ...(await fetch(`https://shibe.online/api/cats?count=${numb}`).then(data => + data.json() + )), + ...(await fetch(`https://api.thecatapi.com/v1/images/search?limit=${numb}`) + .then(data => data.json()) + .then(json => json.map(item => item.url))), + ]; + e.reply("涩图也不看了,就看猫是吧, 探索中..."); reqRes.forEach(item => { images.push({ - message: segment.image(item), nickname: this.e.sender.card || this.e.user_id, user_id: this.e.user_id - }) - }) - return !!(await this.reply(await Bot.makeForwardMsg(images))) + message: segment.image(item), + nickname: this.e.sender.card || this.e.user_id, + user_id: this.e.user_id, + }); + }); + return !!(await this.reply(await Bot.makeForwardMsg(images))); } - async computerRecommended (e) { - let url = 'https://www.ghxi.com/ghapi?type=query&n=pc' + async computerRecommended(e) { + let url = "https://www.ghxi.com/ghapi?type=query&n=pc"; /** 调用接口获取数据 */ - let res = await fetch(url).catch((err) => logger.error(err)) + let res = await fetch(url).catch(err => logger.error(err)); /** 接口结果,json字符串转对象 */ - res = await res.json() - let msg = [] - res.data.list.forEach((element) => { - const template = `推荐软件:${ element.title }\n地址:${ element.url }\n` + res = await res.json(); + let msg = []; + res.data.list.forEach(element => { + const template = `推荐软件:${element.title}\n地址:${element.url}\n`; msg.push({ - message: { type: 'text', text: `${ template }` }, nickname: Bot.nickname, user_id: Bot.user_id - }) - }) + message: { type: "text", text: `${template}` }, + nickname: Bot.nickname, + user_id: Bot.user_id, + }); + }); /** 最后回复消息 */ - return !!this.reply(await Bot.makeForwardMsg(msg)) + return !!this.reply(await Bot.makeForwardMsg(msg)); } - async androidRecommended (e) { - let url = 'https://www.ghxi.com/ghapi?type=query&n=and' - let res = await fetch(url).catch((err) => logger.error(err)) - res = await res.json() - let msg = [] - res.data.list.forEach((element) => { - const template = `推荐软件:${ element.title }\n地址:${ element.url }\n` + async androidRecommended(e) { + let url = "https://www.ghxi.com/ghapi?type=query&n=and"; + let res = await fetch(url).catch(err => logger.error(err)); + res = await res.json(); + let msg = []; + res.data.list.forEach(element => { + const template = `推荐软件:${element.title}\n地址:${element.url}\n`; msg.push({ - message: { type: 'text', text: `${ template }` }, nickname: Bot.nickname, user_id: Bot.user_id - }) - }) - return !!this.reply(await Bot.makeForwardMsg(msg)) + message: { type: "text", text: `${template}` }, + nickname: Bot.nickname, + user_id: Bot.user_id, + }); + }); + return !!this.reply(await Bot.makeForwardMsg(msg)); } - async hotSearch (e) { - let keyword = e.msg.replace(/#|热搜/g, '').trim() - console.log(keyword) + async hotSearch(e) { + let keyword = e.msg.replace(/#|热搜/g, "").trim(); + console.log(keyword); // 虎扑/知乎/36氪/百度/哔哩哔哩/贴吧/微博/抖音/豆瓣/少数派/IT资讯/微信 - let url = 'https://api.vvhan.com/api/hotlist?type=' + let url = "https://api.vvhan.com/api/hotlist?type="; switch (keyword) { - case '虎扑': - url += 'huPu' - break - case '知乎': - url += 'zhihuHot' - break - case '36氪': - url += '36Ke' - break - case '百度': - url += 'baiduRD' - break - case '哔哩哔哩': - url += 'bili' - break - case '贴吧': - url += 'baiduRY' - break - case '微博': - url += 'wbHot' - break - case '抖音': - url += 'douyinHot' - break - case '豆瓣': - url += 'douban' - break - case '少数派': - url += 'ssPai' - break - case 'IT资讯': - url += 'itInfo' - break - case '微信': - url += 'wxHot' - break + case "虎扑": + url += "huPu"; + break; + case "知乎": + url += "zhihuHot"; + break; + case "36氪": + url += "36Ke"; + break; + case "百度": + url += "baiduRD"; + break; + case "哔哩哔哩": + url += "bili"; + break; + case "贴吧": + url += "baiduRY"; + break; + case "微博": + url += "wbHot"; + break; + case "抖音": + url += "douyinHot"; + break; + case "豆瓣": + url += "douban"; + break; + case "少数派": + url += "ssPai"; + break; + case "IT资讯": + url += "itInfo"; + break; + case "微信": + url += "wxHot"; + break; default: - url += 'history' - break + url += "history"; + break; } let sendTemplate = { - nickname: this.e.sender.card || this.e.user_id, user_id: this.e.user_id - } - let msg = [] + nickname: this.e.sender.card || this.e.user_id, + user_id: this.e.user_id, + }; + let msg = []; await fetch(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", - } + "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", + }, }) - .then((resp) => resp.json()) - .then((resp) => { + .then(resp => resp.json()) + .then(resp => { for (let element of resp.data) { if (_.isUndefined(element)) { - continue + continue; } const template = ` - 标题:${ _.isNull(element.title) ? '暂无' : element.title }\n - 简介:${ _.isNull(element.desc) ? '暂无' : element.desc }\n - 热度:${ _.isNull(element.hot) ? '暂无' : element.hot }\n - 访问详情:${ _.isNull(element.url) ? '暂无' : element.url }\n + 标题:${_.isNull(element.title) ? "暂无" : element.title}\n + 简介:${_.isNull(element.desc) ? "暂无" : element.desc}\n + 热度:${_.isNull(element.hot) ? "暂无" : element.hot}\n + 访问详情:${_.isNull(element.url) ? "暂无" : element.url}\n `; msg.push({ - message: { type: 'text', text: `${ template }` }, - ...sendTemplate - }) + message: { type: "text", text: `${template}` }, + ...sendTemplate, + }); } }) - .catch((err) => logger.error(err)) - return !!this.reply(await Bot.makeForwardMsg(msg)) + .catch(err => logger.error(err)); + return !!this.reply(await Bot.makeForwardMsg(msg)); } - async buyerShow (e) { + async buyerShow(e) { // http://3650000.xyz/api/?type=img // https://api.vvhan.com/api/tao // https://api.uomg.com/api/rand.img3?format=json // const randomIndex = Math.floor(Math.random() * urls.length); // const randomElement = urls.splice(randomIndex, 1)[0]; const p1 = new Promise((resolve, reject) => { - fetch("https://api.vvhan.com/api/tao").then(resp => { - return resolve(resp.url) - }).catch(err => reject(err)) - }) + fetch("https://api.vvhan.com/api/tao") + .then(resp => { + return resolve(resp.url); + }) + .catch(err => reject(err)); + }); const p2 = new Promise((resolve, reject) => { - fetch("https://api.uomg.com/api/rand.img3?format=json").then(resp => resp.json()).then(resp => { - return resolve(resp.imgurl) - }).catch(err => reject(err)) - }) + fetch("https://api.uomg.com/api/rand.img3?format=json") + .then(resp => resp.json()) + .then(resp => { + return resolve(resp.imgurl); + }) + .catch(err => reject(err)); + }); Promise.all([p1, p2]).then(res => { res.forEach(item => { - e.reply(segment.image(item)) - }) - }) + e.reply(segment.image(item)); + }); + }); return true; } // 删除标签 - removeTag (title) { - const titleRex = /<[^>]+>/g - return title.replace(titleRex, '') + removeTag(title) { + const titleRex = /<[^>]+>/g; + return title.replace(titleRex, ""); } } diff --git a/apps/tools.js b/apps/tools.js index 3ff82e0..27eebfd 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -5,19 +5,19 @@ import { segment } from "oicq"; // 其他库 import md5 from "md5"; import axios from "axios"; -import _ from 'lodash' -import tunnel from 'tunnel' -import { TwitterApi } from 'twitter-api-v2' -import HttpProxyAgent from 'https-proxy-agent' -import { mkdirsSync } from '../utils/file.js' -import { downloadBFile, getDownloadUrl, mergeFileToMp4 } from '../utils/bilibili.js' -import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from '../utils/acfun.js' +import _ from "lodash"; +import tunnel from "tunnel"; +import { TwitterApi } from "twitter-api-v2"; +import HttpProxyAgent from "https-proxy-agent"; +import { mkdirsSync } from "../utils/file.js"; +import { downloadBFile, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js"; +import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js"; // import { get, remove, add } from "../utils/redisu.js"; -const transMap = { "中": "zh", "日": "jp", "文": "wyw", "英": "en" } +const transMap = { 中: "zh", 日: "jp", 文: "wyw", 英: "en" }; export class tools extends plugin { - constructor () { + constructor() { super({ name: "工具和学习类", dsc: "工具相关指令", @@ -49,177 +49,197 @@ export class tools extends plugin { fnc: "twitter", }, { - reg: "https:\/\/(m.)?v.qq.com\/(.*)", - fnc: "tx" + reg: "https://(m.)?v.qq.com/(.*)", + fnc: "tx", }, { reg: "(.*)(acfun.cn)", - fnc: "acfun" + fnc: "acfun", }, { reg: "(.*)(xhslink.com|xiaohongshu.com)", - fnc: "redbook" - } + fnc: "redbook", + }, ], }); // http://api.tuwei.space/girl // 视频保存路径 this.defaultPath = `./data/rcmp4/`; // redis的key - this.redisKey = `Yz:tools:cache:${ this.group_id }`; + this.redisKey = `Yz:tools:cache:${this.group_id}`; // 代理接口 // TODO 填写服务器的内网ID和clash的端口 - this.proxyAddr = '10.0.8.10'; - this.proxyPort = '7890' + this.proxyAddr = "10.0.8.10"; + this.proxyPort = "7890"; this.myProxy = `http://${this.proxyAddr}:${this.proxyPort}`; - } // 翻译插件 - async trans (e) { + async trans(e) { const languageReg = /翻(.)/g; const msg = e.msg.trim(); const language = languageReg.exec(msg); if (!transMap.hasOwnProperty(language[1])) { - e.reply("输入格式有误!例子:翻中 China's policy has been consistent, but Japan chooses a path of mistrust, decoupling and military expansion") + e.reply( + "输入格式有误!例子:翻中 China's policy has been consistent, but Japan chooses a path of mistrust, decoupling and military expansion" + ); return; } 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=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=&salt=&sign=${ md5("" + place + "" + "") }&q=${ place }`; + 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) - .then((res) => this.reply(`${ res[0].dst }`, true)) - .catch((err) => logger.error(err)); + .then(resp => 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) { + 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) => { + 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 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`)); + e.reply( + segment.video( + `${this.defaultPath}${this.e.group_id || this.e.user_id}/temp.mp4` + ) + ); }); }); return true; } // tiktok解析 - async tiktok (e) { + 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() + let url = e.msg.trim(); // 短号处理 - if (url.includes('vt.tiktok')) { - const temp_url = urlShortRex.exec(url)[0] + 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 - }) + agent: new HttpProxyAgent(this.myProxy), + }).then(resp => { + url = resp.url; + }); } else { - url = urlRex.exec(url)[0] + url = urlRex.exec(url)[0]; } - const idVideo = await this.getIdVideo(url) + const idVideo = await this.getIdVideo(url); // 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.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`)); + 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 }, + }), }) - }) - return true + .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) { + 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() + let url = e.msg.trim(); // 短号处理 - if (url.includes('b23.tv')) { - const bShortUrl = bShortRex.exec(url)[0] + 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 }/` + const path = `${this.defaultPath}${this.e.group_id || this.e.user_id}/`; if (!fs.existsSync(path)) { mkdirsSync(path); } // 视频信息获取例子:http://api.bilibili.com/x/web-interface/view?bvid=BV1hY411m7cB // 请求视频信息 - (function() { + (function () { const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view"; const videoId = /video\/[^\?\/ ]+/.exec(url)[0].split("/")[1]; // 获取视频信息,然后发送 - fetch(videoId.startsWith("BV") ? `${baseVideoInfo}?bvid=${videoId}` : `${baseVideoInfo}?aid=${videoId}`) + fetch( + videoId.startsWith("BV") + ? `${baseVideoInfo}?bvid=${videoId}` + : `${baseVideoInfo}?aid=${videoId}` + ) .then(resp => resp.json()) .then(resp => { - e.reply(`识别:哔哩哔哩, ${resp.data.title}`) - .catch(err => { - e.reply("解析失败,重试一下"); - console.log(err); - }) - }) - }()) + e.reply(`识别:哔哩哔哩, ${resp.data.title}`).catch(err => { + e.reply("解析失败,重试一下"); + console.log(err); + }); + }); + })(); await getDownloadUrl(url) .then(data => { this.downBili(`${path}temp`, data.videoUrl, data.audioUrl) .then(data => { - e.reply(segment.video(`${ path }temp.mp4`)) + e.reply(segment.video(`${path}temp.mp4`)); }) .catch(err => { - console.log(err) - e.reply('解析失败,请重试一下') + console.log(err); + e.reply("解析失败,请重试一下"); }); }) .catch(err => { - console.log(err) - e.reply('解析失败,请重试一下') + console.log(err); + e.reply("解析失败,请重试一下"); }); - return true + return true; } // 百科 - async wiki (e) { + 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 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, { @@ -238,98 +258,96 @@ export class tools extends plugin { // } // 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, - }) + 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 + 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) - 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`)); - }); - } + // 小鸡解释:${ _.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); + 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 + 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 + e.reply("解析腾讯视频失败~\n去浏览器使用拼接接口吧..."); + let forward = await this.makeForwardMsg(url); + e.reply(forward); + return true; } } - // 请求参数 - async douyinRequest (url) { + async douyinRequest(url) { const params = { headers: { "User-Agent": @@ -340,23 +358,23 @@ export class tools extends plugin { return new Promise((resolve, reject) => { axios .head(url, params) - .then((resp) => { - const location = resp.request.res.responseUrl + .then(resp => { + const location = resp.request.res.responseUrl; resolve(location); }) - .catch((err) => { + .catch(err => { reject(err); }); }); } // 工具:根URL据下载视频 / 音频 - async downloadVideo (url, isProxy=false) { - const groupPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; + 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`; + const target = `${groupPath}/temp.mp4`; // 待优化 if (fs.existsSync(target)) { console.log(`视频已存在`); @@ -378,11 +396,15 @@ export class tools extends plugin { "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 } }), + httpAgent: tunnel.httpOverHttp({ + proxy: { host: this.proxyAddr, port: this.proxyPort }, + }), + httpsAgent: tunnel.httpOverHttp({ + proxy: { host: this.proxyAddr, port: this.proxyPort }, + }), }); } - console.log(`开始下载: ${ url }`); + console.log(`开始下载: ${url}`); const writer = fs.createWriteStream(target); res.data.pipe(writer); @@ -393,19 +415,19 @@ export class tools extends plugin { } // 工具:找到tiktok的视频id - async getIdVideo (url) { - const matching = url.includes("/video/") + async getIdVideo(url) { + const matching = url.includes("/video/"); if (!matching) { - this.e.reply("没找到,正在获取随机视频!") - return null + 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; + 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/` + const path = `${this.defaultPath}${this.e.group_id || this.e.user_id}/temp/`; if (!fs.existsSync(path)) { mkdirsSync(path); } @@ -413,124 +435,134 @@ export class tools extends plugin { 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]}` + 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 => { + 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`)) - }) - }) - }) - }) + 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}` + 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 = / { + const reg = / { - const filepath = `${downloadPath}/${/com\/(.*)\?/.exec(addr)[1]}.jpg` - const writer = fs.createWriteStream(filepath); - resp.data.pipe(writer) - return new Promise((resolve, reject) => { - writer.on('finish', () => resolve(filepath)); - writer.on('error', reject); - }); - }) - .then( filepath => { - e.reply(segment.image(fs.readFileSync(filepath))) - fs.unlinkSync(filepath) - }) - } - }) + const downloadPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`; + // 创建文件夹(如果没有过这个群) + if (!fs.existsSync(downloadPath)) { + mkdirsSync(downloadPath); + } + while ((res = reg.exec(resp.data))) { + const addr = `https://ci.xiaohongshu.com${res[2]}`; + axios + .get(addr, { + 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", + }) + .then(resp => { + const filepath = `${downloadPath}/${/com\/(.*)\?/.exec(addr)[1]}.jpg`; + const writer = fs.createWriteStream(filepath); + resp.data.pipe(writer); + return new Promise((resolve, reject) => { + writer.on("finish", () => resolve(filepath)); + writer.on("error", reject); + }); + }) + .then(filepath => { + e.reply(segment.image(fs.readFileSync(filepath))); + fs.unlinkSync(filepath); + }); + } + }); return true; } - async downBili (title, videoUrl, audioUrl) { + async downBili(title, videoUrl, audioUrl) { return Promise.all([ downloadBFile( videoUrl, - title + '-video.m4s', + title + "-video.m4s", _.throttle( value => - console.log('download-progress', { - type: 'video', + console.log("download-progress", { + type: "video", data: value, }), - 1000, - ), + 1000 + ) ), downloadBFile( audioUrl, - title + '-audio.m4s', + title + "-audio.m4s", _.throttle( value => - console.log('download-progress', { - type: 'audio', + console.log("download-progress", { + type: "audio", data: value, }), - 1000, - ), + 1000 + ) ), - ]) - .then(data => { - return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, title + '.mp4'); - }) + ]).then(data => { + return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, title + ".mp4"); + }); } // 工具:下载一张网络图片 async downloadImgs(img, dir) { - - const filename = img.split('/').pop(); + 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); + 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); + }); }); - }); } } diff --git a/apps/update.js b/apps/update.js index 666f0e5..72d5915 100644 --- a/apps/update.js +++ b/apps/update.js @@ -1,9 +1,9 @@ // 主库 -import Version from '../model/version.js' -import config from '../model/index.js' -import puppeteer from '../../../lib/puppeteer/puppeteer.js' +import Version from "../model/version.js"; +import config from "../model/index.js"; +import puppeteer from "../../../lib/puppeteer/puppeteer.js"; -import { exec, execSync } from 'node:child_process' +import { exec, execSync } from "node:child_process"; const _path = process.cwd(); @@ -11,38 +11,36 @@ const _path = process.cwd(); * 处理插件更新 */ export class update extends plugin { - constructor () { + constructor() { super({ - name: '更新插件', - dsc: '更新插件代码', - event: 'message', + name: "更新插件", + dsc: "更新插件代码", + event: "message", priority: 4000, rule: [ { - reg: '^#*R(插件)?版本$', - fnc: 'version' + reg: "^#*R(插件)?版本$", + fnc: "version", }, { /** 命令正则匹配 */ - reg: '^#(R更新|R强制更新)$', + reg: "^#(R更新|R强制更新)$", /** 执行方法 */ - fnc: 'rconsoleUpdate' + fnc: "rconsoleUpdate", }, - ] - }) + ], + }); - this.versionData = config.getConfig('version') + this.versionData = config.getConfig("version"); } /** * rule - 插件版本信息 */ - async version () { - const data = await new Version(this.e).getData( - this.versionData.slice(0, 3) - ) - let img = await puppeteer.screenshot('version', data) - this.e.reply(img) + async version() { + const data = await new Version(this.e).getData(this.versionData.slice(0, 3)); + let img = await puppeteer.screenshot("version", data); + this.e.reply(img); } /** @@ -65,38 +63,56 @@ export class update extends plugin { } else { await this.e.reply("正在执行更新操作,请稍等"); } - const th = this - exec(command, { cwd: `${ _path }/plugins/rconsole-plugin/` }, async function (error, stdout, stderr) { - if (error) { - let isChanges = error.toString().includes("Your local changes to the following files would be overwritten by merge"); + const th = this; + exec( + command, + { cwd: `${_path}/plugins/rconsole-plugin/` }, + async function (error, stdout, stderr) { + if (error) { + let isChanges = error + .toString() + .includes( + "Your local changes to the following files would be overwritten by merge" + ); - let isNetwork = error.toString().includes("fatal: unable to access"); + let isNetwork = error.toString().includes("fatal: unable to access"); - if (isChanges) { - //git stash && git pull && git stash pop stash@{0} - //需要设置email和username,暂不做处理 - await me.e.reply( - "失败!\nError code: " + - error.code + - "\n" + - error.stack + - "\n\n本地代码与远程代码存在冲突,上面报错信息中包含冲突文件名称及路径,请尝试处理冲突\n如果不想保存本地修改请使用【#强制更新】\n(注意:强制更新命令会忽略所有本地对R插件本身文件的修改,本地修改均不会保存,请注意备份)" - ); - } else if (isNetwork) { - await e.reply( - "失败!\nError code: " + error.code + "\n" + error.stack + "\n\n可能是网络问题,请关闭加速器之类的网络工具,或请过一会尝试。" - ); + if (isChanges) { + //git stash && git pull && git stash pop stash@{0} + //需要设置email和username,暂不做处理 + await me.e.reply( + "失败!\nError code: " + + error.code + + "\n" + + error.stack + + "\n\n本地代码与远程代码存在冲突,上面报错信息中包含冲突文件名称及路径,请尝试处理冲突\n如果不想保存本地修改请使用【#强制更新】\n(注意:强制更新命令会忽略所有本地对R插件本身文件的修改,本地修改均不会保存,请注意备份)" + ); + } else if (isNetwork) { + await e.reply( + "失败!\nError code: " + + error.code + + "\n" + + error.stack + + "\n\n可能是网络问题,请关闭加速器之类的网络工具,或请过一会尝试。" + ); + } else { + await e.reply( + "失败!\nError code: " + + error.code + + "\n" + + error.stack + + "\n\n出错了。请尝试处理错误" + ); + } } else { - await e.reply("失败!\nError code: " + error.code + "\n" + error.stack + "\n\n出错了。请尝试处理错误"); + if (/Already up to date/.test(stdout)) { + e.reply("目前已经是最新了~"); + return true; + } + await th.restartApp(); } - } else { - if (/Already up to date/.test(stdout)) { - e.reply("目前已经是最新了~"); - return true; - } - await th.restartApp(); } - }); + ); } async restartApp() { @@ -113,7 +129,6 @@ export class update extends plugin { }); try { - await redis.set("Yunzai:rconsole:restart", data, { EX: 120 }); let cm = `npm run start`;