Separates and formats Stable Diffusion prompts from EXIF data on jimpl.com
// ==UserScript==
// @name Jimpl SD Prompt Parser & Copier
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Separates and formats Stable Diffusion prompts from EXIF data on jimpl.com
// @author qualia
// @match *://jimpl.com/results/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=jimpl.com
// @license MIT
// @grant none
// ==/UserScript==
(function() {
'use strict';
function createSectionBox(title, content, showCopy = true) {
if (!content) return null;
const container = document.createElement('div');
container.style.marginBottom = '12px';
container.style.padding = '12px';
container.style.backgroundColor = 'rgba(255, 255, 255, 0.05)';
container.style.border = '1px solid rgba(255, 255, 255, 0.1)';
container.style.borderRadius = '6px';
container.style.position = 'relative';
const header = document.createElement('strong');
header.innerText = title;
header.style.display = 'block';
header.style.marginBottom = '8px';
header.style.color = '#e0e0e0';
header.style.fontSize = '14px';
const textNode = document.createElement('div');
textNode.innerText = content;
textNode.style.wordBreak = 'break-word';
textNode.style.color = '#aaaaaa';
textNode.style.fontSize = '13px';
textNode.style.lineHeight = '1.4';
textNode.style.maxHeight = '200px';
textNode.style.overflowY = 'auto';
container.appendChild(header);
if (showCopy) {
const copyBtn = document.createElement('button');
copyBtn.innerText = 'Copy';
copyBtn.style.position = 'absolute';
copyBtn.style.top = '8px';
copyBtn.style.right = '8px';
copyBtn.style.padding = '4px 10px';
copyBtn.style.cursor = 'pointer';
copyBtn.style.backgroundColor = '#3b82f6';
copyBtn.style.color = 'white';
copyBtn.style.border = 'none';
copyBtn.style.borderRadius = '4px';
copyBtn.style.fontSize = '12px';
copyBtn.style.fontWeight = 'bold';
copyBtn.style.transition = 'background-color 0.2s';
copyBtn.onmouseover = () => copyBtn.style.backgroundColor = '#2563eb';
copyBtn.onmouseout = () => copyBtn.style.backgroundColor = '#3b82f6';
copyBtn.onclick = () => {
navigator.clipboard.writeText(content).then(() => {
const originalText = copyBtn.innerText;
copyBtn.innerText = 'Copied!';
copyBtn.style.backgroundColor = '#10b981';
setTimeout(() => {
copyBtn.innerText = originalText;
copyBtn.style.backgroundColor = '#3b82f6';
}, 1500);
});
};
container.appendChild(copyBtn);
}
container.appendChild(textNode);
return container;
}
function parseAndInject() {
const rows = Array.from(document.querySelectorAll('tr'));
const targetRow = rows.find(tr => {
const firstCell = tr.children[0];
if (!firstCell) return false;
const text = firstCell.textContent.trim();
return text === 'UserComment' || text === 'parameters';
});
if (!targetRow || targetRow.dataset.parsed === 'true') return;
const valueCell = targetRow.children[1];
if (!valueCell) return;
const fullText = valueCell.textContent.trim();
if (!fullText.includes('Steps:')) return;
targetRow.dataset.parsed = 'true';
let positive = "";
let negative = "";
let settings = "";
const negativeIndex = fullText.indexOf("Negative prompt:");
const stepsIndex = fullText.lastIndexOf("Steps:");
if (negativeIndex !== -1 && stepsIndex !== -1 && negativeIndex < stepsIndex) {
positive = fullText.substring(0, negativeIndex).trim();
negative = fullText.substring(negativeIndex + 16, stepsIndex).trim();
settings = fullText.substring(stepsIndex).trim();
} else if (negativeIndex !== -1) {
positive = fullText.substring(0, negativeIndex).trim();
negative = fullText.substring(negativeIndex + 16).trim();
} else if (stepsIndex !== -1) {
positive = fullText.substring(0, stepsIndex).trim();
settings = fullText.substring(stepsIndex).trim();
} else {
positive = fullText;
}
valueCell.innerHTML = '';
valueCell.style.padding = '10px';
const posBox = createSectionBox('Positive Prompt', positive, true);
const negBox = createSectionBox('Negative Prompt', negative, true);
const setBox = createSectionBox('Settings', settings, false);
if (posBox) valueCell.appendChild(posBox);
if (negBox) valueCell.appendChild(negBox);
if (setBox) valueCell.appendChild(setBox);
}
const observer = new MutationObserver((mutations) => {
parseAndInject();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
window.addEventListener('load', parseAndInject);
parseAndInject();
})();