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