mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-22 15:07:42 +01:00
Add character asset type
This commit is contained in:
parent
a8cd6c9fe7
commit
c06fe6abfc
@ -3,8 +3,9 @@ TODO:
|
|||||||
*/
|
*/
|
||||||
//const DEBUG_TONY_SAMA_FORK_MODE = true
|
//const DEBUG_TONY_SAMA_FORK_MODE = true
|
||||||
|
|
||||||
import { getRequestHeaders, callPopup } from '../../../script.js';
|
import { getRequestHeaders, callPopup, processDroppedFiles } from '../../../script.js';
|
||||||
import { deleteExtension, extensionNames, installExtension, renderExtensionTemplate } from '../../extensions.js';
|
import { deleteExtension, extensionNames, getContext, installExtension, renderExtensionTemplate } from '../../extensions.js';
|
||||||
|
import { executeSlashCommands } from '../../slash-commands.js';
|
||||||
import { getStringHash, isValidUrl } from '../../utils.js';
|
import { getStringHash, isValidUrl } from '../../utils.js';
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
@ -61,8 +62,8 @@ function downloadAssetsList(url) {
|
|||||||
for (const i in availableAssets[assetType]) {
|
for (const i in availableAssets[assetType]) {
|
||||||
const asset = availableAssets[assetType][i];
|
const asset = availableAssets[assetType][i];
|
||||||
const elemId = `assets_install_${assetType}_${i}`;
|
const elemId = `assets_install_${assetType}_${i}`;
|
||||||
let element = $('<button />', { id: elemId, type: 'button', class: 'asset-download-button menu_button' });
|
let element = $('<div />', { id: elemId, class: 'asset-download-button right_menu_button' });
|
||||||
const label = $('<i class="fa-fw fa-solid fa-download fa-xl"></i>');
|
const label = $('<i class="fa-fw fa-solid fa-download fa-lg"></i>');
|
||||||
element.append(label);
|
element.append(label);
|
||||||
|
|
||||||
//if (DEBUG_TONY_SAMA_FORK_MODE)
|
//if (DEBUG_TONY_SAMA_FORK_MODE)
|
||||||
@ -90,6 +91,11 @@ function downloadAssetsList(url) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const assetDelete = async function () {
|
const assetDelete = async function () {
|
||||||
|
if (assetType === 'character') {
|
||||||
|
toastr.error('Go to the characters menu to delete a character.', 'Character deletion not supported');
|
||||||
|
await executeSlashCommands(`/go ${asset['id']}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
element.off('click');
|
element.off('click');
|
||||||
await deleteAsset(assetType, asset['id']);
|
await deleteAsset(assetType, asset['id']);
|
||||||
label.removeClass('fa-check');
|
label.removeClass('fa-check');
|
||||||
@ -126,20 +132,27 @@ function downloadAssetsList(url) {
|
|||||||
const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);
|
const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);
|
||||||
const description = DOMPurify.sanitize(asset['description'] || '');
|
const description = DOMPurify.sanitize(asset['description'] || '');
|
||||||
const url = isValidUrl(asset['url']) ? asset['url'] : '';
|
const url = isValidUrl(asset['url']) ? asset['url'] : '';
|
||||||
const previewIcon = assetType == 'extension' ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';
|
const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';
|
||||||
|
|
||||||
$('<i></i>')
|
const assetBlock = $('<i></i>')
|
||||||
.append(element)
|
.append(element)
|
||||||
.append(`<div class="flex-container flexFlowColumn">
|
.append(`<div class="flex-container flexFlowColumn flexNoGap">
|
||||||
<span class="flex-container alignitemscenter">
|
<span class="asset-name flex-container alignitemscenter">
|
||||||
<b>${displayName}</b>
|
<b>${displayName}</b>
|
||||||
<a class="asset_preview" href="${url}" target="_blank" title="Preview in browser">
|
<a class="asset_preview" href="${url}" target="_blank" title="Preview in browser">
|
||||||
<i class="fa-solid fa-sm ${previewIcon}"></i>
|
<i class="fa-solid fa-sm ${previewIcon}"></i>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span>${description}</span>
|
<small class="asset-description">
|
||||||
</div>`)
|
${description}
|
||||||
.appendTo(assetTypeMenu);
|
</small>
|
||||||
|
</div>`);
|
||||||
|
|
||||||
|
if (assetType === 'character') {
|
||||||
|
assetBlock.find('.asset-name').prepend(`<div class="avatar"><img src="${asset['url']}" alt="${displayName}"></div>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
assetTypeMenu.append(assetBlock);
|
||||||
}
|
}
|
||||||
assetTypeMenu.appendTo('#assets_menu');
|
assetTypeMenu.appendTo('#assets_menu');
|
||||||
assetTypeMenu.on('click', 'a.asset_preview', previewAsset);
|
assetTypeMenu.on('click', 'a.asset_preview', previewAsset);
|
||||||
@ -186,6 +199,10 @@ function isAssetInstalled(assetType, filename) {
|
|||||||
assetList = extensionNames.filter(x => x.startsWith(thirdPartyMarker)).map(x => x.replace(thirdPartyMarker, ''));
|
assetList = extensionNames.filter(x => x.startsWith(thirdPartyMarker)).map(x => x.replace(thirdPartyMarker, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (assetType == 'character') {
|
||||||
|
assetList = getContext().characters.map(x => x.avatar);
|
||||||
|
}
|
||||||
|
|
||||||
for (const i of assetList) {
|
for (const i of assetList) {
|
||||||
//console.debug(DEBUG_PREFIX,i,filename)
|
//console.debug(DEBUG_PREFIX,i,filename)
|
||||||
if (i.includes(filename))
|
if (i.includes(filename))
|
||||||
@ -215,6 +232,13 @@ async function installAsset(url, assetType, filename) {
|
|||||||
});
|
});
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
console.debug(DEBUG_PREFIX, 'Download success.');
|
console.debug(DEBUG_PREFIX, 'Download success.');
|
||||||
|
if (category === 'character') {
|
||||||
|
console.debug(DEBUG_PREFIX, 'Importing character ', filename);
|
||||||
|
const blob = await result.blob();
|
||||||
|
const file = new File([blob], filename, { type: blob.type });
|
||||||
|
await processDroppedFiles([file]);
|
||||||
|
console.debug(DEBUG_PREFIX, 'Character downloaded.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
|
@ -27,17 +27,14 @@
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets-list-div i {
|
.assets-list-div > i {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
gap: 5px;
|
||||||
|
|
||||||
.assets-list-div i span {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets-list-div i span:first-of-type {
|
.assets-list-div i span:first-of-type {
|
||||||
@ -46,12 +43,11 @@
|
|||||||
|
|
||||||
.asset-download-button {
|
.asset-download-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 50px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
filter: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.asset-download-button:active {
|
.asset-download-button:active {
|
||||||
@ -85,6 +81,21 @@
|
|||||||
animation: asset-download-button-loading-spinner 1s ease infinite;
|
animation: asset-download-button-loading-spinner 1s ease infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asset-name .avatar {
|
||||||
|
--imgSize: 30px !important;
|
||||||
|
flex: unset;
|
||||||
|
width: var(--imgSize);
|
||||||
|
height: var(--imgSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-name .avatar img {
|
||||||
|
width: var(--imgSize);
|
||||||
|
height: var(--imgSize);
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes asset-download-button-loading-spinner {
|
@keyframes asset-download-button-loading-spinner {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0turn);
|
transform: rotate(0turn);
|
||||||
|
@ -8,7 +8,7 @@ const { DIRECTORIES, UNSAFE_EXTENSIONS } = require('../constants');
|
|||||||
const { jsonParser } = require('../express-common');
|
const { jsonParser } = require('../express-common');
|
||||||
const { clientRelativePath } = require('../util');
|
const { clientRelativePath } = require('../util');
|
||||||
|
|
||||||
const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm'];
|
const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm', 'character'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the input filename for the asset.
|
* Validates the input filename for the asset.
|
||||||
@ -199,6 +199,13 @@ router.post('/download', jsonParser, async (request, response) => {
|
|||||||
const fileStream = fs.createWriteStream(destination, { flags: 'wx' });
|
const fileStream = fs.createWriteStream(destination, { flags: 'wx' });
|
||||||
await finished(res.body.pipe(fileStream));
|
await finished(res.body.pipe(fileStream));
|
||||||
|
|
||||||
|
if (category === 'character') {
|
||||||
|
response.sendFile(temp_path, { root: process.cwd() }, () => {
|
||||||
|
fs.rmSync(temp_path);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Move into asset place
|
// Move into asset place
|
||||||
console.debug('Download finished, moving file from', temp_path, 'to', file_path);
|
console.debug('Download finished, moving file from', temp_path, 'to', file_path);
|
||||||
fs.renameSync(temp_path, file_path);
|
fs.renameSync(temp_path, file_path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user