Refactor findChar to utils - Refactor and move finChar to utils, instead of slashcommands function - Refactor scrapers to use actual init functionality

d7bad6335c34744a7c58875c1d075d61f69cc333

Wolfsblvt <wolfsblvt@gmail.com>

6 files changed, +88 -104Showing whitespace changes
public/script.js+2 -1
@@ -230,7 +230,7 @@ import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros
230import { currentUser, setUserControls } from './scripts/user.js';230import { currentUser, setUserControls } from './scripts/user.js';
231import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';231import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';
232import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';232import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';
233import { ScraperManager } from './scripts/scrapers.js';233import { initScrapers, ScraperManager } from './scripts/scrapers.js';
234import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js';234import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js';
235import { SlashCommand } from './scripts/slash-commands/SlashCommand.js';235import { SlashCommand } from './scripts/slash-commands/SlashCommand.js';
236import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js';236import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js';
@@ -959,6 +959,7 @@ async function firstLoadInit() {
959 initCfg();959 initCfg();
960 initLogprobs();960 initLogprobs();
961 initInputMarkdown();961 initInputMarkdown();
962 initScrapers();
962 doDailyExtensionUpdatesCheck();963 doDailyExtensionUpdatesCheck();
963 await hideLoader();964 await hideLoader();
964 await fixViewport();965 await fixViewport();
public/scripts/extensions/expressions/index.js+1 -2
@@ -2,7 +2,7 @@ import { callPopup, eventSource, event_types, generateRaw, getRequestHeaders, ma
2import { dragElement, isMobile } from '../../RossAscends-mods.js';2import { dragElement, isMobile } from '../../RossAscends-mods.js';
3import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';3import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
4import { loadMovingUIState, power_user } from '../../power-user.js';4import { loadMovingUIState, power_user } from '../../power-user.js';
5import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition } from '../../utils.js';5import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar } from '../../utils.js';
6import { hideMutedSprites } from '../../group-chats.js';6import { hideMutedSprites } from '../../group-chats.js';
7import { isJsonSchemaSupported } from '../../textgen-settings.js';7import { isJsonSchemaSupported } from '../../textgen-settings.js';
8import { debounce_timeout } from '../../constants.js';8import { debounce_timeout } from '../../constants.js';
@@ -12,7 +12,6 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
12import { isFunctionCallingSupported } from '../../openai.js';12import { isFunctionCallingSupported } from '../../openai.js';
13import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';13import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
14import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';14import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
15import { findChar } from '../../slash-commands.js';
16export { MODULE_NAME };15export { MODULE_NAME };
1716
18const MODULE_NAME = 'expressions';17const MODULE_NAME = 'expressions';
public/scripts/scrapers.js+9 -0
@@ -13,6 +13,7 @@ import { isValidUrl } from './utils.js';
13 * @property {string} description13 * @property {string} description
14 * @property {string} iconClass14 * @property {string} iconClass
15 * @property {boolean} iconAvailable15 * @property {boolean} iconAvailable
16 * @property {() => Promise<void>} [init=null]
16 * @property {() => Promise<boolean>} isAvailable17 * @property {() => Promise<boolean>} isAvailable
17 * @property {() => Promise<File[]>} scrape18 * @property {() => Promise<File[]>} scrape
18 */19 */
@@ -42,6 +43,10 @@ export class ScraperManager {
42 return;43 return;
43 }44 }
4445
46 if (scraper.init) {
47 scraper.init();
48 }
49
45 ScraperManager.#scrapers.push(scraper);50 ScraperManager.#scrapers.push(scraper);
46 }51 }
4752
@@ -462,7 +467,9 @@ class YouTubeScraper {
462 this.description = 'Download a transcript from a YouTube video.';467 this.description = 'Download a transcript from a YouTube video.';
463 this.iconClass = 'fa-brands fa-youtube';468 this.iconClass = 'fa-brands fa-youtube';
464 this.iconAvailable = true;469 this.iconAvailable = true;
470 }
465471
472 async init() {
466 SlashCommandParser.addCommandObject(SlashCommand.fromProps({473 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
467 name: 'yt-script',474 name: 'yt-script',
468 callback: async (args, url) => {475 callback: async (args, url) => {
@@ -564,9 +571,11 @@ class YouTubeScraper {
564 }571 }
565}572}
566573
574export function initScrapers() {
567 ScraperManager.registerDataBankScraper(new FileScraper());575 ScraperManager.registerDataBankScraper(new FileScraper());
568 ScraperManager.registerDataBankScraper(new Notepad());576 ScraperManager.registerDataBankScraper(new Notepad());
569 ScraperManager.registerDataBankScraper(new WebScraper());577 ScraperManager.registerDataBankScraper(new WebScraper());
570 ScraperManager.registerDataBankScraper(new MediaWikiScraper());578 ScraperManager.registerDataBankScraper(new MediaWikiScraper());
571 ScraperManager.registerDataBankScraper(new FandomScraper());579 ScraperManager.registerDataBankScraper(new FandomScraper());
572 ScraperManager.registerDataBankScraper(new YouTubeScraper());580 ScraperManager.registerDataBankScraper(new YouTubeScraper());
581}
public/scripts/slash-commands.js+1 -97
@@ -55,7 +55,7 @@ import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockStat
55import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';55import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
56import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js';56import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js';
57import { decodeTextTokens, getAvailableTokenizers, getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, selectTokenizer } from './tokenizers.js';57import { decodeTextTokens, getAvailableTokenizers, getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, selectTokenizer } from './tokenizers.js';
58import { debounce, delay, equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';58import { debounce, delay, equalsIgnoreCaseAndAccents, findChar, isFalseBoolean, isTrueBoolean, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';
59import { registerVariableCommands, resolveVariable } from './variables.js';59import { registerVariableCommands, resolveVariable } from './variables.js';
60import { background_settings } from './backgrounds.js';60import { background_settings } from './backgrounds.js';
61import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';61import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
@@ -68,10 +68,8 @@ import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashComma
68import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';68import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
69import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';69import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
70import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';70import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
71import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js';
72import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';71import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';
73import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';72import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
74import { getTagsList } from './tags.js';
75export {73export {
76 executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,74 executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
77};75};
@@ -2969,29 +2967,6 @@ async function deleteMessagesByNameCallback(_, name) {
2969 return '';2967 return '';
2970}2968}
29712969
2972function findCharacterIndex(name) {
2973 const matchTypes = [
2974 (a, b) => a === b,
2975 (a, b) => a.startsWith(b),
2976 (a, b) => a.includes(b),
2977 ];
2978
2979 const exactAvatarMatch = characters.findIndex(x => x.avatar === name);
2980
2981 if (exactAvatarMatch !== -1) {
2982 return exactAvatarMatch;
2983 }
2984
2985 for (const matchType of matchTypes) {
2986 const index = characters.findIndex(x => matchType(x.name.toLowerCase(), name.toLowerCase()));
2987 if (index !== -1) {
2988 return index;
2989 }
2990 }
2991
2992 return -1;
2993}
2994
2995async function goToCharacterCallback(_, name) {2970async function goToCharacterCallback(_, name) {
2996 if (!name) {2971 if (!name) {
2997 console.warn('WARN: No character name provided for /go command');2972 console.warn('WARN: No character name provided for /go command');
@@ -3238,77 +3213,6 @@ export function getNameAndAvatarForMessage(character, name = null) {
3238 };3213 };
3239}3214}
32403215
3241/**
3242 * Finds a character by name, with optional filtering and precedence for avatars
3243 * @param {object} [options={}] - The options for the search
3244 * @param {string?} [options.name=null] - The name to search for
3245 * @param {boolean} [options.allowAvatar=true] - Whether to allow searching by avatar
3246 * @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive
3247 * @param {string[]?} [options.filteredByTags=null] - Tags to filter characters by
3248 * @param {boolean} [options.preferCurrentChar=true] - Whether to prefer the current character(s)
3249 * @param {boolean} [options.quiet=false] - Whether to suppress warnings
3250 * @returns {any?} - The found character or null if not found
3251 */
3252export function findChar({ name = null, allowAvatar = true, insensitive = true, filteredByTags = null, preferCurrentChar = true, quiet = false } = {}) {
3253 const matches = (char) => (allowAvatar && char.avatar === name) || (insensitive ? equalsIgnoreCaseAndAccents(char.name, name) : char.name === name);
3254
3255 // Filter characters by tags if provided
3256 let filteredCharacters = characters;
3257 if (filteredByTags) {
3258 filteredCharacters = characters.filter(char => {
3259 const charTags = getTagsList(char.avatar, false);
3260 return filteredByTags.every(tagName => charTags.some(x => x.name == tagName));
3261 });
3262 }
3263
3264 // Get the current character(s)
3265 /** @type {any[]} */
3266 const currentChars = selected_group ? groups.find(group => group.id === selected_group)?.members.map(member => filteredCharacters.find(char => char.avatar === member))
3267 : [filteredCharacters.find(char => characters[this_chid]?.avatar === char.avatar)];
3268
3269 // If we have a current char and prefer it, return that if it matches
3270 if (preferCurrentChar) {
3271 const preferredCharSearch = currentChars.filter(matches);
3272 if (preferredCharSearch.length > 1) {
3273 if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`);
3274 else console.warn(`Multiple characters found for name "${name}". Returning the first match.`);
3275 }
3276 if (preferredCharSearch.length) {
3277 return preferredCharSearch[0];
3278 }
3279 }
3280
3281 // If allowAvatar is true, search by avatar first
3282 if (allowAvatar && name) {
3283 const characterByAvatar = filteredCharacters.find(char => char.avatar === name);
3284 if (characterByAvatar) {
3285 return characterByAvatar;
3286 }
3287 }
3288
3289 // Search for matching characters by name
3290 const matchingCharacters = name ? filteredCharacters.filter(matches) : filteredCharacters;
3291 if (matchingCharacters.length > 1) {
3292 if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`);
3293 else console.warn(`Multiple characters found for name "${name}". Returning the first match.`);
3294 }
3295
3296 return matchingCharacters[0] || null;
3297}
3298
3299/**
3300 * Gets the index of a character based on the character object
3301 * @param {object} char - The character object to find the index for
3302 * @throws {Error} If the character is not found
3303 * @returns {number} The index of the character in the characters array
3304 */
3305export function getCharIndex(char) {
3306 if (!char) throw new Error('Character is undefined');
3307 const index = characters.findIndex(c => c.avatar === char.avatar);
3308 if (index === -1) throw new Error(`Character not found: ${char.avatar}`);
3309 return index;
3310}
3311
3312export async function sendMessageAs(args, text) {3216export async function sendMessageAs(args, text) {
3313 if (!text) {3217 if (!text) {
3314 return '';3218 return '';
public/scripts/tags.js+1 -3
@@ -15,7 +15,7 @@ import {
15import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js';15import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js';
1616
17import { groupCandidatesFilter, groups, selected_group } from './group-chats.js';17import { groupCandidatesFilter, groups, selected_group } from './group-chats.js';
18import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay, flashHighlight, equalsIgnoreCaseAndAccents, includesIgnoreCaseAndAccents, removeFromArray, getFreeName, debounce } from './utils.js';18import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay, flashHighlight, equalsIgnoreCaseAndAccents, includesIgnoreCaseAndAccents, removeFromArray, getFreeName, debounce, findChar } from './utils.js';
19import { power_user } from './power-user.js';19import { power_user } from './power-user.js';
20import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';20import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
21import { SlashCommand } from './slash-commands/SlashCommand.js';21import { SlashCommand } from './slash-commands/SlashCommand.js';
@@ -26,7 +26,6 @@ import { debounce_timeout } from './constants.js';
26import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';26import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
27import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';27import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';
28import { renderTemplateAsync } from './templates.js';28import { renderTemplateAsync } from './templates.js';
29import { findChar } from './slash-commands.js';
3029
31export {30export {
32 TAG_FOLDER_TYPES,31 TAG_FOLDER_TYPES,
@@ -51,7 +50,6 @@ export {
51 removeTagFromMap,50 removeTagFromMap,
52};51};
5352
54/** @typedef {import('../scripts/popup.js').Popup} Popup */
55/** @typedef {import('../script.js').Character} Character */53/** @typedef {import('../script.js').Character} Character */
5654
57const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';55const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';
public/scripts/utils.js+74 -1
@@ -1,10 +1,12 @@
1import { getContext } from './extensions.js';1import { getContext } from './extensions.js';
2import { getRequestHeaders } from '../script.js';2import { characters, getRequestHeaders, this_chid } from '../script.js';
3import { isMobile } from './RossAscends-mods.js';3import { isMobile } from './RossAscends-mods.js';
4import { collapseNewlines } from './power-user.js';4import { collapseNewlines } from './power-user.js';
5import { debounce_timeout } from './constants.js';5import { debounce_timeout } from './constants.js';
6import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';6import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
7import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';7import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
8import { getTagsList } from './tags.js';
9import { groups, selected_group } from './group-chats.js';
810
9/**11/**
10 * Pagination status string template.12 * Pagination status string template.
@@ -2110,3 +2112,74 @@ export async function showFontAwesomePicker(customList = null) {
2110 }2112 }
2111 return null;2113 return null;
2112}2114}
2115
2116/**
2117 * Finds a character by name, with optional filtering and precedence for avatars
2118 * @param {object} [options={}] - The options for the search
2119 * @param {string?} [options.name=null] - The name to search for
2120 * @param {boolean} [options.allowAvatar=true] - Whether to allow searching by avatar
2121 * @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive
2122 * @param {string[]?} [options.filteredByTags=null] - Tags to filter characters by
2123 * @param {boolean} [options.preferCurrentChar=true] - Whether to prefer the current character(s)
2124 * @param {boolean} [options.quiet=false] - Whether to suppress warnings
2125 * @returns {any?} - The found character or null if not found
2126 */
2127export function findChar({ name = null, allowAvatar = true, insensitive = true, filteredByTags = null, preferCurrentChar = true, quiet = false } = {}) {
2128 const matches = (char) => (allowAvatar && char.avatar === name) || (insensitive ? equalsIgnoreCaseAndAccents(char.name, name) : char.name === name);
2129
2130 // Filter characters by tags if provided
2131 let filteredCharacters = characters;
2132 if (filteredByTags) {
2133 filteredCharacters = characters.filter(char => {
2134 const charTags = getTagsList(char.avatar, false);
2135 return filteredByTags.every(tagName => charTags.some(x => x.name == tagName));
2136 });
2137 }
2138
2139 // Get the current character(s)
2140 /** @type {any[]} */
2141 const currentChars = selected_group ? groups.find(group => group.id === selected_group)?.members.map(member => filteredCharacters.find(char => char.avatar === member))
2142 : [filteredCharacters.find(char => characters[this_chid]?.avatar === char.avatar)];
2143
2144 // If we have a current char and prefer it, return that if it matches
2145 if (preferCurrentChar) {
2146 const preferredCharSearch = currentChars.filter(matches);
2147 if (preferredCharSearch.length > 1) {
2148 if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`);
2149 else console.warn(`Multiple characters found for name "${name}". Returning the first match.`);
2150 }
2151 if (preferredCharSearch.length) {
2152 return preferredCharSearch[0];
2153 }
2154 }
2155
2156 // If allowAvatar is true, search by avatar first
2157 if (allowAvatar && name) {
2158 const characterByAvatar = filteredCharacters.find(char => char.avatar === name);
2159 if (characterByAvatar) {
2160 return characterByAvatar;
2161 }
2162 }
2163
2164 // Search for matching characters by name
2165 const matchingCharacters = name ? filteredCharacters.filter(matches) : filteredCharacters;
2166 if (matchingCharacters.length > 1) {
2167 if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`);
2168 else console.warn(`Multiple characters found for name "${name}". Returning the first match.`);
2169 }
2170
2171 return matchingCharacters[0] || null;
2172}
2173
2174/**
2175 * Gets the index of a character based on the character object
2176 * @param {object} char - The character object to find the index for
2177 * @throws {Error} If the character is not found
2178 * @returns {number} The index of the character in the characters array
2179 */
2180export function getCharIndex(char) {
2181 if (!char) throw new Error('Character is undefined');
2182 const index = characters.findIndex(c => c.avatar === char.avatar);
2183 if (index === -1) throw new Error(`Character not found: ${char.avatar}`);
2184 return index;
2185}