miao-plugin/apps/character/ImgUpload.js

227 lines
6.8 KiB
JavaScript
Raw Normal View History

import fs from 'fs'
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'
2022-08-18 10:13:42 +00:00
import { Data } from '../../components/index.js'
import { Character } from '../../models/index.js'
2022-06-25 13:56:05 +00:00
const resPath = process.cwd() + '/plugins/miao-plugin/resources/'
let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/
let profileRegex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:面板图)\s*$/
let isProfile = false;
export async function uploadCharacterImg(e) {
let promise = await isAllowedToUploadCharacterImage(e)
2022-06-25 13:56:05 +00:00
if (!promise) {
return false
2022-06-25 13:56:05 +00:00
}
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
2022-06-25 13:56:05 +00:00
}
let char = Character.get(regRet[1])
if (!char || !char.name) {
return false
}
let name = char.name
2022-06-25 13:56:05 +00:00
for (let val of e.message) {
if (val.type === 'image') {
imageMessages.push(val)
2022-06-25 13:56:05 +00:00
}
}
if (imageMessages.length === 0) {
let source
if (e.isGroup) {
// 支持at图片添加以及支持后发送
source = (await e.group.getChatHistory(e.source?.seq, 1)).pop()
} else {
source = (await e.friend.getChatHistory((e.source?.time + 1), 1)).pop()
}
if (source) {
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)
}
}
}
}
}
}
}
2022-06-25 13:56:05 +00:00
if (imageMessages.length <= 0) {
e.reply('消息中未找到图片,请将要发送的图片与消息一同发送或引用要添加的图像..')
return true
2022-06-25 13:56:05 +00:00
}
await saveImages(e, name, imageMessages)
return true
2022-06-25 13:56:05 +00:00
}
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
2022-06-25 13:56:05 +00:00
if (!fs.existsSync(path)) {
2022-09-04 09:33:14 +00:00
Data.createDir(pathSuffix, resPath)
2022-06-25 13:56:05 +00:00
}
let senderName = lodash.truncate(e.sender.card, { length: 8 })
let imgCount = 0
let urlMap = {}
2022-06-25 13:56:05 +00:00
for (let val of imageMessages) {
if (!val.url || urlMap[val.url]) {
continue
}
urlMap[val.url] = true
const response = await fetch(val.url)
2022-06-25 13:56:05 +00:00
if (!response.ok) {
e.reply('图片下载失败。')
return true
2022-06-25 13:56:05 +00:00
}
if (response.headers.get('size') > 1024 * 1024 * imgMaxSize) {
e.reply([segment.at(e.user_id, senderName), '添加失败:图片太大了。'])
return true
2022-06-25 13:56:05 +00:00
}
let fileName = val.file.substring(0, val.file.lastIndexOf('.'))
let fileType = val.file.substring(val.file.lastIndexOf('.') + 1)
if (response.headers.get('content-type') === 'image/gif') {
fileType = 'gif'
2022-06-25 13:56:05 +00:00
}
if (isProfile) fileType = 'webp'
let imgPath = `${path}/${fileName}.${fileType}`
const streamPipeline = promisify(pipeline)
await streamPipeline(response.body, fs.createWriteStream(imgPath))
// 使用md5作为文件名
let buffers = fs.readFileSync(imgPath)
let base64 = 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, () => {
})
imgCount++
Bot.logger.mark(`添加成功: ${path}/${fileName}`)
2022-06-25 13:56:05 +00:00
}
e.reply([segment.at(e.user_id, senderName), `\n成功添加${imgCount}${name}图片。`])
return true
2022-06-25 13:56:05 +00:00
}
async function isAllowedToUploadCharacterImage(e) {
let sendMsg = e.msg.includes('上传') ? '添加' : '删除';
2022-06-25 13:56:05 +00:00
if (!e.message) {
return false
2022-06-25 13:56:05 +00:00
}
if (!e.msg) {
return false
2022-06-25 13:56:05 +00:00
}
// master直接返回true
if (e.isMaster) {
return true
2022-06-25 13:56:05 +00:00
}
if (e.isPrivate) {
e.reply(`只有主人才能${sendMsg}...`)
return false
}
let groupId = e.group_id
if (!groupId) {
return false
2022-06-25 13:56:05 +00:00
}
const addLimit = e.groupConfig?.imgAddLimit || 2
const isAdmin = ['owner', 'admin'].includes(e.sender.role)
if (addLimit === 2) {
e.reply(`只有主人才能${sendMsg}...`)
return false
2022-06-25 13:56:05 +00:00
}
if (addLimit === 1 && !isAdmin) {
e.reply(`只有管理员才能${sendMsg}...`)
return false
}
return true
}
//仅支持面板图删除
export async function delProflie(e) {
let promise = await isAllowedToUploadCharacterImage(e)
if (!promise) {
return false
2022-06-25 13:56:05 +00:00
}
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
2022-06-25 13:56:05 +00:00
}
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('没有角色面板图')
}
}