// ==UserScript== // @name Sexy.AI to SillyTavern origin // @namespace http://tampermonkey.net/ // @version 1.4 // @description Sync between Sexy.AI and SillyTavern with improved mobile support // @author You // @match https://sexy.ai/workflow* // @match https://staticui.sexy.ai/* // @match http://ducninh.top:8000/* // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function() { 'use strict'; GM_addStyle(` #sexyai-panel input, #sexyai-panel select { background-color: #444; color: white; background-color: black; border: none; padding: 5px; margin: 5px 0; white-space: nowrap; } #sexyai-panel button { background-color: #444; color: white; border: none; padding: 5px 10px; cursor: pointer; } #sexyai-panel button:hover { background-color: #555; } `); const isSexyAI = window.location.href.includes('staticui.sexy.ai'); const isSillyTavern = window.location.href.includes('ducninh.top:8000'); let panel; function addSexyAIButton() { const targetElement = document.querySelector('#option_toggle_AN'); if (targetElement) { const newElement = document.createElement('a'); newElement.id = 'option_toggle_sexyai'; const icon = document.createElement('i'); icon.className = 'fa-lg fa-solid fa-images'; newElement.appendChild(icon); const span = document.createElement('span'); span.setAttribute('data-i18n', "SexyAI Tools"); span.textContent = 'SexyAI Tools'; newElement.appendChild(span); targetElement.parentNode.insertBefore(newElement, targetElement.nextSibling); newElement.addEventListener('click', showSexyAIPanel); } } function createSexyAIPanel() { const panel = document.createElement('div'); panel.id = 'sexyai-panel'; panel.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: black; color: white; padding: 20px; border: 1px solid white; z-index: 10000; display: none; overflow-y: auto; max-height: 80vh; `; let html = `

SexyAI Tools

`; if (isSexyAI) { html += `
`; } if (isSillyTavern) { html += `

`; } panel.innerHTML = html; document.body.appendChild(panel); panel.querySelector('#close-panel').addEventListener('click', hideSexyAIPanel); if (isSexyAI) { panel.querySelector('#get-prompt').addEventListener('click', () => { const prompt = GM_getValue('st_prompt', null); if (prompt) { const positiveInput = document.querySelector('textarea') || document.querySelector('input[type="text"]'); if (positiveInput) { positiveInput.value = prompt; const event = new Event('input', { bubbles: true }); positiveInput.dispatchEvent(event); GM_setValue('st_prompt', null); alert('Prompt added!'); } } else { alert('No prompt found. Copy from SillyTavern first.'); } hideSexyAIPanel(); }); } return panel; } function showSexyAIPanel() { if (!panel) { panel = createSexyAIPanel(); } panel.style.display = 'block'; } function hideSexyAIPanel() { if (panel) { panel.style.display = 'none'; } } if (isSexyAI) { const checkInterval = setInterval(() => { if (document.querySelector('#option_toggle_AN')) { clearInterval(checkInterval); addSexyAIButton(); } }, 1000); document.addEventListener('click', (e) => { if (e.target.tagName === 'IMG') { const markdownUrls = [`![alt-text](${e.target.src})`]; GM_setValue('sexyai_images', markdownUrls.join('\n')); alert('Image copied! Switch to SillyTavern tab.'); } }, true); } if (isSillyTavern) { const checkInterval = setInterval(() => { if (document.querySelector('#option_toggle_AN')) { clearInterval(checkInterval); addSexyAIButton(); } }, 1000); const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.classList?.contains('mes')) { const messageText = node.querySelector('.mes_text'); if (messageText && !messageText.querySelector('.sexyai-tools')) { const syncButton = createButton('📥 Sync Image', () => { const markdownUrls = GM_getValue('sexyai_images', null); if (!markdownUrls) { alert('No images found. Click an image in Sexy.AI first.'); return; } const editButton = node.querySelector('.mes_edit'); if (editButton) { editButton.click(); setTimeout(() => { const textarea = document.getElementById('curEditTextarea'); if (textarea) { textarea.value = textarea.value + '\n' + markdownUrls; setTimeout(() => { const confirmButton = node.querySelector('.mes_edit_done'); if (confirmButton) { confirmButton.click(); GM_setValue('sexyai_images', null); alert('Images added successfully!'); } }, 100); } }, 100); } }); const sendPromptButton = createButton('📤 Send Prompt', () => { const text = messageText.textContent; const match = text.match(/image###([^#]+)###/); if (match) { const prompt = match[1].trim(); GM_setValue('st_prompt', prompt); alert('Prompt copied! Click "Get Prompt" in Sexy.AI tab'); } else { alert('No valid prompt found. Message should contain image###prompt###'); } }); const container = document.createElement('div'); container.className = 'sexyai-tools'; container.appendChild(syncButton); container.appendChild(sendPromptButton); messageText.appendChild(container); } } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); } function createButton(text, onClick) { const button = document.createElement('button'); button.className = 'sexyai-button'; button.textContent = text; button.addEventListener('click', onClick); button.style.cssText = ` margin: 5px; padding: 5px 10px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; `; return button; } })();