| 987 | } | 986 | } |
| 988 | | 987 | |
| 989 | /** | 988 | /** |
| | 989 | * Returns the sprite folder name (including override) for a character. |
| | 990 | * @param {object} char Character object |
| | 991 | * @param {string} char.avatar Avatar filename with extension |
| | 992 | * @returns {string} Sprite folder name |
| | 993 | * @throws {Error} If character not found or avatar not set |
| | 994 | */ |
| | 995 | function spriteFolderNameFromCharacter(char) { |
| | 996 | const avatarFileName = char.avatar.replace(/\.[^/.]+$/, ''); |
| | 997 | const expressionOverride = extension_settings.expressionOverrides.find(e => e.name === avatarFileName); |
| | 998 | return expressionOverride?.path ? expressionOverride.path : avatarFileName; |
| | 999 | } |
| | 1000 | |
| | 1001 | /** |
| | 1002 | * Slash command callback for /uploadsprite |
| | 1003 | * |
| | 1004 | * label= is required |
| | 1005 | * if name= is provided, it will be used as a findChar lookup |
| | 1006 | * if name= is not provided, the last character's name will be used |
| | 1007 | * if folder= is a full path, it will be used as the folder |
| | 1008 | * if folder= is a partial path, it will be appended to the character's name |
| | 1009 | * if folder= is not provided, the character's override folder will be used, if set |
| | 1010 | * |
| | 1011 | * @param {object} args |
| | 1012 | * @param {string} args.name Character name or avatar key, passed through findChar |
| | 1013 | * @param {string} args.label Expression label |
| | 1014 | * @param {string} args.folder Sprite folder path, processed using backslash rules |
| | 1015 | * @param {string} imageUrl Image URI to fetch and upload |
| | 1016 | * @returns {Promise<void>} |
| | 1017 | */ |
| | 1018 | async function uploadSpriteCommand({ name, label, folder }, imageUrl) { |
| | 1019 | if (!imageUrl) throw new Error('Image URL is required'); |
| | 1020 | if (!label || typeof label !== 'string') throw new Error('Expression label is required'); |
| | 1021 | |
| | 1022 | label = label.replace(/[^a-z]/gi, '').toLowerCase().trim(); |
| | 1023 | if (!label) throw new Error('Expression label must contain at least one letter'); |
| | 1024 | |
| | 1025 | name = name || getLastCharacterMessage().original_avatar || getLastCharacterMessage().name; |
| | 1026 | const char = findChar({ name }); |
| | 1027 | |
| | 1028 | if (!folder) { |
| | 1029 | folder = spriteFolderNameFromCharacter(char); |
| | 1030 | } else if (folder.startsWith('/') || folder.startsWith('\\')) { |
| | 1031 | const subfolder = folder.slice(1); |
| | 1032 | folder = `${char.name}/${subfolder}`; |
| | 1033 | } |
| | 1034 | |
| | 1035 | try { |
| | 1036 | const response = await fetch(imageUrl); |
| | 1037 | const blob = await response.blob(); |
| | 1038 | const file = new File([blob], 'image.png', { type: 'image/png' }); |
| | 1039 | |
| | 1040 | const formData = new FormData(); |
| | 1041 | formData.append('name', folder); // this is the folder or character name |
| | 1042 | formData.append('label', label); // this is the expression label |
| | 1043 | formData.append('avatar', file); // this is the image file |
| | 1044 | |
| | 1045 | await handleFileUpload('/api/sprites/upload', formData); |
| | 1046 | console.debug(`[${MODULE_NAME}] Upload of ${imageUrl} completed for ${name} with label ${label}`); |
| | 1047 | } catch (error) { |
| | 1048 | console.error(`[${MODULE_NAME}] Error uploading file:`, error); |
| | 1049 | throw error; |
| | 1050 | } |
| | 1051 | } |
| | 1052 | |
| | 1053 | /** |
| 990 | * Processes the classification text to reduce the amount of text sent to the API. | 1054 | * Processes the classification text to reduce the amount of text sent to the API. |
| 991 | * Quotes and asterisks are to be removed. If the text is less than 300 characters, it is returned as is. | 1055 | * Quotes and asterisks are to be removed. If the text is less than 300 characters, it is returned as is. |
| 992 | * If the text is more than 300 characters, the first and last 150 characters are returned. | 1056 | * If the text is more than 300 characters, the first and last 150 characters are returned. |