import path from 'path'; import fs from 'fs'; import fetch from 'node-fetch'; import lodash from 'lodash'; import common from '../../../lib/common/common.js'; import { ZZZPlugin } from '../lib/plugin.js'; import { rulePrefix } from '../lib/common.js'; import { atlasToName } from '../lib/convert/char.js'; import { imageResourcesPath, configPath } from '../lib/path.js'; import _ from 'lodash'; import settings from '../lib/settings.js'; const ZZZ_GUIDES_PATH = path.join(imageResourcesPath, 'guides'); const ZZZ_GUIDES_CONFIG_PATH = path.join(configPath, 'guide.yaml'); export class Guide extends ZZZPlugin { constructor() { super({ name: '[ZZZ-Plugin]Guide', dsc: '#zzz角色攻略', event: 'message', priority: _.get(settings.getConfig('priority'), 'guide', 70), rule: [ { reg: `^${rulePrefix}攻略(说明|帮助)$`, fnc: 'GuideHelp' }, { reg: `^${rulePrefix}设置默认攻略(\\d+|all)$`, fnc: 'SetDefaultGuide' }, { reg: `^${rulePrefix}设置所有攻略显示个数(\\d+)$`, fnc: 'SetMaxForwardGuide' }, { reg: `${rulePrefix}(更新)?\\S+攻略(\\d+|all)?$`, fnc: 'Guide', } ], }); this.url = 'https://bbs-api.mihoyo.com/post/wapi/getPostFullInCollection?&gids=8&collection_id='; this.collection_id = [ [], // 来源:新艾利都快讯 [2712859], [2727116], [2721968], [2724610], [2722266], ]; this.source = [ '新艾利都快讯', '清茶沐沐Kiyotya', '小橙子阿', '猫冬', '月光中心', ]; // 最大攻略数量 this.maxNum = this.source.length; // 最大显示攻略数量 this.maxForwardGuides = _.get(settings.getConfig('guide'), 'max_forward_guides', 4); } async init() { for (let group = 1; group <= this.maxNum; group++) { let guideFolder = this.getGuideFolder(group); if (!fs.existsSync(guideFolder)) { fs.mkdirSync(guideFolder, { recursive: true }); } } } getGuideFolder(groupIndex) { let guideFolder = path.join(ZZZ_GUIDES_PATH, this.source[groupIndex - 1]); return guideFolder; } getGuidePath(groupIndex, characterName) { let filename = `role_guide_${characterName}.png`; let guidePath = path.join(this.getGuideFolder(groupIndex), filename); return guidePath; } canGetImageFromFile(guidePath, isUpdate) { return fs.existsSync(guidePath) && !isUpdate; } async Guide() { let reg = new RegExp(`${rulePrefix}(更新)?(\\S+)攻略(\\d+|all)?$`); let [ , , , , isUpdate, atlas, group = _.get(settings.getConfig('guide'), 'default_guide', 1).toString(), ] = this.e.msg.match(reg); // all -> 0 if (group == 'all') { group = '0'; } group = Number(group); if (group > this.maxNum) { await this.reply(`超过攻略数量(${this.maxNum})`); return; } let name = atlasToName(atlas); if (!name) { await this.reply('该角色不存在'); return; } if (group === 0) { // eslint-disable-next-line no-unused-vars let msg = []; // eslint-disable-next-line no-unused-vars for (let i = 1; i <= this.maxNum; i++) { let guidePath = this.getGuidePath(i, name); if (this.canGetImageFromFile(guidePath, isUpdate)) { msg.push(segment.image(`file://${guidePath}`)); continue; } if (i <= this.maxForwardGuides && (await this.getImg(name, i))) { msg.push(segment.image(`file://${guidePath}`)); } } if (msg.length) { await this.reply(await common.makeForwardMsg(this.e, [msg])); } return false; } let guidePath = this.getGuidePath(group, name); if (this.canGetImageFromFile(guidePath, isUpdate)) { await this.e.reply(segment.image(`file://${guidePath}`)); return; } if (await this.getImg(name, group)) { await this.e.reply(segment.image(`file://${guidePath}`)); } } /** 下载攻略图 */ async getImg(name, group) { let mysRes = []; this.collection_id[group].forEach(id => mysRes.push(this.getData(this.url + id)) ); try { mysRes = await Promise.all(mysRes); } catch (error) { this.e.reply('暂无攻略数据,请稍后再试'); console.log(`米游社接口报错:${error}}`); return false; } // 搜索时过滤特殊符号,譬如「11号」 const filtered_name = name.replace(/[^\w\s]|_/g, '') let posts = lodash.flatten(lodash.map(mysRes, item => item.data.posts)); let url, created_at, updated_at; for (let val of posts) { if (val.post.subject.replace(/【[^】]*本[^】]*】/g, '').includes(filtered_name)) { let max = 0; val.image_list.forEach((v, i) => { if ( Number(v.size) >= Number(val.image_list[max].size) && v.format != 'gif' // 动图天生 size 会撑得很大 ) { max = i; } }); url = val.image_list[max].url; created_at = val.post.created_at; updated_at = val.post.updated_at; break; } } if (!url) { this.e.reply( `暂无${name}攻略 (${this.source[group - 1]})\n请尝试其他的攻略来源查询` ); return false; } console.log(`${this.e.logFnc} 下载${name}攻略图 - ${this.source[group - 1]}`); const download = await fetch(url); const arrayBuffer = await download.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); let guidePath = this.getGuidePath(group, name); fs.writeFileSync(guidePath, buffer); console.log(`${this.e.logFnc} 下载${name}攻略成功 - ${this.source[group - 1]}`); return true; } /** 获取数据 */ async getData(url) { let response = await fetch(url, { method: 'get' }); if (!response.ok) { return false; } return await response.json(); } /** %攻略帮助 */ async GuideHelp () { let reply_msg = [ '绝区零角色攻略帮助:', '%艾莲攻略+攻略id', '%更新艾莲攻略+攻略id', '%设置默认攻略+攻略id', '%设置所有攻略显示个数+攻略id', '示例: %艾莲攻略2', '', '攻略来源:' ].concat(this.source.map((element, index) => `${index + 1}: ${element}`)) await this.e.reply(reply_msg.join('\n')) } setConfig(key, value) { let config = fs.readFileSync(ZZZ_GUIDES_CONFIG_PATH, 'utf8') let newREG = new RegExp(`^${key}: (.*)`, 'gm') config = config.replace(newREG, `${key}: ${value}`) fs.writeFileSync(ZZZ_GUIDES_CONFIG_PATH, config, 'utf8') } /** %设置默认攻略1 */ async SetDefaultGuide () { let match = /设置默认攻略(\d+|all)$/g.exec(this.e.msg) let guide_id = match[1] if (guide_id == 'all') { guide_id = 0 } if (guide_id > this.maxNum) { let reply_msg = [ '绝区零默认攻略设置方式为:', '%设置默认攻略[0123...]', `请增加数字0-${this.maxNum}其中一个,或者增加 all 以显示所有攻略`, '攻略来源请输入 %攻略帮助 查看' ] await this.e.reply(reply_msg.join('\n')) return } this.setConfig('default_guide', guide_id) let source_name = guide_id == 0 ? 'all' : this.source[guide_id - 1] await this.e.reply(`绝区零默认攻略已设置为: ${guide_id} (${source_name})`) } /** %设置所有攻略显示个数3 */ async SetMaxForwardGuide () { let match = /设置所有攻略显示个数(\d+)$/g.exec(this.e.msg) let max_forward_guide = Number(match[1]) this.setConfig('max_forward_guides', max_forward_guide) await this.e.reply(`绝区零所有攻略显示个数已设置为: ${max_forward_guide}`) } }