From 15db7b1cd2b8d4ec6e69eb5844982dec7a913843 Mon Sep 17 00:00:00 2001 From: bbaban <3102509561@qq.com> Date: Sun, 30 Jul 2023 11:05:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=8A=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=B1=B3=E6=B8=B8=E7=A4=BE=E5=85=AC=E5=91=8A=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bot.js | 1 + plugins/genshin/apps/mysNews.js | 145 ++++-------- plugins/genshin/defSet/mys/pushNews.yaml | 47 +++- plugins/genshin/model/mysNews.js | 168 ++++++++------ plugins/genshin/model/mysSrNews.js | 282 ----------------------- 5 files changed, 190 insertions(+), 453 deletions(-) delete mode 100644 plugins/genshin/model/mysSrNews.js diff --git a/lib/bot.js b/lib/bot.js index f23da06..4dbb3f6 100644 --- a/lib/bot.js +++ b/lib/bot.js @@ -15,6 +15,7 @@ export default class Yunzai extends Client { /** 加载icqq事件监听 */ await ListenerLoader.load(bot) await bot.login(cfg.qq, cfg.pwd) + bot[bot.uin] = bot return bot } } diff --git a/plugins/genshin/apps/mysNews.js b/plugins/genshin/apps/mysNews.js index 3401fc3..7c5eb19 100644 --- a/plugins/genshin/apps/mysNews.js +++ b/plugins/genshin/apps/mysNews.js @@ -1,6 +1,5 @@ import plugin from '../../../lib/plugins/plugin.js' import MysNews from '../model/mysNews.js' -import MysSrNews from '../model/mysSrNews.js' import fs from 'node:fs' import lodash from 'lodash' import gsCfg from '../model/gsCfg.js' @@ -8,7 +7,7 @@ import YAML from 'yaml' gsCfg.cpCfg('mys', 'pushNews') export class mysNews extends plugin { - constructor (e) { + constructor(e) { super({ name: '米游社公告', dsc: '#公告 #资讯 #活动', @@ -16,26 +15,13 @@ export class mysNews extends plugin { priority: 700, rule: [ { - reg: '^(#*官方(公告|资讯|活动)|#*原神(公告|资讯|活动)|#公告|#资讯|#活动)[0-9]*$', + reg: '^#*(官方|星铁|原神|崩坏三|崩三|绝区零|崩坏二|崩二|崩坏学园二|未定|未定事件簿)?(公告|资讯|活动)[0-9]*$', fnc: 'news' }, { reg: '^(#米游社|#mys)(.*)', fnc: 'mysSearch' }, - { - reg: '^(#*铁道(公告|资讯|活动)|#*星铁(公告|资讯|活动)|#星穹公告|#星穹资讯|#星穹活动)[0-9]*$', - fnc: 'srNews' - }, - { - reg: '^#*(开启|关闭)(铁道|星铁|星穹)(公告|资讯)推送$', - fnc: 'srSetPush' - }, - { - reg: '^#推送(铁道|星铁|星穹)(公告|资讯)$', - permission: 'master', - fnc: 'srMysNewsTask' - }, { reg: '(.*)(bbs.mihoyo.com|miyoushe.com)/ys(.*)/article(.*)', fnc: 'mysUrl' @@ -45,85 +31,66 @@ export class mysNews extends plugin { fnc: 'ysEstimate' }, { - reg: '^#*(开启|关闭)(公告|资讯)推送$', + reg: '^#*(星铁|原神|崩坏三|崩三|绝区零|崩坏二|崩二|崩坏学园二|未定|未定事件簿)?(开启|关闭)(公告|资讯)推送$', fnc: 'setPush' }, { - reg: '^#推送(公告|资讯)$', + reg: '^#(星铁|原神|崩坏三|崩三|绝区零|崩坏二|崩二|崩坏学园二|未定|未定事件簿)?推送(公告|资讯)$', permission: 'master', fnc: 'mysNewsTask' } - ] }) this.file = './plugins/genshin/config/mys.pushNews.yaml' /** 定时任务 */ - this.task = [ - { - cron: gsCfg.getConfig('mys', 'pushNews').pushTime, - name: '米游社公告推送任务', - fnc: () => this.mysNewsTask(), - log: false - }, - { - cron: gsCfg.getConfig('mys', 'pushNews').pushTime, - name: '崩坏星穹铁道公告推送任务', - fnc: () => this.srMysNewsTask(), - log: false - } - ] + this.task = { + cron: gsCfg.getConfig('mys', 'pushNews').pushTime, + name: '米游社公告推送任务', + fnc: () => this.mysNewsTask(), + log: false + } } - async init () { + async init() { if (fs.existsSync(this.file)) return fs.copyFileSync('./plugins/genshin/defSet/mys/pushNews.yaml', this.file) } - async news () { - let data = await new MysNews(this.e).getNews() + async news() { + let gids = this.gids() + let data = await new MysNews(this.e).getNews(gids) if (!data) return await this.reply(data) } - async srNews () { - let data = await new MysSrNews(this.e).getNews() - if (!data) return - await this.reply(data) - } - - async mysNewsTask () { + async mysNewsTask() { let mysNews = new MysNews(this.e) await mysNews.mysNewsTask() } - async srMysNewsTask () { - let mysNews = new MysSrNews(this.e) - await mysNews.mysNewsTask() - } - - async mysSearch () { + async mysSearch() { if (/签到/g.test(this.e.msg)) return false let data = await new MysNews(this.e).mysSearch() if (!data) return await this.reply(data) } - async mysUrl () { + async mysUrl() { let data = await new MysNews(this.e).mysUrl() if (!data) return await this.reply(data) } - async ysEstimate () { + async ysEstimate() { let data = await new MysNews(this.e).ysEstimate() if (!data) return await this.reply(data) } - async srSetPush () { + async setPush() { if (!this.e.isGroup) { await this.reply('推送请在群聊中设置') return @@ -134,25 +101,31 @@ export class mysNews extends plugin { } let cfg = gsCfg.getConfig('mys', 'pushNews') + let gids = this.gids() - let type = 'srannounceGroup' + let game = gids == 1 ? 'bbb' : gids == 2 ? 'gs' : gids == 3 ? 'bb' : gids == 4 ? 'wd' : gids == 6 ? 'sr' : 'zzz' + let type = `${game}announceGroup` let typeName = '公告' if (this.e.msg.includes('资讯')) { - type = 'srinfoGroup' + type = `${game}infoGroup` typeName = '资讯' } let model - let msg = `崩坏星穹铁道${typeName}推送已` + let name = await new MysNews(this.e).game(gids) + let msg = `${name}${typeName}推送已` + if (!Array.isArray(cfg[type][this.e.self_id])) + cfg[type][this.e.self_id] = [] + if (this.e.msg.includes('开启')) { model = '开启' - cfg[type].push(this.e.group_id) - cfg[type] = lodash.uniq(cfg[type]) + cfg[type][this.e.self_id].push(this.e.group_id) + cfg[type][this.e.self_id] = lodash.uniq(cfg[type][this.e.self_id]) msg += `${model}\n如有最新${typeName}将自动推送至此` } else { model = '关闭' msg += `${model}` - cfg[type] = lodash.difference(cfg[type], [this.e.group_id]) + cfg[type][this.e.self_id] = lodash.difference(cfg[type][this.e.self_id], [this.e.group_id]) } let yaml = YAML.stringify(cfg) @@ -162,42 +135,26 @@ export class mysNews extends plugin { await this.reply(msg) } - async setPush () { - if (!this.e.isGroup) { - await this.reply('推送请在群聊中设置') - return + gids() { + let msg = this.e.msg.replace(/[#公告资讯活动开启关闭推送]/g, ''); + switch (msg) { + case '崩坏三': + case '崩三': + return 1 + case '原神': + return 2 + case '崩坏学园二': + case '崩坏二': + case '崩二': + return 3 + case '未定事件簿': + case '未定': + return 4 + case '星铁': + return 6 + case '绝区零': + return 8 } - if (!this.e.member?.is_admin && !this.e.isMaster) { - await this.reply('暂无权限,只有管理员才能操作', true) - return true - } - - let cfg = gsCfg.getConfig('mys', 'pushNews') - - let type = 'announceGroup' - let typeName = '公告' - if (this.e.msg.includes('资讯')) { - type = 'infoGroup' - typeName = '资讯' - } - - let model - let msg = `原神${typeName}推送已` - if (this.e.msg.includes('开启')) { - model = '开启' - cfg[type].push(this.e.group_id) - cfg[type] = lodash.uniq(cfg[type]) - msg += `${model}\n如有最新${typeName}将自动推送至此` - } else { - model = '关闭' - msg += `${model}` - cfg[type] = lodash.difference(cfg[type], [this.e.group_id]) - } - - let yaml = YAML.stringify(cfg) - fs.writeFileSync(this.file, yaml, 'utf8') - - logger.mark(`${this.e.logFnc} ${model}${typeName}推送:${this.e.group_id}`) - await this.reply(msg) + return 2 } } diff --git a/plugins/genshin/defSet/mys/pushNews.yaml b/plugins/genshin/defSet/mys/pushNews.yaml index 6cca109..888185a 100644 --- a/plugins/genshin/defSet/mys/pushNews.yaml +++ b/plugins/genshin/defSet/mys/pushNews.yaml @@ -1,18 +1,51 @@ - # 米游社公共推送定时任务,修改需要重启 pushTime: 0 0/5 * * * ? # 最多同时推送条数 maxNum: 1 -#公共推送群 -announceGroup: [] +# 包含关键字不推送 +banWord: { + gs: /冒险助力礼包|纪行|预下载|脚本外挂|集中反馈|已开奖|云·原神|魔神任务|传说任务|线下赛|晋级赛|战绩更新|海选赛|邀请赛|积分赛|战绩工具|交流平台|首日赛|线上赛|社区内容|个人专访|全民赛|决赛|总决赛|半决赛|淘汰赛|作品展示|同人|大别野/g, + sr: /预下载|脚本外挂|集中反馈|已开奖|问题说明|意见反馈|账号封禁|工具|直播预告|获奖名单|大别野/g, + wd: /大别野|已开奖/g, + bb: /已开奖|大别野/g, + bbb: /封禁名单|大别野|马克兔速报|预下载/g, + zzz: /作品展示|已开奖|大别野/g +} -#资讯推送群 -infoGroup: [] +#原神公告推送群 +gsannounceGroup: {} + +#原神资讯推送群 +gsinfoGroup: {} #崩坏星穹铁道公告推送群 -srannounceGroup: [] +srannounceGroup: {} #崩坏星穹铁道资讯推送群 -srinfoGroup: [] \ No newline at end of file +srinfoGroup: {} + +#绝区零公告推送群 +zzzannounceGroup: {} + +#绝区零资讯推送群 +zzzinfoGroup: {} + +#未定事件簿公告推送群 +wdannounceGroup: {} + +#未定事件簿资讯推送群 +wdinfoGroup: {} + +#崩坏3公告推送群 +bbbannounceGroup: {} + +#崩坏3资讯推送群 +bbbinfoGroup: {} + +#崩坏学园2公告推送群 +bbannounceGroup: {} + +#崩坏学园2资讯推送群 +bbinfoGroup: {} \ No newline at end of file diff --git a/plugins/genshin/model/mysNews.js b/plugins/genshin/model/mysNews.js index 0bb40c2..5cf35be 100644 --- a/plugins/genshin/model/mysNews.js +++ b/plugins/genshin/model/mysNews.js @@ -5,16 +5,15 @@ import puppeteer from '../../../lib/puppeteer/puppeteer.js' import common from '../../../lib/common/common.js' import gsCfg from '../model/gsCfg.js' -const _path = process.cwd() let emoticon export default class MysNews extends base { - constructor (e) { + constructor(e) { super(e) this.model = 'mysNews' } - async getNews () { + async getNews(gid) { let type = 1 let typeName = '公告' if (this.e.msg.includes('资讯')) { @@ -26,7 +25,7 @@ export default class MysNews extends base { typeName = '活动' } - const res = await this.postData('getNewsList', { gids: 2, page_size: 20, type }) + const res = await this.postData('getNewsList', { gids: gid, page_size: 20, type }) if (!res) return const data = res.data.list @@ -34,7 +33,7 @@ export default class MysNews extends base { return true } - const page = this.e.msg.replace(/#|#|官方|原神|公告|资讯|活动/g, '').trim() || 1 + const page = this.e.msg.replace(/#|#|官方|星铁|原神|崩坏三|崩三|绝区零|崩坏二|崩二|崩坏学园二|未定|未定事件簿|公告|资讯|活动/g, '').trim() || 1 if (page > data.length) { await this.e.reply('目前只查前20条最新的公告,请输入1-20之间的整数。') return true @@ -42,22 +41,22 @@ export default class MysNews extends base { const postId = data[page - 1].post.post_id - const param = await this.newsDetail(postId) + const param = await this.newsDetail(postId, gid) const img = await this.render(param) - - return await this.replyMsg(img, `原神${typeName}:${param.data.post.subject}`) + let game = this.game() + return await this.replyMsg(img, `${game}${typeName}:${param.data.post.subject}`) } - async render (param) { + async render(param) { return await puppeteer.screenshots(this.model, param) } - async newsDetail (postId) { - const res = await this.postData('getPostFull', { gids: 2, read: 1, post_id: postId }) + async newsDetail(postId, gid) { + const res = await this.postData('getPostFull', { gids: gid, read: 1, post_id: postId }) if (!res) return - const data = await this.detalData(res.data.post) + const data = await this.detalData(res.data.post, gid) return { ...this.screenData, @@ -67,15 +66,15 @@ export default class MysNews extends base { } } - postApi (type, data) { - let host = 'https://bbs-api-static.mihoyo.com/' + postApi(type, data) { + let host = 'https://bbs-api.miyoushe.com/' let param = [] lodash.forEach(data, (v, i) => param.push(`${i}=${v}`)) param = param.join('&') switch (type) { // 搜索 case 'searchPosts': - host = 'https://bbs-api.mihoyo.com/post/wapi/searchPosts?' + host = 'https://bbs-api.miyoushe.com/post/wapi/searchPosts?' break // 帖子详情 case 'getPostFull': @@ -92,10 +91,10 @@ export default class MysNews extends base { return host + param } - async postData (type, data) { + async postData(type, data) { const url = this.postApi(type, data) const headers = { - Referer: 'https://bbs.mihoyo.com/', + Referer: 'https://www.miyoushe.com', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' } let response @@ -114,7 +113,7 @@ export default class MysNews extends base { return res } - async detalData (data) { + async detalData(data, gid) { let json try { json = JSON.parse(data.post.content) @@ -134,7 +133,7 @@ export default class MysNews extends base { } if (!emoticon) { - emoticon = await this.mysEmoticon() + emoticon = await this.mysEmoticon(gid) } data.post.content = data.post.content.replace(/_\([^)]*\)/g, function (t, e) { @@ -161,10 +160,10 @@ export default class MysNews extends base { return data } - async mysEmoticon () { + async mysEmoticon(gid) { const emp = new Map() - const res = await this.postData('emoticon', { gids: 2 }) + const res = await this.postData('emoticon', { gids: gid }) if (res.retcode != 0) { return emp @@ -181,7 +180,7 @@ export default class MysNews extends base { return emp } - async mysSearch () { + async mysSearch() { let msg = this.e.msg msg = msg.replace(/#|米游社|mys/g, '') @@ -214,7 +213,7 @@ export default class MysNews extends base { return await this.replyMsg(img, `${param.data.post.subject}`) } - async mysUrl () { + async mysUrl() { let msg = this.e.msg let postId = /[0-9]+/g.exec(msg)[0] @@ -227,7 +226,7 @@ export default class MysNews extends base { return await this.replyMsg(img, `${param.data.post.subject}`) } - async ysEstimate () { + async ysEstimate() { let msg = '版本原石盘点' let res = await this.postData('searchPosts', { gids: 2, size: 20, keyword: msg }) if (res?.data?.posts.length <= 0) { @@ -258,81 +257,93 @@ export default class MysNews extends base { return await this.replyMsg(img, `${param.data.post.subject}`) } - async replyMsg (img, title) { + async replyMsg(img, title = '') { if (!img || img.length <= 0) return false if (img.length == 1) { return img[0] } else { - let msg = [title, ...img] - return await common.makeForwardMsg(this.e, msg, title) + return await common.makeForwardMsg(this.e, img, title) } } - async mysNewsTask (type = 1) { + async mysNewsTask() { let cfg = gsCfg.getConfig('mys', 'pushNews') // 推送2小时内的公告资讯 let interval = 7200 // 最多同时推送两条 this.maxNum = cfg.maxNum - // 包含关键字不推送 - let banWord = /冒险助力礼包|纪行|预下载|脚本外挂|集中反馈|已开奖|云·原神|魔神任务|传说任务说明/g - let anno = await this.postData('getNewsList', { gids: 2, page_size: 10, type: 1 }) - let info = await this.postData('getNewsList', { gids: 2, page_size: 10, type: 3 }) + for (let gid of [1, 2, 3, 4, 6, 8]) { + let type = gid == 1 ? 'bbb' : gid == 2 ? 'gs' : gid == 3 ? 'bb' : gid == 4 ? 'wd' : gid == 6 ? 'sr' : 'zzz' + if (lodash.isEmpty(cfg[`${type}announceGroup`]) && lodash.isEmpty(cfg[`${type}infoGroup`])) continue - let news = [] - if (anno) anno.data.list.forEach(v => { news.push({ ...v, typeName: '公告', post_id: v.post.post_id }) }) - if (info) info.data.list.forEach(v => { news.push({ ...v, typeName: '资讯', post_id: v.post.post_id }) }) - if (news.length <= 0) return + // 包含关键字不推送 + let banWord = cfg.banWord[type] - news = lodash.orderBy(news, ['post_id'], ['asc']) - - let now = Date.now() / 1000 - - this.key = 'Yz:genshin:mys:newPush:' - this.e.isGroup = true - this.pushGroup = [] - for (let val of news) { - if (Number(now - val.post.created_at) > interval) { - continue + let news = [] + if (!lodash.isEmpty(cfg[`${type}announceGroup`])) { + let anno = await this.postData('getNewsList', { gids: gid, page_size: 10, type: 1 }) + if (anno) anno.data.list.forEach(v => { news.push({ ...v, typeName: '公告', post_id: v.post.post_id }) }) } - if (new RegExp(banWord).test(val.post.subject)) { - continue + if (!lodash.isEmpty(cfg[`${type}infoGroup`])) { + let info = await this.postData('getNewsList', { gids: gid, page_size: 10, type: 3 }) + if (info) info.data.list.forEach(v => { news.push({ ...v, typeName: '资讯', post_id: v.post.post_id }) }) } - if (val.typeName == '公告') { - for (let groupId of cfg.announceGroup) { - await this.sendNews(groupId, val.typeName, val.post.post_id) + + if (news.length <= 0) continue + + news = lodash.orderBy(news, ['post_id'], ['asc']) + + let now = Date.now() / 1000 + + this.key = `Yz:${type}:mys:newPush:` + this.e.isGroup = true + this.pushGroup = [] + for (let val of news) { + if (Number(now - val.post.created_at) > interval) { + continue } - } - if (val.typeName == '资讯') { - for (let groupId of cfg.infoGroup) { - await this.sendNews(groupId, val.typeName, val.post.post_id) + if (new RegExp(banWord).test(val.post.subject)) { + continue + } + if (val.typeName == '公告') { + for (let botId in cfg[`${type}announceGroup`]) { + for (let groupId of cfg[`${type}announceGroup`][botId]) { + await this.sendNews(botId, groupId, val.typeName, val.post.post_id, gid) + } + } + } + if (val.typeName == '资讯') { + for (let botId in cfg[`${type}infoGroup`]) { + for (let groupId of cfg[`${type}infoGroup`][botId]) { + await this.sendNews(botId, groupId, val.typeName, val.post.post_id, gid) + } + } } } } } - async sendNews (groupId, typeName, postId) { + async sendNews(botId, groupId, typeName, postId, gid) { if (!this.pushGroup[groupId]) this.pushGroup[groupId] = 0 if (this.pushGroup[groupId] >= this.maxNum) return - let sended = await redis.get(`${this.key}${groupId}:${postId}`) + let sended = await redis.get(`${this.key}${botId}:${groupId}:${postId}`) if (sended) return - // TODO: 暂时处理,后续待更好的解决方案 (定时任务无法获取e.bot) - this.e.bot = Bot - + let game = this.game(gid) // 判断是否存在群关系 - if (!this.e.bot.gl.get(Number(groupId))) { - logger.mark(`[米游社${typeName}推送] 群${groupId}未关联`) + this.e.group = Bot[botId]?.pickGroup(groupId) + if (!this.e.group) { + logger.mark(`[米游社${game}${typeName}推送] 群${botId}:${groupId}未关联`) return } if (!this[postId]) { - const param = await this.newsDetail(postId) + const param = await this.newsDetail(postId, gid) - logger.mark(`[米游社${typeName}推送] ${param.data.post.subject}`) + logger.mark(`[米游社${game}${typeName}推送] ${param.data.post.subject}`) this[postId] = { img: await this.render(param), @@ -341,20 +352,37 @@ export default class MysNews extends base { } this.pushGroup[groupId]++ - this.e.group = this.e.bot.pickGroup(Number(groupId)) - this.e.group_id = Number(groupId) - let tmp = await this.replyMsg(this[postId].img, `原神${typeName}推送:${this[postId].title}`) + this.e.group_id = groupId + let tmp = await this.replyMsg(this[postId].img, `${game}${typeName}推送:${this[postId].title}`) await common.sleep(1000) if (!tmp) return if (tmp?.type != 'xml') { - tmp = [`原神${typeName}推送\n`, tmp] + tmp = [`${game}${typeName}推送\n`, tmp] } - await redis.set(`${this.key}${groupId}:${postId}`, '1', { EX: 3600 * 10 }) + await redis.set(`${this.key}${botId}:${groupId}:${postId}`, '1', { EX: 3600 * 10 }) // 随机延迟10-90秒 await common.sleep(lodash.random(10, 90) * 1000) await this.e.group.sendMsg(tmp) } -} + + game(gid) { + switch (gid) { + case 1: + return '崩坏三' + case 2: + return '原神' + case 3: + return '崩坏二' + case 4: + return '未定事件簿' + case 6: + return '崩坏星穹铁道' + case 8: + return '绝区零' + } + return '' + } +} \ No newline at end of file diff --git a/plugins/genshin/model/mysSrNews.js b/plugins/genshin/model/mysSrNews.js deleted file mode 100644 index 69e6c64..0000000 --- a/plugins/genshin/model/mysSrNews.js +++ /dev/null @@ -1,282 +0,0 @@ -import base from './base.js' -import fetch from 'node-fetch' -import lodash from 'lodash' -import puppeteer from '../../../lib/puppeteer/puppeteer.js' -import common from '../../../lib/common/common.js' -import gsCfg from '../model/gsCfg.js' - -let emoticon - -export default class MysSrNews extends base { - constructor (e) { - super(e) - this.model = 'mysNews' - } - - async getNews () { - let type = 1 - let typeName = '公告' - if (this.e.msg.includes('资讯')) { - type = '3' - typeName = '资讯' - } - if (this.e.msg.includes('活动')) { - type = '2' - typeName = '活动' - } - - const res = await this.postData('getNewsList', { gids: 6, page_size: 20, type }) - if (!res) return - - const data = res.data.list - if (data.length == 0) { - return true - } - - const page = this.e.msg.replace(/#|#|星铁|星穹|铁道|公告|资讯|活动/g, '').trim() || 1 - if (page > data.length) { - await this.e.reply('目前只查前20条最新的公告,请输入1-20之间的整数。') - return true - } - - const postId = data[page - 1].post.post_id - - const param = await this.newsDetail(postId) - - const img = await this.render(param) - - return await this.replyMsg(img, `崩坏星穹铁道${typeName}:${param.data.post.subject}`) - } - - async render (param) { - return await puppeteer.screenshots(this.model, param) - } - - async newsDetail (postId) { - const res = await this.postData('getPostFull', { gids: 6, read: 1, post_id: postId }) - if (!res) return - - const data = await this.detalData(res.data.post) - - return { - ...this.screenData, - saveId: postId, - dataConent: data.post.content, - data - } - } - - postApi (type, data) { - let host = 'https://bbs-api-static.mihoyo.com/' - let param = [] - lodash.forEach(data, (v, i) => param.push(`${i}=${v}`)) - param = param.join('&') - switch (type) { - // 搜索 - case 'searchPosts': - host = 'https://bbs-api.mihoyo.com/post/wapi/searchPosts?' - break - // 帖子详情 - case 'getPostFull': - host += 'post/wapi/getPostFull?' - break - // 公告列表 - case 'getNewsList': - host += 'post/wapi/getNewsList?' - break - case 'emoticon': - host += 'misc/api/emoticon_set?' - break - } - return host + param - } - - async postData (type, data) { - const url = this.postApi(type, data) - const headers = { - Referer: 'https://bbs.mihoyo.com/', - 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' - } - let response - try { - response = await fetch(url, { method: 'get', headers }) - } catch (error) { - logger.error(error.toString()) - return false - } - - if (!response.ok) { - logger.error(`[米游社接口错误][${type}] ${response.status} ${response.statusText}`) - return false - } - const res = await response.json() - return res - } - - async detalData (data) { - let json - try { - json = JSON.parse(data.post.content) - } catch (error) { - - } - - if (typeof json == 'object') { - if (json.imgs && json.imgs.length > 0) { - for (const val of json.imgs) { - data.post.content = `
` - } - } - } else { - for (const img of data.post.images) { - data.post.content = data.post.content.replace(img, img + '?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,jpg') - } - - if (!emoticon) { - emoticon = await this.mysEmoticon() - } - - data.post.content = data.post.content.replace(/_\([^)]*\)/g, function (t, e) { - t = t.replace(/_\(|\)/g, '') - if (emoticon.has(t)) { - return `` - } else { - return '' - } - }) - - const arrEntities = { lt: '<', gt: '>', nbsp: ' ', amp: '&', quot: '"' } - data.post.content = data.post.content.replace(/&(lt|gt|nbsp|amp|quot);/ig, function (all, t) { - return arrEntities[t] - }) - } - - data.post.created_time = new Date(data.post.created_at * 1000).toLocaleString() - - for (const i in data.stat) { - data.stat[i] = data.stat[i] > 10000 ? (data.stat[i] / 10000).toFixed(2) + '万' : data.stat[i] - } - - return data - } - - async mysEmoticon () { - const emp = new Map() - - const res = await this.postData('emoticon', { gids: 6 }) - - if (res.retcode != 0) { - return emp - } - - for (const val of res.data.list) { - if (!val.icon) continue - for (const list of val.list) { - if (!list.icon) continue - emp.set(list.name, list.icon) - } - } - - return emp - } - - async replyMsg (img, title) { - if (!img || img.length <= 0) return false - if (img.length == 1) { - return img[0] - } else { - let msg = [title, ...img] - return await common.makeForwardMsg(this.e, msg, title) - } - } - - async mysNewsTask (type = 1) { - let cfg = gsCfg.getConfig('mys', 'pushNews') - - // 推送2小时内的公告资讯 - let interval = 7200 - // 最多同时推送两条 - this.maxNum = cfg.maxNum - // 包含关键字不推送 - let banWord = /冒险助力礼包|纪行|预下载|脚本外挂|集中反馈|已开奖|云·原神|魔神任务|传说任务说明/g - - let anno = await this.postData('getNewsList', { gids: 6, page_size: 10, type: 1 }) - let info = await this.postData('getNewsList', { gids: 6, page_size: 10, type: 3 }) - - let news = [] - if (anno) anno.data.list.forEach(v => { news.push({ ...v, typeName: '公告', post_id: v.post.post_id }) }) - if (info) info.data.list.forEach(v => { news.push({ ...v, typeName: '资讯', post_id: v.post.post_id }) }) - if (news.length <= 0) return - - news = lodash.orderBy(news, ['post_id'], ['asc']) - - let now = Date.now() / 1000 - - this.key = 'Yz:genshin:mys:newPush:' - this.e.isGroup = true - this.pushGroup = [] - for (let val of news) { - if (Number(now - val.post.created_at) > interval) { - continue - } - if (new RegExp(banWord).test(val.post.subject)) { - continue - } - if (val.typeName == '公告') { - for (let groupId of cfg.srannounceGroup) { - await this.sendNews(groupId, val.typeName, val.post.post_id) - } - } - if (val.typeName == '资讯') { - for (let groupId of cfg.srinfoGroup) { - await this.sendNews(groupId, val.typeName, val.post.post_id) - } - } - } - } - - async sendNews (groupId, typeName, postId) { - if (!this.pushGroup[groupId]) this.pushGroup[groupId] = 0 - if (this.pushGroup[groupId] >= this.maxNum) return - - let sended = await redis.get(`${this.key}${groupId}:${postId}`) - if (sended) return - - // TODO: 暂时处理,后续待更好的解决方案 (定时任务无法获取e.bot) - this.e.bot = Bot - - // 判断是否存在群关系 - if (!this.e.bot.gl.get(Number(groupId))) { - logger.mark(`[崩坏星穹铁道${typeName}推送] 群${groupId}未关联`) - return - } - - if (!this[postId]) { - const param = await this.newsDetail(postId) - - logger.mark(`[崩坏星穹铁道${typeName}推送] ${param.data.post.subject}`) - - this[postId] = { - img: await this.render(param), - title: param.data.post.subject - } - } - - this.pushGroup[groupId]++ - this.e.group = Bot.pickGroup(Number(groupId)) - this.e.group_id = Number(groupId) - let tmp = await this.replyMsg(this[postId].img, `崩坏星穹铁道${typeName}推送:${this[postId].title}`) - - await common.sleep(1000) - if (!tmp) return - - if (tmp?.type != 'xml') { - tmp = [`崩坏星穹铁道${typeName}推送\n`, tmp] - } - - redis.set(`${this.key}${groupId}:${postId}`, '1', { EX: 3600 * 10 }) - // 随机延迟10-90秒 - await common.sleep(lodash.random(10, 90) * 1000) - await this.e.group.sendMsg(tmp) - } -}