Update backend returned sprites list
| @@ -18,10 +18,10 @@ import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js'; | ||
| 18 | 18 | export { MODULE_NAME }; |
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | 21 | * @typedef {object} Expression Expression definition with label and file path |
| 22 | 22 | * @property {string} label The label of the expression |
| 23 | 23 | * @property {stringExpressionImage[]} pathfiles TheOne pathor more images to therepresent expressionthis imageexpression |
| 24 | 24 | */ |
| 25 | 25 | |
| 26 | 26 | /** |
| 27 | 27 | * @typedef {object} ExpressionImage An expression image |
| @@ -86,6 +86,7 @@ let lastCharacter = undefined; | ||
| 86 | 86 | let lastMessage = null; |
| 87 | 87 | let lastTalkingState = false; |
| 88 | 88 | let lastTalkingStateMessage = null; // last message as seen by `updateTalkingState` (tracked separately, different timer) |
| 89 | +/** @type {{[characterKey: string]: Expression[]}} */ | |
| 89 | 90 | let spriteCache = {}; |
| 90 | 91 | let inApiCall = false; |
| 91 | 92 | let lastServerResponseTime = 0; |
| @@ -1307,6 +1308,11 @@ function removeExpression() { | ||
| 1307 | 1308 | $('#no_chat_expressions').show(); |
| 1308 | 1309 | } |
| 1309 | 1310 | |
| 1311 | +/** | |
| 1312 | + * Validate a character's sprites, and redraw the sprites list if not done before or forced to redraw. | |
| 1313 | + * @param {string} character - The character to validate | |
| 1314 | + * @param {boolean} forceRedrawCached - Whether to force redrawing the sprites list even if it's already been drawn before | |
| 1315 | + */ | |
| 1310 | 1316 | async function validateImages(character, forceRedrawCached) { |
| 1311 | 1317 | if (!character) { |
| 1312 | 1318 | return; |
| @@ -1330,7 +1336,7 @@ async function validateImages(character, forceRedrawCached) { | ||
| 1330 | 1336 | |
| 1331 | 1337 | /** |
| 1332 | 1338 | * Takes a given sprite as returned from the server, and enriches it with additional data for display/sorting |
| 1333 | 1339 | * @param {Expression{ path: string, label: string }} sprite |
| 1334 | 1340 | * @returns {ExpressionImage} |
| 1335 | 1341 | */ |
| 1336 | 1342 | function getExpressionImageData(sprite) { |
| @@ -1371,7 +1377,8 @@ async function drawSpritesList(character, labels, sprites) { | ||
| 1371 | 1377 | const isCustom = extension_settings.expressions.custom?.includes(expression); |
| 1372 | 1378 | const images = sprites |
| 1373 | 1379 | .filter(s => s.label === expression) |
| 1374 | 1380 | .map(getExpressionImageDatas => s.files) |
| 1381 | + .flat() | |
| 1375 | 1382 | .sort((a, b) => a.title.localeCompare(b.title)); |
| 1376 | 1383 | |
| 1377 | 1384 | if (images.length === 0) { |
| @@ -1384,7 +1391,7 @@ async function drawSpritesList(character, labels, sprites) { | ||
| 1384 | 1391 | } |
| 1385 | 1392 | |
| 1386 | 1393 | // TODO: Fix valid expression lists/caching and group them correctly |
| 1387 | 1394 | validExpressions.push({ label: expression, pathsfiles: images }); |
| 1388 | 1395 | |
| 1389 | 1396 | // Render main = first file, additional = rest |
| 1390 | 1397 | let listItem = await getListItem(expression, { |
| @@ -1408,13 +1415,35 @@ async function getListItem(expression, { images, isCustom = false } = {}) { | ||
| 1408 | 1415 | return renderExtensionTemplateAsync(MODULE_NAME, 'list-item', { expression, images, isCustom: isCustom ?? false }); |
| 1409 | 1416 | } |
| 1410 | 1417 | |
| 1418 | +/** | |
| 1419 | + * Fetches and processes the list of sprites for a given character name. | |
| 1420 | + * Retrieves sprite data from the server and organizes it into labeled groups. | |
| 1421 | + * | |
| 1422 | + * @param {string} name - The character name to fetch sprites for | |
| 1423 | + * @returns {Promise<Expression[]>} A promise that resolves to an array of grouped expression objects, each containing a label and associated image data | |
| 1424 | + */ | |
| 1425 | + | |
| 1411 | 1426 | async function getSpritesList(name) { |
| 1412 | 1427 | console.debug('getting sprites list'); |
| 1413 | 1428 | |
| 1414 | 1429 | try { |
| 1415 | 1430 | const result = await fetch(`/api/sprites/get?name=${encodeURIComponent(name)}`); |
| 1431 | + /** @type {{ label: string, path: string }[]} */ | |
| 1416 | 1432 | let sprites = result.ok ? (await result.json()) : []; |
| 1417 | - return sprites; | |
| 1433 | + | |
| 1434 | + /** @type {Expression[]} */ | |
| 1435 | + const grouped = sprites.reduce((acc, sprite) => { | |
| 1436 | + const imageData = getExpressionImageData(sprite); | |
| 1437 | + let existingExpression = acc.find(exp => exp.label === sprite.label); | |
| 1438 | + if (existingExpression) { | |
| 1439 | + existingExpression.files.push(imageData); | |
| 1440 | + } else { | |
| 1441 | + acc.push({ label: sprite.label, files: [imageData] }); | |
| 1442 | + } | |
| 1443 | + | |
| 1444 | + return acc; | |
| 1445 | + }, []); | |
| 1446 | + return grouped; | |
| 1418 | 1447 | } |
| 1419 | 1448 | catch (err) { |
| 1420 | 1449 | console.log(err); |