diff --git a/CHANGELOG.md b/CHANGELOG.md index 24369abe..fcefcb37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 2.1.5 + +* 角色立绘 + * 支持`#上传刻晴面板图`上传 + * 新增`#刻晴面板图列表` + * 可通过指令查询当前可看的面板立绘 + * 立绘支持`#原图`指令 +* 支持删除uid缓存data文件数据 `#删除面板数据` # 2.1.4 * 角色立绘支持随机,用于面板场景 diff --git a/apps/character/ImgUpload.js b/apps/character/ImgUpload.js index 8daef0c6..012dddaf 100644 --- a/apps/character/ImgUpload.js +++ b/apps/character/ImgUpload.js @@ -10,8 +10,9 @@ import { Character } from '../../models/index.js' const resPath = process.cwd() + '/plugins/miao-plugin/resources/' let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/ - -export async function uploadCharacterImg (e) { +let profileRegex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:面板图)\s*$/ +let isProfile = false; +export async function uploadCharacterImg(e) { let promise = await isAllowedToUploadCharacterImage(e) if (!promise) { return false @@ -20,6 +21,11 @@ export async function uploadCharacterImg (e) { let imageMessages = [] let msg = e.msg let regRet = regex.exec(msg) + if (msg.includes('面板')) { + isProfile = true; + regRet = profileRegex.exec(msg) + } + // 通过解析正则获取消息中的角色名 if (!regRet || !regRet[1]) { return false @@ -46,6 +52,17 @@ export async function uploadCharacterImg (e) { for (let val of source.message) { if (val.type === 'image') { imageMessages.push(val) + } else if (val.type === 'xml') { //支持合并转发消息内置的图片批量上传,喵喵 喵喵喵? 喵喵喵喵 + let resid = val.data.match(/m_resid="(\d|\w|\/)*"/)[0].replace(/m_resid=|"/g, '') + if (!resid) break; + let message = await Bot.getForwardMsg(resid) + for (const item of message) { + for (const i of item.message) { + if (i.type === 'image') { + imageMessages.push(i) + } + } + } } } } @@ -58,9 +75,10 @@ export async function uploadCharacterImg (e) { return true } -async function saveImages (e, name, imageMessages) { +async function saveImages(e, name, imageMessages) { let imgMaxSize = e?.groupConfig?.imgMaxSize || 5 let pathSuffix = `character-img/${name}/upload` + if (isProfile) pathSuffix = `profile/normal-character/${name}`; let path = resPath + pathSuffix if (!fs.existsSync(path)) { @@ -88,6 +106,7 @@ async function saveImages (e, name, imageMessages) { if (response.headers.get('content-type') === 'image/gif') { fileType = 'gif' } + if (isProfile) fileType = 'webp' let imgPath = `${path}/${fileName}.${fileType}` const streamPipeline = promisify(pipeline) await streamPipeline(response.body, fs.createWriteStream(imgPath)) @@ -111,7 +130,8 @@ async function saveImages (e, name, imageMessages) { return true } -async function isAllowedToUploadCharacterImage (e) { +async function isAllowedToUploadCharacterImage(e) { + let sendMsg = e.msg.includes('上传') ? '添加' : '删除'; if (!e.message) { return false } @@ -123,7 +143,7 @@ async function isAllowedToUploadCharacterImage (e) { return true } if (e.isPrivate) { - e.reply('只有主人才能添加...') + e.reply(`只有主人才能${sendMsg}...`) return false } let groupId = e.group_id @@ -133,12 +153,75 @@ async function isAllowedToUploadCharacterImage (e) { const addLimit = e.groupConfig?.imgAddLimit || 2 const isAdmin = ['owner', 'admin'].includes(e.sender.role) if (addLimit === 2) { - e.reply('只有主人才能添加...') + e.reply(`只有主人才能${sendMsg}...`) return false } if (addLimit === 1 && !isAdmin) { - e.reply('只有管理员才能添加...') + e.reply(`只有管理员才能${sendMsg}...`) return false } return true } +//仅支持面板图删除 +export async function delProflie(e) { + let promise = await isAllowedToUploadCharacterImage(e) + if (!promise) { + return false + } + let char = Character.get(e.msg.replace(/#|面板图|列表|上传|删除|\d+/g, '').trim()) + if (!char || !char.name) { + return false + } + let name = char.name + let pathSuffix = `profile/normal-character/${name}`; + let path = resPath + pathSuffix + let num = e.msg.match(/\d+/) + if (!num) { + e.reply(`删除哪张捏?请输入数字序列号,可输入【#${name}面板图列表】查看序列号`) + return + } + try { + let File = fs.readdirSync(`${path}`) + fs.unlinkSync(`${path}/${File[num - 1]}`) + e.reply('删除成功') + } catch (err) { + e.reply('删除失败,请检查序列号是否正确') + } + return true +} + +export async function proflieList(e) { + let msglist = [] + let char = Character.get(e.msg.replace(/#|面板图列表/g, '')) + if (!char || !char.name) { + return false + } + let nickname = Bot.nickname; + if (e.isGroup) { + let info = await Bot.getGroupMemberInfo(e.group_id, Bot.uin) + nickname = info.card || info.nickname + } + let name = char.name + let pathSuffix = `profile/normal-character/${name}`; + let path = resPath + pathSuffix + try { + + let File = fs.readdirSync(`${path}`) + msglist.push({ + message: [`当前查看的是${name}面板图,共${File.length}张,可输入【#删除${name}面板图(序列号)】进行删除`], + nickname: nickname, + user_id: Bot.uin + }) + for (let i = 0; i < File.length; i++) { //合并转发最多99? 但是我感觉不会有这么多先不做处理 + msglist.push({ + message: [`${i + 1}.`, segment.image(`${path}/${File[i]}`)], + nickname: nickname, + user_id: Bot.uin + }) + } + let msgRsg = await e.reply(await Bot.makeForwardMsg(msglist)) + if (!msgRsg) e.reply('风控了,可私聊查看', true) + } catch (err) { + logger.error(err); e.reply('没有角色面板图') + } +} \ No newline at end of file diff --git a/apps/character/ProfileDetail.js b/apps/character/ProfileDetail.js index 087b272e..7ed792fc 100644 --- a/apps/character/ProfileDetail.js +++ b/apps/character/ProfileDetail.js @@ -97,7 +97,7 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) { let artisKeyTitle = ProfileArtis.getArtisKeyTitle() let imgs = char.getImgs(profile.costume) // 渲染图像 - return await Common.render('character/profile-detail', { + let msgRes = await Common.render('character/profile-detail', { save_id: uid, uid, data: avatar.getData('name,abbr,cons,level,weapon,talent,dataSource,updateTime,_attrCalc'), @@ -116,5 +116,10 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) { bodyClass: `char-${char.name}`, mode, changeProfile: e._profileMsg - }, { e, scale: 1.6 }) + }, { e, scale: 1.6,retMsgId: true }) + if (msgRes && msgRes.message_id) { + // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 + await redis.set(`miao:original-picture:${msgRes.message_id}`, imgs.splash0, { EX: 3600 * 3 }) + } + return true } diff --git a/apps/profile.js b/apps/profile.js index 7b639715..afa4817e 100644 --- a/apps/profile.js +++ b/apps/profile.js @@ -1,10 +1,11 @@ -import { Common, App } from '../components/index.js' +import { Common, App, Data } from '../components/index.js' import { Character } from '../models/index.js' import { getTargetUid, getProfile, profileHelp } from './character/ProfileCommon.js' import { profileArtis, profileArtisList } from './character/ProfileArtis.js' import { renderProfile } from './character/ProfileDetail.js' import { profileStat } from './character/ProfileStat.js' import { profileList } from './character/ProfileList.js' +import { uploadCharacterImg,delProflie,proflieList } from './character/ImgUpload.js' import { enemyLv } from './character/ProfileUtils.js' import ProfileChange from './profile/ProfileChange.js' import { groupRank, resetRank, refreshRank } from './character/ProfileRank.js' @@ -73,10 +74,36 @@ app.reg('profile-refresh', getProfile, { describe: '【#角色】 获取游戏橱窗详情数据' }) -export default app +app.reg('upload-img', uploadCharacterImg, { + rule: /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:面板图)\s*$/, + describe: '【#上传刻晴面板图】 上传角色面板图' +}) +app.reg('del-profile', delProflie, { + rule: /^#?\s*(?:喵喵)?(?:移除|清除|删除)(.+)(?:面板图)(\d){1,}\s*$/, + describe: '【#删除刻晴面板图1】 删除指定角色面板图(序号)' +}) +app.reg('profile-list', proflieList, { + rule: /^#?\s*(?:喵喵)?(.+)(?:面板图列表)\s*$/, + describe: '【#刻晴面板图列表】 删除指定角色面板图(序号)' +}) +app.reg('del-uidflie', delUidProfile, { + rule: /^#?\s*(?:喵喵)?(?:移除|清除|删除)面板数据$/, + describe: '【#删除面板数据】 删除面板数据' +}) +export default app +export async function delUidProfile(e){ + let uid = await getTargetUid(e) + if (!uid) { + return true + } + if(Data.delfile(`data/UserData/${uid}.json`)){ + e.reply(`uid:${uid}缓存面板数据已删除~`) + } + return true; +} // 查看当前角色 -export async function profileDetail (e) { +export async function profileDetail(e) { let msg = e.original_msg || e.msg if (!msg) { return false diff --git a/components/Data.js b/components/Data.js index ab8d6cbb..d8d6747e 100644 --- a/components/Data.js +++ b/components/Data.js @@ -58,7 +58,15 @@ let Data = { delete data._res return fs.writeFileSync(`${root}/${file}`, JSON.stringify(data, null, space)) }, - + delfile(file){ + try { + fs.unlinkSync(`${_path}/${file}`) + return true; + } catch (error) { + logger.error(`文件删除失败:${error}`) + } + return false; + }, async getCacheJSON (key) { try { let txt = await redis.get(key) diff --git a/models/character-lib/CharImg.js b/models/character-lib/CharImg.js index 45f55af9..27121939 100644 --- a/models/character-lib/CharImg.js +++ b/models/character-lib/CharImg.js @@ -67,7 +67,7 @@ const CharImg = { return /\.(png|webp)$/.test(file) }) for (let img of imgs) { - ret.push(`${imgPath}/${encodeURI(img)}`) + ret.push(`${imgPath}/${encodeURIComponent(img)}`) } } if (ret.length > 0) {