#更新面板 支持切换更新API

This commit is contained in:
yoimiya-kokomi 2022-07-28 02:36:49 +08:00
parent 996ed5692c
commit b456adbe6d
12 changed files with 485 additions and 439 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@
/resources/character-img/*/upload/
/resources/help/help-list.js
/resources/help/help-cfg.js
/config/character.js
/config/profile.js

View File

@ -1,3 +1,9 @@
# 1.9.1
* `#更新面板`支持配置更新API
* 若面板更新失败可尝试在**config/profile.js**文件中配置切换更新API
* 修正部分V3Yunzai下的适配问题
# 1.9.0
* 初步适配Yunzai V3

View File

@ -5,6 +5,7 @@ import lodash from 'lodash'
import { segment } from 'oicq'
import Profile from '../../components/Profile.js'
import { Character } from '../../components/models.js'
import { isV3 } from '../../components/Changelog.js'
/*
* 获取面板查询的 目标uid
@ -34,6 +35,7 @@ export async function getTargetUid (e) {
return uid
}
}
if (!isV3) {
let botQQ = global.BotConfig ? global.BotConfig.account.qq : false
if (e.at && e.at !== botQQ) {
uid = await getUid(e.at)
@ -46,6 +48,7 @@ export async function getTargetUid (e) {
if (uid) {
return uid
}
}
try {
let MysApi = await e.getMysApi({

View File

@ -1,19 +1,19 @@
let Format = {
int: function (d) {
return parseInt(d);
return parseInt(d)
},
comma: function (num, fix = 0) {
num = parseFloat((num * 1).toFixed(fix));
let [integer, decimal] = String.prototype.split.call(num, '.');
integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,'); // 正则先行断言
return `${integer}${decimal ? '.' + decimal : ''}`;
num = parseFloat((num * 1).toFixed(fix))
let [integer, decimal] = String.prototype.split.call(num, '.')
integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,') // 正则先行断言
return `${integer}${decimal ? '.' + decimal : ''}`
},
pct: function (num, fix = 1) {
return (num * 1).toFixed(fix) + "%";
return (num * 1).toFixed(fix) + '%'
},
percent: function (num, fix = 1) {
return Format.pct(num * 100, fix);
return Format.pct(num * 100, fix)
}
}
export default Format;
export default Format

View File

@ -1,215 +1,207 @@
import fs from "fs";
import lodash from "lodash";
import Format from "./Format.js";
import Character from "./models/Character.js";
import Reliquaries from "./models/Reliquaries.js";
import Miao from "./profile-data/miao.js";
import Enka from "./profile-data/enka.js";
import fs from 'fs'
import lodash from 'lodash'
import Format from './Format.js'
import Character from './models/Character.js'
import Reliquaries from './models/Reliquaries.js'
import Miao from './profile-data/miao.js'
import Enka from './profile-data/enka.js'
import Data from './Data.js'
const _path = process.cwd();
const cfgPath = `${_path}/plugins/miao-plugin/config.js`;
let config = {};
const _path = process.cwd()
if (fs.existsSync(cfgPath)) {
let fileData = await import (`file://${cfgPath}`);
if (fileData && fileData.config) {
config = fileData.config;
}
}
let sysCfg = await Data.importModule('plugins/miao-plugin/config/system', 'profile.js')
let diyCfg = await Data.importModule('plugins/miao-plugin/config/', 'profile.js')
const userPath = `${_path}/data/UserData/`;
const userPath = `${_path}/data/UserData/`
if (!fs.existsSync(userPath)) {
fs.mkdirSync(userPath);
fs.mkdirSync(userPath)
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
function getServ(uid) {
if (config.profileApi) {
return config.profileApi({ Enka, Miao })
}
if ((uid + '')[0] === '5') {
return Miao;
}
return Enka;
function getServ (uid) {
return (diyCfg.profileApi || sysCfg.profileApi)({ uid, Miao, Enka })
}
let Profile = {
async request(uid, e) {
async request (uid, e) {
if (uid.toString().length !== 9) {
return false;
return false
}
let Serv = getServ(uid);
let Serv = getServ(uid)
let inCd = await redis.get(`miao:role-all:${uid}`);
let inCd = await redis.get(`miao:role-all:${uid}`)
if (inCd === 'loading') {
e.reply("请求过快,请稍后重试..");
return false;
e.reply('请求过快,请稍后重试..')
return false
} else if (inCd === 'pending' && false) {
e.reply(`距上次请求刷新成功间隔小于${Serv.cd}分钟,请稍后重试..`);
return false;
e.reply(`距上次请求刷新成功间隔小于${Serv.cd}分钟,请稍后重试..`)
return false
}
await redis.set(`miao:role-all:${uid}`, 'loading', { EX: 20 });
e.reply("开始获取数据,可能会需要一定时间~");
await sleep(1000);
let data;
await redis.set(`miao:role-all:${uid}`, 'loading', { EX: 20 })
e.reply('开始获取数据,可能会需要一定时间~')
await sleep(1000)
let data
try {
data = await Serv.request({ uid, e, config });
data = await Serv.request({ uid, e, sysCfg, diyCfg })
// enka服务测冷却时间5分钟
await redis.set(`miao:role-all:${uid}`, 'pending', { EX: Serv.cd * 60 });
return Profile.save(uid, data, Serv.key);
await redis.set(`miao:role-all:${uid}`, 'pending', { EX: Serv.cd * 60 })
return Profile.save(uid, data, Serv.key)
} catch (err) {
console.log(err);
e.reply(`请求失败`);
return false;
console.log(err)
e.reply('请求失败')
return false
}
},
save(uid, data, dataSource = 'enka') {
let userData = {};
const userFile = `${userPath}/${uid}.json`;
save (uid, data, dataSource = 'enka') {
let userData = {}
const userFile = `${userPath}/${uid}.json`
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {};
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
lodash.assignIn(userData, lodash.pick(data, "uid,name,lv,avatar".split(",")));
userData.chars = userData.chars || {};
lodash.assignIn(userData, lodash.pick(data, 'uid,name,lv,avatar'.split(',')))
userData.chars = userData.chars || {}
lodash.forEach(data.chars, (char, charId) => {
let original = userData.chars[charId] || {};
if (char.dataSource === "miao-pre" && original && original.dataSource) {
original.dataSource = char.dataSource;
let original = userData.chars[charId] || {}
if (char.dataSource === 'miao-pre' && original && original.dataSource) {
original.dataSource = char.dataSource
} else {
userData.chars[charId] = char;
userData.chars[charId] = char
}
});
fs.writeFileSync(userFile, JSON.stringify(userData), "", " ");
return data;
})
fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ')
return data
},
saveCharData(uid, ds) {
saveCharData (uid, ds) {
if (!uid || !ds.id) {
return;
return
}
let userData = {};
const userFile = `${userPath}/${uid}.json`;
let userData = {}
const userFile = `${userPath}/${uid}.json`
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {};
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
userData.chars = userData.chars || {};
userData.chars[ds.id] = ds;
fs.writeFileSync(userFile, JSON.stringify(userData), "", " ");
return ds;
userData.chars = userData.chars || {}
userData.chars[ds.id] = ds
fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ')
return ds
},
_get(uid, charId) {
const userFile = `${userPath}/${uid}.json`;
let userData = {};
_get (uid, charId) {
const userFile = `${userPath}/${uid}.json`
let userData = {}
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {};
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
if (userData && userData.chars && userData.chars[charId]) {
return userData.chars[charId];
return userData.chars[charId]
}
return false;
return false
},
async get(uid, charId, onlyAvailable = false) {
async get (uid, charId, onlyAvailable = false) {
if (onlyAvailable) {
let data = await Profile.get(uid, charId);
if (data && data.dataSource && data.dataSource !== "input") {
return data;
let data = await Profile.get(uid, charId)
if (data && data.dataSource && data.dataSource !== 'input') {
return data
}
return false;
return false
}
let data = Profile._get(uid, charId);
let Serv = getServ(uid);
let data = Profile._get(uid, charId)
let Serv = getServ(uid)
if (Serv.getCharData && data && data.id) {
return await Serv.getCharData(uid, data, Profile.saveCharData, { config });
return await Serv.getCharData(uid, data, Profile.saveCharData, { sysCfg, diyCfg })
}
return data;
return data
},
getAll(uid) {
const userFile = `${userPath}/${uid}.json`;
let userData = {};
getAll (uid) {
const userFile = `${userPath}/${uid}.json`
let userData = {}
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {};
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
if (userData && userData.chars) {
return userData.chars;
return userData.chars
}
return false;
return false
},
formatArti(ds, markCfg = false, isMain = false) {
formatArti (ds, markCfg = false, isMain = false) {
if (lodash.isArray(ds[0])) {
let ret = [];
let ret = []
lodash.forEach(ds, (d) => {
ret.push(Profile.formatArti(d, markCfg, isMain));
ret.push(Profile.formatArti(d, markCfg, isMain))
})
return ret;
return ret
}
let title = ds[0], key = "", val = ds[1], num = ds[1];
if (!title || title === "undefined") {
return [];
let title = ds[0]
let key = ''
let val = ds[1]
let num = ds[1]
if (!title || title === 'undefined') {
return []
}
if (/伤害加成/.test(title) && val < 1) {
val = Format.pct(val * 100);
num = num * 100;
val = Format.pct(val * 100)
num = num * 100
} else if (/伤害加成|大|暴|充能|治疗/.test(title)) {
val = Format.pct(val);
val = Format.pct(val)
} else {
val = Format.comma(val, 1);
val = Format.comma(val, 1)
}
if (/元素伤害加成/.test(title)) {
title = title.replace("元素伤害", "伤");
key = "dmg";
} else if (title === "物理伤害加成") {
title = "物伤加成";
key = "phy";
title = title.replace('元素伤害', '伤')
key = 'dmg'
} else if (title === '物理伤害加成') {
title = '物伤加成'
key = 'phy'
}
key = key || keyMap[title];
key = key || keyMap[title]
let mark = 0;
let mark = 0
if (markCfg) {
mark = Format.comma(markCfg[title] * num || 0);
mark = Format.comma(markCfg[title] * num || 0)
if (isMain) {
mark = mark / 4;
mark = mark / 4
}
}
return { title, val, mark };
return { title, val, mark }
},
getArtiMark(data, ds) {
getArtiMark (data, ds) {
Reliquaries.getMark(data)
let total = 0;
let total = 0
lodash.forEach(data, (ret) => {
if (ret[0] && ret[1]) {
total += mark[ret[0]] * ret[1];
total += mark[ret[0]] * ret[1]
}
})
if (ds && /暴/.test(ds[0])) {
total += 20;
total += 20
}
return total;
return total
},
inputProfile(uid, e) {
let { avatar, inputData } = e;
let char = Character.get(avatar);
let originalData = Profile._get(uid, char.id);
inputProfile (uid, e) {
let { avatar, inputData } = e
let char = Character.get(avatar)
let originalData = Profile._get(uid, char.id)
if (!originalData || !['enka', 'input2'].includes(originalData.dataSource)) {
return `请先获取${char.name}的面板数据后,再进行面板数据更新`;
return `请先获取${char.name}的面板数据后,再进行面板数据更新`
}
inputData = inputData.replace("#", "");
inputData = inputData.replace(/||、|\n|\t/g, ",");
let attr = originalData.attr || {};
inputData = inputData.replace('#', '')
inputData = inputData.replace(/||、|\n|\t/g, ',')
let attr = originalData.attr || {}
let attrMap = {
hp: /生命/,
def: /防御/,
@ -222,71 +214,71 @@ let Profile = {
dmgBonus: /[火|水|雷|草|风|岩|冰|素|^]伤/,
phyBonus: /(物理|物伤)/
}
lodash.forEach(inputData.split(","), (ds, idx) => {
ds = ds.trim();
lodash.forEach(inputData.split(','), (ds, idx) => {
ds = ds.trim()
if (!ds) {
return;
return
}
let dRet = /(.*?)([0-9\.\+\s]+)/.exec(ds);
let dRet = /(.*?)([0-9\.\+\s]+)/.exec(ds)
if (!dRet || !dRet[1] || !dRet[2]) {
return;
return
}
let name = dRet[1].trim(),
data = dRet[2].trim();
name = name.replace("爆", "暴");
let range = (src, min = 0, max = 1200) => Math.max(min, Math.min(max, src * 1 || 0));
let name = dRet[1].trim()
let data = dRet[2].trim()
name = name.replace('爆', '暴')
let range = (src, min = 0, max = 1200) => Math.max(min, Math.min(max, src * 1 || 0))
lodash.forEach(attrMap, (reg, key) => {
if (reg.test(name)) {
let tmp = data.split("+");
let tmp = data.split('+')
switch (key) {
case "hp":
attr[key + "Base"] = range(tmp[0].trim(), 0, 16000);
attr[key] = range(tmp[0].trim() * 1 + tmp[1].trim() * 1, attr[key + "Base"], 50000);
break;
case "def":
case "atk":
attr[key + "Base"] = range(tmp[0].trim(), 0, 1100);
attr[key] = range(tmp[0].trim() * 1 + tmp[1].trim() * 1, attr[key + "Base"], 4500);
break;
case "mastery":
attr[key] = range(data, 0, 1200);
break;
case "cRate":
attr[key] = range(data, -95, 120);
break;
case "cDmg":
attr[key] = range(data, 0, 320);
break;
case "recharge":
case "hInc":
attr[key] = range(data, 0, 400);
break;
case "dmgBonus":
case "phyBonus":
attr[key] = range(data, 0, 200);
break;
case 'hp':
attr[key + 'Base'] = range(tmp[0].trim(), 0, 16000)
attr[key] = range(tmp[0].trim() * 1 + tmp[1].trim() * 1, attr[key + 'Base'], 50000)
break
case 'def':
case 'atk':
attr[key + 'Base'] = range(tmp[0].trim(), 0, 1100)
attr[key] = range(tmp[0].trim() * 1 + tmp[1].trim() * 1, attr[key + 'Base'], 4500)
break
case 'mastery':
attr[key] = range(data, 0, 1200)
break
case 'cRate':
attr[key] = range(data, -95, 120)
break
case 'cDmg':
attr[key] = range(data, 0, 320)
break
case 'recharge':
case 'hInc':
attr[key] = range(data, 0, 400)
break
case 'dmgBonus':
case 'phyBonus':
attr[key] = range(data, 0, 200)
break
}
}
})
})
if (lodash.keys(attr) < 3) {
return false;
return false
}
originalData.dataSource = "input2";
originalData.attr = attr;
originalData.dataSource = 'input2'
originalData.attr = attr
let userData = {};
const userFile = `${userPath}/${uid}.json`;
let userData = {}
const userFile = `${userPath}/${uid}.json`
if (fs.existsSync(userFile)) {
userData = JSON.parse(fs.readFileSync(userFile, "utf8")) || {};
userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {}
}
userData.chars = userData.chars || {};
userData.chars[avatar] = originalData;
fs.writeFileSync(userFile, JSON.stringify(userData), "", " ");
return true;
userData.chars = userData.chars || {}
userData.chars[avatar] = originalData
fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ')
return true
}
};
export default Profile;
}
export default Profile

View File

@ -1,81 +1,79 @@
import lodash from "lodash";
import Character from "../models/Character.js";
import meta from "./enka-meta.js";
import cmeta from "./enka-char.js";
import _Data from "../Data.js";
import moment from "moment";
import lodash from 'lodash'
import Character from '../models/Character.js'
import meta from './enka-meta.js'
import cmeta from './enka-char.js'
import _Data from '../Data.js'
import moment from 'moment'
moment.locale("zh-cn");
let _path = process.cwd();
let relis = _Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, "data.json") || {};
moment.locale('zh-cn')
let _path = process.cwd()
let relis = _Data.readJSON(`${_path}/plugins/miao-plugin/resources/meta/reliquaries/`, 'data.json') || {}
let relisMap = {}
lodash.forEach(relis, (ds) => {
relisMap[ds.name] = ds;
relisMap[ds.name] = ds
})
const artiIdx = {
EQUIP_BRACER: 1,
EQUIP_NECKLACE: 2,
EQUIP_SHOES: 3,
EQUIP_RING: 4,
EQUIP_DRESS: 5
};
}
const attrMap = {
HP: "小生命",
HP_PERCENT: "大生命",
ATTACK: "小攻击",
ATTACK_PERCENT: "大攻击",
DEFENSE: "小防御",
DEFENSE_PERCENT: "大防御",
FIRE_ADD_HURT: "火元素伤害加成",
ICE_ADD_HURT: "冰元素伤害加成",
ROCK_ADD_HURT: "岩元素伤害加成",
ELEC_ADD_HURT: "雷元素伤害加成",
WIND_ADD_HURT: "风元素伤害加成",
WATER_ADD_HURT: "水元素伤害加成",
PHYSICAL_ADD_HURT: "物理伤害加成",
HEAL_ADD: "治疗加成",
ELEMENT_MASTERY: "元素精通",
CRITICAL: "暴击率",
CRITICAL_HURT: "暴击伤害",
CHARGE_EFFICIENCY: "充能效率",
};
HP: '小生命',
HP_PERCENT: '大生命',
ATTACK: '小攻击',
ATTACK_PERCENT: '大攻击',
DEFENSE: '小防御',
DEFENSE_PERCENT: '大防御',
FIRE_ADD_HURT: '火元素伤害加成',
ICE_ADD_HURT: '冰元素伤害加成',
ROCK_ADD_HURT: '岩元素伤害加成',
ELEC_ADD_HURT: '雷元素伤害加成',
WIND_ADD_HURT: '风元素伤害加成',
WATER_ADD_HURT: '水元素伤害加成',
PHYSICAL_ADD_HURT: '物理伤害加成',
HEAL_ADD: '治疗加成',
ELEMENT_MASTERY: '元素精通',
CRITICAL: '暴击率',
CRITICAL_HURT: '暴击伤害',
CHARGE_EFFICIENCY: '充能效率'
}
let Data = {
getData(uid, data) {
getData (uid, data) {
let ret = {
uid,
chars: {}
}
lodash.forEach({
name: "nickname",
avatar: "profilePicture.avatarId",
lv: "level"
name: 'nickname',
avatar: 'profilePicture.avatarId',
lv: 'level'
}, (src, key) => {
ret[key] = lodash.get(data.playerInfo, src, "");
ret[key] = lodash.get(data.playerInfo, src, '')
})
lodash.forEach(data.avatarInfoList, (ds) => {
let char = Data.getAvatar(ds);
ret.chars[char.id] = char;
let char = Data.getAvatar(ds)
ret.chars[char.id] = char
})
return ret;
return ret
},
getAvatar(data) {
let char = Character.get(data.avatarId);
let now = moment();
getAvatar (data) {
let char = Character.get(data.avatarId)
let now = moment()
let ret = {
id: data["avatarId"],
name: char ? char.name : "",
dataSource: "enka",
updateTime: now.format("YYYY-MM-DD HH:mm:ss"),
id: data.avatarId,
name: char ? char.name : '',
dataSource: 'enka',
updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: data.propMap['4001'].val * 1,
fetter: data.fetterInfo.expLevel,
attr: Data.getAttr(data.fightPropMap),
@ -83,11 +81,11 @@ let Data = {
artis: Data.getArtifact(data.equipList),
cons: data.talentIdList ? data.talentIdList.length : 0,
talent: Data.getTalent(char.id, data.skillLevelMap, data.proudSkillExtraLevelMap || {})
};
return Data.dataFix(ret);
}
return Data.dataFix(ret)
},
getAttr(data) {
let ret = {};
getAttr (data) {
let ret = {}
let attrKey = {
// atk: 2001,
atkBase: 4,
@ -112,56 +110,55 @@ let Data = {
src: 23,
pct: true
}
};
}
lodash.forEach(attrKey, (cfg, key) => {
if (!lodash.isObject(cfg)) {
cfg = { src: cfg };
cfg = { src: cfg }
}
let val = data[cfg.src] || 0;
let val = data[cfg.src] || 0
if (cfg.pct) {
val = val * 100
}
ret[key] = val;
});
ret.atk = data['4'] * (1 + (data['6'] || 0)) + (data['5'] || 0);
let maxDmg = 0;
ret[key] = val
})
ret.atk = data['4'] * (1 + (data['6'] || 0)) + (data['5'] || 0)
let maxDmg = 0
// 火40 水42 风44 岩45 冰46 雷46
// 41 雷
lodash.forEach("40,41,42,43,44,45,45,46".split(","), (key) => {
maxDmg = Math.max(data[key] * 1, maxDmg);
});
lodash.forEach('40,41,42,43,44,45,45,46'.split(','), (key) => {
maxDmg = Math.max(data[key] * 1, maxDmg)
})
// phy 30
ret.dmgBonus = maxDmg * 100;
ret.phyBonus = data['30'] * 100;
ret.dmgBonus = maxDmg * 100
ret.phyBonus = data['30'] * 100
return ret;
return ret
},
getArtifact(data) {
let ret = {};
getArtifact (data) {
let ret = {}
let get = function (d) {
if (!d) {
return [];
return []
}
let id = d.appendPropId || d.mainPropId || "";
id = id.replace("FIGHT_PROP_", "");
let id = d.appendPropId || d.mainPropId || ''
id = id.replace('FIGHT_PROP_', '')
if (!attrMap[id]) {
return [];
return []
}
return [attrMap[id], d.statValue];
return [attrMap[id], d.statValue]
}
lodash.forEach(data, (ds) => {
let flat = ds.flat || {}, sub = flat.reliquarySubstats || [];
let idx = artiIdx[flat.equipType];
let flat = ds.flat || {}; let sub = flat.reliquarySubstats || []
let idx = artiIdx[flat.equipType]
if (!idx) {
return;
return
}
let setName = meta[flat.setNameTextMapHash] || "";
let setCfg = relisMap[setName] || { name: "", sets: {} },
artiCfg = setCfg.sets[`arti${idx}`] || { name: "" };
let setName = meta[flat.setNameTextMapHash] || ''
let setCfg = relisMap[setName] || { name: '', sets: {} }
let artiCfg = setCfg.sets[`arti${idx}`] || { name: '' }
ret[`arti${idx}`] = {
name: artiCfg.name,
@ -176,17 +173,17 @@ let Data = {
]
}
})
return ret;
return ret
},
getWeapon(data) {
getWeapon (data) {
let ds = {}
lodash.forEach(data, (temp) => {
if (temp.flat && temp.flat.itemType === "ITEM_WEAPON") {
ds = temp;
return false;
if (temp.flat && temp.flat.itemType === 'ITEM_WEAPON') {
ds = temp
return false
}
})
let { weapon, flat } = ds;
let { weapon, flat } = ds
return {
name: meta[flat.nameTextMapHash],
star: flat.rankLevel,
@ -195,62 +192,61 @@ let Data = {
affix: (lodash.values(weapon.affixMap)[0] || 0) + 1
}
},
getTalent(charid, ds = {}, ext = {}) {
let cm = cmeta[charid] || {};
let cn = cm.Skills || {}, ce = cm.ProudMap;
let idx = 1;
let idxMap = { 1: 'a', 2: 'e', 3: 'q', 'a': 'a', 's': 'e', 'e': 'q' };
getTalent (charid, ds = {}, ext = {}) {
let cm = cmeta[charid] || {}
let cn = cm.Skills || {}; let ce = cm.ProudMap
let idx = 1
let idxMap = { 1: 'a', 2: 'e', 3: 'q', a: 'a', s: 'e', e: 'q' }
lodash.forEach(cn, (n, id) => {
let nRet = /skill_(\w)/.exec(n.toLowerCase());
idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx];
idx++;
});
lodash.forEach(ce, (n, id) => {
idxMap[n] = idxMap[id];
let nRet = /skill_(\w)/.exec(n.toLowerCase())
idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx]
idx++
})
let ret = {};
lodash.forEach(ce, (n, id) => {
idxMap[n] = idxMap[id]
})
let ret = {}
lodash.forEach(ds, (lv, id) => {
let key = idxMap[id];
let key = idxMap[id]
ret[key] = {
level_original: lv,
level_current: lv
}
})
lodash.forEach(ext, (lv, id) => {
let key = idxMap[id];
let key = idxMap[id]
if (ret[key]) {
ret[key].level_current = ret[key].level_current + lv;
ret[key].level_current = ret[key].level_current + lv
}
})
return ret;
return ret
},
dataFix(ret) {
dataFix (ret) {
if (ret._fix) {
return ret;
return ret
}
let { attr, id } = ret;
id = id * 1;
let { attr, id } = ret
id = id * 1
switch (id) {
case 10000052:
// 雷神被动加成fix
attr.dmgBonus = Math.max(0, attr.dmgBonus - (attr.recharge - 100) * 0.4)
break;
break
case 10000041:
// 莫娜被动fix
attr.dmgBonus = Math.max(0, attr.dmgBonus - attr.recharge * 0.2)
break;
break
/*
case 10000060:
// 夜兰被动fix
attr.hp = attr.hp - attr.hpBase * 0.3
break;
*/
}
ret._fix = true;
return ret;
ret._fix = true
return ret
}
};
}
export default Data;
export default Data

View File

@ -1,28 +1,27 @@
import fetch from "node-fetch";
import Data from "./enka-data.js";
import fetch from 'node-fetch'
import EnkaData from './enka-data.js'
import Data from '../Data.js'
let Enka = {
key: "enka",
key: 'enka',
cd: 5,
async request({ e, uid, avatar, config }) {
let profileApi = config.enkaApi || function ({ uid }) {
return `https://enka.shinshin.moe/u/${uid}/__data.json`
};
let api = profileApi({ uid, avatar });
let req = await fetch(api);
let data = await req.json();
async request ({ e, uid, avatar, diyCfg, sysCfg }) {
let url = diyCfg?.enkaApi?.url || sysCfg.enkaApi.url
let profileApi = diyCfg?.enkaApi?.listApi || sysCfg.enkaApi.listApi
let api = profileApi({ url, uid, avatar })
let req = await fetch(api)
let data = await req.json()
if (!data.playerInfo) {
e.reply(`请求失败:${data.msg || "可能是面板服务并发过高,请稍后重试"}`);
return false;
e.reply(`请求失败:${data.msg || '可能是面板服务并发过高,请稍后重试'}`)
return false
}
let details = data.avatarInfoList;
let details = data.avatarInfoList
if (!details || details.length === 0 || !details[0].propMap) {
e.reply(`请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板`);
return false;
e.reply('请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板')
return false
}
return Data.getData(uid, data);
return EnkaData.getData(uid, data)
}
}
export default Enka;
export default Enka

View File

@ -1,104 +1,98 @@
import fetch from "node-fetch";
import lodash from "lodash";
import Character from "../models/Character.js";
import moment from "moment";
import { artiIdx, artiSetMap, attrMap } from "./miao-meta.js";
import cmeta from "./enka-char.js";
const url = "http://49.232.91.210/profile/detail?token=kokomi";
import fetch from 'node-fetch'
import lodash from 'lodash'
import Character from '../models/Character.js'
import moment from 'moment'
import { artiIdx, artiSetMap, attrMap } from './miao-meta.js'
import cmeta from './enka-char.js'
let Miao = {
key: "miao",
key: 'miao',
cd: 1,
async request({ e, uid, avatar = '', config }) {
let profileApi = config.miaoApi && lodash.isFunction(config.miaoApi) ? config.miaoApi : function ({ uid }) {
return `http://49.232.91.210/profile/list?uid=${uid}`
};
let api = profileApi({ uid, avatar });
let data;
let req = await fetch(api);
data = await req.json();
async request ({ e, uid, avatar = '', diyCfg, sysCfg }) {
let url = diyCfg?.miaoApi?.url || sysCfg.miaoApi.url
let token = diyCfg?.miaoApi?.token || sysCfg.miaoApi.token
let profileApi = diyCfg?.miaoApi?.listApi || sysCfg.miaoApi.listApi
let api = profileApi({ url, uid, avatar, token })
let data
let req = await fetch(api)
data = await req.json()
if (data.status !== 0) {
e.reply(data.msg || "请求失败");
return false;
e.reply(data.msg || '请求失败')
return false
}
if (!data.uidListData || data.uidListData.length === 0) {
e.reply(`请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板`);
return false;
e.reply('请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板')
return false
}
return Miao.getData(uid, data);
return Miao.getData(uid, data)
},
getData(uid, data) {
getData (uid, data) {
let ret = {
uid,
chars: {}
}
lodash.forEach({
name: "nickname",
//avatar: "profilePicture.avatarId",
lv: "level"
name: 'nickname',
// avatar: "profilePicture.avatarId",
lv: 'level'
}, (src, key) => {
ret[key] = lodash.get(data, src, "");
ret[key] = lodash.get(data, src, '')
})
lodash.forEach(data.uidListData, (ds) => {
let char = Miao.getAvatar(ds);
ret.chars[char.id] = char;
let char = Miao.getAvatar(ds)
ret.chars[char.id] = char
})
return ret;
return ret
},
getAvatar(ds) {
let char = Character.get(ds.usernameid);
let now = moment();
getAvatar (ds) {
let char = Character.get(ds.usernameid)
let now = moment()
return {
id: ds.usernameid,
name: char ? char.name : "",
dataSource: "miao-pre",
updateTime: now.format("YYYY-MM-DD HH:mm:ss"),
name: char ? char.name : '',
dataSource: 'miao-pre',
updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: ds.level
};
}
},
async getCharData(uid, ds, saveCharData, { config = {} }) {
if (ds.dataSource !== "miao-pre" || !ds.id) {
return ds;
async getCharData (uid, ds, saveCharData, { diyCfg = {}, sysCfg = {} }) {
if (ds.dataSource !== 'miao-pre' || !ds.id) {
return ds
}
try {
let profileApi = function ({ uid, avatar }) {
return `http://49.232.91.210/profile/detail?uid=${uid}&avatar=${avatar}`
};
if (config.miaoApi && lodash.isFunction(config.miaoApi)) {
profileApi = config.miaoApi;
}
let api = profileApi({ uid, avatar: ds.id });
let req = await fetch(api);
let data = await req.json();
let url = diyCfg?.miaoApi?.url || sysCfg.miaoApi.url
let token = diyCfg?.miaoApi?.token || sysCfg.miaoApi.token
let profileApi = diyCfg?.miaoApi?.detailApi || sysCfg.miaoApi.detailApi
let api = profileApi({ url, token, uid, avatar: ds.id })
let req = await fetch(api)
let data = await req.json()
if (data.status === 0 && data.uidData) {
data = Miao.getAvatarDetail(data);
data = Miao.getAvatarDetail(data)
if (data) {
saveCharData(uid, data);
return data;
saveCharData(uid, data)
return data
}
}
return ds;
return ds
} catch (err) {
console.log(err);
return ds;
console.log(err)
return ds
}
},
getAvatarDetail(data) {
let ds = data.uidData;
let char = Character.get(ds.id);
let now = moment();
getAvatarDetail (data) {
let ds = data.uidData
let char = Character.get(ds.id)
let now = moment()
return {
id: ds.id,
name: char ? char.name : "",
dataSource: "miao",
updateTime: now.format("YYYY-MM-DD HH:mm:ss"),
name: char ? char.name : '',
dataSource: 'miao',
updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: ds.level,
fetter: ds.fetterLevel,
attr: Miao.getAttr(data.uidDataCombatValue),
@ -107,53 +101,54 @@ let Miao = {
cons: ds.constellationNum,
talent: Miao.getTalent(char.id, ds.skill),
_priority: 10
};
}
},
getAttr(data) {
let ret = {};
getAttr (data) {
let ret = {}
lodash.forEach({
atk: "attack",
atkBase: "baseATK",
hp: "health",
hpBase: "baseHP",
def: "defense",
defBase: "baseDEF",
mastery: "elementMastery",
atk: 'attack',
atkBase: 'baseATK',
hp: 'health',
hpBase: 'baseHP',
def: 'defense',
defBase: 'baseDEF',
mastery: 'elementMastery',
cRate: {
src: "critRate",
src: 'critRate',
pct: true
},
cDmg: {
src: "critDamage",
src: 'critDamage',
pct: true
},
hInc: {
src: "heal",
src: 'heal',
pct: true
},
recharge: {
src: "recharge",
src: 'recharge',
pct: true
}
}, (cfg, key) => {
if (!lodash.isObject(cfg)) {
cfg = { src: cfg };
cfg = { src: cfg }
}
let val = data[cfg.src] || 0;
let val = data[cfg.src] || 0
if (cfg.pct) {
val = val * 100
}
ret[key] = val;
ret[key] = val
})
let maxDmg = 0, hurt = data.addHurt || {};
lodash.forEach("fire,elec,water,grass,wind,rock,ice".split(","), (key) => {
maxDmg = Math.max(hurt[key] * 100, maxDmg);
});
ret.dmgBonus = maxDmg;
ret.phyBonus = hurt.physical * 100;
return ret;
let maxDmg = 0;
let hurt = data.addHurt || {}
lodash.forEach('fire,elec,water,grass,wind,rock,ice'.split(','), (key) => {
maxDmg = Math.max(hurt[key] * 100, maxDmg)
})
ret.dmgBonus = maxDmg
ret.phyBonus = hurt.physical * 100
return ret
},
getWeapon(weapon) {
getWeapon (weapon) {
return {
name: weapon.name,
star: weapon.rank,
@ -162,33 +157,33 @@ let Miao = {
affix: (weapon.affixLevel || 0) + 1
}
},
getArtifact(data) {
let ret = {};
getArtifact (data) {
let ret = {}
let get = function (d) {
if (!d) {
return [];
return []
}
let name = d.name;
name = name.replace("FIGHT_PROP_", "");
let name = d.name
name = name.replace('FIGHT_PROP_', '')
if (!attrMap[name]) {
return [];
return []
}
let value = d.value;
let value = d.value
if (value && value < 1) {
value = value * 100;
value = value * 100
}
return [attrMap[name], value];
return [attrMap[name], value]
}
lodash.forEach(data, (ds) => {
let sub = ds.appendAffix || [];
let idx = artiIdx[ds.type];
let sub = ds.appendAffix || []
let idx = artiIdx[ds.type]
if (!idx) {
return;
return
}
ret[`arti${idx}`] = {
name: ds.name,
set: artiSetMap[ds.name] || "",
set: artiSetMap[ds.name] || '',
level: ds.level,
main: get(ds.mainAffix),
attrs: [
@ -199,29 +194,29 @@ let Miao = {
]
}
})
return ret;
return ret
},
getTalent(charid, data = {}) {
let cm = cmeta[charid] || {};
let cn = cm.Skills || {};
let idx = 1;
let idxMap = { 0: 'a', 1: 'e', 2: 'q', 'a': 'a', 's': 'e', 'e': 'q' };
getTalent (charid, data = {}) {
let cm = cmeta[charid] || {}
let cn = cm.Skills || {}
let idx = 1
let idxMap = { 0: 'a', 1: 'e', 2: 'q', a: 'a', s: 'e', e: 'q' }
lodash.forEach(cn, (n, id) => {
let nRet = /skill_(\w)/.exec(n.toLowerCase());
idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx];
idx++;
});
let nRet = /skill_(\w)/.exec(n.toLowerCase())
idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx]
idx++
})
let ret = {};
let ret = {}
lodash.forEach(data, (ds) => {
let key = idxMap[ds.id];
let key = idxMap[ds.id]
ret[key] = {
level_original: ds.level,
level_current: ds.level
}
})
return ret;
},
return ret
}
}
export default Miao;
export default Miao

View File

@ -1,8 +1,6 @@
/*
* 请不要直接修改此或删除此文件防止后续更新冲突
* 如需新增自定义角色可复制此文件改名为character.js
* 复制的character.js中可按格式及自己需求进行配置
* 最终character.js character_default.js两份配置会叠加生效
*
* 暂未做热更新修改完毕请重启yunzai
* */
@ -22,7 +20,7 @@ export const customCharacters = {
}
/*
* 追加设置每个关系的可选角色会与yunzai的设置同时起作用
* 追加设置每个关系的可选角色会与原有设置同时起作用
* 一个角色可以在多个关系中
* */
export const wifeData = {

26
config/profile_default.js Normal file
View File

@ -0,0 +1,26 @@
/*
* 如需配置复制此文件改名为profile.js
*
* 暂未做热更新修改完毕请重启yunzai
* */
/*
* Enka面板服务API配置
* *
* 若enka服务无法正常访问可尝试修改下配置文件中的地址
* 默认地址https://enka.shinshin.moe/
* 国内服务https://enka.microgg.cn/
* */
export const enkaApi = {
url: 'https://enka.shinshin.moe/'
}
/*
* MiaoApi面板更新地址暂时只支持B服角色
* */
export const miaoApi = {
url: 'http://49.232.91.210/profile',
token: 'miao-token'
}

View File

@ -76,8 +76,8 @@ export const characters = {
// 以下为Miao新增自定义角色
paimon: ['派蒙', '应急食物', '应急食品', '吉祥物', '宠物', '外置器官', '会说话的动物', '矮堇瓜', '飞行矮堇瓜', '最好的伙伴'],
sb: ['散兵', '国崩', '雷电国崩', '大炮', '雷电大炮', '雷大炮', '伞兵'],
nvshi: ['女士', '炽热的炎之魔女', '炎之魔女'],
sb: ['散兵', '国崩', '雷电国崩', '大炮', '雷电大炮', '雷大炮', '伞兵', '斯卡拉姆齐'],
nvshi: ['女士', '炽热的炎之魔女', '炎之魔女', '罗莎琳'],
baizhu: ['白术', '长生'],
yaoyao: ['瑶瑶', '遥遥', '遥遥无期'],
fanan: ['伐难', '水夜叉'],
@ -89,7 +89,7 @@ export const characters = {
boshi: ['多托雷', '博士'],
muou: ['桑多涅', '木偶', '人偶'],
choujue: ['皮耶罗', '丑角', '老爷子'],
gongji: ['普契涅拉', '公鸡'],
gongji: ['普契涅拉', '公鸡', '鸽子'],
duizhang: ['卡皮塔诺', '队长'],
nilu: ['妮露'],
nahida: ['纳西妲', '草神']

29
config/system/profile.js Normal file
View File

@ -0,0 +1,29 @@
/*
* 此配置文件为系统使用请勿修改否则可能无法正常使用
* 如需自定义配置请复制修改上一级profile_detail.js
* */
export const profileApi = ({ uid, Miao, Enka }) => {
if ((uid + '')[0] === '5') {
return Miao
}
return Enka
}
export const miaoApi = {
url: 'http://49.232.91.210/profile',
token: 'miao-token',
listApi: ({ url, uid, token }) => {
return `${url}/list?uid=${uid}&token=${token}`
},
detailApi: ({ url, uid, avatar, token }) => {
return `${url}/detail?uid=${uid}&avatar=${avatar}&token=${token}`
}
}
export const enkaApi = {
url: 'https://enka.shinshin.moe/',
listApi: ({ url, uid }) => {
return `${url}u/${uid}/__data.json`
}
}