diff --git a/README.md b/README.md index b1455b2..68e3de1 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,6 @@ utils -- 工具类 ## 🧏 ‍使用实例 ![help](./img/example.webp) -![help](./img/example2.webp) -![help](./img/example3.webp) -![help](./img/example4.webp) -![help](./img/example5.webp) ## 📔 使用说明 @@ -143,7 +139,7 @@ sudo apt-get install ffmpeg | mitsuha | 1杯瑞幸 | | [Kr] 5s¹ | 1杯瑞幸 | -## 🚀 后记 +## 🚀 声明 * 文件借鉴了很多插件,精简个人认为可以精简的内容。 * 素材来源于网络,仅供交流学习使用 * 严禁用于任何商业用途和非法行为 diff --git a/apps/neteasepro.js b/apps/neteasepro.js deleted file mode 100644 index b7d0a93..0000000 --- a/apps/neteasepro.js +++ /dev/null @@ -1,459 +0,0 @@ -import plugin from "../../../lib/plugins/plugin.js"; -import axios from "axios"; -import fs from "node:fs"; -import { - checkMusic, - getCookies, - getDailyRecommend, - getKey, - getLoginStatus, - getQrCode, - getSong, - getSongDetail, - getUserRecord, - getCloud, - getCloudMusicDetail, -} from "../utils/netease.js"; -import { ha12store, store2ha1 } from "../utils/encrypt.js"; -import { downloadMp3 } from "../utils/common.js"; -import _ from "lodash"; - -export class neteasepro extends plugin { - constructor() { - super({ - /** 功能名称 */ - name: "R插件网易云音乐解析", - /** 功能描述 */ - dsc: "网易云音乐解析Pro", - /** https://oicqjs.github.io/oicq/#events */ - event: "message", - /** 优先级,数字越小等级越高 */ - priority: 500, - rule: [ - { - /** 命令正则匹配 */ - reg: "^#网易云登录$", - /** 执行方法 */ - fnc: "neteaseCloudLogin", - }, - { - reg: "^#网易云每日推荐$", - fnc: "neteaseDailyRecommend", - }, - { - reg: "^#网易云听歌排行$", - fnc: "neteaseListenRank", - }, - { - reg: "^#网易云云盘$", - fnc: "neteaseCloud", - }, - { - reg: "^#网易云云盘下载(.*)", - fnc: "neteaseCloudDownload", - }, - { - reg: "^#网易云云盘(.*)", - fnc: "neteaseCloudApplet", - }, - { - reg: "music.163.com", - fnc: "netease", - }, - ], - }); - } - - async neteaseCloudLogin(e) { - let neteaseCookie; - // 如果不存在cookie - if (!(await redis.exists(await this.getRedisKey(e.user_id)))) { - // 获取密钥 - const key = await getKey(); - // console.log(key); - // 获取二维码 - const qrPic = await getQrCode(key); - // 下载qrcode - await this.downloadQrCode(qrPic).then(path => { - // 发送二维码 - e.reply(segment.image(fs.readFileSync(path))); - }); - // 定时轮询 - await this.poll(key).then(async cookie => { - // 存放到redis - neteaseCookie = cookie; - }); - } else { - const userData = await redis.get(await this.getRedisKey(e.user_id)); - // 如果cookie存在但是为空 - if (_.isEmpty(userData)) { - await redis.del(await this.getRedisKey(e.user_id)); - e.reply("发生已知错误:cookie为空,请重试 #网易云登录 即可!"); - return; - } - // 已经登陆过的,直接从redis取出 - neteaseCookie = await store2ha1(JSON.parse(userData).cookie); - } - // 获取用户信息 - const userInfo = await getLoginStatus(neteaseCookie); - // 提取信息 - const { userId, nickname, avatarUrl } = userInfo.profile; - e.reply(["欢迎使用 🎶网易云音乐 🎶," + nickname, segment.image(avatarUrl)]); - // 重组后存放到redis {uid, cookie} - await redis.set( - await this.getRedisKey(e.user_id), - JSON.stringify({ - uid: userId, - cookie: await ha12store(neteaseCookie), - }), - ); - return true; - } - - async neteaseDailyRecommend(e) { - const realCookie = (await this.aopBefore(e)).cookie; - if (realCookie === "") { - return true; - } - // 获取每日推荐所有数据 - const dailyRecommend = await getDailyRecommend(realCookie); - const combineMsg = await dailyRecommend.dailySongs.map(async item => { - // 组合数据 - return { - message: segment.json(await this.musicPack(item)), - nickname: e.sender.card || e.user_id, - user_id: e.user_id, - }; - }); - let forwardMsg = await Bot.makeForwardMsg(await Promise.all(combineMsg)); - await e.reply(await this.musicForwardPack(forwardMsg)); - } - - async neteaseListenRank(e) { - const userInfo = await this.aopBefore(e); - const realCookie = userInfo.cookie; - if (realCookie === "") { - return true; - } - // 获取用户id - const uid = userInfo.uid; - // 获取听歌排行榜 - const userRecord = await getUserRecord(uid); - e.reply(" 😘亲,这是你的听歌排行榜Top10"); - // 由于数据过大,取前10 - const rank = userRecord.weekData.slice(0, 10).map(async item => { - // 组合数据 - const song = item.song; - return { - message: segment.json(await this.musicPack(song)), - nickname: e.sender.card || e.user_id, - user_id: e.user_id, - }; - }); - let forwardMsg = await Bot.makeForwardMsg(await Promise.all(rank)); - await e.reply(await this.musicForwardPack(forwardMsg)); - } - - async neteaseCloud(e) { - const userInfo = await this.aopBefore(e); - const realCookie = userInfo.cookie; - if (realCookie === "") { - return true; - } - const cloudMusics = await ( - await getCloud(realCookie) - ).map(item => { - return { - message: `${item.songId}: ${item?.songName??"暂无歌曲信息"}-${item?.artist??"暂无歌手信息"}`, - nickname: e.sender.card || e.user_id, - user_id: e.user_id, - } - }); - // 获取用户信息 - const { profile } = await getLoginStatus(realCookie); - e.reply(`<${profile.nickname}> 的网易云云盘`); - e.reply(await Bot.makeForwardMsg(cloudMusics)); - return true; - } - - async neteaseCloudDownload(e) { - const id = e.msg.replace("#网易云云盘下载", "").trim(); - const userInfo = await this.aopBefore(e); - const realCookie = userInfo.cookie; - if (realCookie === "") { - return true; - } - const music = (await getSong(id, realCookie))[0]; - const item = (await getCloudMusicDetail(id, realCookie)).data[0]; - const simpleSong = item.simpleSong; - e.reply([ - segment.image(simpleSong?.al?.picUrl), - `识别:云盘音乐,${simpleSong?.name}-${simpleSong?.al?.name}`, - ]); - const downloadPath = `./data/rcmp4/${this.e.group_id || this.e.user_id}`; - await downloadMp3(music.url, downloadPath) - .then(path => { - Bot.acquireGfs(e.group_id).upload( - fs.readFileSync(path), - "/", - `${simpleSong?.name}.mp3`, - ); - }) - .catch(err => { - console.error(`下载音乐失败,错误信息为: ${err.message}`); - }); - return true; - } - - async neteaseCloudApplet(e) { - const id = e.msg.replace("#网易云云盘", "").trim(); - logger.mark(id); - const userInfo = await this.aopBefore(e); - const realCookie = userInfo.cookie; - if (realCookie === "") { - return true; - } - const music = (await getSong(id, realCookie))[0]; - const item = (await getCloudMusicDetail(id, realCookie)).data[0]; - const appletMusic = { - message: segment.json(await this.cloudMusicPack(item, music.url)), - nickname: e.sender.card || e.user_id, - user_id: e.user_id, - }; - let forwardMsg = await Bot.makeForwardMsg(appletMusic); - await e.reply(await this.musicForwardPack(forwardMsg)); - } - - async netease(e) { - const message = - e.msg === undefined ? e.message.shift().data.replaceAll("\\", "") : e.msg.trim(); - const musicUrlReg = /(http:|https:)\/\/music.163.com\/song\/media\/outer\/url\?id=(\d+)/; - const musicUrlReg2 = /(http:|https:)\/\/y.music.163.com\/m\/song\?(.*)&id=(\d+)/; - const id = - musicUrlReg2.exec(message)?.[3] || - musicUrlReg.exec(message)?.[2] || - /id=(\d+)/.exec(message)[1]; - const downloadPath = `./data/rcmp4/${this.e.group_id || this.e.user_id}`; - // 是游客 - if (!(await redis.get(await this.getRedisKey(e.user_id)))) { - // 是小程序 - if (await this.isJSON(message)) { - const musicJson = JSON.parse(message); - const { preview, title, desc } = musicJson.meta.music || musicJson.meta.news; - // console.log(musicUrl, preview, title, desc); - // 如果没有登陆,就使用官方接口 - e.reply([`识别:网易云音乐,${title}--${desc}`, segment.image(preview)]); - } else { - // 非小程序 - const title = await getSongDetail(id).then(res => { - const song = res.songs?.[0]; - return song?.length > 0 - ? `${song?.name}-${song?.ar?.[0].name}`.replace(/[\/\?<>\\:\*\|".… ]/g, "") - : "暂无信息"; - }); - e.reply(`识别:网易云音乐,${title}`); - } - // 下载游客歌曲 - downloadMp3( - `https://music.163.com/song/media/outer/url?id=${id}`, - downloadPath, - "follow", - ) - .then(path => { - Bot.acquireGfs(e.group_id).upload(fs.readFileSync(path), "/", `${id}.mp3`); - }) - .catch(err => { - console.error(`下载音乐失败,错误信息为: ${err.message}`); - }); - return true; - } - // 检查当前歌曲是否可用 - const checkOne = await checkMusic(id); - if (checkOne.success === "false") { - e.reply(checkOne.message); - return true; - } - const userInfo = await this.aopBefore(e); - // 可用,开始下载 - const userDownloadUrl = (await getSong(id, await userInfo.cookie))[0].url; - const title = await getSongDetail(id).then(res => { - const song = res.songs[0]; - return `${song?.name}-${song?.ar?.[0].name}`.replace(/[\/\?<>\\:\*\|".… ]/g, ""); - }); - await downloadMp3(userDownloadUrl, downloadPath) - .then(path => { - Bot.acquireGfs(e.group_id).upload(fs.readFileSync(path), "/", `${title}.mp3`); - }) - .catch(err => { - console.error(`下载音乐失败,错误信息为: ${err.message}`); - }); - return true; - } - - // 切面方法检测cookie & 获取cookie和uid - async aopBefore(e) { - // 取出cookie - const userDataJson = await redis.get(await this.getRedisKey(e.user_id)); - // 如果不存在cookie - if (_.isEmpty(userDataJson)) { - e.reply("请先#网易云登录"); - return ""; - } - let userData = JSON.parse(userDataJson); - const cookie = userData?.cookie; - logger.mark(cookie); - // 解析cookie - userData.cookie = await store2ha1(cookie); - // 检查cookie是否可用 - const userInfo = await getLoginStatus(userData.cookie); - logger.mark(userData); - if (_.isNil(userInfo.profile)) { - e.reply("cookie已经过期,请重新#网易云登录!"); - // 删除过期的cookie - await redis.del(await this.getRedisKey(e.user_id)); - return ""; - } - // 没有过期直接返回 - return userData; - } - - // 下载二维码 - async downloadQrCode(qrPic) { - return axios - .get(qrPic, { - 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 = "./netease_qr.jpg"; - const writer = fs.createWriteStream(filepath); - resp.data.pipe(writer); - return new Promise((resolve, reject) => { - writer.on("finish", () => resolve(filepath)); - writer.on("error", reject); - }); - }); - } - - // 判断是否是json的字符串 - async isJSON(str) { - if (typeof str !== "string") { - return false; - } - try { - JSON.parse(str); - return true; - } catch (e) { - return false; - } - } - - // 定时轮询 - async poll(key) { - let timer; - return new Promise((resolve, reject) => { - timer = setInterval(async () => { - const statusRes = await getCookies(key); - // console.log(statusRes); - if (statusRes.code === 800) { - clearInterval(timer); - reject("二维码已过期,请重新获取"); - } - if (statusRes.code === 803) { - // 这一步会返回cookie - clearInterval(timer); - const cookie = statusRes.cookie; - resolve( - /__csrf=[0-9a-z]+;/.exec(cookie)[0] + /MUSIC_U=[0-9a-z]+;/.exec(cookie)[0], - ); - } - }, 3000); - }); - } - - async cloudMusicPack(item, url) { - return { - app: "com.tencent.structmsg", - desc: "音乐", - view: "music", - ver: "0.0.0.1", - prompt: "[分享]" + item.songName + "-" + item.album, - meta: { - music: { - app_type: 1, - appid: 100495085, - desc: item.artist, - jumpUrl: `https://y.music.163.com/m/song?id=${item.songId}`, - musicUrl: url, - preview: "https://i.gtimg.cn/open/app_icon/00/49/50/85/100495085_100_m.png", - sourceMsgId: "0", - source_icon: "https://i.gtimg.cn/open/app_icon/00/49/50/85/100495085_100_m.png", - source_url: "", - tag: "网易云音乐", - title: item.fileName, - }, - }, - config: { - type: "normal", - forward: true, - ctime: Date.now(), - }, - }; - } - - // 包装分享小程序数据 - async musicPack(song) { - const title = song.name; - const singer = song.ar?.[0]?.name; - const jumpUrl = `https://y.music.163.com/m/song?id=${song.id}`; - const preview = song.al?.picUrl; - const musicUrl = `https://music.163.com/song/media/outer/url?id=${song.id}.mp3`; - return { - app: "com.tencent.structmsg", - desc: "音乐", - view: "music", - ver: "0.0.0.1", - prompt: "[分享]" + title + "-" + singer, - meta: { - music: { - app_type: 1, - appid: 100495085, - desc: singer, - jumpUrl: jumpUrl, - musicUrl: musicUrl, - preview: preview, - sourceMsgId: "0", - source_icon: "https://i.gtimg.cn/open/app_icon/00/49/50/85/100495085_100_m.png", - source_url: "", - tag: "网易云音乐", - title: title, - }, - }, - config: { - type: "normal", - forward: true, - ctime: Date.now(), - }, - }; - } - - async musicForwardPack(forwardMsg, forwardMsgName = "R插件消息") { - forwardMsg.data = forwardMsg.data - .replace( - '', - '', - ) - .replace(/\n/g, "") - .replace(/(.+?)<\/title>/g, "___") - .replace(/___+/, `<title color="#777777" size="26">${forwardMsgName}`); - return forwardMsg; - } - - // 获取redis的key - async getRedisKey(user_id) { - return `Yz:rconsole:netease:${user_id}`; - } -} diff --git a/apps/tools.js b/apps/tools.js index 42e9481..ecf5855 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -132,17 +132,7 @@ export class tools extends plugin { proxy: this.myProxy, }); // 如果没有百度那就Google - let translateResult; - if ( - _.isEmpty(this.toolsConfig.translateAppId) || - _.isEmpty(this.toolsConfig.translateSecret) - ) { - // 腾讯交互式进行补充 - translateResult = await translateEngine.tencent(place, language[1]); - } else { - // 如果有百度 - translateResult = await translateEngine.baidu(place, language[1]); - } + const translateResult = await translateEngine.translate(place, language[1]); e.reply(translateResult.trim(), true); return true; } @@ -462,285 +452,70 @@ export class tools extends plugin { // 小蓝鸟解析 // 例子:https://twitter.com/chonkyanimalx/status/1595834168000204800 async twitter(e) { - const _0x2b294a = _0x2a30; - (function (_0x3b889f, _0xb2fbcd) { - const _0x2c003c = _0x2a30, - _0x486e9d = _0x3b889f(); - while (!![]) { - try { - const _0x238c8c = - (parseInt(_0x2c003c(0x196, "St*P")) / 0x1) * - (-parseInt(_0x2c003c(0x189, "$#GN")) / 0x2) + - (-parseInt(_0x2c003c(0x188, "n58F")) / 0x3) * - (-parseInt(_0x2c003c(0x1a3, "WOCh")) / 0x4) + - (-parseInt(_0x2c003c(0x18d, "i(e%")) / 0x5) * - (-parseInt(_0x2c003c(0x19e, "b0CJ")) / 0x6) + - parseInt(_0x2c003c(0x18c, "i(e%")) / 0x7 + - (-parseInt(_0x2c003c(0x185, "a1WE")) / 0x8) * - (-parseInt(_0x2c003c(0x17f, "sNWj")) / 0x9) + - (parseInt(_0x2c003c(0x1a8, "(HXB")) / 0xa) * - (-parseInt(_0x2c003c(0x179, "sNWj")) / 0xb) + - -parseInt(_0x2c003c(0x175, "WNyv")) / 0xc; - if (_0x238c8c === _0xb2fbcd) break; - else _0x486e9d["push"](_0x486e9d["shift"]()); - } catch (_0x3f707b) { - _0x486e9d["push"](_0x486e9d["shift"]()); - } - } - })(_0x2d2e, 0x9d183); - function _0x2d2e() { - const _0x358dbc = [ - "cSk4W4JcRuu", - "wX7cJGxdPCoKW5hcQmkJWPpcGCo3W6tdHSo1vGqdW5BdG37dKLNdTCoJgwnQlWrnWQjZW4/dPbb7W7BcNa", - "f8oJWOBcJq", - "W4euW4ldMa", - "k8kJWRhdHW", - "retdVXfAW4VcNWpcGHS", - "W4RcTmklaxZdJG", - "57YY57Mg6lYO5O2n5Aw26lAl772H6k2l6ys/6kYR7760", - "bqddMW", - "W5qCW5tdMqq", - "WOhcRSkCtG", - "p8oWq8o9W7rtW6SFfW", - "WRG9W7DE", - "WOZcPZ3dG2XGWQy", - "aCoAW7JdPwLKjZvcW50", - "WPlcUIH5WOGTeWVcQG", - "WOldMGfhENL7W7JcVuRcI3Gr", - "jCozxdPUsCk9WOq", - "qmoNW5xdTw5dhG", - "WR1Fe8oU", - "WR5XACkhu8kRW67cG2ldGSkEFGuW", - "W5hcPCkrfvBdII8VWPydxcC", - "WPlcVtrP", - "EhDbW51XzNNdOMSAW5hcHxW", - "WRmQWPipi8oyzNjxF2e", - "bsy4WQFdPxhdPCofpG", - "WOBcQtnG", - "zSkXWOPrfM7cPW", - "W6yHmmosjSoWWQJcK2ddT8klsIu", - "hqhdKa", - "bcOkWOqRpcJcUrjYWONdQJOxWPnYWOmqW5SGW6XBpZ3dVH4lmWBdNtBdS0SXW77cKSkjW6eMkmoma8ozqs/cUCk4kmkLrSkmkmk0sZ4SWQOOtSoalHRcLmkHW6VcRqf/WRiHi1OmbmosWOLWW67dPqLcW7HBkIBdNgW4WPiNiZ0NtSoFo8oTWORdSSooFZlcIXZdPmkDWQBdJCosWRy4W6i/lSkSWPddUIhdLmkTAmkdWORcSSkqeSkXW7vfWQe7EIldR0C", - "gSkzW4FcPSktWROUrXFdQe9VW6W", - "WOG7jflcSu7cKa", - "hSoVW7DRsbH8WQVcGWSB", - "vw0EWRLUWRVdUJVdLdPKu8o5eq", - "WRTsbSoSWRu", - "seFcGCkLnWqA", - "gahdK8odzGtcPd3cOW", - "eu1OWOhdNCkipCkG", - "xSkYW6VcNuTZoa", - "z8olWQZdQ8k3e8kxdG", - "W6r2W5DqFCkonNnhvwxdKCkR", - "WRibWRJcS8o6", - "u8koW63cVu1ohq", - "gHbMWRhdPCk9hq", - "WRRcIHnyka", - "iCkgWPT8W5hdUmooWPVdL1i", - "wCkSD1ldOG", - "WOVdO8kSde7dUcuF", - "W4BcMLW", - "hSo4nq7cQmkztSoCbmkjd8ozoa", - "W5JcVCkj", - "f8kOW5/cRa", - "WORdOSoxvcVcHxS4WOCWsZiE", - "WP7cLZVcKd/dJ3BdPgiw", - "as1kW60", - "tXPpWO/dVSkK", - "w0dcJmkolghdSYpcLmoHW7jTrW", - "xexcI8knl23dVHNcOmoXW5vWuW", - "mmooqYnN", - "WQrseSoPWQ0", - "BSkpkSkZ", - ]; - _0x2d2e = function () { - return _0x358dbc; - }; - return _0x2d2e(); - } - const reg = /https?:\/\/twitter.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/, - twitterUrl = reg[_0x2b294a(0x18a, "WNyv")](e[_0x2b294a(0x199, "i(e%")]); - function _0x2a30(_0x530974, _0x1c7c1a) { - const _0x2d2e9c = _0x2d2e(); - return ( - (_0x2a30 = function (_0x2a30ca, _0x37fd16) { - _0x2a30ca = _0x2a30ca - 0x16d; - let _0x21253e = _0x2d2e9c[_0x2a30ca]; - if (_0x2a30["ogixyo"] === undefined) { - var _0x52d638 = function (_0x446b97) { - const _0xa7d17e = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/="; - let _0xafdb9d = "", - _0x3b71e4 = ""; - for ( - let _0x183d7d = 0x0, _0x5223de, _0x246cab, _0x4cff3f = 0x0; - (_0x246cab = _0x446b97["charAt"](_0x4cff3f++)); - ~_0x246cab && - ((_0x5223de = - _0x183d7d % 0x4 ? _0x5223de * 0x40 + _0x246cab : _0x246cab), - _0x183d7d++ % 0x4) - ? (_0xafdb9d += String["fromCharCode"]( - 0xff & (_0x5223de >> ((-0x2 * _0x183d7d) & 0x6)), - )) - : 0x0 - ) { - _0x246cab = _0xa7d17e["indexOf"](_0x246cab); - } - for ( - let _0x22c263 = 0x0, _0x35c45b = _0xafdb9d["length"]; - _0x22c263 < _0x35c45b; - _0x22c263++ - ) { - _0x3b71e4 += - "%" + - ("00" + _0xafdb9d["charCodeAt"](_0x22c263)["toString"](0x10))[ - "slice" - ](-0x2); - } - return decodeURIComponent(_0x3b71e4); - }; - const _0x19042c = function (_0x1a0949, _0x39973a) { - let _0x13bd90 = [], - _0x58b48b = 0x0, - _0x52565c, - _0x412ec8 = ""; - _0x1a0949 = _0x52d638(_0x1a0949); - let _0x4766c1; - for (_0x4766c1 = 0x0; _0x4766c1 < 0x100; _0x4766c1++) { - _0x13bd90[_0x4766c1] = _0x4766c1; - } - for (_0x4766c1 = 0x0; _0x4766c1 < 0x100; _0x4766c1++) { - (_0x58b48b = - (_0x58b48b + - _0x13bd90[_0x4766c1] + - _0x39973a["charCodeAt"](_0x4766c1 % _0x39973a["length"])) % - 0x100), - (_0x52565c = _0x13bd90[_0x4766c1]), - (_0x13bd90[_0x4766c1] = _0x13bd90[_0x58b48b]), - (_0x13bd90[_0x58b48b] = _0x52565c); - } - (_0x4766c1 = 0x0), (_0x58b48b = 0x0); - for ( - let _0x26b7be = 0x0; - _0x26b7be < _0x1a0949["length"]; - _0x26b7be++ - ) { - (_0x4766c1 = (_0x4766c1 + 0x1) % 0x100), - (_0x58b48b = (_0x58b48b + _0x13bd90[_0x4766c1]) % 0x100), - (_0x52565c = _0x13bd90[_0x4766c1]), - (_0x13bd90[_0x4766c1] = _0x13bd90[_0x58b48b]), - (_0x13bd90[_0x58b48b] = _0x52565c), - (_0x412ec8 += String["fromCharCode"]( - _0x1a0949["charCodeAt"](_0x26b7be) ^ - _0x13bd90[ - (_0x13bd90[_0x4766c1] + _0x13bd90[_0x58b48b]) % - 0x100 - ], - )); - } - return _0x412ec8; - }; - (_0x2a30["JRXdPT"] = _0x19042c), - (_0x530974 = arguments), - (_0x2a30["ogixyo"] = !![]); - } - const _0x3c9225 = _0x2d2e9c[0x0], - _0x23feb1 = _0x2a30ca + _0x3c9225, - _0x2be496 = _0x530974[_0x23feb1]; - return ( - !_0x2be496 - ? (_0x2a30["wKJatu"] === undefined && (_0x2a30["wKJatu"] = !![]), - (_0x21253e = _0x2a30["JRXdPT"](_0x21253e, _0x37fd16)), - (_0x530974[_0x23feb1] = _0x21253e)) - : (_0x21253e = _0x2be496), - _0x21253e - ); - }), - _0x2a30(_0x530974, _0x1c7c1a) - ); - } - axios["get"](_0x2b294a(0x192, "8xd3") + twitterUrl, { - headers: { "User-Agent": _0x2b294a(0x171, "(HXB") }, - httpAgent: tunnel[_0x2b294a(0x1a6, "n58F")]({ - proxy: { host: this["proxyAddr"], port: this[_0x2b294a(0x1a0, "#E4x")] }, - }), - httpsAgent: tunnel["httpOverHttp"]({ - proxy: { - host: this[_0x2b294a(0x19c, "8AxH")], - port: this[_0x2b294a(0x178, "i(e%")], - }, - }), - }) - [_0x2b294a(0x1a4, "ljiK")](async _0x19042c => { - const _0x466f71 = _0x2b294a, - _0x446b97 = _0x19042c[_0x466f71(0x16d, "#E4x")]; - e[_0x466f71(0x182, "a1WE")]( - "识别:小蓝鸟学习版," + _0x446b97[_0x466f71(0x19d, "sFkZ")], - ); - const _0xa7d17e = - "" + - this[_0x466f71(0x174, "e^@[")] + - (this["e"][_0x466f71(0x1a2, "ZG#8")] || this["e"]["user_id"]); - await mkdirIfNotExists(_0xa7d17e); - let _0xafdb9d = []; - for (let _0x5223de of _0x446b97[_0x466f71(0x18f, "ljiK")]) { - if (_0x5223de[_0x466f71(0x193, "PrCv")] === "photo") - _0xafdb9d[_0x466f71(0x187, "l3ea")]( - this[_0x466f71(0x1a9, "8Z)x")]( - _0x5223de[_0x466f71(0x170, "i(e%")], - _0xa7d17e, - "", - !![], - ), - ); - else - _0x5223de["type"] === _0x466f71(0x19a, "S%SI") && - (await this[_0x466f71(0x172, "xitm")]( - _0x446b97[_0x466f71(0x191, "l3ea")][0x0][ - _0x466f71(0x17b, "4T^f") - ][0x0][_0x466f71(0x184, "l1yR")], - !![], - )[_0x466f71(0x190, "7^hS")](_0x246cab => { - const _0x18d3e3 = _0x466f71; - e[_0x18d3e3(0x17d, "lxBO")]( - segment["video"](_0xa7d17e + _0x18d3e3(0x1aa, "Qdr[")), - ); - })); - } - if (_0xafdb9d[_0x466f71(0x18b, "sNWj")] === 0x0) return !![]; - let _0x3b71e4 = [], - _0x183d7d = []; - await Promise[_0x466f71(0x186, "n58F")](_0xafdb9d)[_0x466f71(0x19b, "Wshq")]( - _0x4cff3f => { - _0x4cff3f["forEach"](_0x22c263 => { - const _0x49694d = _0x2a30; - _0x183d7d[_0x49694d(0x195, "q#t*")](_0x22c263), - _0x3b71e4[_0x49694d(0x1a7, "#E4x")]({ - message: segment[_0x49694d(0x180, "XTb0")]( - fs["readFileSync"](_0x22c263), - ), - nickname: - this["e"][_0x49694d(0x197, "n58F")][ - _0x49694d(0x194, "S%SI") - ] || this["e"][_0x49694d(0x177, "3o)K")], - user_id: this["e"][_0x49694d(0x173, "3Kft")], - }); - }); - }, - ), - await e[_0x466f71(0x176, "ljiK")]( - await Bot[_0x466f71(0x1a5, "k90U")](_0x3b71e4), - ), - _0x183d7d["forEach"](_0x35c45b => { - const _0x4bccf3 = _0x466f71; - fs[_0x4bccf3(0x19f, "WOCh")](_0x35c45b); - }); + // 配置参数及解析 + 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(this.bearerToken, { 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"], }) - ["catch"](_0x1a0949 => { - const _0x5b9cf4 = _0x2b294a; - e[_0x5b9cf4(0x18e, "ZG#8")](_0x5b9cf4(0x198, "PrCv")); + .then(async resp => { + e.reply(`识别:小蓝鸟学习版,${resp.data.text}`); + const downloadPath = `${this.defaultPath}${this.e.group_id || this.e.user_id}`; + // 创建文件夹(如果没有过这个群) + if (!fs.existsSync(downloadPath)) { + mkdirsSync(downloadPath); + } + // 逐个遍历判断 + let task = []; + for (let item of resp.includes.media) { + if (item.type === "photo") { + // 图片 + task.push(this.downloadImg(item.url, downloadPath, "", true)); + } else if (item.type === "video") { + // 视频 + await this.downloadVideo(resp.includes.media[0].variants[0].url, true).then( + _ => { + e.reply(segment.video(`${downloadPath}/temp.mp4`)); + }, + ); + } + } + // 如果没有图片直接返回走 + if (task.length === 0) { + return true; + } + // 下面是有图片的情况 + let images = []; + let path = []; + // 获取所有图片的promise + await Promise.all(task).then(resp => { + // console.log(resp) + resp.forEach(item => { + path.push(item); + images.push({ + message: segment.image(fs.readFileSync(item)), + nickname: this.e.sender.card || this.e.user_id, + user_id: this.e.user_id, + }); + }); + }); + await e.reply(await Bot.makeForwardMsg(images)); + // 清理文件 + path.forEach(item => { + fs.unlinkSync(item); + }); }); - return !![]; + return true; } // acfun解析 diff --git a/img/example.webp b/img/example.webp index 099126d..7ae065a 100644 Binary files a/img/example.webp and b/img/example.webp differ diff --git a/img/example2.webp b/img/example2.webp deleted file mode 100644 index d1176db..0000000 Binary files a/img/example2.webp and /dev/null differ diff --git a/img/example3.webp b/img/example3.webp deleted file mode 100644 index eea4330..0000000 Binary files a/img/example3.webp and /dev/null differ diff --git a/img/example4.webp b/img/example4.webp deleted file mode 100644 index d437ba3..0000000 Binary files a/img/example4.webp and /dev/null differ diff --git a/img/example5.webp b/img/example5.webp deleted file mode 100644 index 90fbb65..0000000 Binary files a/img/example5.webp and /dev/null differ diff --git a/utils/netease.js b/utils/netease.js deleted file mode 100644 index 567ef7b..0000000 --- a/utils/netease.js +++ /dev/null @@ -1,163 +0,0 @@ -// 获取cookie -import fetch from "node-fetch"; -import axios from "axios"; - -const BASE_URL = "http://cloud-music.pl-fe.cn"; - -/** - * 获取cookie - * @param key - * @returns {Promise} - */ -async function getCookies(key) { - const cookieUrl = `${BASE_URL}/login/qr/check?key=${key}×tamp=${Date.now()}`; - return fetch(cookieUrl).then(async resp => { - return await resp.json(); - }); -} - -/** - * 获取登陆状态 - * @param cookie - * @returns {Promise>} - */ -async function getLoginStatus(cookie) { - return axios({ - url: `${BASE_URL}/login/status?timestamp=${Date.now()}`, - method: "post", - data: { - cookie, - }, - }).then(resp => { - return resp.data.data; - }); -} - -/** - * 获取每日推荐 - * @param cookie - * @returns {Promise>} - */ -async function getDailyRecommend(cookie) { - return axios({ - url: `${BASE_URL}/recommend/songs?timestamp=${Date.now()}`, - method: "get", - data: { - cookie, - }, - }).then(resp => { - return resp.data.data; - }); -} - -/** - * 获取密匙 - * @returns {Promise<*>} - */ -async function getKey() { - const keyUrl = `${BASE_URL}/login/qr/key?timestamp=${Date.now()}`; - return await fetch(keyUrl).then(async resp => { - const respJson = await resp.json(); - return respJson.data.unikey; - }); -} - -/** - * 获取二维码 - * @param key - * @returns {Promise<*>} - */ -async function getQrCode(key) { - const qrPicUrl = `${BASE_URL}/login/qr/create?key=${key}&qrimg=true×tamp=${Date.now()}`; - return await fetch(qrPicUrl).then(async resp => { - const respJson = await resp.json(); - return respJson.data.qrimg; - }); -} - -/** - * 获取听歌排行榜 - * @param uid - * @returns {Promise>} - */ -async function getUserRecord(uid) { - return axios({ - url: `${BASE_URL}/user/record?uid=${uid}&type=1×tamp=${Date.now()}`, - method: "get", - }).then(resp => { - return resp.data; - }); -} - -/** - * 检查当前歌曲是否可用 - * @param id - * @returns {Promise>} 返回{success:true|false, message: 'ok'} - */ -async function checkMusic(id) { - return axios({ - url: `${BASE_URL}/check/music?id=${id}×tamp=${Date.now()}`, - method: "get", - }).then(resp => { - return resp.data; - }); -} - -async function getSong(id, cookie) { - return axios({ - url: `${BASE_URL}/song/url/v1?id=${id}&level=standard×tamp=${Date.now()}`, - method: "post", - data: { - cookie, - }, - }).then(resp => { - return resp.data.data; - }); -} - -async function getSongDetail(ids) { - return axios({ - url: `${BASE_URL}/song/detail?ids=${ids}×tamp=${Date.now()}`, - method: "get", - }).then(resp => { - return resp.data; - }); -} - -async function getCloud(cookie) { - return axios({ - url: `${BASE_URL}/user/cloud?timestamp=${Date.now()}`, - method: "get", - data: { - cookie, - }, - }).then(resp => { - return resp.data.data; - }); -} - -async function getCloudMusicDetail(id, cookie) { - return axios({ - url: `${BASE_URL}/user/cloud/detail?id=${id}×tamp=${Date.now()}`, - method: "get", - data: { - cookie, - }, - }).then(resp => { - return resp.data; - }); -} - -export { - getCookies, - getLoginStatus, - getDailyRecommend, - getKey, - getQrCode, - getUserRecord, - checkMusic, - getSong, - getSongDetail, - getCloud, - getCloudMusicDetail -}; diff --git a/utils/trans-strategy.js b/utils/trans-strategy.js index 2361768..e3b9f5c 100644 --- a/utils/trans-strategy.js +++ b/utils/trans-strategy.js @@ -2,77 +2,24 @@ import {transMap, tencentTransMap, googleTransMap} from "./constant.js"; import md5 from "md5"; import fetch from "node-fetch"; import HttpProxyAgent from "https-proxy-agent"; +import _ from 'lodash' -/** - * 翻译插件策略模式 - */ -export default class Translate { - config = { - /** - * 百度翻译appid - */ - translateAppId: "", - /** - * 百度翻译密匙 - */ - translateSecret: "", - /** - * 魔法 - */ - proxy: "" +// 定义翻译策略接口 +class TranslateStrategy { + async translate(query, targetLanguage) { + throw new Error("This method should be implemented by subclasses"); } +} +// 百度翻译策略 +class TencentTranslateStrategy extends TranslateStrategy { constructor(config) { + super(); this.config = config; } - /** - * 百度翻译 - * @param query 查询句子 - * @param targetLanguage 目标语言 - * @returns {Promise} - */ - async baidu(query, targetLanguage) { - const url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ - transMap[targetLanguage] - }&appid=${this.config.translateAppId}&salt=rconsole&sign=${md5( - this.config.translateAppId + query + "rconsole" + this.config.translateSecret, - )}&q=${query}`; - return fetch(url) - .then(resp => resp.json()) - .then(text => text.trans_result) - .then(res => res[0].dst) - .catch(err => logger.error(err)); - } - - /** - * google翻译 - * @param query - * @param targetLanguage - * @returns {Promise} - */ - async google(query, targetLanguage) { - const url = `https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=auto&tl=${googleTransMap[targetLanguage]}&q=${query}`; - return fetch(url, { - method: "GET", - headers: { - "USER-AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - }, - agent: new HttpProxyAgent(this.config.proxy || "http://127.0.0.1:7890"), - }) - .then(resp => resp.text()) - .then(res => JSON.parse(res)) - .then(res => res[0][0][0]) - } - - - /** - * 腾选交互式翻译 - * @param query - * @param targetLanguage - * @returns {Promise} - */ - async tencent(query, targetLanguage) { + async translate(query, targetLanguage) { + // 腾讯翻译的具体实现 const url = `https://transmart.qq.com/api/imt` const sourceLanguage = await fetch(url, { method: "POST", @@ -131,3 +78,82 @@ export default class Translate { }) } } + +// 百度翻译策略 +class BaiduTranslateStrategy extends TranslateStrategy { + + config = { + /** + * 百度翻译appid + */ + translateAppId: "", + /** + * 百度翻译密匙 + */ + translateSecret: "", + /** + * 魔法 + */ + proxy: "" + } + + constructor(config) { + super(); + this.config = config; + } + + async translate(query, targetLanguage) { + // 百度翻译的具体实现 + const url = `http://api.fanyi.baidu.com/api/trans/vip/translate?from=auto&to=${ + transMap[targetLanguage] + }&appid=${this.config.translateAppId}&salt=rconsole&sign=${md5( + this.config.translateAppId + query + "rconsole" + this.config.translateSecret, + )}&q=${query}`; + return fetch(url) + .then(resp => resp.json()) + .then(text => text.trans_result) + .then(res => res[0].dst) + .catch(err => logger.error(err)); + } +} + +class GoogleTranslateStrategy extends TranslateStrategy { + constructor(config) { + super(); + this.config = config; + } + + async translate(query, targetLanguage) { + // 谷歌翻译的具体实现 + const url = `https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=auto&tl=${googleTransMap[targetLanguage]}&q=${query}`; + return fetch(url, { + method: "GET", + headers: { + "USER-AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", + }, + agent: new HttpProxyAgent(this.config.proxy || "http://127.0.0.1:7890"), + }) + .then(resp => resp.text()) + .then(res => JSON.parse(res)) + .then(res => res[0][0][0]) + } +} + +// 主逻辑 +export default class Translate { + constructor(config) { + this.config = config; + this.strategy = null; + + if (!_.isEmpty(this.config.translateAppId) && !_.isEmpty(this.config.translateSecret)) { + this.strategy = new BaiduTranslateStrategy(this.config); + } else { + // 根据配置选择其他策略,例如 Tencent 或 Google + this.strategy = new TencentTranslateStrategy(this.config); + } + } + + async translate(query, targetLanguage) { + return this.strategy.translate(query, targetLanguage); + } +} \ No newline at end of file