// ==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 = [``];
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;
}
})();