(WIP) Import JSON from .charx
This commit is contained in:
parent
a41fe1d801
commit
20d12dc98e
|
@ -4788,7 +4788,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="rm_character_import" class="right_menu" style="display: none;">
|
<div id="rm_character_import" class="right_menu" style="display: none;">
|
||||||
<form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
<form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||||
<input multiple type="file" id="character_import_file" accept=".json, image/png, .yaml, .yml" name="avatar">
|
<input multiple type="file" id="character_import_file" accept=".json, image/png, .yaml, .yml, .charx" name="avatar">
|
||||||
<input id="character_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off">
|
<input id="character_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off">
|
||||||
</form>
|
</form>
|
||||||
<input type="file" id="character_replace_file" accept="image/png" name="replace_avatar" hidden>
|
<input type="file" id="character_replace_file" accept="image/png" name="replace_avatar" hidden>
|
||||||
|
|
|
@ -8288,8 +8288,13 @@ export async function processDroppedFiles(files, preserveFileNames = false) {
|
||||||
'text/x-yaml',
|
'text/x-yaml',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const allowedExtensions = [
|
||||||
|
'charx',
|
||||||
|
];
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (allowedMimeTypes.includes(file.type)) {
|
const extension = file.name.split('.').pop().toLowerCase();
|
||||||
|
if (allowedMimeTypes.includes(file.type) || allowedExtensions.includes(extension)) {
|
||||||
await importCharacter(file, preserveFileNames);
|
await importCharacter(file, preserveFileNames);
|
||||||
} else {
|
} else {
|
||||||
toastr.warning('Unsupported file type: ' + file.name);
|
toastr.warning('Unsupported file type: ' + file.name);
|
||||||
|
@ -8310,7 +8315,7 @@ async function importCharacter(file, preserveFileName = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ext = file.name.match(/\.(\w+)$/);
|
const ext = file.name.match(/\.(\w+)$/);
|
||||||
if (!ext || !(['json', 'png', 'yaml', 'yml'].includes(ext[1].toLowerCase()))) {
|
if (!ext || !(['json', 'png', 'yaml', 'yml', 'charx'].includes(ext[1].toLowerCase()))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const jimp = require('jimp');
|
||||||
|
|
||||||
const { UPLOADS_PATH, AVATAR_WIDTH, AVATAR_HEIGHT } = require('../constants');
|
const { UPLOADS_PATH, AVATAR_WIDTH, AVATAR_HEIGHT } = require('../constants');
|
||||||
const { jsonParser, urlencodedParser } = require('../express-common');
|
const { jsonParser, urlencodedParser } = require('../express-common');
|
||||||
const { deepMerge, humanizedISO8601DateTime, tryParse } = require('../util');
|
const { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer } = require('../util');
|
||||||
const { TavernCardValidator } = require('../validator/TavernCardValidator');
|
const { TavernCardValidator } = require('../validator/TavernCardValidator');
|
||||||
const characterCardParser = require('../character-card-parser.js');
|
const characterCardParser = require('../character-card-parser.js');
|
||||||
const { readWorldInfoFile } = require('./worldinfo');
|
const { readWorldInfoFile } = require('./worldinfo');
|
||||||
|
@ -486,6 +486,37 @@ async function importFromYaml(uploadPath, context) {
|
||||||
return result ? fileName : '';
|
return result ? fileName : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a character card from CharX (ZIP) file.
|
||||||
|
* @param {string} uploadPath
|
||||||
|
* @param {object} params
|
||||||
|
* @param {import('express').Request} params.request
|
||||||
|
* @returns {Promise<string>} Internal name of the character
|
||||||
|
*/
|
||||||
|
async function importFromCharX(uploadPath, { request }) {
|
||||||
|
const data = fs.readFileSync(uploadPath);
|
||||||
|
fs.rmSync(uploadPath);
|
||||||
|
console.log('Importing from CharX');
|
||||||
|
const cardBuffer = await extractFileFromZipBuffer(data, 'card.json');
|
||||||
|
|
||||||
|
if (!cardBuffer) {
|
||||||
|
throw new Error('Failed to extract card.json from CharX file');
|
||||||
|
}
|
||||||
|
|
||||||
|
const card = readFromV2(JSON.parse(cardBuffer.toString()));
|
||||||
|
|
||||||
|
if (card.spec === undefined) {
|
||||||
|
throw new Error('Invalid CharX card file: missing spec field');
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetFavFlag(card);
|
||||||
|
card['create_date'] = humanizedISO8601DateTime();
|
||||||
|
card.name = sanitize(card.name);
|
||||||
|
const fileName = getPngName(card.name, request.user.directories);
|
||||||
|
const result = await writeCharacterData(defaultAvatarPath, JSON.stringify(card), fileName, request);
|
||||||
|
return result ? fileName : '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a character from a JSON file.
|
* Import a character from a JSON file.
|
||||||
* @param {string} uploadPath Path to the uploaded file
|
* @param {string} uploadPath Path to the uploaded file
|
||||||
|
@ -1016,6 +1047,7 @@ router.post('/import', urlencodedParser, async function (request, response) {
|
||||||
'yml': importFromYaml,
|
'yml': importFromYaml,
|
||||||
'json': importFromJson,
|
'json': importFromJson,
|
||||||
'png': importFromPng,
|
'png': importFromPng,
|
||||||
|
'charx': importFromCharX,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -149,7 +149,7 @@ async function extractFileFromZipBuffer(archiveBuffer, fileExtension) {
|
||||||
|
|
||||||
zipfile.readEntry();
|
zipfile.readEntry();
|
||||||
zipfile.on('entry', (entry) => {
|
zipfile.on('entry', (entry) => {
|
||||||
if (entry.fileName.endsWith(fileExtension)) {
|
if (entry.fileName.endsWith(fileExtension) && !entry.fileName.startsWith('__MACOSX')) {
|
||||||
console.log(`Extracting ${entry.fileName}`);
|
console.log(`Extracting ${entry.fileName}`);
|
||||||
zipfile.openReadStream(entry, (err, readStream) => {
|
zipfile.openReadStream(entry, (err, readStream) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
Loading…
Reference in New Issue