miao-plugin/apps/character.js
2022-03-27 05:34:33 +08:00

532 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fetch from "node-fetch";
import { segment } from "oicq";
import lodash from "lodash";
import { Character } from "../components/models.js"
import fs from "fs";
import sizeOf from "image-size";
let getUrl, getServer;
//角色昵称
let nameID = "";
let genshin = {};
await init();
export async function init(isUpdate = false) {
let _path = "file://" + process.cwd();
console.log(_path + "config/gen");
let version = isUpdate ? new Date().getTime() : 0;
genshin = await import(_path + `/config/genshin/roleId.js?version=${version}`);
nameID = "";
}
// 查看当前角色
export async function character(e, { render, MysApi }) {
let name = e.msg.replace(/#|老婆|老公|[1|2|5][0-9]{8}/g, "").trim();
let char = Character.get(name);
if (!char) {
return false;
}
let roleId = char.id;
getUrl = MysApi.getUrl;
getServer = MysApi.getServer;
let uidRes = await getUid(e);
if (!uidRes.uid && uidRes.isSelf) {
e.reply("请先发送#+你游戏的uid");
return true;
}
if (!(await limitGet(e))) return true;
let uid = uidRes.uid;
let res = await mysApi(e, uid, "character", {
role_id: uid,
server: getServer(uid),
});
if (res.retcode == "-1") {
return true;
}
if (checkRetcode(res, uid, e)) {
return true;
}
let avatars = res.data.avatars;
let length = avatars.length;
avatars = lodash.keyBy(avatars, "id");
if (roleId == 20000000) {
if (avatars["10000005"]) {
roleId = "10000005";
}
if (avatars["10000007"]) {
roleId = "10000007";
}
}
if (!avatars[roleId]) {
let name = lodash.truncate(e.sender.card, { length: 8 });
if (length > 8) {
e.reply([segment.at(e.user_id, name), `\n没有${e.msg}`]);
} else {
e.reply([segment.at(e.user_id, name), "\n请先在米游社展示该角色"]);
}
return true;
}
limitSet(e);
avatars = avatars[roleId];
let talent = await getTalent(e, uid, avatars);
let crownNum = lodash.filter(lodash.map(talent, (d) => d.level_original), (d) => d >= 10).length
let base64 = await render("miao-plugin", "character", {
_plugin: true,
save_id: uid,
uid: uid,
talent,
crownNum,
talentMap: { a: "普攻", e: "战技", q: "爆发" },
bg: getCharacterImg(char.name),
...getCharacterData(avatars),
ds: char.getData("name,id,title,desc"),
}, "png");
if (base64) {
e.reply(segment.image(`base64://${base64}`));
}
return true; //事件结束不再往下
}
// 设置角色图像
export async function setCharacterImg(e, render) {
}
//获取角色技能数据
async function getTalent(e, uid, avatars) {
let skill = {};
if (NoteCookie && NoteCookie[e.user_id] && NoteCookie[e.user_id].uid == uid && NoteCookie[e.user_id].cookie.includes("cookie_token")) {
let skillres = await mysApi(e, uid, "detail", {
role_id: uid,
server: getServer(uid),
avatar_id: avatars.id,
});
if (skillres.retcode == 0 && skillres.data && skillres.data.skill_list) {
skill.id = avatars.id;
let skill_list = lodash.orderBy(skillres.data.skill_list, ["id"], ["asc"]);
for (let val of skill_list) {
val.level_original = val.level_current;
if (val.name.includes("普通攻击")) {
skill.a = val;
continue;
}
if (val.max_level >= 10 && !skill.e) {
skill.e = val;
continue;
}
if (val.max_level >= 10 && !skill.q) {
skill.q = val;
continue;
}
}
if (avatars.actived_constellation_num >= 3) {
if (avatars.constellations[2].effect.includes(skill.e.name)) {
skill.e.level_current += 3;
} else if (avatars.constellations[2].effect.includes(skill.q.name)) {
skill.q.level_current += 3;
}
}
if (avatars.actived_constellation_num >= 5) {
if (avatars.constellations[4].effect.includes(skill.e.name)) {
skill.e.level_current += 3;
} else if (avatars.constellations[4].effect.includes(skill.q.name)) {
skill.q.level_current += 3;
}
}
}
}
return skill;
}
function getCharacterData(avatars) {
let list = [];
let set = {};
let setArr = [];
let text1 = "";
let text2 = "";
let weapon = {
type: "weapon",
name: avatars.weapon.name,
showName: genshin.abbr[avatars.weapon.name] ? genshin.abbr[avatars.weapon.name] : avatars.weapon.name,
level: avatars.weapon.level,
affix_level: avatars.weapon.affix_level,
};
for (let val of avatars.reliquaries) {
if (set[val.set.name]) {
set[val.set.name]++;
if (set[val.set.name] == 2) {
if (text1) {
text2 = "2件套" + val.set.affixes[0].effect;
} else {
text1 = "2件套" + val.set.affixes[0].effect;
}
}
if (set[val.set.name] == 4) {
text2 = "4件套" + val.set.name;
}
} else {
set[val.set.name] = 1;
}
list.push({
type: "reliquaries",
name: val.name,
level: val.level,
});
}
for (let val of Object.keys(set)) {
setArr.push({
name: val,
num: set[val],
showName: genshin.abbr[val] ? genshin.abbr[val] : val,
});
}
if (avatars.reliquaries.length >= 2 && !text1) {
text1 = "无套装效果";
}
if (avatars.id == "10000005") {
avatars.name = "空";
} else if (avatars.id == "10000007") {
avatars.name = "荧";
}
let reliquaries = list[0];
return {
name: avatars.name,
showName: genshin.abbr[avatars.name] ? genshin.abbr[avatars.name] : avatars.name,
level: avatars.level,
fetter: avatars.fetter,
actived_constellation_num: avatars.actived_constellation_num,
weapon,
text1,
text2,
reliquaries,
set: setArr,
};
}
//获取uid
async function getUid(e) {
let res;
let reg = /[1|2|5][0-9]{8}/g;
//从消息中获取
if (e.msg) {
res = e.msg.match(reg);
if (res) {
//redis保存uid
redis.set(`genshin:uid:${e.user_id}`, res[0], { EX: 2592000 });
return { isSelf: false, uid: res[0] };
}
}
//从群昵称获取
res = e.sender.card.toString().match(reg);
if (res) {
//redis保存uid
redis.set(`genshin:uid:${e.user_id}`, res[0], { EX: 2592000 });
return { isSelf: true, uid: res[0] };
}
//从redis获取
res = await redis.get(`genshin:uid:${e.user_id}`);
if (res) {
redis.expire(`genshin:uid:${e.user_id}`, 2592000);
return { isSelf: true, uid: res };
}
return { isSelf: true, uid: false };
}
async function mysApi(e, uid, type, data = {}) {
if (BotConfig.mysCookies.length <= 0) {
Bot.logger.error("请打开config.js,配置米游社cookie");
return { retcode: -300 };
}
let dayEnd = getDayEnd();
let cookie, index, isNew;
let selfCookie = NoteCookie[e.user_id];
//私聊发送的cookie
if (selfCookie && selfCookie.uid == uid) {
cookie = selfCookie.cookie;
}
//配置里面的cookie
else if (BotConfig.dailyNote && BotConfig.dailyNote[e.user_id] && BotConfig.dailyNote[e.user_id].uid == uid) {
cookie = BotConfig.dailyNote[e.user_id].cookie;
} else {
//获取uid集合
let uid_arr = await redis.get(`genshin:ds:qq:${e.user_id}`);
if (uid_arr) {
uid_arr = JSON.parse(uid_arr);
if (!uid_arr.includes(uid)) {
uid_arr.push(uid);
await redis.set(`genshin:ds:qq:${e.user_id}`, JSON.stringify(uid_arr), {
EX: dayEnd,
});
}
} else {
uid_arr = [uid];
await redis.set(`genshin:ds:qq:${e.user_id}`, JSON.stringify(uid_arr), {
EX: dayEnd,
});
}
if (uid_arr.length > e.groupConfig.mysUidLimit && !e.isMaster) {
return { retcode: -200 };
}
//限制无用uid查询
if (uid < 100000050) {
return { retcode: 10102, message: "Data is not public for the user" };
}
isNew = false;
index = await redis.get(`genshin:ds:uid:${uid}`);
if (!index) {
//获取没有到30次的index
for (let i in BotConfig.mysCookies) {
//跳过达到上限的cookie
if (await redis.get(`genshin:ds:max:${i}}`)) {
continue;
}
let count = await redis.sendCommand(["scard", `genshin:ds:index:${i}`]);
if (count < 27) {
index = i;
break;
}
}
//查询已达上限
if (!index) {
return { retcode: -100 };
}
isNew = true;
}
if (!BotConfig.mysCookies[index]) {
return { retcode: -300 };
}
if (!BotConfig.mysCookies[index].includes("ltoken")) {
Bot.logger.error("米游社cookie错误请重新配置");
return { retcode: -400 };
}
}
let { url, headers, query, body } = getUrl(type, uid, data);
headers.Cookie = cookie || BotConfig.mysCookies[index];
let param = {
headers,
timeout: 10000,
};
if (body) {
param.method = "post";
param.body = body;
} else {
param.method = "get";
}
let response = {};
try {
response = await fetch(url, param);
} catch (error) {
Bot.logger.error(error);
return false;
}
if (!response.ok) {
Bot.logger.error(response);
return false;
}
const res = await response.json();
if (!res) {
Bot.logger.mark(`mys接口没有返回`);
return false;
}
if (isNew) {
await redis.sendCommand(["sadd", `genshin:ds:index:${index}`, uid]);
redis.expire(`genshin:ds:index:${index}`, dayEnd);
redis.set(`genshin:ds:uid:${uid}`, index, { EX: dayEnd });
}
if (res.retcode != 0 && ![10102, 1008, -1].includes(res.retcode)) {
let ltuid = headers.Cookie.match(/ltuid=(\w{0,9})/g)[0].replace(/ltuid=|;/g, "");
if (selfCookie && selfCookie.uid == uid) {
Bot.logger.mark(`mys接口报错:${JSON.stringify(res)}体力配置cookieltuid:${ltuid}`);
//体力cookie失效
if (res.message == "Please login") {
delete NoteCookie[e.user_id];
}
} else {
Bot.logger.mark(`mys接口报错:${JSON.stringify(res)},第${Number(index) + 1}个cookieltuid:${ltuid}`);
//标记达到上限的cookie自动切换下一个
if ([10101].includes(res.retcode)) {
redis.set(`genshin:ds:max:${index}`, "1", { EX: dayEnd });
}
}
}
return res;
}
function checkRetcode(res, uid, e) {
let qqName = "";
switch (res.retcode) {
case 0:
Bot.logger.debug(`mys查询成功:${uid}`);
return false;
case -1:
break;
case -100:
e.reply("无法查询,已达上限\n请配置更多cookie");
break;
case -200:
qqName = lodash.truncate(e.sender.card, { length: 8 });
e.reply([segment.at(e.user_id, qqName), "\n今日查询已达上限"]);
break;
case -300:
e.reply("尚未配置公共查询cookie无法查询原神角色信息\n私聊发送【配置cookie】进行设置");
break;
case -400:
e.reply("米游社cookie错误请重新配置");
break;
case 1001:
case 10001:
case 10103:
e.reply("米游社接口报错,暂时无法查询");
break;
case 1008:
qqName = lodash.truncate(e.sender.card, { length: 8 });
e.reply([segment.at(e.user_id, qqName), "\n请先去米游社绑定角色"]);
break;
case 10101:
e.reply("查询已达今日上限");
break;
case 10102:
if (res.message == "Data is not public for the user") {
qqName = lodash.truncate(e.sender.card, { length: 8 });
e.reply([segment.at(e.user_id, qqName), "\n米游社数据未公开"]);
} else {
e.reply(`id:${uid}请先去米游社绑定角色`);
}
break;
}
return true;
}
/**
* @param {角色昵称} keyword
* @param {是否搜索角色默认名} search_val
* @returns
*/
export function roleIdToName(keyword, search_val = false) {
if (!keyword) {
return false;
}
if (search_val) {
return genshin.roleId[keyword][0] ? genshin.roleId[keyword][0] : "";
}
if (!nameID) {
nameID = new Map();
for (let i in genshin.roleId) {
for (let val of genshin.roleId[i]) {
nameID.set(val, i);
}
}
}
let name = nameID.get(keyword);
return name ? name : "";
}
async function limitGet(e) {
if (!e.isGroup) {
return true;
}
if (e.isMaster) {
return true;
}
let key = `genshin:limit:${e.user_id}`;
let num = await redis.get(key);
if (num && num >= e.groupConfig.mysDayLimit - 1) {
let name = lodash.truncate(e.sender.card, { length: 8 });
e.reply([segment.at(e.user_id, name), "\n今日查询已达上限"]);
return false;
}
return true;
}
async function limitSet(e) {
if (!e.isGroup) {
return true;
}
let key = `genshin:limit:${e.user_id}`;
let dayEnd = getDayEnd();
await redis.incr(key);
redis.expire(key, dayEnd);
}
function getDayEnd() {
let now = new Date();
let dayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate(), "23", "59", "59").getTime() / 1000;
return dayEnd - parseInt(now.getTime() / 1000);
}
function getCharacterImg(name) {
let imgs = fs.readdirSync(`./plugins/miao-plugin/resources/characterImg/${name}/`);
imgs = imgs.filter((img) => /\.(png|jpg|webp)/.test(img));
let img = lodash.sample(imgs);
let ret = sizeOf(`./plugins/miao-plugin/resources/characterImg/${name}/${img}`);
ret.img = `/characterImg/${name}/${img}`;
ret.mode = ret.width > ret.height ? "left" : "bottom";
return ret;
}