您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Chants script for NovelAI
当前为
// ==UserScript== // @name Chants for NovelAI // @namespace https://www6.notion.site/dc99953d5f04405c893fba95dace0722 // @version 9.4 // @description Chants script for NovelAI // @author SenY // @match https://novelai.net/image // @icon https://www.google.com/s2/favicons?sz=64&domain=novelai.net // @grant none // @license MIT // ==/UserScript== (function () { const colors = { "-1": ["red", "maroon"], "0": ["lightblue", "dodgerblue"], "1": ["gold", "goldenrod"], "3": ["violet", "darkorchid"], "4": ["lightgreen", "darkgreen"], "5": ["tomato", "darksalmon"], "6": ["red", "maroon"], "7": ["whitesmoke", "black"], "8": ["seagreen", "darkseagreen"] } const getChantURL = function (force) { if (force === true) { localStorage.removeItem("chantURL"); } let chantURL = localStorage.getItem("chantURL") || prompt("Input your chants json url.\nThe URL must be a Cors-enabled server (e.g., gist.github.com).", "https://gist.githubusercontent.com/vkff5833/989808aadebf8648831955cdf2a7b3e3/raw/yuuri.json"); if (chantURL) { localStorage.setItem("chantURL", chantURL); } return chantURL; } let chantURL = getChantURL(null); let ui = document.createElement("div"); ui.style.padding = "0.5rem"; let seedButton; const saveJpeg = function () { let seed = Array.from(seedButton.querySelectorAll("span")).map(x => x.textContent).find(x => x.search(/^[0-9]*$/) == 0); let filename = seed + ".jpg"; let url = document.querySelector('img[src]').getAttribute("src"); let blob = fetch(url).then(r => r.blob()).then(blob => { let fileReader = new FileReader(); fileReader.onload = function () { let dataURI = this.result; let canvas = document.createElement("canvas"); let context = canvas.getContext("2d"); let image = new Image(); image.src = dataURI; image.onload = function () { canvas.width = image.width; canvas.height = image.height; context.drawImage(image, 0, 0); let JPEG = canvas.toDataURL("image/jpeg", document.getElementById("jpegQuality").value - 0); let link = document.createElement('a'); link.href = JPEG; link.download = filename; link.click(); }; } fileReader.readAsDataURL(blob); }); } let jpegButton = document.createElement("div"); let jpegQuality = document.createElement("div"); jpegButton.textContent = "JPEG"; jpegButton.addEventListener("click", () => { saveJpeg(); }); jpegQuality.textContent = ""; let input = document.createElement("input"); input.value = 0.85; input.setAttribute("id", "jpegQuality"); input.setAttribute("type", "number"); input.setAttribute("step", "0.01"); input.setAttribute("max", "1"); input.setAttribute("min", "0"); input.style.maxWidth = "3rem"; jpegQuality.appendChild(input); setInterval(() => { document.querySelectorAll("textarea[placeholder]").forEach(el => { if (el.offsetParent && !ui.offsetParent) { el.parentElement.appendChild(ui); } }); seedButton = Array.from(document.querySelectorAll('span[style]')).find(x => x.textContent.trim().search(/^[0-9]*(seed|シード)/i) == 0); if ( seedButton ) { seedButton = seedButton.closest("button"); seedButton.classList.forEach(x => { jpegButton.classList.add(x); jpegQuality.classList.add(x); }); seedButton.parentNode.insertBefore(jpegButton, seedButton); seedButton.parentNode.insertBefore(jpegQuality, seedButton); } }, 500); let allTags = []; fetch("https://gist.githubusercontent.com/vkff5833/275ccf8fa51c2c4ba767e2fb9c653f9a/raw/danbooru.json", { method: "GET", }).then((response) => response.json()) .then((data) => { allTags = data; fetch("https://gist.githubusercontent.com/vkff5833/275ccf8fa51c2c4ba767e2fb9c653f9a/raw/danbooru_wiki.slim.json", { method: "GET", }).then((response) => response.json()) .then((wikiPages) => { allTags = allTags.map(x => { let wikiPage = wikiPages.find(y => y.name == x.name); if (wikiPage) { x.terms = x.terms.concat(wikiPage.otherNames); } return x; }); }); }); let chants = []; const getTargetTag = function () { let textarea = document.querySelector("textarea[placeholder]"); if (textarea) { let oldTags = textarea.value.split(",").map(x => x.trim()); let beforeTags = textarea.value.slice(0, textarea.selectionEnd).split(",").map(x => x.trim()); let targetTag = beforeTags[beforeTags.length - 2]; targetTag = oldTags[oldTags.indexOf(targetTag) + 1]; return targetTag.trim(); } else { return null; } }; const Crease = function (value) { const getTagPower = function (tag) { let tagPower = 0; tagPower += tag.split("").filter(x => x == "{").length; tagPower -= tag.split("").filter(x => x == "[").length; return tagPower; } let textarea = document.querySelector("textarea[placeholder]"); let selectionEnd = textarea.selectionEnd; let oldTags = textarea.value.split(",").map(x => x.trim()); let targetTag = getTargetTag(); let tags = []; if (targetTag) { oldTags.forEach(tag => { if (tag == targetTag) { let tagPower = getTagPower(targetTag) + value; tag = tag.replace(/[\{\}\[\]]/g, "", tag); for (let i = 0; i < Math.abs(tagPower); i++) { if (tagPower > 0) { tag = '{' + tag + '}'; } if (tagPower < 0) { tag = '[' + tag + ']'; } } } tags.push(tag); }); tags = tags.filter(x => x); textarea.textContent = tags.join(", ").replace(/^, /g, ""); textarea.value = tags.join(", ").replace(/^, /g, "") + ", "; textarea._valueTracker = ''; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.focus(); textarea.selectionEnd = selectionEnd; } } const Append = function (key, value) { let targetTag = getTargetTag(); let text; let newTags; let textarea = document.querySelector("textarea[placeholder]"); let selectionEnd = textarea.selectionEnd; let oldTags = textarea.value.split(",").map(x => x.trim()); if (key) { let chant = chants.find(x => x.name == key.trim()); if (chant) { newTags = chant.content.split(",").map(x => x.trim()); } } if (value) { newTags = [value.trim()]; } if (newTags.length) { //let tags = oldTags.concat(newTags).filter(x => x); let tags = []; oldTags.forEach(tag => { if (tag == targetTag) { if (key) { tags.push(tag); } newTags.forEach(newTag => { tags.push(newTag); }); } else { tags.push(tag); } }); if (!targetTag) { tags = tags.concat(newTags); } tags = Array.from(new Set(tags.filter(x => x))); textarea.textContent = tags.join(", ").replace(/^, /g, ""); textarea.value = tags.join(", ").replace(/^, /g, "") + ", "; // Special Thanks to https://fate.5ch.net/test/read.cgi/liveuranus/1702763225/730 textarea._valueTracker = ''; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.focus(); textarea.selectionEnd = selectionEnd; } } const Suggest = function () { let textarea = document.querySelector("textarea[placeholder]"); if (textarea) { let tags = textarea.value.split(",").map(x => x.trim()); if (tags.length) { let targetTag = getTargetTag().replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); document.getElementById("suggestionField").textContent = ""; let suggestions = []; if (targetTag) { suggestions = allTags.filter(x => x.name.search(targetTag.replace(/_/g, " ").replace(/[\{\}\[\]\\]/g, "")) >= 0).slice(0, 10); suggestions = suggestions.concat(allTags.filter(x => { return x.terms.map(y => y.search(targetTag.replace(/_/g, " ").replace(/[\{\}\[\]\\]/g, "")) >= 0).includes(true); }).slice(0, 20)); } let done = new Set(); suggestions.forEach(tag => { if (!done.has(tag.name)) { let button = document.createElement("button"); let count = tag.coumt; if (count > 1000) { count /= 1000; count = Math.round(count * 10) / 10; count += "k"; } button.textContent = tag.name + " (" + count + ")"; button.style.color = colors[tag.category][1]; button.setAttribute("title", tag.terms.map(x => x.trim()).filter(x => x).join(", ")); button.addEventListener("click", function () { Append(null, tag.name); }); document.getElementById("suggestionField").appendChild(button); if (textarea.value.split(",").map(y => y.trim().replace(/_/g, " ").replace(/[\{\}\[\]\\]/g, "")).includes(tag.name.replace(/_/g, " "))) { button.style.opacity = 0.5; } } done.add(tag.name); }); } } } const Build = function () { ui.textContent = ""; let hr = document.createElement("hr"); hr.style.color = "grey"; hr.style.borderWidth = "2px"; let optionField = document.createElement("div"); let chantsField = document.createElement("div"); let suggestionField = document.createElement("div"); suggestionField.setAttribute("id", "suggestionField"); ui.appendChild(optionField); ui.appendChild(hr.cloneNode()); ui.appendChild(chantsField); ui.appendChild(hr.cloneNode()); ui.appendChild(suggestionField); let resetButton = document.createElement("button"); resetButton.textContent = "Reset Chants URL"; resetButton.style.color = "red"; resetButton.addEventListener("click", function () { chantURL = getChantURL(true); Build(); }); optionField.appendChild(resetButton); let clearButton = document.createElement("button"); clearButton.textContent = "Clear Suggestion"; clearButton.style.color = "red"; clearButton.addEventListener("click", function () { document.getElementById("suggestionField").textContent = ""; }); optionField.appendChild(clearButton); fetch(chantURL, { method: "GET", }).then((response) => response.json()) .then((data) => { chants = data; chants.forEach(chant => { let button = document.createElement("button"); button.textContent = chant.name; button.style.color = colors[chant.color][1]; button.addEventListener("click", function () { Append(chant.name, null); }); chantsField.appendChild(button); }); }); } let init = false; document.addEventListener("DOMContentLoaded", function () { if (init === false) { Build(); init = true; } }); document.addEventListener("keydown", function (e) { if (e.ctrlKey == true && e.code == "ArrowUp") { e.preventDefault(); Crease(1); } if (e.ctrlKey == true && e.code == "ArrowDown") { e.preventDefault(); Crease(-1); } }); document.addEventListener("keyup", function (e) { if (e.target.tagName == "TEXTAREA") { Suggest(); } }); document.addEventListener("click", function (e) { if (e.target.tagName == "TEXTAREA") { Suggest(); } }); })();