feat: 自定义角色图上传

This commit is contained in:
bietiaop 2024-08-01 19:08:43 +08:00
parent be1c00db59
commit 64275de0e8
11 changed files with 498 additions and 326 deletions

44
apps/manage/alias.js Normal file
View file

@ -0,0 +1,44 @@
import { char } from '../../lib/convert.js';
import settings from '../../lib/settings.js';
export async function addAlias() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /添加(\S+)别名(\S+)$/g.exec(this.e.msg);
const key = match[1];
const value = match[2];
const oriName = char.aliasToName(key);
const isExist = char.aliasToName(value);
if (!oriName) {
await this.e.reply(`未找到 ${value} 的对应角色`);
return;
}
if (isExist) {
await this.e.reply(`别名 ${value} 已存在`);
return;
}
settings.addArrayleConfig('alias', oriName, value);
await this.e.reply(`角色 ${key} 别名 ${value} 成功`);
}
export async function deleteAlias() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /删除别名(\S+)$/g.exec(this.e.msg);
const key = match[1];
const oriName = char.aliasToName(key);
if (!oriName) {
await this.e.reply(`未找到 ${key} 的对应角色`);
return;
}
if (key === oriName) {
await this.e.reply(`别名 ${key} 为角色本名,无法删除`);
return;
}
settings.removeArrayleConfig('alias', oriName, key);
await this.e.reply(`角色 ${key} 别名删除成功`);
}

130
apps/manage/assets.js Normal file
View file

@ -0,0 +1,130 @@
import fs from 'fs';
import {
getRoleImage,
getSmallSquareAvatar,
getSquareAvatar,
getSuitImage,
getWeaponImage,
} from '../../lib/download.js';
import { char } from '../../lib/convert.js';
import { getAllEquipID } from '../../lib/convert/equip.js';
import { getAllWeaponID } from '../../lib/convert/weapon.js';
import { imageResourcesPath } from '../../lib/path.js';
export async function downloadAll() {
if (!this.e.isMaster) return false;
const charIDs = char.getAllCharactersID();
const equipSprites = getAllEquipID();
const weaponSprites = getAllWeaponID();
const result = {
char: {
success: 0,
failed: 0,
total: charIDs.length,
},
charSmallSquare: {
success: 0,
failed: 0,
total: charIDs.length,
},
charSquare: {
success: 0,
failed: 0,
total: charIDs.length,
},
equip: {
success: 0,
failed: 0,
total: equipSprites.length,
},
weapon: {
success: 0,
failed: 0,
total: weaponSprites.length,
},
};
await this.reply(
'开始下载资源,注意,仅支持下载面板的角色图、武器图、套装图,以及角色卡片的角色头像图。暂不支持下载邦布头像。'
);
for (const id of charIDs) {
try {
await getSquareAvatar(id);
result.charSquare.success++;
} catch (error) {
logger.error('getSquareAvatar', id, error);
result.charSquare.failed++;
}
try {
await getSmallSquareAvatar(id);
result.charSmallSquare.success++;
} catch (error) {
logger.error('getSmallSquareAvatar', id, error);
result.charSmallSquare.failed++;
}
try {
await getRoleImage(id);
result.char.success++;
} catch (error) {
logger.error('getRoleImage', id, error);
result.char.failed++;
}
}
for (const sprite of equipSprites) {
try {
await getSuitImage(sprite);
result.equip.success++;
} catch (error) {
logger.error('getSuitImage', sprite, error);
result.equip.failed++;
}
}
for (const sprite of weaponSprites) {
try {
await getWeaponImage(sprite);
result.weapon.success++;
} catch (error) {
logger.error('getWeaponImage', sprite, error);
result.weapon.failed++;
}
}
const messages = [
'资源下载完成(成功的包含先前下载的图片)',
'角色图需下载' +
charIDs.length +
'张,成功' +
result.char.success +
'张,失败' +
result.char.failed +
'张',
'角色头像图需下载' +
charIDs.length +
'张,成功' +
result.charSquare.success +
'张,失败' +
result.charSquare.failed +
'张',
'套装图需下载' +
equipSprites.length +
'张,成功' +
result.equip.success +
'张,失败' +
result.equip.failed +
'张',
'武器图需下载' +
weaponSprites.length +
'张,成功' +
result.weapon.success +
'张,失败' +
result.weapon.failed +
'张',
];
await this.reply(messages.join('\n'));
}
export async function deleteAll() {
if (!this.e.isMaster) return false;
await this.reply('【注意】正在删除所有资源图片,后续使用需要重新下载!');
if (fs.existsSync(imageResourcesPath)) {
fs.rmSync(imageResourcesPath, { recursive: true });
}
await this.reply('资源图片已删除!');
}

63
apps/manage/config.js Normal file
View file

@ -0,0 +1,63 @@
import settings from '../../lib/settings.js';
/** 设置渲染精度 */
export async function setRenderPrecision() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /渲染精度(\d+)$/g.exec(this.e.msg);
const render_precision = Number(match[1]);
if (render_precision < 50) {
await this.e.reply('渲染精度不能小于50');
return false;
}
if (render_precision > 200) {
await this.e.reply('渲染精度不能大于200');
return false;
}
settings.setSingleConfig('config', 'render', {
scale: render_precision,
});
await this.e.reply(`绝区零渲染精度已设置为: ${render_precision}`);
}
/** 设置刷新抽卡间隔 */
export async function setRefreshGachaInterval() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /刷新抽卡间隔(\d+)$/g.exec(this.e.msg);
const refresh_gacha_interval = Number(match[1]);
if (refresh_gacha_interval < 0) {
await this.e.reply('刷新抽卡间隔不能小于0秒');
return false;
}
if (refresh_gacha_interval > 1000) {
await this.e.reply('刷新抽卡间隔不能大于1000秒');
return false;
}
settings.setSingleConfig('gacha', 'interval', refresh_gacha_interval);
await this.e.reply(`绝区零刷新抽卡间隔已设置为: ${refresh_gacha_interval}`);
}
/** 设置刷新面板间隔 */
export async function setRefreshPanelInterval() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /刷新面板间隔(\d+)$/g.exec(this.e.msg);
const refresh_panel_interval = Number(match[1]);
if (refresh_panel_interval < 0) {
await this.e.reply('刷新面板间隔不能小于0秒');
return false;
}
if (refresh_panel_interval > 1000) {
await this.e.reply('刷新面板间隔不能大于1000秒');
return false;
}
settings.setSingleConfig('panel', 'interval', refresh_panel_interval);
await this.e.reply(`绝区零刷新面板间隔已设置为: ${refresh_panel_interval}`);
}

50
apps/manage/guides.js Normal file
View file

@ -0,0 +1,50 @@
import guides from '../../lib/guides.js';
import settings from '../../lib/settings.js';
/** 设置默认攻略 */
export async function setDefaultGuide() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /设置默认攻略(\d+|all)$/g.exec(this.e.msg);
let guide_id = match[1];
if (guide_id == 'all') {
guide_id = 0;
}
guide_id = Number(guide_id);
if (guide_id > guides.guideMaxNum) {
const reply_msg = [
'绝区零默认攻略设置方式为:',
'%设置默认攻略[0123...]',
`请增加数字0-${guides.guideMaxNum}其中一个,或者增加 all 以显示所有攻略`,
'攻略来源请输入 %攻略帮助 查看',
];
await this.e.reply(reply_msg.join('\n'));
return;
}
settings.setSingleConfig('guide', 'default_guide', guide_id);
const source_name = guide_id == 0 ? 'all' : this.source[guide_id - 1];
await this.e.reply(`绝区零默认攻略已设置为: ${guide_id} (${source_name})`);
}
/** 设置所有攻略显示个数 */
export async function setMaxForwardGuide() {
if (!this.e.isMaster) {
this.reply('仅限主人设置');
return false;
}
const match = /设置所有攻略显示个数(\d+)$/g.exec(this.e.msg);
const max_forward_guide = Number(match[1]);
if (max_forward_guide < 1) {
await this.e.reply('所有攻略显示个数不能小于1');
return false;
}
if (max_forward_guide > guides.guideMaxNum) {
await this.e.reply(`所有攻略显示个数不能大于${guides.guideMaxNum}`);
return false;
}
settings.setSingleConfig('guide', 'max_forward_guides', max_forward_guide);
await this.e.reply(`绝区零所有攻略显示个数已设置为: ${max_forward_guide}`);
}

17
apps/manage/index.js Normal file
View file

@ -0,0 +1,17 @@
import * as assets from './assets.js';
import * as guides from './guides.js';
import * as config from './config.js';
import * as alias from './alias.js';
import * as panel from './panel.js';
export default {
assets,
guides,
config,
alias,
panel,
};

97
apps/manage/panel.js Normal file
View file

@ -0,0 +1,97 @@
import { char } from '../../lib/convert.js';
import { downloadFile } from '../../lib/download.js';
import { imageResourcesPath } from '../../lib/path.js';
import path from 'path';
export async function uploadCharacterImg() {
if (!this.e.isMaster) {
this.reply('只有主人才能添加...');
return false;
}
const reg = /(上传|添加)(.+)(角色|面板)图$/;
const match = this.e.msg.match(reg);
if (!match) {
return false;
}
const charName = match[2].trim();
const name = char.aliasToName(charName);
const images = [];
// 下面方法来源于miao-plugin/apps/character/ImgUpload.js
for (const val of this.e.message) {
if (val.type === 'image') {
images.push(val);
}
}
if (images.length === 0) {
let source;
if (this.e.getReply) {
source = await this.e.getReply();
} else if (this.e.source) {
if (this.e.group?.getChatHistory) {
// 支持at图片添加以及支持后发送
source = (
await this.e.group.getChatHistory(this.e.source?.seq, 1)
).pop();
} else if (this.e.friend?.getChatHistory) {
source = (
await this.e.friend.getChatHistory(this.e.source?.time + 1, 1)
).pop();
}
}
if (source) {
for (const val of source.message) {
if (val.type === 'image') {
images.push(val);
} else if (val.type === 'xml' || val.type === 'forward') {
let resid;
try {
resid = val.data
.match(/m_resid="(\d|\w|\/|\+)*"/)[0]
.replace(/m_resid=|"/g, '');
} catch (err) {
resid = val.id;
}
if (!resid) break;
let message = await this.e.bot.getForwardMsg(resid);
for (const item of message) {
for (const i of item.message) {
if (i.type === 'image') {
images.push(i);
}
}
}
}
}
}
}
logger.debug('images', images);
if (images.length <= 0) {
this.reply(
'消息中未找到图片,请将要发送的图片与消息一同发送或引用要添加的图像。'
);
return false;
}
const resourcesImagesPath = imageResourcesPath;
const panelImagesPath = path.join(resourcesImagesPath, `panel/${name}`);
let success = 0;
let failed = 0;
for (const image of images) {
let fileName = new Date().getTime().toString();
let fileType = 'png';
if (val.file) {
fileName = val.file.substring(0, val.file.lastIndexOf('.'));
fileType = val.file.substring(val.file.lastIndexOf('.') + 1);
}
if (response.headers.get('content-type') === 'image/gif') {
fileType = 'gif';
}
const filePath = path.join(panelImagesPath, `${fileName}.${fileType}`);
const result = await downloadFile(image.url, filePath);
if (result) {
success++;
} else {
failed++;
}
}
this.reply(`成功上传${success}张图片,失败${failed}张图片。`);
return false;
}