From d7bad6335c34744a7c58875c1d075d61f69cc333 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Sun, 29 Sep 2024 03:20:01 +0200 Subject: [PATCH] Refactor findChar to utils - Refactor and move finChar to utils, instead of slashcommands function - Refactor scrapers to use actual init functionality --- public/script.js | 3 +- .../scripts/extensions/expressions/index.js | 3 +- public/scripts/scrapers.js | 21 ++-- public/scripts/slash-commands.js | 98 +------------------ public/scripts/tags.js | 4 +- public/scripts/utils.js | 75 +++++++++++++- 6 files changed, 94 insertions(+), 110 deletions(-) diff --git a/public/script.js b/public/script.js index 6d93bc03b..b0ca08f6a 100644 --- a/public/script.js +++ b/public/script.js @@ -230,7 +230,7 @@ import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros import { currentUser, setUserControls } from './scripts/user.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; -import { ScraperManager } from './scripts/scrapers.js'; +import { initScrapers, ScraperManager } from './scripts/scrapers.js'; import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; import { SlashCommand } from './scripts/slash-commands/SlashCommand.js'; import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js'; @@ -959,6 +959,7 @@ async function firstLoadInit() { initCfg(); initLogprobs(); initInputMarkdown(); + initScrapers(); doDailyExtensionUpdatesCheck(); await hideLoader(); await fixViewport(); diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index dc8ce8ba6..edb19ff05 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -2,7 +2,7 @@ import { callPopup, eventSource, event_types, generateRaw, getRequestHeaders, ma import { dragElement, isMobile } from '../../RossAscends-mods.js'; import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; import { loadMovingUIState, power_user } from '../../power-user.js'; -import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition } from '../../utils.js'; +import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar } from '../../utils.js'; import { hideMutedSprites } from '../../group-chats.js'; import { isJsonSchemaSupported } from '../../textgen-settings.js'; import { debounce_timeout } from '../../constants.js'; @@ -12,7 +12,6 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from ' import { isFunctionCallingSupported } from '../../openai.js'; import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; -import { findChar } from '../../slash-commands.js'; export { MODULE_NAME }; const MODULE_NAME = 'expressions'; diff --git a/public/scripts/scrapers.js b/public/scripts/scrapers.js index 86d2ba567..09d42edb1 100644 --- a/public/scripts/scrapers.js +++ b/public/scripts/scrapers.js @@ -13,6 +13,7 @@ import { isValidUrl } from './utils.js'; * @property {string} description * @property {string} iconClass * @property {boolean} iconAvailable + * @property {() => Promise} [init=null] * @property {() => Promise} isAvailable * @property {() => Promise} scrape */ @@ -42,6 +43,10 @@ export class ScraperManager { return; } + if (scraper.init) { + scraper.init(); + } + ScraperManager.#scrapers.push(scraper); } @@ -462,7 +467,9 @@ class YouTubeScraper { this.description = 'Download a transcript from a YouTube video.'; this.iconClass = 'fa-brands fa-youtube'; this.iconAvailable = true; + } + async init() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'yt-script', callback: async (args, url) => { @@ -564,9 +571,11 @@ class YouTubeScraper { } } -ScraperManager.registerDataBankScraper(new FileScraper()); -ScraperManager.registerDataBankScraper(new Notepad()); -ScraperManager.registerDataBankScraper(new WebScraper()); -ScraperManager.registerDataBankScraper(new MediaWikiScraper()); -ScraperManager.registerDataBankScraper(new FandomScraper()); -ScraperManager.registerDataBankScraper(new YouTubeScraper()); +export function initScrapers() { + ScraperManager.registerDataBankScraper(new FileScraper()); + ScraperManager.registerDataBankScraper(new Notepad()); + ScraperManager.registerDataBankScraper(new WebScraper()); + ScraperManager.registerDataBankScraper(new MediaWikiScraper()); + ScraperManager.registerDataBankScraper(new FandomScraper()); + ScraperManager.registerDataBankScraper(new YouTubeScraper()); +} diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 4be6bca7b..1e961beaa 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -55,7 +55,7 @@ import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockStat import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js'; import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; import { decodeTextTokens, getAvailableTokenizers, getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, selectTokenizer } from './tokenizers.js'; -import { debounce, delay, equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js'; +import { debounce, delay, equalsIgnoreCaseAndAccents, findChar, isFalseBoolean, isTrueBoolean, showFontAwesomePicker, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js'; import { registerVariableCommands, resolveVariable } from './variables.js'; import { background_settings } from './backgrounds.js'; import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; @@ -68,10 +68,8 @@ import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashComma import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; -import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js'; import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js'; import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js'; -import { getTagsList } from './tags.js'; export { executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand, }; @@ -2969,29 +2967,6 @@ async function deleteMessagesByNameCallback(_, name) { return ''; } -function findCharacterIndex(name) { - const matchTypes = [ - (a, b) => a === b, - (a, b) => a.startsWith(b), - (a, b) => a.includes(b), - ]; - - const exactAvatarMatch = characters.findIndex(x => x.avatar === name); - - if (exactAvatarMatch !== -1) { - return exactAvatarMatch; - } - - for (const matchType of matchTypes) { - const index = characters.findIndex(x => matchType(x.name.toLowerCase(), name.toLowerCase())); - if (index !== -1) { - return index; - } - } - - return -1; -} - async function goToCharacterCallback(_, name) { if (!name) { console.warn('WARN: No character name provided for /go command'); @@ -3238,77 +3213,6 @@ export function getNameAndAvatarForMessage(character, name = null) { }; } -/** - * Finds a character by name, with optional filtering and precedence for avatars - * @param {object} [options={}] - The options for the search - * @param {string?} [options.name=null] - The name to search for - * @param {boolean} [options.allowAvatar=true] - Whether to allow searching by avatar - * @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive - * @param {string[]?} [options.filteredByTags=null] - Tags to filter characters by - * @param {boolean} [options.preferCurrentChar=true] - Whether to prefer the current character(s) - * @param {boolean} [options.quiet=false] - Whether to suppress warnings - * @returns {any?} - The found character or null if not found - */ -export function findChar({ name = null, allowAvatar = true, insensitive = true, filteredByTags = null, preferCurrentChar = true, quiet = false } = {}) { - const matches = (char) => (allowAvatar && char.avatar === name) || (insensitive ? equalsIgnoreCaseAndAccents(char.name, name) : char.name === name); - - // Filter characters by tags if provided - let filteredCharacters = characters; - if (filteredByTags) { - filteredCharacters = characters.filter(char => { - const charTags = getTagsList(char.avatar, false); - return filteredByTags.every(tagName => charTags.some(x => x.name == tagName)); - }); - } - - // Get the current character(s) - /** @type {any[]} */ - const currentChars = selected_group ? groups.find(group => group.id === selected_group)?.members.map(member => filteredCharacters.find(char => char.avatar === member)) - : [filteredCharacters.find(char => characters[this_chid]?.avatar === char.avatar)]; - - // If we have a current char and prefer it, return that if it matches - if (preferCurrentChar) { - const preferredCharSearch = currentChars.filter(matches); - if (preferredCharSearch.length > 1) { - if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`); - else console.warn(`Multiple characters found for name "${name}". Returning the first match.`); - } - if (preferredCharSearch.length) { - return preferredCharSearch[0]; - } - } - - // If allowAvatar is true, search by avatar first - if (allowAvatar && name) { - const characterByAvatar = filteredCharacters.find(char => char.avatar === name); - if (characterByAvatar) { - return characterByAvatar; - } - } - - // Search for matching characters by name - const matchingCharacters = name ? filteredCharacters.filter(matches) : filteredCharacters; - if (matchingCharacters.length > 1) { - if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`); - else console.warn(`Multiple characters found for name "${name}". Returning the first match.`); - } - - return matchingCharacters[0] || null; -} - -/** - * Gets the index of a character based on the character object - * @param {object} char - The character object to find the index for - * @throws {Error} If the character is not found - * @returns {number} The index of the character in the characters array - */ -export function getCharIndex(char) { - if (!char) throw new Error('Character is undefined'); - const index = characters.findIndex(c => c.avatar === char.avatar); - if (index === -1) throw new Error(`Character not found: ${char.avatar}`); - return index; -} - export async function sendMessageAs(args, text) { if (!text) { return ''; diff --git a/public/scripts/tags.js b/public/scripts/tags.js index 447e01ded..9a1950d0a 100644 --- a/public/scripts/tags.js +++ b/public/scripts/tags.js @@ -15,7 +15,7 @@ import { import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js'; import { groupCandidatesFilter, groups, selected_group } from './group-chats.js'; -import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay, flashHighlight, equalsIgnoreCaseAndAccents, includesIgnoreCaseAndAccents, removeFromArray, getFreeName, debounce } from './utils.js'; +import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay, flashHighlight, equalsIgnoreCaseAndAccents, includesIgnoreCaseAndAccents, removeFromArray, getFreeName, debounce, findChar } from './utils.js'; import { power_user } from './power-user.js'; import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { SlashCommand } from './slash-commands/SlashCommand.js'; @@ -26,7 +26,6 @@ import { debounce_timeout } from './constants.js'; import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js'; import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; import { renderTemplateAsync } from './templates.js'; -import { findChar } from './slash-commands.js'; export { TAG_FOLDER_TYPES, @@ -51,7 +50,6 @@ export { removeTagFromMap, }; -/** @typedef {import('../scripts/popup.js').Popup} Popup */ /** @typedef {import('../script.js').Character} Character */ const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter'; diff --git a/public/scripts/utils.js b/public/scripts/utils.js index 9fc1e1e99..9ddd0413c 100644 --- a/public/scripts/utils.js +++ b/public/scripts/utils.js @@ -1,10 +1,12 @@ import { getContext } from './extensions.js'; -import { getRequestHeaders } from '../script.js'; +import { characters, getRequestHeaders, this_chid } from '../script.js'; import { isMobile } from './RossAscends-mods.js'; import { collapseNewlines } from './power-user.js'; import { debounce_timeout } from './constants.js'; import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; +import { getTagsList } from './tags.js'; +import { groups, selected_group } from './group-chats.js'; /** * Pagination status string template. @@ -2110,3 +2112,74 @@ export async function showFontAwesomePicker(customList = null) { } return null; } + +/** + * Finds a character by name, with optional filtering and precedence for avatars + * @param {object} [options={}] - The options for the search + * @param {string?} [options.name=null] - The name to search for + * @param {boolean} [options.allowAvatar=true] - Whether to allow searching by avatar + * @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive + * @param {string[]?} [options.filteredByTags=null] - Tags to filter characters by + * @param {boolean} [options.preferCurrentChar=true] - Whether to prefer the current character(s) + * @param {boolean} [options.quiet=false] - Whether to suppress warnings + * @returns {any?} - The found character or null if not found + */ +export function findChar({ name = null, allowAvatar = true, insensitive = true, filteredByTags = null, preferCurrentChar = true, quiet = false } = {}) { + const matches = (char) => (allowAvatar && char.avatar === name) || (insensitive ? equalsIgnoreCaseAndAccents(char.name, name) : char.name === name); + + // Filter characters by tags if provided + let filteredCharacters = characters; + if (filteredByTags) { + filteredCharacters = characters.filter(char => { + const charTags = getTagsList(char.avatar, false); + return filteredByTags.every(tagName => charTags.some(x => x.name == tagName)); + }); + } + + // Get the current character(s) + /** @type {any[]} */ + const currentChars = selected_group ? groups.find(group => group.id === selected_group)?.members.map(member => filteredCharacters.find(char => char.avatar === member)) + : [filteredCharacters.find(char => characters[this_chid]?.avatar === char.avatar)]; + + // If we have a current char and prefer it, return that if it matches + if (preferCurrentChar) { + const preferredCharSearch = currentChars.filter(matches); + if (preferredCharSearch.length > 1) { + if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`); + else console.warn(`Multiple characters found for name "${name}". Returning the first match.`); + } + if (preferredCharSearch.length) { + return preferredCharSearch[0]; + } + } + + // If allowAvatar is true, search by avatar first + if (allowAvatar && name) { + const characterByAvatar = filteredCharacters.find(char => char.avatar === name); + if (characterByAvatar) { + return characterByAvatar; + } + } + + // Search for matching characters by name + const matchingCharacters = name ? filteredCharacters.filter(matches) : filteredCharacters; + if (matchingCharacters.length > 1) { + if (!quiet) toastr.warning(`Multiple characters found for name "${name}" and given conditions.`); + else console.warn(`Multiple characters found for name "${name}". Returning the first match.`); + } + + return matchingCharacters[0] || null; +} + +/** + * Gets the index of a character based on the character object + * @param {object} char - The character object to find the index for + * @throws {Error} If the character is not found + * @returns {number} The index of the character in the characters array + */ +export function getCharIndex(char) { + if (!char) throw new Error('Character is undefined'); + const index = characters.findIndex(c => c.avatar === char.avatar); + if (index === -1) throw new Error(`Character not found: ${char.avatar}`); + return index; +}