const TAB_PREFIX_LIST = ['txt2img', 'img2img']; const MODEL_TYPE_LIST: ['textual_inversion', 'hypernetworks', 'checkpoints', 'lora', 'lycoris'] = [ 'textual_inversion', 'hypernetworks', 'checkpoints', 'lora', 'lycoris', ]; const MODEL_TYPE = { checkpoints: 'ckp', hypernetworks: 'hyper', lora: 'lora', lycoris: 'lycoris', textual_inversion: 'ti', }; const CARDID_SUFFIX = 'cards'; // CSS const BTN_MARGIN = '0'; const BTN_FONT_SIZE = '15px'; const BTN_THUMB_FONT_SIZE = '100%'; const BTN_THUMB_DISPLAY = 'inline'; const BTN_THUMB_POS = 'static'; const BTN_THUMB_BACKGROUND_IMAGE = 'none'; const BTN_THUMB_BACKGROUND = 'rgba(0, 0, 0, 0.8)'; const CH_BTN_TXTS = new Set(['🌐', '💡', '🏷️']); const styleButton = (node: HTMLElement, isThumbMode: boolean) => { if (isThumbMode) { node.style.display = BTN_THUMB_DISPLAY; node.style.fontSize = BTN_THUMB_FONT_SIZE; node.style.position = BTN_THUMB_POS; node.style.backgroundImage = BTN_THUMB_BACKGROUND_IMAGE; } else { node.style.fontSize = BTN_FONT_SIZE; node.style.margin = BTN_MARGIN; } }; const updateCardForCivitai = () => { if (!document.querySelector('#tab_civitai_helper')) return; const replacePreviewText = getTranslation('replace preview') || 'replace preview'; // Get component const chAlwaysDisplayCkb = document.querySelector( '#ch_always_display_ckb input', ) as HTMLInputElement; const chShowButtonOnThumbCkb = document.querySelector( '#ch_show_btn_on_thumb_ckb input', ) as HTMLInputElement; const chAlwaysDisplay = chAlwaysDisplayCkb?.checked || false; const chShowButtonOnThumb = chShowButtonOnThumbCkb?.checked || false; // Change all "replace preview" into an icon let extraNetworkId = ''; let extraNetworkNode: any; let metadataButton: any; let additionalNode: any; let replacePreviewButton: any; let ulNode: any; let searchTermNode: any; let searchTerm = ''; let modelType = ''; let cards; let needToAddButtons = false; let isThumbMode = false; // Get current tab for (const activeTabType of TAB_PREFIX_LIST) { for (const jsModelType of MODEL_TYPE_LIST) { modelType = MODEL_TYPE[jsModelType]; // Get model_type for python side extraNetworkId = `${activeTabType}_${jsModelType}_${CARDID_SUFFIX}`; extraNetworkNode = document.querySelector(`#${extraNetworkId}`); // Check if extra network node exists if (extraNetworkNode === undefined) continue; // Check if extr network is under thumbnail mode isThumbMode = false; if (extraNetworkNode?.className === 'extra-network-thumbs') isThumbMode = true; // Get all card nodes cards = extraNetworkNode?.querySelectorAll('.card'); if (!cards) continue; for (const card of cards) { if (card.querySelectorAll('.actions .additional a').length > 2) continue; // Metadata_buttoncard metadataButton = card.querySelector('.metadata-button'); // Additional node additionalNode = card.querySelector('.actions .additional'); // Get ul node, which is the parent of all buttons ulNode = card.querySelector('.actions .additional ul'); if (ulNode === undefined) { ulNode = document.createElement('ul'); additionalNode.append(ulNode); } // Replace preview text button replacePreviewButton = card.querySelector('.actions .additional a'); if (replacePreviewButton === undefined) { replacePreviewButton = document.createElement('a'); additionalNode.append(replacePreviewButton); } // Check thumb mode if (isThumbMode && additionalNode) { additionalNode.style.display = undefined; if (chShowButtonOnThumb) { ulNode.style.background = BTN_THUMB_BACKGROUND; } else { // Reset ulNode.style.background = undefined; // Remove existed buttons if (ulNode) { // Find all .a child nodes const atags = ulNode?.querySelectorAll('a'); if (!atags) continue; for (const atag of atags) { // Reset display atag.style.display = undefined; // Remove extension's button if (CH_BTN_TXTS.has(atag.innerHTML)) { // Need to remove atag.remove(); } else { // Do not remove, just reset atag.innerHTML = replacePreviewText; atag.style.display = undefined; atag.style.fontSize = undefined; atag.style.position = undefined; atag.style.backgroundImage = undefined; } } // Also remove br tag in ul const brtag = ulNode.querySelector('br'); if (brtag) brtag.remove(); } // Just reset and remove nodes, do nothing else continue; } } else { // Full preview mode additionalNode.style.display = chAlwaysDisplay ? 'block' : undefined; // Remove br tag const brtag = ulNode.querySelector('br'); if (brtag) brtag.remove(); } // Change replace preview text button into icon if (replacePreviewButton?.innerHTML !== '🖼️') { needToAddButtons = true; replacePreviewButton.innerHTML = '🖼️'; styleButton(replacePreviewButton, isThumbMode); } if (!needToAddButtons) continue; // Search_term node // Search_term = subfolder path + model name + ext searchTermNode = card.querySelector('.actions .additional .search_term'); if (!searchTermNode) return; // Get search_term searchTerm = searchTermNode.innerHTML; if (!searchTerm) continue; // Then we need to add 3 buttons to each ul node: const openUrlNode = document.createElement('a'); openUrlNode.href = '#'; openUrlNode.innerHTML = '🌐'; styleButton(openUrlNode, isThumbMode); openUrlNode.title = "Open this model's civitai url"; openUrlNode.setAttribute( 'onclick', `open_model_url(event, '${modelType}', '${searchTerm}')`, ); const addTriggerWordsNode = document.createElement('a'); addTriggerWordsNode.href = '#'; addTriggerWordsNode.innerHTML = '💡'; styleButton(addTriggerWordsNode, isThumbMode); addTriggerWordsNode.title = 'Add trigger words to prompt'; addTriggerWordsNode.setAttribute( 'onclick', `add_trigger_words(event, '${modelType}', '${searchTerm}')`, ); const usePreviewPromptNode = document.createElement('a'); usePreviewPromptNode.href = '#'; usePreviewPromptNode.innerHTML = '🏷️'; styleButton(usePreviewPromptNode, isThumbMode); usePreviewPromptNode.title = 'Use prompt from preview image'; usePreviewPromptNode.setAttribute( 'onclick', `use_preview_prompt(event, '${modelType}', '${searchTerm}')`, ); // Add to card ulNode.append(openUrlNode); // Add br if metadata_button exists if (isThumbMode && metadataButton) ulNode.append(document.createElement('br')); ulNode.append(addTriggerWordsNode); ulNode.append(usePreviewPromptNode); } } } }; export default () => { let retryTimes = 0; const fixInterval = setInterval(() => { console.debug('🤯 [civitai helper] update card for civitai'); const checkDom = document.querySelector('#txt2img_lora_cards'); if (checkDom || retryTimes > 10) { updateCardForCivitai(); clearInterval(fixInterval); } retryTimes++; }, 1000); };