Upload or delete a sprite image.

This commit is contained in:
SillyLossy
2023-05-29 01:17:52 +03:00
parent 5efd55d343
commit 602bceb26e
3 changed files with 685 additions and 509 deletions

View File

@ -1,4 +1,4 @@
import { saveSettingsDebounced } from "../../../script.js";
import { callPopup, getRequestHeaders, saveSettingsDebounced } from "../../../script.js";
import { getContext, getApiUrl, modules, extension_settings } from "../../extensions.js";
export { MODULE_NAME };
@ -240,6 +240,14 @@ function drawSpritesList(character, labels, sprites) {
function getListItem(item, imageSrc, textClass) {
return `
<div id="${item}" class="expression_list_item">
<div class="expression_list_buttons">
<div class="menu_button expression_list_upload" title="Upload image">
<i class="fa-solid fa-upload"></i>
</div>
<div class="menu_button expression_list_delete" title="Delete image">
<i class="fa-solid fa-trash"></i>
</div>
</div>
<span class="expression_list_title ${textClass}">${item}</span>
<img class="expression_list_image" src="${imageSrc}" />
</div>
@ -340,6 +348,80 @@ function onClickExpressionImage() {
setExpression(name, expression, true);
}
}
async function onClickExpressionUpload(event) {
// Prevents the expression from being set
event.stopPropagation();
const id = $(this).closest('.expression_list_item').attr('id');
const name = $('#image_list').data('name');
const handleExpressionUploadChange = async (e) => {
const file = e.target.files[0];
if (!file) {
return;
}
const formData = new FormData();
formData.append('name', name);
formData.append('label', id);
formData.append('avatar', file);
try {
await jQuery.ajax({
type: "POST",
url: "/upload_sprite",
data: formData,
beforeSend: function () { },
cache: false,
contentType: false,
processData: false,
});
// Refresh sprites list
delete spriteCache[name];
await validateImages(name);
} catch (error) {
toastr.error('Failed to upload image');
}
// Reset the input
e.target.form.reset();
};
$('#expression_upload')
.off('change')
.on('change', handleExpressionUploadChange)
.trigger('click');
}
async function onClickExpressionDelete(event) {
// Prevents the expression from being set
event.stopPropagation();
const confirmation = await callPopup("<h3>Are you sure?</h3>Once deleted, it's gone forever!", 'confirm');
if (!confirmation) {
return;
}
const id = $(this).closest('.expression_list_item').attr('id');
const name = $('#image_list').data('name');
try {
await fetch('/delete_sprite', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ name, label: id }),
});
} catch (error) {
toastr.error('Failed to delete image. Try again later.');
}
// Refresh sprites list
delete spriteCache[name];
await validateImages(name);
}
(function () {
function addExpressionImage() {
@ -369,12 +451,15 @@ function onClickExpressionImage() {
<label for="expressions_show_default"><input id="expressions_show_default" type="checkbox">Show default images (emojis) if missing</label>
</div>
</div>
<form><input type="file" id="expression_upload" name="expression_upload" accept="image/*" hidden></form>
</div>
`;
$('#extensions_settings').append(html);
$('#expressions_show_default').on('input', onExpressionsShowDefaultInput);
$('#expressions_show_default').prop('checked', extension_settings.expressions.showDefault).trigger('input');
$(document).on('click', '.expression_list_item', onClickExpressionImage);
$(document).on('click', '.expression_list_upload', onClickExpressionUpload);
$(document).on('click', '.expression_list_delete', onClickExpressionDelete);
$('.expression_settings').hide();
}

View File

@ -78,9 +78,23 @@ img.expression.default {
align-items: center;
}
.expression_list_buttons {
position: absolute;
top: 0;
left: 0;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 20%;
padding: 0.25rem;
}
.expression_list_image {
max-width: 100%;
height: 100%;
object-fit: cover;
}
#image_list {

View File

@ -3061,6 +3061,83 @@ app.post('/google_translate', jsonParser, async (request, response) => {
}
});
app.post('/delete_sprite', jsonParser, async (request, response) => {
const label = request.body.label;
const name = request.body.name;
if (!label || !name) {
return response.sendStatus(400);
}
try {
const spritesPath = path.join(directories.characters, name);
// No sprites folder exists, or not a directory
if (!fs.existsSync(spritesPath) || !fs.statSync(spritesPath).isDirectory()) {
return response.sendStatus(404);
}
const files = fs.readdirSync(spritesPath);
// Remove existing sprite with the same label
for (const file of files) {
if (path.parse(file).name === label) {
fs.rmSync(path.join(spritesPath, file));
}
}
return response.sendStatus(200);
} catch (error) {
console.error(error);
return response.sendStatus(500);
}
});
app.post('/upload_sprite', urlencodedParser, async (request, response) => {
const file = request.file;
const label = request.body.label;
const name = request.body.name;
if (!file || !label || !name) {
return response.sendStatus(400);
}
try {
const spritesPath = path.join(directories.characters, name);
// Path to sprites is not a directory. This should never happen.
if (!fs.statSync(spritesPath).isDirectory()) {
return response.sendStatus(404);
}
// Create sprites folder if it doesn't exist
if (!fs.existsSync(spritesPath)) {
fs.mkdirSync(spritesPath);
}
const files = fs.readdirSync(spritesPath);
// Remove existing sprite with the same label
for (const file of files) {
if (path.parse(file).name === label) {
fs.rmSync(path.join(spritesPath, file));
}
}
const filename = label + path.parse(file.originalname).ext;
const spritePath = path.join("./uploads/", file.filename);
const pathToFile = path.join(spritesPath, filename);
// Copy uploaded file to sprites folder
fs.cpSync(spritePath, pathToFile);
// Remove uploaded file
fs.rmSync(spritePath);
return response.sendStatus(200);
} catch (error) {
console.error(error);
return response.sendStatus(500);
}
});
function writeSecret(key, value) {
if (!fs.existsSync(SECRETS_FILE)) {
const emptyFile = JSON.stringify({});