From 67394bf6233bd177de323fe8a9ac618f017bed99 Mon Sep 17 00:00:00 2001 From: yoimiya-kokomi <592981798@qq.com> Date: Tue, 28 Jun 2022 04:46:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`#=E6=B7=BB=E5=8A=A0=E5=88=BB?= =?UTF-8?q?=E6=99=B4=E5=9B=BE=E5=83=8F`=E5=91=BD=E4=BB=A4=EF=BC=8C?= =?UTF-8?q?=E6=84=9F=E8=B0=A2=20**@=E5=8F=B6**=20*=20=E5=8F=AF=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E5=91=BD=E4=BB=A4=E4=B8=8A=E4=BC=A0=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E8=A7=92=E8=89=B2=E5=9B=BE=E7=89=87=EF=BC=8C?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E8=87=B3=20**resources/character-img/?= =?UTF-8?q?=E5=88=BB=E6=99=B4/upload**=20*=20=E8=AF=B7=E5=B0=86=E5=9B=BE?= =?UTF-8?q?=E5=83=8F=E4=B8=8E=E5=91=BD=E4=BB=A4=E4=B8=80=E5=90=8C=E5=8F=91?= =?UTF-8?q?=E9=80=81=EF=BC=8C=E5=90=8E=E7=BB=AD=E4=BC=9A=E6=94=AF=E6=8C=81?= =?UTF-8?q?at=E5=9B=BE=E5=83=8F=E5=8F=8A=E5=91=BD=E4=BB=A4=E5=90=8E?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=9B=BE=E5=83=8F=20=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E7=9A=84=E9=A1=B5=E9=9D=A2=E6=96=87=E6=A1=88?= =?UTF-8?q?=E5=8F=8A=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + CHANGELOG.md | 8 +- apps/character.js | 3 + .../character-img-upload.js} | 76 +++++++++++------- apps/character/profile-artis.js | 18 ++++- apps/character/profile-common.js | 38 ++++++++- apps/wiki.js | 2 +- components/Profile.js | 3 + components/models/Character.js | 1 + components/profile-data/enka.js | 15 ++-- components/profile-data/miao.js | 10 ++- index.js | 25 +++--- resources/character/artis-mark.html | 26 +++--- resources/character/detail.html | 9 ++- resources/common/bg/bg-dendro.jpg | Bin 0 -> 206752 bytes resources/common/bg/talent-dendro.png | Bin 0 -> 41393 bytes resources/common/common.css | 7 ++ resources/common/common.less | 2 +- .../meta/reliquaries/reliquaries-mark-new.js | 8 +- resources/stat/abyss-pct.html | 13 ++- resources/stat/character.html | 2 +- 21 files changed, 183 insertions(+), 84 deletions(-) rename apps/{uploadCharacterImage.js => character/character-img-upload.js} (57%) create mode 100644 resources/common/bg/bg-dendro.jpg create mode 100644 resources/common/bg/talent-dendro.png diff --git a/.gitignore b/.gitignore index 14a43878..de7c53ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /components/setting.json /config.js *.css.map +/resources/character-img/*/upload/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c87e60d..7de14427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 1.8.1 + +* 增加`#添加刻晴图像`命令,感谢 **@叶** + * 可通过命令上传添加指定角色图片,上传至 **resources/character-img/刻晴/upload** + * 请将图像与命令一同发送,后续会支持at图像及命令后发送图像 +* 部分功能的页面文案及功能优化 + # 1.8.0 * `#角色面板`、`#圣遗物列表` 使用新的圣遗物评分逻辑计算评分 @@ -22,7 +29,6 @@ * 角色图像增加小清新开关,默认关闭 * 对增量包内的角色图像进行分级,较为清凉的图像独立管理 * 勇士们可使用 `#喵喵设置小清新开启` 启用 - * 自行添加请到 **resources/character-img/** 的对应角色目录下添加 * 伤害计算增加扩散、感电的计算逻辑,感谢 **@49631073**的逻辑梳理 * `#角色面板` 伤害计算增加部分角色,目前支持 * 长柄武器:雷神、胡桃、魈、钟离、香菱 diff --git a/apps/character.js b/apps/character.js index 3aa83a83..e3e737ff 100644 --- a/apps/character.js +++ b/apps/character.js @@ -8,6 +8,9 @@ import { renderProfile } from "./character/profile-detail.js"; export { enemyLv, getOriginalPicture } from "./character/utils.js"; +// 角色图像上传 +export { uploadCharacterImg } from "./character/character-img-upload.js"; + // export { getProfileAll, getProfile, profileHelp }; diff --git a/apps/uploadCharacterImage.js b/apps/character/character-img-upload.js similarity index 57% rename from apps/uploadCharacterImage.js rename to apps/character/character-img-upload.js index ddef57ab..9ef2c5bb 100644 --- a/apps/uploadCharacterImage.js +++ b/apps/character/character-img-upload.js @@ -1,15 +1,16 @@ -import { segment } from "oicq"; -import fetch from "node-fetch"; import fs from "fs"; -import Data from "../components/Data.js"; -import { Character } from "../components/models.js"; -import lodash from "lodash"; import { promisify } from "util"; import { pipeline } from "stream"; +import { segment } from "oicq"; +import MD5 from "md5"; +import fetch from "node-fetch"; +import lodash from "lodash"; +import Data from "../../components/Data.js"; +import { Character } from "../../components/models.js"; -const rootPath = process.cwd() + "/plugins/miao-plugin/"; -let regex = /^#*喵喵(上传|添加)(.+)写真.*$/; +const _res_path = process.cwd() + "/plugins/miao-plugin/resources/"; +let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/; export const rule = { uploadCharacterImage: { @@ -19,47 +20,48 @@ export const rule = { }, }; -export async function uploadCharacterImage(e) { +export async function uploadCharacterImg(e) { let promise = await isAllowedToUploadCharacterImage(e); if (!promise) { - return true; + return; } let imageMessages = []; let msg = e.msg; - let regexResult = regex.exec(msg); + let regRet = regex.exec(msg); //通过解析正则获取消息中的角色名 - let characterName = regexResult[2]; - //将消息中的角色名转换为官方名称 - let officialName = Character.get(characterName).name; - if (officialName === undefined) { - e.reply("未查询到该角色。请输入有效的角色名或别名。"); - return true; + if (!regRet || !regRet[1]) { + return; } - console.log("本次要上传的角色是: ", officialName); + let char = Character.get(regRet[1]); + if (!char || !char.name) { + return; + } + let name = char.name; for (let val of e.message) { if ("image" === val.type) { imageMessages.push(val); } } if (imageMessages.length <= 0) { - e.reply("消息中未找到图片,无法添加。"); + // TODO 支持at图片添加,以及支持后发送 + e.reply("消息中未找到图片,请将要发送的图片与消息一同发送.."); return true; } - await saveImages(e, officialName, imageMessages); + await saveImages(e, name, imageMessages); return true; } -async function saveImages(e, officialName, imageMessages) { +async function saveImages(e, name, imageMessages) { let imgMaxSize = e.groupConfig.imgMaxSize || 1; - let pathSuffix = "resources/miao-res-plus/character-img/" + officialName; - let path = rootPath + pathSuffix; + let pathSuffix = `character-img/${name}/upload`; + let path = _res_path + pathSuffix; if (!fs.existsSync(path)) { - console.log("路径不存在,创建目录: ", path); - Data.createDir(rootPath, pathSuffix); + Data.createDir(_res_path, pathSuffix); } let senderName = lodash.truncate(e.sender.card, { length: 8 }); + let imgCount = 0; for (let val of imageMessages) { const response = await fetch(val.url); if (!response.ok) { @@ -75,12 +77,27 @@ async function saveImages(e, officialName, imageMessages) { if (response.headers.get("content-type") === "image/gif") { fileType = "gif"; } - + let imgPath = `${path}/${fileName}.${fileType}`; const streamPipeline = promisify(pipeline); - await streamPipeline(response.body, fs.createWriteStream(`${path}/${fileName}.${fileType}`)); + await streamPipeline(response.body, fs.createWriteStream(imgPath)); + + // 使用md5作为文件名 + let buffers = fs.readFileSync(imgPath); + let base64 = new Buffer.from(buffers, 'base64').toString(); + let md5 = MD5(base64); + let newImgPath = `${path}/${md5}.${fileType}` + if (fs.existsSync(newImgPath)) { + fs.unlink(newImgPath, (err) => { + console.log('unlink', err); + }); + } + fs.rename(imgPath, newImgPath, (err) => { + console.log('rename', err); + }) + imgCount++; Bot.logger.mark(`添加成功: ${path}/${fileName}`); } - e.reply([segment.at(e.user_id, senderName), `\n添加${officialName}信息成功。`]); + e.reply([segment.at(e.user_id, senderName), `\n成功添加${imgCount}张${name}图片。`]); return true; } @@ -91,6 +108,11 @@ async function isAllowedToUploadCharacterImage(e) { if (!e.msg) { return false; } + if (!e.isMaster) { + return false; + } + + // 由于添加角色图是全局,暂时屏蔽非管理员的添加 if (e.isPrivate) { if (!e.isMaster) { e.reply(`只有主人才能添加。`); diff --git a/apps/character/profile-artis.js b/apps/character/profile-artis.js index 77422849..ab0991d6 100644 --- a/apps/character/profile-artis.js +++ b/apps/character/profile-artis.js @@ -4,7 +4,7 @@ * */ import lodash from "lodash"; import { Profile, Common, Models, Format } from "../../components/index.js"; -import { getTargetUid, profileHelp } from "./profile-common.js"; +import { autoRefresh, getTargetUid, profileHelp, autoGetProfile } from "./profile-common.js"; import { Character, Artifact } from "../../components/models.js"; /* @@ -13,11 +13,22 @@ import { Character, Artifact } from "../../components/models.js"; export async function profileArtis(e, { render }) { let { uid, avatar } = e; - let profile = await Profile.get(uid, avatar); - let char = Character.get(profile.name); + let { profile, char, err } = await autoGetProfile(e, uid, avatar, async () => { + await profileArtis(e, { render }); + }); + + if (err) { + return; + } let charCfg = Artifact.getCharCfg(profile.name); let { artis, totalMark, totalMarkClass, usefulMark } = getArtis(profile.name, profile.artis); + + if (!profile.artis || profile.artis.length === 0) { + e.reply("未能获得圣遗物详情,请重新获取面板信息后查看") + return true; + } + let { attrMap } = Artifact.getMeta(); //渲染图像 @@ -52,7 +63,6 @@ export async function profileArtisList(e, { render }) { return true; } - lodash.forEach(profiles || [], (ds) => { let name = ds.name; if (!name || name === "空" || name === "荧") { diff --git a/apps/character/profile-common.js b/apps/character/profile-common.js index 192ea42d..94f6d090 100644 --- a/apps/character/profile-common.js +++ b/apps/character/profile-common.js @@ -95,7 +95,7 @@ export async function autoRefresh(e) { } if (!data.chars) { - e.reply("请确认角色已在【游戏内】橱窗展示并开放了查看详情。设置完毕后请5分钟后使用 #面板更新 重新获取"); + e.reply("请确认角色已在【游戏内】橱窗展示并开放了查看详情。请在设置完毕5分钟后使用 #面板更新 重新获取"); return false; } else { let ret = []; @@ -106,7 +106,7 @@ export async function autoRefresh(e) { } }) if (ret.length === 0) { - e.reply("请确认角色已在【游戏内】橱窗展示并开放了查看详情。设置完毕后请5分钟后使用 #面板更新 重新获取") + e.reply("请确认角色已在【游戏内】橱窗展示并开放了查看详情。请在设置完毕5分钟后使用 #面板更新 重新获取") return false; } else { // e.reply(`本次获取成功角色: ${ret.join(", ")} `) @@ -116,6 +116,40 @@ export async function autoRefresh(e) { return true; } +export async function autoGetProfile(e, uid, avatar, callback) { + + let refresh = async () => { + let refreshRet = await autoRefresh(e); + if (refreshRet) { + await callback(); + } + return refreshRet; + } + + let char = Character.get(avatar); + if (!char) { + return { err: true }; + } + + let profile = await Profile.get(uid, char.id); + if (!profile) { + if (await refresh()) { + return { err: true }; + } else { + e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`); + } + return { err: true }; + } else if (!['enka', 'input2', 'miao', 'miao-pre'].includes(profile.dataSource)) { + if (!await refresh()) { + e.reply(`由于数据格式升级,请重新获取面板信息后查看`); + } + return { err: true }; + } + + return { profile, char, refresh } + +} + /* * 面板数据更新 * */ diff --git a/apps/wiki.js b/apps/wiki.js index b48940ca..b29b4dd8 100644 --- a/apps/wiki.js +++ b/apps/wiki.js @@ -19,7 +19,7 @@ export async function wiki(e, { render }) { return false; } - let reg = /#?(.+)(命座|命之座|天赋|技能|资料|照片|写真|图片|插画)$/, msg = e.msg; + let reg = /#?(.+)(命座|命之座|天赋|技能|资料|照片|写真|图片|图像)$/, msg = e.msg; let ret = reg.exec(msg); if (!ret || !ret[1] || !ret[2]) { diff --git a/components/Profile.js b/components/Profile.js index 0119a20a..cb98f01d 100644 --- a/components/Profile.js +++ b/components/Profile.js @@ -28,6 +28,9 @@ function sleep(ms) { } function getServ(uid) { + if (config.profileApi) { + return config.profileApi({ Enka, Miao }) + } if ((uid + '')[0] === '5') { return Miao; } diff --git a/components/models/Character.js b/components/models/Character.js index e55fd906..228868b0 100644 --- a/components/models/Character.js +++ b/components/models/Character.js @@ -54,6 +54,7 @@ class Character extends Base { }); } addImg(`character-img/${name}`); + addImg(`character-img/${name}/upload`); addImg(`character-img/${name}/se`, !se) const plusPath = `./plugins/miao-plugin/resources/miao-res-plus/`; diff --git a/components/profile-data/enka.js b/components/profile-data/enka.js index fd923fd3..ab3e31a6 100644 --- a/components/profile-data/enka.js +++ b/components/profile-data/enka.js @@ -4,26 +4,21 @@ import Data from "./enka-data.js"; let Enka = { key: "enka", cd: 5, - async request({ e, uid, config }) { - let profileApi = config.profileApi || function (uid) { + 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); + let api = profileApi({ uid, avatar }); let req = await fetch(api); let data = await req.json(); if (!data.playerInfo) { - if ((uid + '')[0] === '5') { - e.reply(`请求失败:暂时不支持B服角色面板更新,请等待服务后续升级`); - } else { - e.reply(`请求失败:${data.msg || "请求错误,请稍后重试"}`); - } + e.reply(`请求失败:${data.msg || "可能是面板服务并发过高,请稍后重试"}`); return false; } - let details = data.avatarInfoList; if (!details || details.length === 0 || !details[0].propMap) { - e.reply(`请打开角色展柜的显示详情`); + e.reply(`请打开游戏内角色展柜的“显示详情”后,等待5分钟重新获取面板`); return false; } return Data.getData(uid, data); diff --git a/components/profile-data/miao.js b/components/profile-data/miao.js index 2219e75e..f3af90c4 100644 --- a/components/profile-data/miao.js +++ b/components/profile-data/miao.js @@ -10,10 +10,12 @@ const url = "http://49.232.91.210/profile"; let Miao = { key: "miao", cd: 1, - async request({ e, uid, avatar = '' }) { - let api = `${url}/list?uid=${uid}`; + 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(); if (data.status !== 0) { @@ -21,7 +23,7 @@ let Miao = { return false; } if (!data.uidListData || data.uidListData.length === 0) { - e.reply(`请打开角色展柜的显示详情`); + e.reply(`请打开游戏内角色展柜的“显示详情”后,等待5分钟重新获取面板`); return false; } diff --git a/index.js b/index.js index 3574fbb8..145e338a 100644 --- a/index.js +++ b/index.js @@ -6,8 +6,10 @@ export { profileArtisList, getProfileAll, profileHelp, - getOriginalPicture + getOriginalPicture, + uploadCharacterImg } from "./apps/character.js"; + import { wifeReg } from "./apps/character.js"; import { consStat, abyssPct, abyssTeam } from "./apps/stat.js"; @@ -17,9 +19,7 @@ import lodash from "lodash"; import common from "../../lib/common.js"; import { rule as adminRule, updateRes, sysCfg, updateMiaoPlugin, profileCfg } from "./apps/admin.js"; import { currentVersion } from "./components/Changelog.js"; -import { - uploadCharacterImage -} from "./apps/uploadCharacterImage.js"; + export { consStat, @@ -32,8 +32,7 @@ export { help, versionInfo, calendar, - profileCfg, - uploadCharacterImage + profileCfg }; @@ -43,6 +42,10 @@ let rule = { //reg: "noCheck", describe: "【#角色】角色详情", }, + uploadCharacterImg: { + reg: "^#*(喵喵)?(上传|添加)(.+)(照片|写真|图片|图像)\\s*$", + describe: "喵喵上传角色写真", + }, profileArtisList: { reg: "^#圣遗物列表\\s*(\\d{9})?$", describe: "【#角色】圣遗物列表", @@ -63,10 +66,6 @@ let rule = { reg: "^#?(获取|给我|我要|求|发|发下|发个|发一下)?原图(吧|呗)?$", describe: "【#原图】 回复角色卡片,可获取原图", }, - uploadCharacterImage: { - reg: "^#*喵喵(上传|添加)(.+)写真.*$", - describe: "喵喵上传角色写真", - }, consStat: { reg: "^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计|持有|持有率)?$", describe: "【#统计】 #角色持有率 #角色5命统计", @@ -80,7 +79,7 @@ let rule = { describe: "【#角色】 #深渊组队", }, wiki: { - reg: "^(#|喵喵)?.*(天赋|技能|命座|命之座|资料|照片|写真|图片|插画)$", + reg: "^(#|喵喵)?.*(天赋|技能|命座|命之座|资料|照片|写真|图片|图像)$", describe: "【#资料】 #神里天赋 #夜兰命座", }, help: { @@ -96,11 +95,11 @@ let rule = { describe: "【#角色】 设置伤害计算中目标敌人的等级", }, versionInfo: { - reg: "^#喵喵版本$", + reg: "^#?喵喵版本$", describe: "【#帮助】 喵喵版本介绍", }, calendar: { - reg: "^#喵喵(日历|活动|日历列表)$", + reg: "^#?喵喵(日历|活动|日历列表)$", describe: "【#日历】 活动日历", }, ...adminRule diff --git a/resources/character/artis-mark.html b/resources/character/artis-mark.html index 4453e367..efbe1f64 100644 --- a/resources/character/artis-mark.html +++ b/resources/character/artis-mark.html @@ -107,7 +107,7 @@
副词条最高分
主词条最高分
- {{each attrMap ds key}}{{if ds.type!== "plus"}} + {{each attrMap ds key}}{{if ds.type!== "plus" && charCfg.weight[key] > 0}}
{{ds.title}}
{{charCfg.weight[key]}}
@@ -125,10 +125,10 @@ {{/if}}{{/each}}
@@ -147,15 +147,7 @@
理之冠
-
最优主词条权重值
-
-
-
-
-
{{charCfg.maxMark.m3}}
-
{{charCfg.maxMark.m4}}
-
{{charCfg.maxMark.m5}}
-
-
-
理论最高原始总分
+
最高分(对齐前)
{{each charCfg.maxMark m key}} {{if key.length === 1}}
{{ mark( m / 6 )}}
@@ -163,13 +155,21 @@ {{/each}}
-
理论总分对齐比例
+
总分对齐比例
{{each charCfg.maxMark m key}} {{if key.length === 1}}
{{( 66 / (46.6/6/100 * m) * 100).toFixed(1)}}%
{{/if}} {{/each}}
+
+
最优主词缀权重
+
-
+
-
+
{{charCfg.maxMark.m3}}
+
{{charCfg.maxMark.m4}}
+
{{charCfg.maxMark.m5}}
+