#更新面板 支持切换更新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

4
.gitignore vendored
View File

@ -7,4 +7,6 @@
*.css.map *.css.map
/resources/character-img/*/upload/ /resources/character-img/*/upload/
/resources/help/help-list.js /resources/help/help-list.js
/resources/help/help-cfg.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 # 1.9.0
* 初步适配Yunzai V3 * 初步适配Yunzai V3

View File

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

View File

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

View File

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

View File

@ -1,28 +1,27 @@
import fetch from "node-fetch"; import fetch from 'node-fetch'
import Data from "./enka-data.js"; import EnkaData from './enka-data.js'
import Data from '../Data.js'
let Enka = { let Enka = {
key: "enka", key: 'enka',
cd: 5, cd: 5,
async request({ e, uid, avatar, config }) { async request ({ e, uid, avatar, diyCfg, sysCfg }) {
let profileApi = config.enkaApi || function ({ uid }) { let url = diyCfg?.enkaApi?.url || sysCfg.enkaApi.url
return `https://enka.shinshin.moe/u/${uid}/__data.json` let profileApi = diyCfg?.enkaApi?.listApi || sysCfg.enkaApi.listApi
}; let api = profileApi({ url, uid, avatar })
let api = profileApi({ uid, avatar }); let req = await fetch(api)
let data = await req.json()
let req = await fetch(api);
let data = await req.json();
if (!data.playerInfo) { if (!data.playerInfo) {
e.reply(`请求失败:${data.msg || "可能是面板服务并发过高,请稍后重试"}`); e.reply(`请求失败:${data.msg || '可能是面板服务并发过高,请稍后重试'}`)
return false; return false
} }
let details = data.avatarInfoList; let details = data.avatarInfoList
if (!details || details.length === 0 || !details[0].propMap) { if (!details || details.length === 0 || !details[0].propMap) {
e.reply(`请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板`); e.reply('请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板')
return false; 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 fetch from 'node-fetch'
import lodash from "lodash"; import lodash from 'lodash'
import Character from "../models/Character.js"; import Character from '../models/Character.js'
import moment from "moment"; import moment from 'moment'
import { artiIdx, artiSetMap, attrMap } from "./miao-meta.js"; import { artiIdx, artiSetMap, attrMap } from './miao-meta.js'
import cmeta from "./enka-char.js"; import cmeta from './enka-char.js'
const url = "http://49.232.91.210/profile/detail?token=kokomi";
let Miao = { let Miao = {
key: "miao", key: 'miao',
cd: 1, cd: 1,
async request({ e, uid, avatar = '', config }) { async request ({ e, uid, avatar = '', diyCfg, sysCfg }) {
let profileApi = config.miaoApi && lodash.isFunction(config.miaoApi) ? config.miaoApi : function ({ uid }) { let url = diyCfg?.miaoApi?.url || sysCfg.miaoApi.url
return `http://49.232.91.210/profile/list?uid=${uid}` let token = diyCfg?.miaoApi?.token || sysCfg.miaoApi.token
}; let profileApi = diyCfg?.miaoApi?.listApi || sysCfg.miaoApi.listApi
let api = profileApi({ uid, avatar }); let api = profileApi({ url, uid, avatar, token })
let data; let data
let req = await fetch(api); let req = await fetch(api)
data = await req.json(); data = await req.json()
if (data.status !== 0) { if (data.status !== 0) {
e.reply(data.msg || "请求失败"); e.reply(data.msg || '请求失败')
return false; return false
} }
if (!data.uidListData || data.uidListData.length === 0) { if (!data.uidListData || data.uidListData.length === 0) {
e.reply(`请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板`); e.reply('请打开游戏内角色展柜的“显示详情”后等待5分钟重新获取面板')
return false; return false
} }
return Miao.getData(uid, data); return Miao.getData(uid, data)
}, },
getData(uid, data) { getData (uid, data) {
let ret = { let ret = {
uid, uid,
chars: {} chars: {}
} }
lodash.forEach({ lodash.forEach({
name: "nickname", name: 'nickname',
//avatar: "profilePicture.avatarId", // avatar: "profilePicture.avatarId",
lv: "level" lv: 'level'
}, (src, key) => { }, (src, key) => {
ret[key] = lodash.get(data, src, ""); ret[key] = lodash.get(data, src, '')
}) })
lodash.forEach(data.uidListData, (ds) => { lodash.forEach(data.uidListData, (ds) => {
let char = Miao.getAvatar(ds); let char = Miao.getAvatar(ds)
ret.chars[char.id] = char; ret.chars[char.id] = char
}) })
return ret; return ret
}, },
getAvatar(ds) { getAvatar (ds) {
let char = Character.get(ds.usernameid); let char = Character.get(ds.usernameid)
let now = moment(); let now = moment()
return { return {
id: ds.usernameid, id: ds.usernameid,
name: char ? char.name : "", name: char ? char.name : '',
dataSource: "miao-pre", dataSource: 'miao-pre',
updateTime: now.format("YYYY-MM-DD HH:mm:ss"), updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: ds.level lv: ds.level
}; }
}, },
async getCharData(uid, ds, saveCharData, { config = {} }) { async getCharData (uid, ds, saveCharData, { diyCfg = {}, sysCfg = {} }) {
if (ds.dataSource !== "miao-pre" || !ds.id) { if (ds.dataSource !== 'miao-pre' || !ds.id) {
return ds; return ds
} }
try { try {
let profileApi = function ({ uid, avatar }) { let url = diyCfg?.miaoApi?.url || sysCfg.miaoApi.url
return `http://49.232.91.210/profile/detail?uid=${uid}&avatar=${avatar}` let token = diyCfg?.miaoApi?.token || sysCfg.miaoApi.token
}; let profileApi = diyCfg?.miaoApi?.detailApi || sysCfg.miaoApi.detailApi
if (config.miaoApi && lodash.isFunction(config.miaoApi)) { let api = profileApi({ url, token, uid, avatar: ds.id })
profileApi = config.miaoApi; let req = await fetch(api)
} let data = await req.json()
let api = profileApi({ uid, avatar: ds.id });
let req = await fetch(api);
let data = await req.json();
if (data.status === 0 && data.uidData) { if (data.status === 0 && data.uidData) {
data = Miao.getAvatarDetail(data); data = Miao.getAvatarDetail(data)
if (data) { if (data) {
saveCharData(uid, data); saveCharData(uid, data)
return data; return data
} }
} }
return ds; return ds
} catch (err) { } catch (err) {
console.log(err); console.log(err)
return ds; return ds
} }
}, },
getAvatarDetail(data) { getAvatarDetail (data) {
let ds = data.uidData; let ds = data.uidData
let char = Character.get(ds.id); let char = Character.get(ds.id)
let now = moment(); let now = moment()
return { return {
id: ds.id, id: ds.id,
name: char ? char.name : "", name: char ? char.name : '',
dataSource: "miao", dataSource: 'miao',
updateTime: now.format("YYYY-MM-DD HH:mm:ss"), updateTime: now.format('YYYY-MM-DD HH:mm:ss'),
lv: ds.level, lv: ds.level,
fetter: ds.fetterLevel, fetter: ds.fetterLevel,
attr: Miao.getAttr(data.uidDataCombatValue), attr: Miao.getAttr(data.uidDataCombatValue),
@ -107,53 +101,54 @@ let Miao = {
cons: ds.constellationNum, cons: ds.constellationNum,
talent: Miao.getTalent(char.id, ds.skill), talent: Miao.getTalent(char.id, ds.skill),
_priority: 10 _priority: 10
}; }
}, },
getAttr(data) { getAttr (data) {
let ret = {}; let ret = {}
lodash.forEach({ lodash.forEach({
atk: "attack", atk: 'attack',
atkBase: "baseATK", atkBase: 'baseATK',
hp: "health", hp: 'health',
hpBase: "baseHP", hpBase: 'baseHP',
def: "defense", def: 'defense',
defBase: "baseDEF", defBase: 'baseDEF',
mastery: "elementMastery", mastery: 'elementMastery',
cRate: { cRate: {
src: "critRate", src: 'critRate',
pct: true pct: true
}, },
cDmg: { cDmg: {
src: "critDamage", src: 'critDamage',
pct: true pct: true
}, },
hInc: { hInc: {
src: "heal", src: 'heal',
pct: true pct: true
}, },
recharge: { recharge: {
src: "recharge", src: 'recharge',
pct: true pct: true
} }
}, (cfg, key) => { }, (cfg, key) => {
if (!lodash.isObject(cfg)) { 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) { if (cfg.pct) {
val = val * 100 val = val * 100
} }
ret[key] = val; ret[key] = val
}) })
let maxDmg = 0, hurt = data.addHurt || {}; let maxDmg = 0;
lodash.forEach("fire,elec,water,grass,wind,rock,ice".split(","), (key) => { let hurt = data.addHurt || {}
maxDmg = Math.max(hurt[key] * 100, maxDmg); 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; ret.dmgBonus = maxDmg
return ret; ret.phyBonus = hurt.physical * 100
return ret
}, },
getWeapon(weapon) { getWeapon (weapon) {
return { return {
name: weapon.name, name: weapon.name,
star: weapon.rank, star: weapon.rank,
@ -162,33 +157,33 @@ let Miao = {
affix: (weapon.affixLevel || 0) + 1 affix: (weapon.affixLevel || 0) + 1
} }
}, },
getArtifact(data) { getArtifact (data) {
let ret = {}; let ret = {}
let get = function (d) { let get = function (d) {
if (!d) { if (!d) {
return []; return []
} }
let name = d.name; let name = d.name
name = name.replace("FIGHT_PROP_", ""); name = name.replace('FIGHT_PROP_', '')
if (!attrMap[name]) { if (!attrMap[name]) {
return []; return []
} }
let value = d.value; let value = d.value
if (value && value < 1) { if (value && value < 1) {
value = value * 100; value = value * 100
} }
return [attrMap[name], value]; return [attrMap[name], value]
} }
lodash.forEach(data, (ds) => { lodash.forEach(data, (ds) => {
let sub = ds.appendAffix || []; let sub = ds.appendAffix || []
let idx = artiIdx[ds.type]; let idx = artiIdx[ds.type]
if (!idx) { if (!idx) {
return; return
} }
ret[`arti${idx}`] = { ret[`arti${idx}`] = {
name: ds.name, name: ds.name,
set: artiSetMap[ds.name] || "", set: artiSetMap[ds.name] || '',
level: ds.level, level: ds.level,
main: get(ds.mainAffix), main: get(ds.mainAffix),
attrs: [ attrs: [
@ -199,29 +194,29 @@ let Miao = {
] ]
} }
}) })
return ret; return ret
}, },
getTalent(charid, data = {}) { getTalent (charid, data = {}) {
let cm = cmeta[charid] || {}; let cm = cmeta[charid] || {}
let cn = cm.Skills || {}; let cn = cm.Skills || {}
let idx = 1; let idx = 1
let idxMap = { 0: 'a', 1: 'e', 2: 'q', 'a': 'a', 's': 'e', 'e': 'q' }; let idxMap = { 0: 'a', 1: 'e', 2: 'q', a: 'a', s: 'e', e: 'q' }
lodash.forEach(cn, (n, id) => { lodash.forEach(cn, (n, id) => {
let nRet = /skill_(\w)/.exec(n.toLowerCase()); let nRet = /skill_(\w)/.exec(n.toLowerCase())
idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx]; idxMap[id] = nRet && nRet[1] ? idxMap[nRet[1]] : idxMap[idx]
idx++; idx++
}); })
let ret = {}; let ret = {}
lodash.forEach(data, (ds) => { lodash.forEach(data, (ds) => {
let key = idxMap[ds.id]; let key = idxMap[ds.id]
ret[key] = { ret[key] = {
level_original: ds.level, level_original: ds.level,
level_current: 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.js中可按格式及自己需求进行配置
* 最终character.js character_default.js两份配置会叠加生效
* *
* 暂未做热更新修改完毕请重启yunzai * 暂未做热更新修改完毕请重启yunzai
* */ * */
@ -22,7 +20,7 @@ export const customCharacters = {
} }
/* /*
* 追加设置每个关系的可选角色会与yunzai的设置同时起作用 * 追加设置每个关系的可选角色会与原有设置同时起作用
* 一个角色可以在多个关系中 * 一个角色可以在多个关系中
* */ * */
export const wifeData = { 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新增自定义角色 // 以下为Miao新增自定义角色
paimon: ['派蒙', '应急食物', '应急食品', '吉祥物', '宠物', '外置器官', '会说话的动物', '矮堇瓜', '飞行矮堇瓜', '最好的伙伴'], paimon: ['派蒙', '应急食物', '应急食品', '吉祥物', '宠物', '外置器官', '会说话的动物', '矮堇瓜', '飞行矮堇瓜', '最好的伙伴'],
sb: ['散兵', '国崩', '雷电国崩', '大炮', '雷电大炮', '雷大炮', '伞兵'], sb: ['散兵', '国崩', '雷电国崩', '大炮', '雷电大炮', '雷大炮', '伞兵', '斯卡拉姆齐'],
nvshi: ['女士', '炽热的炎之魔女', '炎之魔女'], nvshi: ['女士', '炽热的炎之魔女', '炎之魔女', '罗莎琳'],
baizhu: ['白术', '长生'], baizhu: ['白术', '长生'],
yaoyao: ['瑶瑶', '遥遥', '遥遥无期'], yaoyao: ['瑶瑶', '遥遥', '遥遥无期'],
fanan: ['伐难', '水夜叉'], fanan: ['伐难', '水夜叉'],
@ -89,7 +89,7 @@ export const characters = {
boshi: ['多托雷', '博士'], boshi: ['多托雷', '博士'],
muou: ['桑多涅', '木偶', '人偶'], muou: ['桑多涅', '木偶', '人偶'],
choujue: ['皮耶罗', '丑角', '老爷子'], choujue: ['皮耶罗', '丑角', '老爷子'],
gongji: ['普契涅拉', '公鸡'], gongji: ['普契涅拉', '公鸡', '鸽子'],
duizhang: ['卡皮塔诺', '队长'], duizhang: ['卡皮塔诺', '队长'],
nilu: ['妮露'], nilu: ['妮露'],
nahida: ['纳西妲', '草神'] 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`
}
}