From a7294079e40ee88007c9e466a6bb0f9743ec8b3a Mon Sep 17 00:00:00 2001 From: ctrlcvs <1509167646@qq.com> Date: Sun, 24 Jul 2022 11:46:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=85=BC=E5=AE=B9yunzaiV3?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 + adapter/index.js | 44 ++ adapter/mys.js | 114 +++++ adapter/render.js | 21 + apps/Note.js | 141 +++--- apps/admin.js | 7 +- apps/index.js | 70 +++ apps/render.js | 30 +- apps/xiaoyao_image.js | 75 +-- components/Changelog.js | 69 +-- components/Common.js | 2 +- components/Data.js | 40 +- config/.gitignore | 2 + defSet/mys/pubCk.yaml | 3 + defSet/mys/set.yaml | 6 + defSet/role/name.yaml | 601 +++++++++++++++++++++++ defSet/role/other.yaml | 19 + index.js | 104 +--- model/gsCfg.js | 233 +++++++++ model/mys/mysApi.js | 219 +++++++++ model/mys/mysInfo.js | 650 +++++++++++++++++++++++++ resources/Atlas_alias/wuqi_tujian.json | 88 ++++ 22 files changed, 2283 insertions(+), 258 deletions(-) create mode 100644 adapter/index.js create mode 100644 adapter/mys.js create mode 100644 adapter/render.js create mode 100644 apps/index.js create mode 100644 config/.gitignore create mode 100644 defSet/mys/pubCk.yaml create mode 100644 defSet/mys/set.yaml create mode 100644 defSet/role/name.yaml create mode 100644 defSet/role/other.yaml create mode 100644 model/gsCfg.js create mode 100644 model/mys/mysApi.js create mode 100644 model/mys/mysInfo.js create mode 100644 resources/Atlas_alias/wuqi_tujian.json diff --git a/CHANGELOG.md b/CHANGELOG.md index da7e528..e15c5bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 1.1.1 +* 初步兼容V3版本 + # 1.1.0 * 增加`#图鉴帮助`用于查看帮助命令 * 增加`#图鉴设置`用于设置图鉴相关功能 diff --git a/adapter/index.js b/adapter/index.js new file mode 100644 index 0000000..a711ebe --- /dev/null +++ b/adapter/index.js @@ -0,0 +1,44 @@ +import plugin from '../../../lib/plugins/plugin.js' +import * as Atlas from '../apps/index.js' +import { render } from './render.js' +import { checkAuth, getMysApi } from './mys.js' + +export class atlas extends plugin { + constructor () { + super({ + name: 'xiaoyao-cvs-plugin', + desc: '图鉴插件', + event: 'message', + priority: 50, + rule: [{ + reg: '.+', + fnc: 'dispatch' + }] + }) + } + + async dispatch (e) { + let msg = e.raw_message + e.checkAuth = async function (cfg) { + return await checkAuth(e, cfg) + } + e.getMysApi = async function (cfg) { + return await getMysApi(e, cfg) + } + msg = '#' + msg.replace('#', '') + for (let fn in Atlas.rule) { + let cfg = Atlas.rule[fn] + if (Atlas[fn] && new RegExp(cfg.reg).test(msg)) { + let ret = await Atlas[fn](e, { + render + }) + if (ret === true) { + console.log('ret true') + return true + } + } + } + + return false + } +} diff --git a/adapter/mys.js b/adapter/mys.js new file mode 100644 index 0000000..fd41d0a --- /dev/null +++ b/adapter/mys.js @@ -0,0 +1,114 @@ +import MysInfo from '../../genshin/model/mys/mysInfo.js' +import lodash from 'lodash' + +class User { + constructor (cfg) { + this.id = cfg.id + this.uid = cfg.uid + this.cookie = '' + } + + // 保存用户配置 + async setCfg (path, value) { + console.log(this.id) + let userCfg = await redis.get(`genshin:user-cfg:${this.id}`) + userCfg = userCfg ? JSON.parse(userCfg) : {} + lodash.set(userCfg, path, value) + await redis.set(`genshin:user-cfg:${this.id}`, JSON.stringify(userCfg)) + } + + /* 获取用户配置 */ + async getCfg (path, defaultValue) { + let userCfg = await redis.get(`genshin:user-cfg:${this.id}`) + userCfg = userCfg ? JSON.parse(userCfg) : {} + return lodash.get(userCfg, path, defaultValue) + } + + async getMysUser () { + return { + uid: this.uid + } + } +} + +class Mys { + constructor (e, uid, MysApi) { + this.selfUser = new User({ id: e.user_id, uid }) + this.targetUser = { + uid + } + this.e = e + this.MysApi = MysApi + e.targetUser = this.targetUser + e.selfUser = this.selfUser + } + + async getData (api, data) { + if (!this.MysApi) { + return false + } + let ret = await MysInfo.get(this.e, api, data) + if (!ret) { + return false + } + return ret.data || ret + } + + // 获取角色信息 + async getCharacter () { + return await this.getData('character') + } + + // 获取角色详情 + async getAvatar (id) { + return await this.getData('detail', { avatar_id: id }) + } + + // 首页宝箱信息 + async getIndex () { + return await this.getData('index') + } + + // 获取深渊信息 + async getSpiralAbyss (type = 1) { + return await this.getData('spiralAbyss', { schedule_type: type }) + } + + async getDetail (id) { + return await this.getData('detail', { avatar_id: id }) + } + + async getCompute (data) { + return await this.getData('compute', data) + } + + async getAvatarSkill (id) { + return await this.getData('avatarSkill', { avatar_id: id }) + } + + get isSelfCookie () { + return true + } +} + +export async function getMysApi (e, cfg) { + let { auth = 'all' } = cfg + let uid = await MysInfo.getUid(e) + if (!uid) return false + + /* 检查user ck */ + let isCookieUser = await MysInfo.checkUidBing(uid) + if (auth === 'cookie' && !isCookieUser) { + e.reply('尚未绑定Cookie...') + return false + } + let MysApi = await MysInfo.init(e, 'roleIndex') + if (!MysApi) { + return false + } + return new Mys(e, uid, MysApi) +} + +export async function checkAuth (e, cfg) { + return new User({ id: e.user_id }) +} diff --git a/adapter/render.js b/adapter/render.js new file mode 100644 index 0000000..3ee70c2 --- /dev/null +++ b/adapter/render.js @@ -0,0 +1,21 @@ +import lodash from 'lodash' +import Data from '../components/Data.js' +import puppeteer from '../../../lib/puppeteer/puppeteer.js' + +const plugin = 'xiaoyao-cvs-plugin' + +const _path = process.cwd() + +export async function render (app = '', tpl = '', data = {}, imgType = 'jpeg') { + // 在data中保存plugin信息 + data._plugin = plugin + + if (lodash.isUndefined(data._res_path)) { + data._res_path = `../../../../../plugins/${plugin}/resources/` + } + Data.createDir(_path + '/data/', `html/${plugin}/${app}/${tpl}`) + data.saveId = data.saveId || data.save_id || tpl + data.tplFile = `./plugins/${plugin}/resources/${app}/${tpl}.html` + data.pluResPath = data._res_path + return await puppeteer.screenshot(`${plugin}/${app}/${tpl}`, data) +} diff --git a/apps/Note.js b/apps/Note.js index 0a023c7..7a20b72 100644 --- a/apps/Note.js +++ b/apps/Note.js @@ -5,24 +5,20 @@ import fetch from "node-fetch"; import Common from "../components/Common.js"; import fs from "fs"; import format from "date-format"; -import puppeteer from "puppeteer"; - -import { MysUser, User } from "../../../lib/components/Models.js"; -import common from "../../../lib/common.js"; +import { isV3 } from '../components/Changelog.js' +import MysInfo from '../model/mys/mysInfo.js' +// import { MysUser } from "../../../lib/components/Models.js"; +// import common from "../../../lib/common.js"; import lodash from "lodash"; -import { getPluginRender } from "../../../lib/render.js" +import { getPluginRender } from "./render.js"; + +import gsCfg from '../model/gsCfg.js' import { Cfg, Data } from "../components/index.js"; import moment from 'moment'; -// import MysApi from "../components/MysApi.js" - -import { - getUrl, - getHeaders -} from "../../../lib/app/mysApi.js"; - +import MysApi from "../model/mys/mysApi.js"; const _path = process.cwd(); let role_user = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/resources/dailyNote/json/`, "dispatch_time"); @@ -44,63 +40,64 @@ export async function Note(e, { if (!Cfg.get("sys.Note")&&!poke) { return false; } - let cookie, uid; - if (NoteCookie[e.user_id]) { - cookie = NoteCookie[e.user_id].cookie; - uid = NoteCookie[e.user_id].uid; - } else if (BotConfig.dailyNote && BotConfig.dailyNote[e.user_id]) { - cookie = BotConfig.dailyNote[e.user_id].cookie; - uid = BotConfig.dailyNote[e.user_id].uid; - } else { - e.reply(`尚未配置,无法查询体力\n配置教程:${BotConfig.cookieDoc}`); - return true; - } - - const response = await getDailyNote(uid, cookie); - if (!response.ok) { - e.reply("米游社接口错误"); - return true; - } - const res = await response.json(); - - if (res.retcode == 10102) { - if (!e.openDailyNote) { - e.openDailyNote = true; - await openDailyNote(cookie); //自动开启 - dailyNote(e); + let cookie, uid,res; + if(isV3){ + res = await MysInfo.get(e, 'dailyNote') + if (!res || res.retcode !== 0) return false + }else{ + if (NoteCookie[e.user_id]) { + cookie = NoteCookie[e.user_id].cookie; + uid = NoteCookie[e.user_id].uid; + } else if (BotConfig.dailyNote && BotConfig.dailyNote[e.user_id]) { + cookie = BotConfig.dailyNote[e.user_id].cookie; + uid = BotConfig.dailyNote[e.user_id].uid; } else { - e.reply("请先开启实时便笺数据展示"); + e.reply(`尚未配置,无法查询体力\n配置教程:${BotConfig.cookieDoc}`); + return true; } - return true; - } - - if (res.retcode != 0) { - if (res.message == "Please login") { - Bot.logger.mark(`体力cookie已失效`); - e.reply(`体力cookie已失效,请重新配置\n注意:退出米游社登录cookie将会失效!`); - - if (NoteCookie[e.user_id]) { - await MysUser.delNote(NoteCookie[e.user_id]); - delete NoteCookie[e.user_id]; - saveJson(); + const response = await getDailyNote(uid, cookie); + if (!response.ok) { + e.reply("米游社接口错误"); + return true; + } + res = await response.json(); + if (res.retcode == 10102) { + if (!e.openDailyNote) { + e.openDailyNote = true; + await openDailyNote(cookie); //自动开启 + dailyNote(e); + } else { + e.reply("请先开启实时便笺数据展示"); } - } else { - e.reply(`体力查询错误:${res.message}`); - Bot.logger.mark(`体力查询错误:${JSON.stringify(res)}`); + return true; + } + if (res.retcode != 0) { + if (res.message == "Please login") { + Bot.logger.mark(`体力cookie已失效`); + e.reply(`体力cookie已失效,请重新配置\n注意:退出米游社登录cookie将会失效!`); + if (NoteCookie[e.user_id]) { + // await MysUser.delNote(NoteCookie[e.user_id]); + delete NoteCookie[e.user_id]; + saveJson(); + } + } else { + e.reply(`体力查询错误:${res.message}`); + Bot.logger.mark(`体力查询错误:${JSON.stringify(res)}`); + } + + return true; + } + + //redis保存uid + redis.set(`genshin:uid:${e.user_id}`, uid, { + EX: 2592000 + }); + + //更新 + if (NoteCookie[e.user_id]) { + NoteCookie[e.user_id].maxTime = new Date().getTime() + res.data.resin_recovery_time * 1000; + saveJson(); } - - return true; - } - - //redis保存uid - redis.set(`genshin:uid:${e.user_id}`, uid, { - EX: 2592000 - }); - - //更新 - if (NoteCookie[e.user_id]) { - NoteCookie[e.user_id].maxTime = new Date().getTime() + res.data.resin_recovery_time * 1000; - saveJson(); } let data = res.data; @@ -143,9 +140,9 @@ export async function Note(e, { val.remained_time = new Date().getTime() + val.remained_time * 1000; // console.log(val.remained_time) var urls_avatar_side = val.avatar_side_icon.split("_"); - let id = YunzaiApps.mysInfo.roleIdToName(urls_avatar_side[urls_avatar_side.length - 1].replace( + let id = gsCfg.roleIdToName(urls_avatar_side[urls_avatar_side.length - 1].replace( /(.png|.jpg)/g, "")); - let name = YunzaiApps.mysInfo.roleIdToName(id, true); + let name = gsCfg.roleIdToName(id, true); var time_cha = 20; if (role_user["12"].includes(name)) { time_cha = 15; @@ -287,14 +284,14 @@ async function dateTime_(time) { time) < 19.5 ? "傍晚" : format("hh", time) < 22 ? "晚上" : "深夜"; } - async function getDailyNote(uid, cookie) { + let mysApi = new MysApi(uid, cookie) let { url, headers, query, body - } = getUrl("dailyNote", uid); + } = mysApi.getUrl("dailyNote", uid); headers.Cookie = cookie; const response = await fetch(url, { method: "get", @@ -302,7 +299,6 @@ async function getDailyNote(uid, cookie) { }); return response; } - export async function saveJson() { let path = "data/NoteCookie/NoteCookie.json"; fs.writeFileSync(path, JSON.stringify(NoteCookie, "", "\t")); @@ -337,7 +333,10 @@ export async function DailyNoteTask() { }; e.reply = (msg) => { - common.relpyPrivate(user_id, msg); + Bot.pickUser(user_id*1).sendMsg(msg).catch((err) => { + logger.mark(err) + }) + // common.relpyPrivate(user_id, msg); }; //判断今天是否推送 if (cookie.maxTime && cookie.maxTime > 0 && new Date().getTime() > cookie.maxTime - (160 - sendResin) * 8 * diff --git a/apps/admin.js b/apps/admin.js index 08bbcfd..a3a0a77 100644 --- a/apps/admin.js +++ b/apps/admin.js @@ -13,9 +13,7 @@ import { Cfg } from "../components/index.js"; import Common from "../components/Common.js"; -import { - init -} from "../apps/xiaoyao_image.js" + const require = createRequire( import.meta.url); @@ -156,14 +154,12 @@ export async function updateRes(e) { } let numRet = /(\d*) files changed,/.exec(stdout); if (numRet && numRet[1]) { - init() e.reply(`报告主人,更新成功,此次更新了${numRet[1]}个图片~`); return true; } if (error) { e.reply("更新失败!\nError code: " + error.code + "\n" + error.stack + "\n 请稍后重试。"); } else { - init() e.reply("图片加量包更新成功~"); } }); @@ -176,7 +172,6 @@ export async function updateRes(e) { if (error) { e.reply("角色图片加量包安装失败!\nError code: " + error.code + "\n" + error.stack + "\n 请稍后重试。"); } else { - init() e.reply("角色图片加量包安装成功!您后续也可以通过 #图鉴更新 命令来更新图像"); } }); diff --git a/apps/index.js b/apps/index.js new file mode 100644 index 0000000..80a8894 --- /dev/null +++ b/apps/index.js @@ -0,0 +1,70 @@ +import lodash from "lodash"; +import { + AtlasAlias +} from "./xiaoyao_image.js"; +import { + versionInfo, + help +} from "./help.js"; +import { + Note,DailyNoteTask, + Note_appoint,pokeNote +} from "./Note.js"; +import { + rule as adminRule, + updateRes, + sysCfg, + updateMiaoPlugin +} from "./admin.js"; +import { + currentVersion +} from "../components/Changelog.js"; +export { + updateRes, + updateMiaoPlugin, + versionInfo, + Note_appoint,pokeNote, + sysCfg, + help,DailyNoteTask, + AtlasAlias, + Note +}; + +let rule = { + versionInfo: { + reg: "^#图鉴版本$", + describe: "【#帮助】 图鉴版本介绍", + }, + help: { + reg: "^#?(图鉴)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$", + describe: "查看插件的功能", + }, + AtlasAlias: { + reg: "^(#(.*)|.*图鉴)$", + describe: "角色、食物、怪物、武器信息图鉴", + }, + Note: { + reg: "^#*(体力|树脂|查询体力|便笺|便签)$", + describe: "体力", + }, + Note_appoint: { + reg: "^#体力模板(设置(.*)|列表)$", + describe: "体力模板设置", + }, + pokeNote: { + reg: "#poke#", + describe: "体力", + }, + + ...adminRule +}; + +lodash.forEach(rule, (r) => { + r.priority = r.priority || 50; + r.prehash = true; + r.hashMark = true; +}); + +export { + rule +}; \ No newline at end of file diff --git a/apps/render.js b/apps/render.js index f5d155c..0b7afa1 100644 --- a/apps/render.js +++ b/apps/render.js @@ -3,7 +3,7 @@ import fs from "fs"; import puppeteer from "puppeteer"; import lodash from "lodash"; -import { Data } from "../../../lib/components/index.js"; +import { Data } from "../components/index.js"; const _path = process.cwd(); //html模板 @@ -33,6 +33,7 @@ let shoting = []; * @param data 前端参数,必传 data.save_id 用来区分模板 * @param imgType 图片类型 jpeg,png(清晰一点,大小更大) */ +const plugin="xiaoyao-cvs-plugin" async function render1(app = "", type = "", data = {}, imgType = "jpeg") { if (lodash.isUndefined(data._res_path)) { data._res_path = `../../../../../plugins/xiaoyao-cvs-plugin/resources/`; @@ -197,4 +198,29 @@ async function browserInit() { } } -export { render1, browserInit, renderNum }; +function getPluginRender(plugin) { + return async function (app = "", type = "", data = {}, imgType = "jpeg") { + // 在data中保存plugin信息 + data._plugin = plugin; + + if (lodash.isUndefined(data._res_path)) { + data._res_path = `../../../../../plugins/${plugin}/resources/`; + } + if (lodash.isUndefined(data._sys_res_path)) { + data._sys_res_path = `../../../../../resources/`; + } + let tplKey = `${plugin}.${app}.${type}`; + let saveId = data.save_id; + let tplFile = _path + `/plugins/${plugin}/resources/${app}/${type}.html`; + Data.createDir(_path + `/data/`, `html/plugin_${plugin}/${app}/${type}`); + let savePath = _path + `/data/html/plugin_${plugin}/${app}/${type}/${saveId}.html`; + return await doRender(app, type, data, imgType, { + tplKey, + tplFile, + savePath, + saveId, + }); + } +} + +export { render1, browserInit, renderNum,getPluginRender }; diff --git a/apps/xiaoyao_image.js b/apps/xiaoyao_image.js index 0f71e62..8249124 100644 --- a/apps/xiaoyao_image.js +++ b/apps/xiaoyao_image.js @@ -8,10 +8,11 @@ import { import Data from "../components/Data.js" import path from 'path'; import fetch from "node-fetch"; +import gsCfg from '../model/gsCfg.js' const _path = process.cwd(); const __dirname = path.resolve(); -const list = ["shiwu_tujian", "yuanmo_tujian", "mijin_tujian", "shengyiwu_tujian"] +const list = ["wuqi_tujian","shiwu_tujian", "yuanmo_tujian", "mijin_tujian", "shengyiwu_tujian"] export async function AtlasAlias(e) { if (!Cfg.get("Atlas.all")) { return false; @@ -25,7 +26,7 @@ export async function AtlasAlias(e) { } if (await Atlas_list(e)) return true; if (await roleInfo(e)) return true; - if (await weaponInfo(e)) return true; + // if (await weaponInfo(e)) return true; // if (await foodInfo(e)) return true; // if (await RelicsInfo(e)) return true; // if (await monsterInfo(e)) return true; @@ -37,7 +38,7 @@ export async function AtlasAlias(e) { export async function roleInfo(e) { // let msg=e.msg.replace(/#|图鉴/g,""); let msg = e.msg.replace(/#|#|信息|图鉴|命座|天赋|突破/g, ""); - let id = YunzaiApps.mysInfo.roleIdToName(msg); + let id = gsCfg.roleNameToID(msg) let name; if (["10000005", "10000007", "20000000"].includes(id)) { if (!["风主", "岩主", "雷主"].includes(msg)) { @@ -46,7 +47,7 @@ export async function roleInfo(e) { } name = msg; } else { - name = YunzaiApps.mysInfo.roleIdToName(id, true); + name = gsCfg.roleIdToName(id, true); if (!name) return false; } send_Msg(e, "juese_tujian", name) @@ -77,43 +78,43 @@ const send_Msg = function(e, type, name) { e.reply(segment.image(`file:///${path}`)); return true; } -let weapon = new Map(); -let weaponFile = []; -await init(); -export async function init(isUpdate = false) { - let weaponJson = JSON.parse(fs.readFileSync("./config/genshin/weapon.json", "utf8")); - for (let i in weaponJson) { - for (let val of weaponJson[i]) { - weapon.set(val, i); - } - } - let paths = "./plugins/xiaoyao-cvs-plugin/resources/xiaoyao-plus/wuqi_tujian"; - if (!fs.existsSync(paths)) { - return true; - } - weaponFile = fs.readdirSync(paths); - for (let val of weaponFile) { - let name = val.replace(".png", ""); - weapon.set(name, name); - } -} +// let weapon = new Map(); +// let weaponFile = []; +// await init(); +// export async function init(isUpdate = false) { +// let weaponJson = JSON.parse(fs.readFileSync("./config/genshin/weapon.json", "utf8")); +// for (let i in weaponJson) { +// for (let val of weaponJson[i]) { +// weapon.set(val, i); +// } +// } +// let paths = "./plugins/xiaoyao-cvs-plugin/resources/xiaoyao-plus/wuqi_tujian"; +// if (!fs.existsSync(paths)) { +// return true; +// } +// weaponFile = fs.readdirSync(paths); +// for (let val of weaponFile) { +// let name = val.replace(".png", ""); +// weapon.set(name, name); +// } +// } -export async function weaponInfo(e) { - let msg = e.msg || ''; - if (e.atBot) { - msg = "#" + msg.replace("#", ""); - } - if (!/(#*(.*)(信息|图鉴|突破|武器|材料)|#(.*))$/.test(msg)) return; +// export async function weaponInfo(e) { +// let msg = e.msg || ''; +// if (e.atBot) { +// msg = "#" + msg.replace("#", ""); +// } +// if (!/(#*(.*)(信息|图鉴|突破|武器|材料)|#(.*))$/.test(msg)) return; - let name = weapon.get(msg.replace(/#|#|信息|图鉴|突破|武器|材料/g, "")); +// let name = weapon.get(msg.replace(/#|#|信息|图鉴|突破|武器|材料/g, "")); - if (name) { - send_Msg(e, "wuqi_tujian", name) - return true; - } +// if (name) { +// send_Msg(e, "wuqi_tujian", name) +// return true; +// } - return false; -} +// return false; +// } export async function Atlas_list(e) { let list = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/resources/Atlas_alias/`, "Atlas_list"); let name = e.msg.replace(/#|井/g, "") diff --git a/components/Changelog.js b/components/Changelog.js index 1ca2e6d..c69f934 100644 --- a/components/Changelog.js +++ b/components/Changelog.js @@ -1,46 +1,48 @@ -import fs from "fs"; -import lodash from "lodash"; +import fs from 'fs' +import lodash from 'lodash' -const _path = process.cwd(); -const _logPath = `${_path}/plugins/xiaoyao-cvs-plugin/CHANGELOG.md`; +const _path = process.cwd() +const _logPath = `${_path}/plugins/xiaoyao-cvs-plugin/CHANGELOG.md` -let logs = {}; -let changelogs = []; -let currentVersion; -let versionCount = 4; +let logs = {} +let changelogs = [] +let currentVersion +let versionCount = 4 -let packageJson = JSON.parse(fs.readFileSync("package.json", "utf8")); +let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) const getLine = function (line) { - line = line.replace(/(^\s*\*|\r)/g, ''); - line = line.replace(/\s*`([^`]+`)/g, '$1'); - line = line.replace(/`\s*/g, ''); + line = line.replace(/(^\s*\*|\r)/g, '') + line = line.replace(/\s*`([^`]+`)/g, '$1') + line = line.replace(/`\s*/g, '') line = line.replace(/\s*\*\*([^\*]+\*\*)/g, '$1') - line = line.replace(/\*\*\s*/g, ''); - line = line.replace(/ⁿᵉʷ/g, ''); - return line; + line = line.replace(/\*\*\s*/g, '') + line = line.replace(/ⁿᵉʷ/g, '') + return line } try { if (fs.existsSync(_logPath)) { - logs = fs.readFileSync(_logPath, "utf8") || ""; - logs = logs.split("\n"); - let temp = {}, lastLine = {}; + logs = fs.readFileSync(_logPath, 'utf8') || '' + logs = logs.split('\n') + + let temp = {}; + let lastLine = {} lodash.forEach(logs, (line) => { if (versionCount <= -1) { - return false; + return false } - let versionRet = /^#\s*([0-9\\.~\s]+?)\s*$/.exec(line); + let versionRet = /^#\s*([0-9\\.~\s]+?)\s*$/.exec(line) if (versionRet && versionRet[1]) { - let v = versionRet[1].trim(); + let v = versionRet[1].trim() if (!currentVersion) { - currentVersion = v; + currentVersion = v } else { - changelogs.push(temp); + changelogs.push(temp) if (/0\s*$/.test(v) && versionCount > 0) { - versionCount = 0; + versionCount = 0 } else { - versionCount--; + versionCount-- } } @@ -50,26 +52,25 @@ try { } } else { if (!line.trim()) { - return; + return } if (/^\*/.test(line)) { lastLine = { title: getLine(line), logs: [] } - temp.logs.push(lastLine); - } else if (/^\s{3,}\*/.test(line)) { - lastLine.logs.push(getLine(line)); + temp.logs.push(lastLine) + } else if (/^\s{2,}\*/.test(line)) { + lastLine.logs.push(getLine(line)) } - } - }); + }) } - } catch (e) { // do nth } -const yunzaiVersion = packageJson.version; +const yunzaiVersion = packageJson.version +const isV3 = yunzaiVersion[0] === '3' -export { currentVersion, yunzaiVersion, changelogs }; \ No newline at end of file +export { currentVersion, yunzaiVersion, isV3, changelogs } diff --git a/components/Common.js b/components/Common.js index 0bfdefb..55e37a0 100644 --- a/components/Common.js +++ b/components/Common.js @@ -29,7 +29,7 @@ export const render_path = async function (path, params, cfg,path_) { let paths = path.split("/"); let { render, e } = cfg; let _layout_path = process.cwd() + path_; - let base64 = await render(paths[0], paths[1], { + let base64 = await render1(paths[0], paths[1], { ...params, _layout_path, defaultLayout: _layout_path + "default.html", diff --git a/components/Data.js b/components/Data.js index 7062063..f4c77a9 100644 --- a/components/Data.js +++ b/components/Data.js @@ -1,6 +1,6 @@ import lodash from "lodash"; import fs from "fs"; -import request from "request"; +const _path = process.cwd() let Data = { @@ -51,7 +51,18 @@ let Data = { Data.createDir(path, true); return fs.writeFileSync(`${path}/${file}`, JSON.stringify(data, null, space)); }, - + async importModule (path, file, rootPath = _path) { + if (!/\.js$/.test(file)) { + file = file + '.js' + } + // 检查并创建目录 + Data.createDir(_path, path, true) + if (fs.existsSync(`${_path}/${path}/${file}`)) { + let data = await import(`file://${_path}/${path}/${file}`) + return data || {} + } + return {} + }, /* * 返回一个从 target 中选中的属性的对象 * @@ -146,34 +157,11 @@ let Data = { return Promise.all(ret); }, - async cacheFile(fileList, cacheRoot) { - - let ret = {}; - let cacheFn = async function (url) { - let path = Data.getUrlPath(url); - if (fs.existsSync(`${cacheRoot}/${path.path}/${path.filename}`)) { - console.log("已存在,跳过 " + path.path + "/" + path.filename); - ret[url] = `${path.path}/${path.filename}`; - return true; - } - - Data.pathExists(cacheRoot, path.path); - await request(url).pipe(fs.createWriteStream(`${cacheRoot}/${path.path}/` + path.filename)); - console.log("下载成功: " + path.path + "/" + path.filname); - ret[url] = `${path.path}/${path.filename}`; - return true; - }; - - await Data.asyncPool(10, fileList, cacheFn); - return ret; - - }, - sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } - + } export default Data; diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/config/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/defSet/mys/pubCk.yaml b/defSet/mys/pubCk.yaml new file mode 100644 index 0000000..8ae7bc1 --- /dev/null +++ b/defSet/mys/pubCk.yaml @@ -0,0 +1,3 @@ +# 米游社公共查询ck,支持多个一行一个,横杆空格开头 +- ltoken=xxx; ltuid=xxx; cookie_token=xxx; account_id=xxx; +- ltoken=xxx; ltuid=xxx; cookie_token=xxx; account_id=xxx; \ No newline at end of file diff --git a/defSet/mys/set.yaml b/defSet/mys/set.yaml new file mode 100644 index 0000000..e3b2075 --- /dev/null +++ b/defSet/mys/set.yaml @@ -0,0 +1,6 @@ +# 公共查询是否使用用户ck 0-不使用 1-使用 +allowUseCookie: 0 +# 默认cookie帮助文档链接地址 +cookieDoc: docs.qq.com/doc/DUWNVQVFTU3liTVlO +# 米游社原神签到定时任务,Cron表达式,默认00:02开始执行,每10s签到一个 +signTime: 0 2 0 * * ? \ No newline at end of file diff --git a/defSet/role/name.yaml b/defSet/role/name.yaml new file mode 100644 index 0000000..9e5352e --- /dev/null +++ b/defSet/role/name.yaml @@ -0,0 +1,601 @@ +20000000: + - 主角 + - 旅行者 + - 卑鄙的外乡人 + - 荣誉骑士 + - 爷 + - 风主 + - 岩主 + - 雷主 + - 草主 + - 履刑者 + - 抽卡不歪真君 +10000002: + - 神里绫华 + - Kamisato Ayaka + - Ayaka + - ayaka + - 神里 + - 绫华 + - 神里凌华 + - 凌华 + - 白鹭公主 + - 神里大小姐 +10000003: + - 琴 + - Jean + - jean + - 团长 + - 代理团长 + - 琴团长 + - 蒲公英骑士 +10000005: + - 空 + - 男主 + - 男主角 + - 龙哥 + - 空哥 +10000006: + - 丽莎 + - Lisa + - lisa + - 图书管理员 + - 图书馆管理员 + - 蔷薇魔女 +10000007: + - 荧 + - 女主 + - 女主角 + - 莹 + - 萤 + - 黄毛阿姨 + - 荧妹 +10000014: + - 芭芭拉 + - Barbara + - barbara + - 巴巴拉 + - 拉粑粑 + - 拉巴巴 + - 内鬼 + - 加湿器 + - 闪耀偶像 + - 偶像 +10000015: + - 凯亚 + - Kaeya + - kaeya + - 盖亚 + - 凯子哥 + - 凯鸭 + - 矿工 + - 矿工头子 + - 骑兵队长 + - 凯子 + - 凝冰渡海真君 +10000016: + - 迪卢克 + - diluc + - Diluc + - 卢姥爷 + - 姥爷 + - 卢老爷 + - 卢锅巴 + - 正义人 + - 正e人 + - 正E人 + - 卢本伟 + - 暗夜英雄 + - 卢卢伯爵 + - 落魄了 + - 落魄了家人们 +10000020: + - 雷泽 + - razor + - Razor + - 狼少年 + - 狼崽子 + - 狼崽 + - 卢皮卡 + - 小狼 + - 小狼狗 +10000021: + - 安柏 + - Amber + - amber + - 安伯 + - 兔兔伯爵 + - 飞行冠军 + - 侦查骑士 + - 点火姬 + - 点火机 + - 打火机 + - 打火姬 +10000022: + - 温迪 + - Venti + - venti + - 温蒂 + - 风神 + - 卖唱的 + - 巴巴托斯 + - 巴巴脱丝 + - 芭芭托斯 + - 芭芭脱丝 + - 干点正事 + - 不干正事 + - 吟游诗人 + - 诶嘿 + - 唉嘿 + - 摸鱼 +10000023: + - 香菱 + - Xiangling + - xiangling + - 香玲 + - 锅巴 + - 厨师 + - 万民堂厨师 + - 香师傅 +10000024: + - 北斗 + - Beidou + - beidou + - 大姐头 + - 大姐 + - 无冕的龙王 + - 龙王 +10000025: + - 行秋 + - Xingqiu + - xingqiu + - 秋秋人 + - 秋妹妹 + - 书呆子 + - 水神 + - 飞云商会二少爷 +10000026: + - 魈 + - Xiao + - xiao + - 杏仁豆腐 + - 打桩机 + - 插秧 + - 三眼五显仙人 + - 三眼五显真人 + - 降魔大圣 + - 护法夜叉 + - 快乐风男 + - 无聊 + - 靖妖傩舞 + - 矮子仙人 + - 三点五尺仙人 + - 跳跳虎 +10000027: + - 凝光 + - Ningguang + - ningguang + - 富婆 + - 天权星 +10000029: + - 可莉 + - Klee + - klee + - 嘟嘟可 + - 火花骑士 + - 蹦蹦炸弹 + - 炸鱼 + - 放火烧山 + - 放火烧山真君 + - 蒙德最强战力 + - 逃跑的太阳 + - 啦啦啦 + - 哒哒哒 + - 炸弹人 + - 禁闭室 +10000030: + - 钟离 + - Zhongli + - zhongli + - 摩拉克斯 + - 岩王爷 + - 岩神 + - 钟师傅 + - 天动万象 + - 岩王帝君 + - 未来可期 + - 帝君 + - 拒收病婿 +10000031: + - 菲谢尔 + - Fischl + - fischl + - 皇女 + - 小艾米 + - 小艾咪 + - 奥兹 + - 断罪皇女 + - 中二病 + - 中二少女 + - 中二皇女 + - 奥兹发射器 +10000032: + - 班尼特 + - Bennett + - bennett + - 点赞哥 + - 点赞 + - 倒霉少年 + - 倒霉蛋 + - 霹雳闪雷真君 + - 班神 + - 班爷 + - 倒霉 + - 火神 + - 六星真神 +10000033: + - 达达利亚 + - Tartaglia + - tartaglia + - Childe + - childe + - Ajax + - ajax + - 达达鸭 + - 达达利鸭 + - 公子 + - 玩具销售员 + - 玩具推销员 + - 钱包 + - 鸭鸭 + - 愚人众末席 +10000034: + - 诺艾尔 + - Noelle + - noelle + - 女仆 + - 高达 + - 岩王帝姬 +10000035: + - 七七 + - Qiqi + - qiqi + - 僵尸 + - 肚饿真君 + - 度厄真君 + - 77 +10000036: + - 重云 + - Chongyun + - chongyun + - 纯阳之体 + - 冰棍 +10000037: + - 甘雨 + - Ganyu + - ganyu + - 椰羊 + - 椰奶 + - 王小美 +10000038: + - 阿贝多 + - Albedo + - albedo + - 可莉哥哥 + - 升降机 + - 升降台 + - 电梯 + - 白垩之子 + - 贝爷 + - 白垩 + - 阿贝少 + - 花呗多 + - 阿贝夕 + - abd + - 阿师傅 +10000039: + - 迪奥娜 + - Diona + - diona + - 迪欧娜 + - dio + - dio娜 + - 冰猫 + - 猫猫 + - 猫娘 + - 喵喵 + - 调酒师 +10000041: + - 莫娜 + - Mona + - mona + - 穷鬼 + - 穷光蛋 + - 穷 + - 莫纳 + - 占星术士 + - 占星师 + - 讨龙真君 + - 半部讨龙真君 + - 阿斯托洛吉斯·莫娜·梅姬斯图斯 +10000042: + - 刻晴 + - Keqing + - keqing + - 刻情 + - 氪晴 + - 刻师傅 + - 刻师父 + - 牛杂 + - 牛杂师傅 + - 斩尽牛杂 + - 免疫 + - 免疫免疫 + - 屁斜剑法 + - 玉衡星 + - 阿晴 + - 啊晴 +10000043: + - 砂糖 + - Sucrose + - sucrose + - 雷莹术士 + - 雷萤术士 + - 雷荧术士 +10000044: + - 辛焱 + - Xinyan + - xinyan + - 辛炎 + - 黑妹 + - 摇滚 +10000045: + - 罗莎莉亚 + - Rosaria + - rosaria + - 罗莎莉娅 + - 白色史莱姆 + - 白史莱姆 + - 修女 + - 罗莎利亚 + - 罗莎利娅 + - 罗沙莉亚 + - 罗沙莉娅 + - 罗沙利亚 + - 罗沙利娅 + - 萝莎莉亚 + - 萝莎莉娅 + - 萝莎利亚 + - 萝莎利娅 + - 萝沙莉亚 + - 萝沙莉娅 + - 萝沙利亚 + - 萝沙利娅 +10000046: + - 胡桃 + - Hu Tao + - hu tao + - HuTao + - hutao + - Hutao + - 胡淘 + - 往生堂堂主 + - 火化 + - 抬棺的 + - 蝴蝶 + - 核桃 + - 堂主 + - 胡堂主 + - 雪霁梅香 +10000047: + - 枫原万叶 + - Kaedehara Kazuha + - Kazuha + - kazuha + - 万叶 + - 叶天帝 + - 天帝 + - 叶师傅 +10000048: + - 烟绯 + - Yanfei + - yanfei + - 烟老师 + - 律师 + - 罗翔 +10000049: + - 宵宫 + - Yoimiya + - yoimiya + - 霄宫 + - 烟花 + - 肖宫 + - 肖工 + - 绷带女孩 +10000050: + - 托马 + - Thoma + - thoma + - 家政官 + - 太郎丸 + - 地头蛇 + - 男仆 + - 拖马 +10000051: + - 优菈 + - Eula + - eula + - 优拉 + - 尤拉 + - 尤菈 + - 浪花骑士 + - 记仇 + - 劳伦斯 +10000052: + - 雷电将军 + - Raiden Shogun + - Raiden + - raiden + - 雷神 + - 将军 + - 雷军 + - 巴尔 + - 阿影 + - 影 + - 巴尔泽布 + - 煮饭婆 + - 奶香一刀 + - 无想一刀 + - 宅女 +10000053: + - 早柚 + - Sayu + - sayu + - 小狸猫 + - 狸猫 + - 忍者 +10000054: + - 珊瑚宫心海 + - Sangonomiya Kokomi + - Kokomi + - kokomi + - 心海 + - 军师 + - 珊瑚宫 + - 书记 + - 观赏鱼 + - 水母 + - 鱼 + - 美人鱼 +10000055: + - 五郎 + - Gorou + - gorou + - 柴犬 + - 土狗 + - 希娜 + - 希娜小姐 +10000056: + - 九条裟罗 + - Kujou Sara + - Sara + - sara + - 九条 + - 九条沙罗 + - 裟罗 + - 沙罗 + - 天狗 +10000057: + - 荒泷一斗 + - Arataki Itto + - Itto + - itto + - 荒龙一斗 + - 荒泷天下第一斗 + - 一斗 + - 一抖 + - 荒泷 + - 1斗 + - 牛牛 + - 斗子哥 + - 牛子哥 + - 牛子 + - 孩子王 + - 斗虫 + - 巧乐兹 + - 放牛的 +10000058: + - 八重神子 + - Yae Miko + - Miko + - miko + - 八重 + - 神子 + - 狐狸 + - 想得美哦 + - 巫女 + - 屑狐狸 + - 骚狐狸 + - 八重宫司 + - 婶子 + - 小八 +10000059: + - 鹿野院平藏 + - shikanoin heizou + - Heizou + - heizou + - heizo + - 鹿野苑 + - 鹿野院 + - 平藏 + - 鹿野苑平藏 + - 鹿野 + - 小鹿 +10000060: + - 夜兰 + - Yelan + - yelan + - 夜阑 + - 叶澜 + - 腋兰 + - 夜天后 +10000062: + - 埃洛伊 + - Aloy + - aloy +10000063: + - 申鹤 + - Shenhe + - shenhe + - 神鹤 + - 小姨 + - 小姨子 + - 审鹤 +10000064: + - 云堇 + - Yun Jin + - yunjin + - yun jin + - 云瑾 + - 云先生 + - 云锦 + - 神女劈观 +10000065: + - 久岐忍 + - Kuki Shinobu + - Kuki + - kuki + - Shinobu + - shinobu + - 97忍 + - 小忍 + - 久歧忍 + - 97 + - 茄忍 + - 阿忍 + - 忍姐 +10000066: + - 神里绫人 + - Kamisato Ayato + - Ayato + - ayato + - 绫人 + - 神里凌人 + - 凌人 + - 0人 + - 神人 + - 零人 + - 大舅哥 +10000067: + - 柯莱 + - Collei + - collei +10000068: + - 多莉 + - Dori + - dori + - 多利 +10000069: + - 提纳里 + - Tighnari + - tighnari \ No newline at end of file diff --git a/defSet/role/other.yaml b/defSet/role/other.yaml new file mode 100644 index 0000000..3e89d22 --- /dev/null +++ b/defSet/role/other.yaml @@ -0,0 +1,19 @@ +# 角色名称缩短 +sortName: + 达达利亚: 公子 + 神里绫华: 绫华 + 神里绫人: 绫人 + 枫原万叶: 万叶 + 雷电将军: 雷神 + 珊瑚宫心海: 心海 + 荒泷一斗: 一斗 + 八重神子: 八重 + 九条裟罗: 九条 + 罗莎莉亚: 罗莎 + 鹿野院平藏: 平藏 + +costumes: + - 海风之梦 + - 闪耀协奏 + - 纱中幽兰 + - 霓裾翩跹 diff --git a/index.js b/index.js index 28acb59..e99a1ea 100644 --- a/index.js +++ b/index.js @@ -1,84 +1,26 @@ -import lodash from "lodash"; -import { - AtlasAlias -} from "./apps/xiaoyao_image.js"; -import { - versionInfo, - help -} from "./apps/help.js"; +// 适配V3 Yunzai,将index.js移至app/index.js +import { currentVersion, isV3 } from './components/Changelog.js' +import Data from './components/Data.js' -import common from "../../lib/common.js"; -import { - Note,DailyNoteTask, - Note_appoint,pokeNote -} from "./apps/Note.js"; -import { - rule as adminRule, - updateRes, - sysCfg, - updateMiaoPlugin -} from "./apps/admin.js"; -import { - currentVersion -} from "./components/Changelog.js"; -export { - updateRes, - updateMiaoPlugin, - versionInfo, - Note_appoint,pokeNote, - sysCfg, - help,DailyNoteTask, - AtlasAlias, - Note -}; +export * from './apps/index.js' +let index = { atlas: {} } +if (isV3) { + index = await Data.importModule('/plugins/xiaoyao-cvs-plugin/adapter', 'index.js') + console.log(index) +} +export const atlas = index.atlas || {} -let rule = { - versionInfo: { - reg: "^#图鉴版本$", - describe: "【#帮助】 图鉴版本介绍", - }, - help: { - reg: "^#?(图鉴)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$", - describe: "查看插件的功能", - }, - AtlasAlias: { - reg: "^(#(.*)|.*图鉴)$", - describe: "角色、食物、怪物、武器信息图鉴", - }, - Note: { - reg: "^#*(体力|树脂|查询体力|便笺|便签)$", - describe: "体力", - }, - Note_appoint: { - reg: "^#体力模板(设置(.*)|列表)$", - describe: "体力模板设置", - }, - pokeNote: { - reg: "#poke#", - describe: "体力", - }, - - ...adminRule -}; +console.log(`图鉴插件${currentVersion}初始化~`) -lodash.forEach(rule, (r) => { - r.priority = r.priority || 50; - r.prehash = true; - r.hashMark = true; -}); - -export { - rule -}; - -console.log(`图鉴插件${currentVersion}初始化~`); -setTimeout(async function() { - let msgStr = await redis.get("xiaoyao:restart-msg"); - if (msgStr) { - let msg = JSON.parse(msgStr); - await common.relpyPrivate(msg.qq, msg.msg); - await redis.del("xiaoyao:restart-msg"); - let msgs = [`当前版本: ${currentVersion}`, `您可使用 #图鉴版本 命令查看更新信息`]; - await common.relpyPrivate(msg.qq, msgs.join("\n")); - } -}, 1000); +setTimeout(async function () { + let msgStr = await redis.get('xiaoyao:restart-msg') + let relpyPrivate = async function () { + } + if (msgStr) { + let msg = JSON.parse(msgStr) + await relpyPrivate(msg.qq, msg.msg) + await redis.del('xiaoyao:restart-msg') + let msgs = [`当前图鉴版本: ${currentVersion}`, '您可使用 #图鉴版本 命令查看更新信息'] + await relpyPrivate(msg.qq, msgs.join('\n')) + } +}, 1000) diff --git a/model/gsCfg.js b/model/gsCfg.js new file mode 100644 index 0000000..bd4aa20 --- /dev/null +++ b/model/gsCfg.js @@ -0,0 +1,233 @@ +import YAML from 'yaml' +import chokidar from 'chokidar' +import fs from 'node:fs' +import { promisify } from 'node:util' +import lodash from 'lodash' + +const plugin="xiaoyao-cvs-plugin" +/** 配置文件 */ +class GsCfg { + constructor () { + /** 默认设置 */ + this.defSetPath = `./plugins/${plugin}/defSet/` + this.defSet = {} + + /** 用户设置 */ + this.configPath = `./plugins/${plugin}/config/` + this.config = {} + + /** 监听文件 */ + this.watcher = { config: {}, defSet: {} } + } + + /** + * @param app 功能 + * @param name 配置文件名称 + */ + getdefSet (app, name) { + return this.getYaml(app, name, 'defSet') + } + + /** 用户配置 */ + getConfig (app, name) { + let ignore = ['mys.pubCk', 'gacha.set'] + + if (ignore.includes(`${app}.${name}`)) { + return this.getYaml(app, name, 'config') + } + + return { ...this.getdefSet(app, name), ...this.getYaml(app, name, 'config') } + } + + /** + * 获取配置yaml + * @param app 功能 + * @param name 名称 + * @param type 默认跑配置-defSet,用户配置-config + */ + getYaml (app, name, type) { + let file = this.getFilePath(app, name, type) + let key = `${app}.${name}` + + if (this[type][key]) return this[type][key] + + this[type][key] = YAML.parse( + fs.readFileSync(file, 'utf8') + ) + + this.watch(file, app, name, type) + + return this[type][key] + } + + getFilePath (app, name, type) { + if (type == 'defSet') return `${this.defSetPath}${app}/${name}.yaml` + else return `${this.configPath}${app}.${name}.yaml` + } + + /** 监听配置文件 */ + watch (file, app, name, type = 'defSet') { + let key = `${app}.${name}` + + if (this.watcher[type][key]) return + + const watcher = chokidar.watch(file) + watcher.on('change', path => { + delete this[type][key] + logger.mark(`[修改配置文件][${type}][${app}][${name}]`) + if (this[`change_${app}${name}`]) { + this[`change_${app}${name}`]() + } + }) + + this.watcher[type][key] = watcher + } + + get element () { + return { ...this.getdefSet('element', 'role'), ...this.getdefSet('element', 'weapon') } + } + + /** 读取用户绑定的ck */ + async getBingCk () { + let ck = {} + let ckQQ = {} + let dir = './data/MysCookie/' + let files = fs.readdirSync(dir).filter(file => file.endsWith('.yaml')) + + const readFile = promisify(fs.readFile) + + let promises = [] + + files.forEach((v) => promises.push(readFile(`${dir}${v}`, 'utf8'))) + + const res = await Promise.all(promises) + + res.forEach((v) => { + let tmp = YAML.parse(v) + lodash.forEach(tmp, (v, i) => { + ck[String(i)] = v + if (v.isMain && !ckQQ[String(v.qq)]) { + ckQQ[String(v.qq)] = v + } + }) + }) + + return { ck, ckQQ } + } + + getBingCkSingle (userId) { + let file = `./data/MysCookie/${userId}.yaml` + try { + let ck = fs.readFileSync(file, 'utf-8') + ck = YAML.parse(ck) + return ck + } catch (error) { + return {} + } + } + + saveBingCk (userId, data) { + let file = `./data/MysCookie/${userId}.yaml` + if (lodash.isEmpty(data)) { + fs.existsSync(file) && fs.unlinkSync(file) + } else { + let yaml = YAML.stringify(data) + fs.writeFileSync(file, yaml, 'utf8') + } + } + + /** + * 原神角色id转换角色名字 + */ + roleIdToName (id) { + let name = this.getdefSet('role', 'name') + if (name[id]) { + return name[id][0] + } + + return '' + } + + /** 原神角色别名转id */ + roleNameToID (keyword) { + if (!this.nameID) { + this.nameID = new Map() + let nameArr = this.getdefSet('role', 'name') + for (let i in nameArr) { + for (let val of nameArr[i]) { + this.nameID.set(val, i) + } + } + } + if (!isNaN(keyword)) keyword = Number(keyword) + let roelId = this.nameID.get(keyword) + return roelId || false + } + + /** + * 原神角色武器长名称缩写 + * @param name 名称 + * @param isWeapon 是否武器 + */ + shortName (name, isWeapon = false) { + let other = {} + if (isWeapon) { + other = this.getdefSet('weapon', 'other') + } else { + other = this.getdefSet('role', 'other') + } + return other.sortName[name] ?? name + } + + /** 公共配置ck文件修改hook */ + async change_myspubCk () { + let MysInfo = await import('./mys/mysInfo.js').default + await new MysInfo().addPubCk() + } + + getGachaSet (groupId = '') { + let config = this.getYaml('gacha', 'set', 'config') + let def = config.default + if (config[groupId]) { + return { ...def, ...config[groupId] } + } + return def + } + + getMsgUid (msg) { + let ret = /[1|2|5][0-9]{8}/g.exec(msg) + if (!ret) return false + return ret[0] + } + + /** + * 获取消息内原神角色名称,uid + * @param msg 判断消息 + * @param filterMsg 过滤消息 + * @return roleId 角色id + * @return name 角色名称 + * @return alias 当前别名 + * @return uid 游戏uid + */ + getRole (msg, filterMsg = '') { + let alias = msg.replace(/#|老婆|老公|[1|2|5][0-9]{8}/g, '').trim() + if (filterMsg) { + alias = alias.replace(new RegExp(filterMsg, 'g'), '').trim() + } + + /** 判断是否命中别名 */ + let roleId = this.roleNameToID(alias) + if (!roleId) return false + /** 获取uid */ + let uid = this.getMsgUid(msg) || '' + + return { + roleId, + uid, + alias, + name: this.roleIdToName(roleId) + } + } +} + +export default new GsCfg() diff --git a/model/mys/mysApi.js b/model/mys/mysApi.js new file mode 100644 index 0000000..b5a8518 --- /dev/null +++ b/model/mys/mysApi.js @@ -0,0 +1,219 @@ +import md5 from 'md5' +import lodash from 'lodash' +import fetch from 'node-fetch' + +export default class MysApi { + /** + * @param uid 游戏uid + * @param cookie 米游社cookie + * @param option 其他参数 + * @param option.log 是否显示日志 + */ + constructor (uid, cookie, option = {}) { + this.uid = uid + this.cookie = cookie + this.server = this.getServer() + + let op = { + log: true, + ...option + } + this.option = op + } + + getUrl (type, data = {}) { + let host, hostRecord + if (['cn_gf01', 'cn_qd01'].includes(this.server)) { + host = 'https://api-takumi.mihoyo.com/' + hostRecord = 'https://api-takumi-record.mihoyo.com/' + } + + let urlMap = { + /** 首页宝箱 */ + index: { + url: `${hostRecord}game_record/app/genshin/api/index`, + query: `role_id=${this.uid}&server=${this.server}` + }, + /** 深渊 */ + spiralAbyss: { + url: `${hostRecord}game_record/app/genshin/api/spiralAbyss`, + query: `role_id=${this.uid}&schedule_type=${data.schedule_type || 1}&server=${this.server}` + }, + /** 角色详情 */ + character: { + url: `${hostRecord}game_record/app/genshin/api/character`, + body: { role_id: this.uid, server: this.server } + }, + /** 树脂 */ + dailyNote: { + url: `${hostRecord}game_record/app/genshin/api/dailyNote`, + query: `role_id=${this.uid}&server=${this.server}` + }, + /** 签到信息 */ + bbs_sign_info: { + url: `${host}event/bbs_sign_reward/info`, + query: `act_id=e202009291139501®ion=${this.server}&uid=${this.uid}`, + sign: true + }, + /** 签到奖励 */ + bbs_sign_home: { + url: `${host}event/bbs_sign_reward/home`, + query: `act_id=e202009291139501®ion=${this.server}&uid=${this.uid}`, + sign: true + }, + /** 签到 */ + bbs_sign: { + url: `${host}event/bbs_sign_reward/sign`, + body: { act_id: 'e202009291139501', region: this.server, uid: this.uid }, + sign: true + }, + /** 详情 */ + detail: { + url: `${host}event/e20200928calculate/v1/sync/avatar/detail`, + query: `uid=${this.uid}®ion=${this.server}&avatar_id=${data.avatar_id}` + }, + /** 札记 */ + ys_ledger: { + url: 'https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo', + query: `month=${data.month}&bind_uid=${this.uid}&bind_region=${this.server}` + }, + /** 养成计算器 */ + compute: { + url: `${host}event/e20200928calculate/v2/compute`, + body: data + }, + /** 角色技能 */ + avatarSkill: { + url: `${host}event/e20200928calculate/v1/avatarSkill/list`, + query: `avatar_id=${data.avatar_id}` + } + } + + if (!urlMap[type]) return false + + let { url, query = '', body = '', sign = '' } = urlMap[type] + + if (query) url += `?${query}` + if (body) body = JSON.stringify(body) + + let headers = this.getHeaders(query, body, sign) + + return { url, headers, body } + } + + getServer () { + let uid = this.uid + switch (String(uid)[0]) { + case '1': + case '2': + return 'cn_gf01' // 官服 + case '5': + return 'cn_qd01' // B服 + } + return 'cn_gf01' + } + + async getData (type, data = {}, isForce = true) { + let { url, headers, body } = this.getUrl(type, data) + + if (!url) return false + + let cahce = await redis.get(`Yz:genshin:mys:cache:${type}:${this.uid}`) + if (cahce && !isForce) return JSON.parse(cahce) + + headers.Cookie = this.cookie + let param = { + headers, + timeout: 10000 + } + + if (body) { + param.method = 'post' + param.body = body + } else { + param.method = 'get' + } + let response = {} + let start = Date.now() + try { + response = await fetch(url, param) + } catch (error) { + logger.error(error) + return false + } + + if (!response.ok) { + logger.error(response) + return false + } + if (this.option.log) { + logger.mark(`[米游社接口][${type}][${this.uid}] ${Date.now() - start}ms`) + } + const res = await response.json() + + if (!res) { + logger.mark('mys接口没有返回') + return false + } + + if (res.retcode !== 0) { + logger.debug(`[米游社接口][请求参数] ${url} ${JSON.stringify(param)}`) + } + + res.api = type + + this.cache(res, type) + + return res + } + + getHeaders (query = '', body = '', sign = false) { + if (sign) { + return { + 'x-rpc-app_version': '2.3.0', + 'x-rpc-client_type': 5, + 'x-rpc-device_id': this.getGuid(), + 'User-Agent': ' miHoYoBBS/2.3.0', + DS: this.getDsSign() + } + } + return { + 'x-rpc-app_version': '2.31.1', + 'x-rpc-client_type': 5, + DS: this.getDs(query, body) + } + } + + getDs (q = '', b = '') { + let n = '' + if (['cn_gf01', 'cn_qd01'].includes(this.server)) { + n = 'xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs' + } + let t = Math.round(new Date().getTime() / 1000) + let r = Math.floor(Math.random() * 900000 + 100000) + let DS = md5(`salt=${n}&t=${t}&r=${r}&b=${b}&q=${q}`) + return `${t},${r},${DS}` + } + + /** 签到ds */ + getDsSign () { + const n = 'h8w582wxwgqvahcdkpvdhbh2w9casgfl' + const t = Math.round(new Date().getTime() / 1000) + const r = lodash.sampleSize('abcdefghijklmnopqrstuvwxyz0123456789', 6).join('') + const DS = md5(`salt=${n}&t=${t}&r=${r}`) + return `${t},${r},${DS}` + } + + getGuid () { + function S4 () { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1) + } + + return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4()) + } + + async cache (res, type) { + if (!res || res.retcode !== 0) return + redis.setEx(`Yz:genshin:mys:cache:${type}:${this.uid}`, 300, JSON.stringify(res)) + } +} diff --git a/model/mys/mysInfo.js b/model/mys/mysInfo.js new file mode 100644 index 0000000..cd8fd76 --- /dev/null +++ b/model/mys/mysInfo.js @@ -0,0 +1,650 @@ +import MysApi from './mysApi.js' +import GsCfg from '../gsCfg.js' +import lodash from 'lodash' +import moment from 'moment' + +/** 公共ck */ +let pubCk = {} +/** 绑定ck */ +let bingCkUid = {} +let bingCkQQ = {} +let bingCkLtuid = {} + +export default class MysInfo { + /** redis key */ + static keyPre = 'Yz:genshin:mys:' + static key = { + /** ck使用次数统计 */ + count: `${MysInfo.keyPre}ck:count`, + /** ck使用详情 */ + detail: `${MysInfo.keyPre}ck:detail`, + /** 单个ck使用次数 */ + ckNum: `${MysInfo.keyPre}ckNum:`, + /** 已失效的ck使用详情 */ + delDetail: `${MysInfo.keyPre}ck:delDetail`, + /** qq-uid */ + qqUid: `${MysInfo.keyPre}qq-uid:` + } + + static tips = '请先#绑定cookie\n发送【体力帮助】查看配置教程' + + constructor (e) { + if (e) { + this.e = e + this.userId = String(e.user_id) + } + /** 当前查询原神uid */ + this.uid = '' + /** 当前ck信息 */ + this.ckInfo = { + ck: '', + uid: '', + qq: '', + ltuid: '', + type: '' + } + + this.auth = ['dailyNote', 'bbs_sign_info', 'bbs_sign_home', 'bbs_sign'] + } + + static async init (e, api) { + let mysInfo = new MysInfo(e) + + /** 检查时间 */ + if (!mysInfo.checkTime()) return false + + /** 初始化绑定ck */ + await mysInfo.initBingCk() + + /** 初始化公共ck */ + await mysInfo.initPubCk() + + if (mysInfo.checkAuth(api)) { + /** 获取ck绑定uid */ + mysInfo.uid = (await MysInfo.getSelfUid(e)).uid + } else { + /** 获取uid */ + mysInfo.uid = await MysInfo.getUid(e) + } + + if (!mysInfo.uid) return false + + mysInfo.e.uid = mysInfo.uid + + /** 获取ck */ + await mysInfo.getCookie() + + /** 判断回复 */ + await mysInfo.checkReply() + + return mysInfo + } + + /** 获取uid */ + static async getUid (e) { + if (e.uid) return e.uid + + let { msg = '', at = '' } = e + + if (!msg) return false + + let uid = false + /** at用户 */ + if (at) { + uid = await redis.get(`${MysInfo.key.qqUid}${at}`) + if (uid) return String(uid) + e.reply('尚未绑定uid', false, { at }) + return false + } + + let matchUid = (msg = '') => { + let ret = /[1|2|5][0-9]{8}/g.exec(msg) + if (!ret) return false + return ret[0] + } + + /** 命令消息携带 */ + uid = matchUid(msg) + if (uid) return String(uid) + + /** 绑定的uid */ + uid = await redis.get(`${MysInfo.key.qqUid}${e.user_id}`) + if (uid) return String(uid) + + /** 群名片 */ + uid = matchUid(e.sender.card) + if (uid) return String(uid) + + e.reply('请先#绑定uid', false, { at }) + + return false + } + + /** 获取ck绑定uid */ + static async getSelfUid (e) { + if (e.uid) return e.uid + + let { msg = '', at = '' } = e + + if (!msg) return false + + /** at用户 */ + if (at && (!bingCkQQ[at] || !bingCkQQ[at].uid)) { + e.reply('尚未绑定cookie', false, { at }) + return false + } + + if (!e.user_id || !bingCkQQ[e.user_id] || !bingCkQQ[e.user_id].uid) { + e.reply(MysInfo.tips, false, { at }) + return false + } + + return bingCkQQ[e.user_id] + } + + /** 判断绑定ck才能查询 */ + checkAuth (api) { + if (lodash.isObject(api)) { + for (let i in api) { + if (this.auth.includes(i)) { + return true + } + } + } else if (this.auth.includes(api)) { + return true + } + return false + } + + /** + * @param api + * * `index` 米游社原神首页宝箱等数据 + * * `spiralAbyss` 原神深渊 + * * `character` 原神角色详情 + * * `dailyNote` 原神树脂 + * * `bbs_sign` 米游社原神签到 + * * `detail` 详情 + * * `ys_ledger` 札记 + * * `compute` 养成计算器 + * * `avatarSkill` 角色技能 + */ + static async get (e, api, data = {}) { + let mysInfo = await MysInfo.init(e, api) + + if (!mysInfo.uid || !mysInfo.ckInfo.ck) return false + e.uid = mysInfo.uid + + let mysApi = new MysApi(mysInfo.uid, mysInfo.ckInfo.ck) + + let res + if (lodash.isObject(api)) { + let all = [] + lodash.forEach(api, (v, i) => { + all.push(mysApi.getData(i, v)) + }) + res = await Promise.all(all) + + for (let i in res) { + res[i] = await mysInfo.checkCode(res[i], res[i].api) + if (res[i].retcode === 0) continue + break + } + } else { + res = await mysApi.getData(api, data) + if (!res) return false + + res = await mysInfo.checkCode(res, api) + } + + return res + } + + async checkReply () { + if (!this.uid) { + this.e.reply('请先#绑定uid') + } + + if (!this.ckInfo.ck) { + if (lodash.isEmpty(pubCk)) { + this.e.reply('请先配置公共查询ck') + } else { + this.e.reply('公共ck查询次数已用完,暂无法查询新uid') + } + } + } + + async getCookie () { + if (this.ckInfo.ck) return this.ckInfo.ck + // 使用用户uid绑定的ck + await this.getBingCK() || + // 使用uid已查询的ck + await this.getCheckCK() || + // 使用用户绑定的ck + await this.getBingCKqq() || + // 使用公共ck + await this.getPublicCK() + + return this.ckInfo.ck + } + + async getBingCK () { + if (!bingCkUid[this.uid]) return false + + this.isSelf = true + + let ck = bingCkUid[this.uid] + + this.ckInfo = ck + this.ckInfo.type = 'self' + + logger.mark(`[米游社查询][uid:${this.uid}]${logger.green(`[使用已绑定ck:${ck.ltuid}]`)}`) + + return ck.ck + } + + async getCheckCK () { + let ltuid = await redis.zScore(MysInfo.key.detail, this.uid) + + if (!ltuid) return false + + this.ckInfo.ltuid = ltuid + this.ckInfo.type = 'public' + + /** 使用用户绑定ck */ + if (bingCkLtuid[ltuid]) { + logger.mark(`[米游社查询][uid:${this.uid}]${logger.blue(`[已查询][使用用户ck:${ltuid}]`)}`) + + this.ckInfo = bingCkLtuid[ltuid] + this.ckInfo.type = 'self' + + return this.ckInfo.ck + } + + /** 公共ck */ + if (pubCk[ltuid]) { + logger.mark(`[米游社查询][uid:${this.uid}]${logger.cyan(`[已查询][使用公共ck:${ltuid}]`)}`) + + this.ckInfo.ck = pubCk[ltuid] + return this.ckInfo.ck + } + + return false + } + + /** 使用用户绑定的ck */ + async getBingCKqq () { + /** 用户没有绑定ck */ + if (!bingCkQQ[this.userId]) return false + + let ck = bingCkQQ[this.userId] + + /** 判断用户ck使用次数 */ + let num = await redis.get(`${MysInfo.key.ckNum}${ck.ltuid}`) + if (num && num >= 27) { + logger.mark(`[米游社查询][uid:${this.uid}] 绑定用户ck次数已用完`) + return + } + + if (!num) num = 0 + + this.ckInfo = ck + this.ckInfo.type = 'bing' + + /** 插入查询详情 */ + await redis.zAdd(MysInfo.key.detail, { score: ck.ltuid, value: this.uid }) + /** 获取ck查询详情 */ + let count = await redis.zRangeByScore(MysInfo.key.detail, ck.ltuid, ck.ltuid) + + /** 用户ck也配置公共ck */ + if (pubCk[ck.ltuid]) { + /** 统计ck查询次数 */ + redis.zAdd(MysInfo.key.count, { score: count.length || 1, value: String(ck.ltuid) }) + } + this.expire(MysInfo.key.detail) + + /** 插入单个查询次数 */ + redis.setEx(`${MysInfo.key.ckNum}${ck.ltuid}`, this.getEnd(), String(count.length)) + + logger.mark(`[米游社查询][uid:${this.uid}]${logger.blue(`[使用用户ck:${ck.ltuid}]`)}[次数:${++num}次]`) + + return ck.ck + } + + async getPublicCK () { + if (lodash.isEmpty(pubCk)) { + logger.mark('请先配置公共查询ck') + return false + } + + /** 获取使用次数最少的ck */ + let list = await redis.zRangeByScore(MysInfo.key.count, 0, 27, true) + + if (lodash.isEmpty(list)) { + logger.mark('公共查询ck已用完') + return false + } + + let ltuid = list[0] + + if (!pubCk[ltuid]) { + logger.mark(`公共查询ck错误[ltuid:${ltuid}]`) + await redis.zAdd(MysInfo.key.count, { score: 99, value: ltuid }) + return false + } + + this.ckInfo.ck = pubCk[ltuid] + this.ckInfo.ltuid = ltuid + this.ckInfo.type = 'public' + + /** 非原子操作,可能存在误差 */ + + /** 插入查询详情 */ + await redis.zAdd(MysInfo.key.detail, { score: ltuid, value: this.uid }) + /** 获取ck查询详情 */ + let count = await redis.zRangeByScore(MysInfo.key.detail, ltuid, ltuid) + /** 统计ck查询次数 */ + redis.zAdd(MysInfo.key.count, { score: count.length, value: ltuid }) + /** 插入单个查询次数 */ + redis.setEx(`${MysInfo.key.ckNum}${ltuid}`, this.getEnd(), String(count.length)) + + this.expire(MysInfo.key.detail) + + logger.mark(`[米游社查询][uid:${this.uid}]${logger.yellow(`[使用公共ck:${ltuid}][次数:${count.length}]`)}`) + + return pubCk[ltuid] + } + + /** 初始化公共查询ck */ + async initPubCk () { + /** 没配置每次都会初始化 */ + if (!lodash.isEmpty(pubCk)) return + + let ckList = await redis.zRangeByScore(MysInfo.key.count, 0, 100) + + await this.addPubCk(ckList) + + /** 使用用户ck当公共查询 */ + let set = GsCfg.getConfig('mys', 'set') + let userNum = 0 + if (set.allowUseCookie == 1) { + lodash.forEach(bingCkUid, async v => { + if (pubCk[v.ltuid]) return + pubCk[v.ltuid] = v.ck + + userNum++ + /** 加入redis统计 */ + if (!ckList.includes(v.ltuid)) { + await redis.zAdd(MysInfo.key.count, { score: 0, value: String(v.ltuid) }) + } + }) + } + + this.expire(MysInfo.key.count) + + if (userNum > 0) logger.mark(`加载用户ck:${userNum}个`) + } + + /** 加入公共ck池 */ + async addPubCk (ckList = '') { + let ckArr = GsCfg.getConfig('mys', 'pubCk') + + if (!ckList) { + ckList = await redis.zRangeByScore(MysInfo.key.count, 0, 100) + } + + let pubNum = 0 + for (let v of ckArr) { + let [ltuid = ''] = v.match(/ltuid=(\w{0,9})/g) + if (!ltuid) return + + ltuid = String(lodash.trim(ltuid, 'ltuid=')) + + if (isNaN(ltuid)) return + + pubCk[ltuid] = v + + pubNum++ + + /** 加入redis统计 */ + if (!ckList.includes(ltuid)) { + await redis.zAdd(MysInfo.key.count, { score: 0, value: ltuid }) + } + } + if (pubNum > 0) logger.mark(`加载公共ck:${pubNum}个`) + } + + async initBingCk () { + if (!lodash.isEmpty(bingCkUid)) return + + let res = await GsCfg.getBingCk() + bingCkUid = res.ck + bingCkQQ = res.ckQQ + bingCkLtuid = lodash.keyBy(bingCkUid, 'ltuid') + } + + async checkCode (res, type) { + res.retcode = Number(res.retcode) + if (type == 'bbs_sign') { + if ([-5003].includes(res.retcode)) { + res.retcode = 0 + } + } + switch (res.retcode) { + case 0:break + case -1: + case -100: + case 1001: + case 10001: + case 10103: + if (/(登录|login)/i.test(res.message)) { + if (this.ckInfo.uid) { + this.e.reply(`UID:${this.ckInfo.uid},米游社cookie已失效,请重新绑定cookie`) + } else { + this.e.reply(`ltuid:${this.ckInfo.ltuid},米游社cookie已失效`) + } + await this.delCk() + } else { + this.e.reply(`米游社接口报错,暂时无法查询:${res.message}`) + } + break + case 1008: + this.e.reply('\n请先去米游社绑定角色', false, { at: this.userId }) + break + case 10101: + this.disableToday() + this.e.reply('查询已达今日上限') + break + case 10102: + if (res.message == 'Data is not public for the user') { + this.e.reply(`\nUID:${this.ckInfo.uid},米游社数据未公开`, false, { at: this.userId }) + } else { + this.e.reply(`uid:${this.uid},请先去米游社绑定角色`) + } + break + // 伙伴不存在~ + case -1002: + if (res.api == 'detail') res.retcode = 0 + break + default: + this.e.reply(`米游社接口报错,暂时无法查询:${res.message || 'error'}`) + break + } + + if (res.retcode !== 0) { + logger.mark(`mys接口报错:${JSON.stringify(res)},uid:${this.uid}`) + } + + return res + } + + /** 删除失效ck */ + async delCk () { + let ltuid = this.ckInfo.ltuid + + /** 记录公共ck失效 */ + if (this.ckInfo.type == 'public') { + if (bingCkLtuid[ltuid]) { + this.ckInfo = bingCkLtuid[ltuid] + this.ckInfo.type = 'self' + } else { + logger.mark(`删除失效ck[ltuid:${ltuid}]`) + } + } + + if (this.ckInfo.type == 'self' || this.ckInfo.type == 'bing') { + /** 获取用户绑定ck */ + let ck = GsCfg.getBingCkSingle(this.userId) + let tmp = ck[this.ckInfo.uid] + if (tmp) { + ltuid = tmp.ltuid + + logger.mark(`删除失效绑定ck[qq:${this.userId}]`) + /** 删除文件保存ck */ + delete ck[this.ckInfo.uid] + GsCfg.saveBingCk(this.userId, ck) + + this.redisDel(ltuid) + + delete pubCk[ltuid] + delete bingCkUid[tmp.uid] + delete bingCkQQ[tmp.qq] + } + } + + delete pubCk[ltuid] + + await this.redisDel(ltuid) + } + + async redisDel (ltuid) { + /** 统计次数设为超限 */ + await redis.zRem(MysInfo.key.count, String(ltuid)) + // await redis.setEx(`${MysInfo.key.ckNum}${ltuid}`, this.getEnd(), '99') + + /** 将当前查询记录移入回收站 */ + await this.detailDel(ltuid) + } + + /** 将当前查询记录移入回收站 */ + async detailDel (ltuid) { + let detail = await redis.zRangeByScore(MysInfo.key.detail, ltuid, ltuid) + if (!lodash.isEmpty(detail)) { + let delDetail = [] + detail.forEach((v) => { + delDetail.push({ score: ltuid, value: String(v) }) + }) + await redis.zAdd(MysInfo.key.delDetail, delDetail) + this.expire(MysInfo.key.delDetail) + } + /** 删除当前ck查询记录 */ + await redis.zRemRangeByScore(MysInfo.key.detail, ltuid, ltuid) + } + + async disableToday () { + /** 统计次数设为超限 */ + await redis.zAdd(MysInfo.key.count, { score: 99, value: String(this.ckInfo.ltuid) }) + await redis.setEx(`${MysInfo.key.ckNum}${this.ckInfo.ltuid}`, this.getEnd(), '99') + } + + async expire (key) { + return await redis.expire(key, this.getEnd()) + } + + getEnd () { + let end = moment().endOf('day').format('X') + return end - moment().format('X') + } + + /** 处理用户绑定ck */ + async addBingCk (ck) { + /** 加入缓存 */ + bingCkUid[ck.uid] = ck + bingCkQQ[ck.qq] = ck + bingCkLtuid[ck.ltuid] = ck + + let set = GsCfg.getConfig('mys', 'set') + + /** qq-uid */ + await redis.setEx(`${MysInfo.key.qqUid}${ck.qq}`, 3600 * 24 * 30, String(ck.uid)) + + /** 恢复回收站查询记录,会覆盖原来记录 */ + let detail = await redis.zRangeByScore(MysInfo.key.delDetail, ck.ltuid, ck.ltuid) + if (!lodash.isEmpty(detail)) { + let delDetail = [] + detail.forEach((v) => { + delDetail.push({ score: ck.ltuid, value: String(v) }) + }) + await redis.zAdd(MysInfo.key.detail, delDetail) + this.expire(MysInfo.key.detail) + } + /** 删除回收站记录 */ + await redis.zRemRangeByScore(MysInfo.key.delDetail, ck.ltuid, ck.ltuid) + + /** 获取ck查询详情 */ + let count = await redis.zRangeByScore(MysInfo.key.detail, ck.ltuid, ck.ltuid) + + /** 开启了用户ck查询 */ + if (set.allowUseCookie == 1) { + pubCk[ck.ltuid] = ck + let ckList = await redis.zRangeByScore(MysInfo.key.count, 0, 100) + if (!ckList.includes(ck.ltuid)) { + await redis.zAdd(MysInfo.key.count, { score: count.length, value: String(ck.ltuid) }) + } + } + } + + async delBingCk (ck) { + delete bingCkUid[ck.uid] + delete bingCkQQ[ck.qq] + delete bingCkLtuid[ck.ltuid] + + this.detailDel(ck.ltuid) + } + + async resetCk () { + return await redis.del(MysInfo.key.count) + } + + static async initCk () { + if (lodash.isEmpty(bingCkUid)) { + let mysInfo = new MysInfo() + await mysInfo.initBingCk() + } + } + + static async getBingCkUid () { + await MysInfo.initCk() + + return bingCkUid + } + + /** 切换uid */ + static toggleUid (qq, ck) { + bingCkQQ[qq] = ck + } + + static async checkUidBing (uid) { + await MysInfo.initCk() + + if (bingCkUid[uid]) return true + + return false + } + + /** 数据更新中,请稍后再试 */ + checkTime () { + let hour = moment().hour() + let min = moment().minute() + let second = moment().second() + + if (hour == 23 && min == 59 && second >= 58) { + this.e.reply('数据更新中,请稍后再试') + return false + } + if (hour == 0 && min == 0 && second <= 3) { + this.e.reply('数据更新中,请稍后再试') + return false + } + return true + } +} diff --git a/resources/Atlas_alias/wuqi_tujian.json b/resources/Atlas_alias/wuqi_tujian.json new file mode 100644 index 0000000..3095721 --- /dev/null +++ b/resources/Atlas_alias/wuqi_tujian.json @@ -0,0 +1,88 @@ +{ + "磐岩结绿": ["绿箭", "绿剑"], + "斫峰之刃": ["斫峰", "盾剑"], + "无工之剑": ["蜈蚣", "蜈蚣大剑", "无工大剑", "盾大剑", "无工"], + "贯虹之槊": ["贯虹", "岩枪", "盾枪"], + "赤角石溃杵": ["赤角", "石溃杵"], + "尘世之锁": ["尘世锁", "尘世", "盾书", "锁"], + + "终末嗟叹之诗": ["终末", "终末弓", "叹气弓", "乐团弓"], + "松籁响起之时": ["松籁", "乐团大剑", "松剑"], + "苍古自由之誓": ["苍古", "乐团剑"], + + "渔获": ["鱼叉"], + "衔珠海皇": ["海皇", "咸鱼剑", "咸鱼大剑"], + + "匣里日月": ["日月"], + "匣里灭辰": ["灭辰"], + "匣里龙吟": ["龙吟"], + + "天空之翼": ["天空弓"], + "天空之刃": ["天空剑"], + "天空之卷": ["天空书", "厕纸"], + "天空之脊": ["天空枪", "薄荷枪"], + "天空之傲": ["天空大剑"], + "四风原典": ["四风"], + + "试作斩岩": ["斩岩"], + "试作星镰": ["星镰"], + "试作金珀": ["金珀"], + "试作古华": ["古华"], + "试作澹月": ["澹月"], + + "千岩长枪": ["千岩枪"], + "千岩古剑": ["千岩剑", "千岩大剑"], + + "暗巷闪光": ["暗巷剑"], + "暗巷猎手": ["暗巷弓"], + + "阿莫斯之弓": ["阿莫斯", "ams", "痛苦弓"], + "雾切之回光": ["雾切"], + "飞雷之弦振": ["飞雷", "飞雷弓"], + "薙草之稻光": ["薙草", "稻光", "薙草稻光", "马尾枪", "马尾", "薙刀"], + "神乐之真意": ["神乐", "真意"], + "狼的末路": ["狼末"], + "护摩之杖": ["护摩", "护摩枪","护膜"], + "和璞鸢": ["鸟枪", "绿枪"], + "风鹰剑": ["风鹰"], + "冬极白星": ["冬极"], + "不灭月华": ["月华"], + "波乱月白经津": ["波乱", "月白", "波乱月白", "经津", "波波津"], + "若水": ["麒麟弓","Aqua","aqua"], + "笼钓瓶一心":["妖刀", "红刀", "笼钓瓶", "一心传名刀"], + "昭心": ["糟心"], + "幽夜华尔兹": ["幽夜", "幽夜弓", "华尔兹", "皇女弓"], + "雪葬的星银": ["雪葬", "星银", "雪葬星银", "雪山大剑"], + "喜多院十文字": ["喜多院", "十文字"], + "万国诸海图谱": ["万国", "万国诸海"], + "天目影打刀": ["天目刀", "天目"], + "破魔之弓": ["破魔弓"], + "曚云之月": ["曚云弓"], + "流月针": ["针"], + "流浪乐章": ["赌狗书", "赌狗乐章", "赌狗"], + "桂木斩长正": ["桂木", "斩长正"], + "腐殖之剑": ["腐殖", "腐殖剑"], + + "风花之颂": ["风花弓"], + "证誓之明瞳": ["证誓", "明瞳", "证誓明瞳"], + "嘟嘟可故事集": ["嘟嘟可"], + "辰砂之纺锤": ["辰砂", "辰砂纺锤", "纺锤"], + "白辰之环": ["白辰", "白辰环"], + + "决斗之枪": ["决斗枪", "决斗", "月卡枪"], + "螭骨剑": ["螭骨", "丈育剑", "离骨剑", "月卡大剑"], + "黑剑": ["月卡剑"], + "苍翠猎弓": ["绿弓", "月卡弓"], + + "讨龙英杰谭": ["讨龙"], + "神射手之誓": ["脚气弓", "神射手"], + "黑缨枪": ["史莱姆枪"], + + "贯月矢":["贯月矢","月矢"], + "竭泽":["竭泽"], + "猎人之径":["猎人之径"], + "森林王器":["森林王器","王器"], + "王下近侍":["王下近侍","近侍"], + "盈满之实":["盈满之实","盈满"], + "原木刀":["原木刀","木刀"] +} \ No newline at end of file