mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-15 20:57:43 +00:00
feat: 自定义角色图上传
This commit is contained in:
parent
be1c00db59
commit
64275de0e8
11 changed files with 498 additions and 326 deletions
|
|
@ -10,6 +10,7 @@ import _ from 'lodash';
|
|||
import settings from '../lib/settings.js';
|
||||
import { downloadFile } from '../lib/download.js';
|
||||
import { char } from '../lib/convert.js';
|
||||
import guides from '../lib/guides.js';
|
||||
|
||||
const ZZZ_GUIDES_PATH = path.join(imageResourcesPath, 'guides');
|
||||
|
||||
|
|
@ -34,39 +35,13 @@ export class Guide extends ZZZPlugin {
|
|||
|
||||
this.url =
|
||||
'https://bbs-api.mihoyo.com/post/wapi/getPostFullInCollection?&gids=8&collection_id=';
|
||||
this.collection_id = [
|
||||
[],
|
||||
// 来源:新艾利都快讯
|
||||
[2712859],
|
||||
[2727116],
|
||||
[2721968],
|
||||
[2724610],
|
||||
[2722266],
|
||||
[2723586],
|
||||
[2716049],
|
||||
];
|
||||
this.source = [
|
||||
'新艾利都快讯',
|
||||
'清茶沐沐Kiyotya',
|
||||
'小橙子阿',
|
||||
'猫冬',
|
||||
'月光中心',
|
||||
'苦雪的清心花凉糕Suki',
|
||||
'HoYo青枫',
|
||||
];
|
||||
// 最大攻略数量
|
||||
this.maxNum = this.source.length;
|
||||
|
||||
// 最大显示攻略数量
|
||||
this.maxForwardGuides = _.get(
|
||||
settings.getConfig('guide'),
|
||||
'max_forward_guides',
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
getGuideFolder(groupIndex) {
|
||||
let guideFolder = path.join(ZZZ_GUIDES_PATH, this.source[groupIndex - 1]);
|
||||
let guideFolder = path.join(
|
||||
ZZZ_GUIDES_PATH,
|
||||
guides.guideSources[groupIndex - 1]
|
||||
);
|
||||
return guideFolder;
|
||||
}
|
||||
|
||||
|
|
@ -93,10 +68,14 @@ export class Guide extends ZZZPlugin {
|
|||
group = '0';
|
||||
}
|
||||
group = Number(group);
|
||||
if (group > this.maxNum) {
|
||||
await this.reply(`超过攻略数量(${this.maxNum})`);
|
||||
if (group > guides.guideMaxNum) {
|
||||
await this.reply(`超过攻略数量(${guides.guideMaxNum})`);
|
||||
return false;
|
||||
}
|
||||
if (alias === '设置默认' || alias === '设置所有') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const name = char.aliasToName(alias);
|
||||
|
||||
if (!name) {
|
||||
|
|
@ -106,13 +85,18 @@ export class Guide extends ZZZPlugin {
|
|||
|
||||
if (group === 0) {
|
||||
const msg = [];
|
||||
for (let i = 1; i <= this.maxNum; i++) {
|
||||
for (
|
||||
let i = 1;
|
||||
i <=
|
||||
Number(_.get(settings.getConfig('guide'), 'max_forward_guides', 4));
|
||||
i++
|
||||
) {
|
||||
const guidePath = await this.getGuidePath(i, name, !!isUpdate);
|
||||
// msg.push(segment.image(`file://${guidePath}`));
|
||||
if (guidePath) {
|
||||
msg.push(segment.image(guidePath));
|
||||
} else {
|
||||
msg.push(`暂无${name}攻略 (${this.source[i - 1]})`);
|
||||
msg.push(`暂无${name}攻略 (${guides.guideSources[i - 1]})`);
|
||||
}
|
||||
}
|
||||
if (msg.length) {
|
||||
|
|
@ -124,7 +108,9 @@ export class Guide extends ZZZPlugin {
|
|||
const guidePath = await this.getGuidePath(group, name, !!isUpdate);
|
||||
if (!guidePath) {
|
||||
this.e.reply(
|
||||
`暂无${name}攻略 (${this.source[group - 1]})\n请尝试其他的攻略来源查询`
|
||||
`暂无${name}攻略 (${
|
||||
guides.guideSources[group - 1]
|
||||
})\n请尝试其他的攻略来源查询`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -135,7 +121,7 @@ export class Guide extends ZZZPlugin {
|
|||
/** 下载攻略图 */
|
||||
async getImg(name, group) {
|
||||
let mysRes = [];
|
||||
this.collection_id[group].forEach(id =>
|
||||
guides.collection_id[group].forEach(id =>
|
||||
mysRes.push(this.getData(this.url + id))
|
||||
);
|
||||
|
||||
|
|
@ -150,7 +136,7 @@ export class Guide extends ZZZPlugin {
|
|||
// 搜索时过滤特殊符号,譬如「11号」
|
||||
const filtered_name = name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '');
|
||||
let posts = lodash.flatten(lodash.map(mysRes, item => item.data.posts));
|
||||
let url, created_at, updated_at;
|
||||
let url;
|
||||
for (const val of posts) {
|
||||
if (
|
||||
val.post.subject
|
||||
|
|
@ -176,7 +162,7 @@ export class Guide extends ZZZPlugin {
|
|||
return false;
|
||||
}
|
||||
logger.debug(
|
||||
`${this.e.logFnc} 下载${name}攻略图 - ${this.source[group - 1]}`
|
||||
`${this.e.logFnc} 下载${name}攻略图 - ${guides.guideSources[group - 1]}`
|
||||
);
|
||||
|
||||
const filename = `role_guide_${name}.png`;
|
||||
|
|
@ -184,7 +170,7 @@ export class Guide extends ZZZPlugin {
|
|||
const download = await downloadFile(url, guidePath);
|
||||
|
||||
logger.debug(
|
||||
`${this.e.logFnc} 下载${name}攻略成功 - ${this.source[group - 1]}`
|
||||
`${this.e.logFnc} 下载${name}攻略成功 - ${guides.guideSources[group - 1]}`
|
||||
);
|
||||
|
||||
return download;
|
||||
|
|
@ -210,7 +196,9 @@ export class Guide extends ZZZPlugin {
|
|||
'示例: %艾莲攻略2',
|
||||
'',
|
||||
'攻略来源:',
|
||||
].concat(this.source.map((element, index) => `${index + 1}: ${element}`));
|
||||
].concat(
|
||||
guides.guideSources.map((element, index) => `${index + 1}: ${element}`)
|
||||
);
|
||||
await this.e.reply(reply_msg.join('\n'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
16
apps/help.js
16
apps/help.js
|
|
@ -189,8 +189,8 @@ export class Help extends ZZZPlugin {
|
|||
commands: ['下载全部/所有资源'],
|
||||
},
|
||||
{
|
||||
title: '删除资源',
|
||||
desc: '删除已经下载的资源,查询时需要再次下载(用于删除错误下载缓存)',
|
||||
title: '删除资源(需注意)',
|
||||
desc: '请注意,此命令会删除自定义面板图,请确认做好备份后再执行!!!删除已经下载的资源,查询时需要再次下载(用于删除错误下载缓存)。',
|
||||
needCK: false,
|
||||
needSK: false,
|
||||
commands: ['删除全部/所有资源'],
|
||||
|
|
@ -244,6 +244,18 @@ export class Help extends ZZZPlugin {
|
|||
needSK: false,
|
||||
commands: ['删除别名+角色别名'],
|
||||
},
|
||||
{
|
||||
title: '上传角色面板图',
|
||||
desc: '上传自定义角色面板图,可以随消息附带图片,可以通过引用消息中的图片上传',
|
||||
needCK: false,
|
||||
needSK: false,
|
||||
commands: [
|
||||
'上传+角色名+面板图',
|
||||
'上传+角色名+角色图',
|
||||
'添加+角色名+面板图',
|
||||
'添加+角色名+角色图',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
301
apps/manage.js
301
apps/manage.js
|
|
@ -1,19 +1,8 @@
|
|||
import { ZZZPlugin } from '../lib/plugin.js';
|
||||
import { rulePrefix } from '../lib/common.js';
|
||||
import { getAllEquipID } from '../lib/convert/equip.js';
|
||||
import { getAllWeaponID } from '../lib/convert/weapon.js';
|
||||
import { imageResourcesPath } from '../lib/path.js';
|
||||
import settings from '../lib/settings.js';
|
||||
import fs from 'fs';
|
||||
import {
|
||||
getRoleImage,
|
||||
getSmallSquareAvatar,
|
||||
getSquareAvatar,
|
||||
getSuitImage,
|
||||
getWeaponImage,
|
||||
} from '../lib/download.js';
|
||||
import _ from 'lodash';
|
||||
import { char } from '../lib/convert.js';
|
||||
import manage from './manage/index.js';
|
||||
|
||||
export class Panel extends ZZZPlugin {
|
||||
constructor() {
|
||||
|
|
@ -32,295 +21,49 @@ export class Panel extends ZZZPlugin {
|
|||
fnc: 'deleteAll',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}设置默认攻略(\\d+|all)$`,
|
||||
reg: `${rulePrefix}设置默认攻略(\\d+|all)$`,
|
||||
fnc: 'setDefaultGuide',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}设置所有攻略显示个数(\\d+)$`,
|
||||
reg: `${rulePrefix}设置所有攻略显示个数(\\d+)$`,
|
||||
fnc: 'setMaxForwardGuide',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}设置渲染精度(\\d+)$`,
|
||||
reg: `${rulePrefix}设置渲染精度(\\d+)$`,
|
||||
fnc: 'setRenderPrecision',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}刷新抽卡间隔(\\d+)$`,
|
||||
reg: `${rulePrefix}刷新抽卡间隔(\\d+)$`,
|
||||
fnc: 'setRefreshGachaInterval',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}刷新面板间隔(\\d+)$`,
|
||||
reg: `${rulePrefix}刷新面板间隔(\\d+)$`,
|
||||
fnc: 'setRefreshPanelInterval',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}添加(\\S+)别名(\\S+)$`,
|
||||
reg: `${rulePrefix}添加(\\S+)别名(\\S+)$`,
|
||||
fnc: 'addAlias',
|
||||
},
|
||||
{
|
||||
reg: `^${rulePrefix}删除别名(\\S+)$`,
|
||||
reg: `${rulePrefix}删除别名(\\S+)$`,
|
||||
fnc: 'deleteAlias',
|
||||
},
|
||||
{
|
||||
reg: `${rulePrefix}(上传|添加)(\\S+)(角色|面板)图$`,
|
||||
fnc: 'uploadCharacterImg',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
async 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'));
|
||||
}
|
||||
async deleteAll() {
|
||||
if (!this.e.isMaster) return false;
|
||||
await this.reply('【注意】正在删除所有资源图片,后续使用需要重新下载!');
|
||||
if (fs.existsSync(imageResourcesPath)) {
|
||||
fs.rmSync(imageResourcesPath, { recursive: true });
|
||||
}
|
||||
await this.reply('资源图片已删除!');
|
||||
}
|
||||
|
||||
/** 设置默认攻略 */
|
||||
async 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 > this.maxNum) {
|
||||
const reply_msg = [
|
||||
'绝区零默认攻略设置方式为:',
|
||||
'%设置默认攻略[0123...]',
|
||||
`请增加数字0-${this.maxNum}其中一个,或者增加 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})`);
|
||||
}
|
||||
|
||||
/** 设置所有攻略显示个数 */
|
||||
async setMaxForwardGuide() {
|
||||
if (!this.e.isMaster) {
|
||||
this.reply('仅限主人设置');
|
||||
return false;
|
||||
}
|
||||
const match = /设置所有攻略显示个数(\d+)$/g.exec(this.e.msg);
|
||||
const max_forward_guide = Number(match[1]);
|
||||
settings.setSingleConfig('guide', 'max_forward_guides', max_forward_guide);
|
||||
await this.e.reply(`绝区零所有攻略显示个数已设置为: ${max_forward_guide}`);
|
||||
}
|
||||
|
||||
/** 设置渲染精度 */
|
||||
async 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}`);
|
||||
}
|
||||
|
||||
/** 设置刷新抽卡间隔 */
|
||||
async 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}`);
|
||||
}
|
||||
|
||||
/** 设置刷新面板间隔 */
|
||||
async 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}`);
|
||||
}
|
||||
|
||||
async 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} 成功`);
|
||||
}
|
||||
|
||||
async 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} 别名删除成功`);
|
||||
this.downloadAll = manage.assets.downloadAll;
|
||||
this.deleteAll = manage.assets.deleteAll;
|
||||
this.setDefaultGuide = manage.guides.setDefaultGuide;
|
||||
this.setMaxForwardGuide = manage.guides.setMaxForwardGuide;
|
||||
this.setRenderPrecision = manage.config.setRenderPrecision;
|
||||
this.setRefreshGachaInterval = manage.config.setRefreshGachaInterval;
|
||||
this.setRefreshPanelInterval = manage.config.setRefreshPanelInterval;
|
||||
this.addAlias = manage.alias.addAlias;
|
||||
this.deleteAlias = manage.alias.deleteAlias;
|
||||
this.uploadCharacterImg = manage.panel.uploadCharacterImg;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
apps/manage/alias.js
Normal file
44
apps/manage/alias.js
Normal 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
130
apps/manage/assets.js
Normal 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
63
apps/manage/config.js
Normal 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
50
apps/manage/guides.js
Normal 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
17
apps/manage/index.js
Normal 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
97
apps/manage/panel.js
Normal 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;
|
||||
}
|
||||
|
|
@ -30,9 +30,11 @@ export class Panel extends ZZZPlugin {
|
|||
const pre = this.e.msg.match(reg)[4].trim();
|
||||
const suf = this.e.msg.match(reg)[5].trim();
|
||||
if (['刷新', '更新'].includes(pre) || ['刷新', '更新'].includes(suf))
|
||||
return this.refreshPanel();
|
||||
if (!pre || suf === '列表') return this.getCharPanelList();
|
||||
return this.getCharPanel();
|
||||
return await this.refreshPanel();
|
||||
if (!pre || suf === '列表') return await this.getCharPanelList();
|
||||
const queryPanelReg = new RegExp(`${rulePrefix}(.*)面板$`);
|
||||
if (queryPanelReg.test(this.e.msg)) return await this.getCharPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
async refreshPanel() {
|
||||
|
|
@ -90,8 +92,9 @@ export class Panel extends ZZZPlugin {
|
|||
const uid = await this.getUID();
|
||||
if (!uid) return false;
|
||||
const reg = new RegExp(`${rulePrefix}(.+)面板$`);
|
||||
const name = this.e.msg.match(reg)[4];
|
||||
if (['刷新', '更新'].includes(name)) return this.getCharPanelList();
|
||||
const match = this.e.msg.match(reg);
|
||||
if (!match) return false;
|
||||
const name = match[4];
|
||||
const data = getPanel(uid, name);
|
||||
if (!data) {
|
||||
await this.reply(`未找到角色${name}的面板信息,请先刷新面板`);
|
||||
|
|
|
|||
25
lib/guides.js
Normal file
25
lib/guides.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
export default {
|
||||
guideSources: [
|
||||
'新艾利都快讯',
|
||||
'清茶沐沐Kiyotya',
|
||||
'小橙子阿',
|
||||
'猫冬',
|
||||
'月光中心',
|
||||
'苦雪的清心花凉糕Suki',
|
||||
'HoYo青枫',
|
||||
],
|
||||
collection_id: [
|
||||
[],
|
||||
// 来源:新艾利都快讯
|
||||
[2712859],
|
||||
[2727116],
|
||||
[2721968],
|
||||
[2724610],
|
||||
[2722266],
|
||||
[2723586],
|
||||
[2716049],
|
||||
],
|
||||
get guideMaxNum() {
|
||||
return this.guideSources.length;
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue