// ==UserScript==
// @name Danbooru Tags Select to Export
// @name:zh-TW Danbooru 標籤導出器
// @name:zh-HK Danbooru 標籤導出器
// @name:zh-CN Danbooru 标签导出器
// @name:ja Danbooru Tags Select to Export
// @namespace https://github.com/FSpark/Danbooru-Tags-Exporter
// @supportURL https://github.com/FSpark/Danbooru-Tags-Exporter/issues
// @homepageURL https://github.com/FSpark/Danbooru-Tags-Exporter
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @version 0.3.4
// @description Select specified tags and copy to clipboard, for Stable Diffusion WebUI or NovelAI to use.
// @description:zh-TW 選擇指定標籤並複製到剪貼板,供Stable Diffusion WebUI或NovelAI等使用
// @description:zh-HK 選擇指定標籤並複製到剪貼板,供Stable Diffusion WebUI或NovelAI等使用
// @description:zh-CN 选择指定标签并复制到剪贴板,供Stable Diffusion WebUI或NovelAI等使用
// @description:ja 指定したタグを選択し、クリップボードにコピーして、Stable Diffusion WebUIやNovelAIなどで使用することができます。
// @author FSpark
// @match https://danbooru.donmai.us/posts/*
// @match https://safebooru.donmai.us/posts/*
// @match https://aibooru.online/posts/*
// @match https://betabooru.donmai.us/posts/*
// @match https://gelbooru.com/index.php?page=post&s=view&id=*
// @icon https://www.google.com/s2/favicons?sz=64&domain=donmai.us
// @grant GM.setClipboard
// @grant GM.notification
// @grant GM.addStyle
// @license AGPL-3.0
// ==/UserScript==
(function () {
'use strict';
if(location.host == "gelbooru.com"){
GM_addStyle(`#tags-exporter-setting h2{ font-size:1.2em}
#tags-exporter-setting { margin: 0px 10px 0px 10px; }
#tags-exporter-container button, #tag-list button {padding: 0.1em 0.3em; margin-bottom:0.1em}
#tags-exporter-container { margin: 0px 10px 0px 10px; }
ul.tag-list li{margin: 2px 0 }
#tags-exporter-setting label{margin: .25em; line-height: 1.5em;}
.tag-weight {width: 3em; margin-left: .25em}`);
}else{
GM_addStyle(`#tags-exporter-setting button, #tag-list button {padding: 0.25em 0.75em;}
#tags-exporter-setting label{margin: .25em; line-height: 1.5em;}
.tag-weight {width: 3em; margin-left: .25em}`);
}
let SettingPanel = document.createElement('section');
SettingPanel.id = "tags-exporter-setting";
SettingPanel.innerHTML = `
<h2>Tags Export Settings</h2>
<input type="checkbox" id="bracket-escape" checked/><label for="bracket-escape"><code>(</code> <code>)</code> -> <code>\\(</code> <code>\\)</code></label><br>
<input type="checkbox" id="set-weight" /><label for="set-weight">Setting weights</label><br>
<div>
<input type="radio" name="use-bracket" id="round-brackets" value="0" checked/><label for="round-brackets">Using ( )</label>
<input type="radio" name="use-bracket" id="curly-brackets" value="-1"/><label for="curly-brackets">Using { }</label></div>
`
let Container = document.createElement('div');
Container.id = "tags-exporter-container";
Container.innerHTML = `<button name="select_all">All</button>
<button name="select_none">None</button>
<button name="invert_select">Invert</button>
<button name="export">Export</button>
`
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function insertBefore(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode);
}
if(location.host == "gelbooru.com"){
insertBefore(SettingPanel, document.querySelector(".aside>.tag-list"))
insertBefore(Container, document.querySelector(".aside>.tag-list"))
}else{
insertAfter(SettingPanel, document.querySelector("#search-box"))
insertAfter(Container, document.querySelector("#tags-exporter-setting > h2"))
}
function addBrackets(prompts,isRound,n){
let l,r;
if(n==0)
return prompts
else if(n>0){
if(isRound){
l='('
r=')'}
else{
l='{'
r='}'
}
}else{
l='['
r=']'
}
n=Math.abs(n)
return l.repeat(n).concat(prompts,r.repeat(n))
}
function exportTags(target){
let tags = []
let bracket_escape = document.getElementById("bracket-escape").checked
let set_weight = document.getElementById("set-weight").checked
let round_brackets = document.getElementById("round-brackets").checked
document.querySelectorAll(target).forEach((e) => {
let prompts = e.value
if(bracket_escape)
prompts = prompts.replaceAll(`(`,`\\(`).replaceAll(`)`,`\\)`)
if(set_weight){
prompts = addBrackets(prompts,round_brackets,e.nextSibling.value)
}
tags.push(prompts)
})
let res = tags.join(", ")
GM.setClipboard(res)
GM.notification(`${tags.length} tag(s) were copied.`, "Danbooru Tags Exporter")
}
function insertButtons(target){
let head = document.querySelector(`h3.${target}-list`)
if(!head) return;
let buttonContainer = Container.cloneNode(true)
buttonContainer.id = `${target}-buttons`
insertAfter(buttonContainer, head)
document.querySelectorAll(`.${target}-list>li`).forEach((e) => {
let chk = document.createElement('input');
chk.type = "checkbox"
chk.name = `${target}s`
chk.value = e.dataset.tagName.replaceAll("_", " ")
e.insertBefore(chk, e.firstChild)
let nbr = document.createElement('input');
nbr.type = "number"
nbr.name = `${target}s-weight`
nbr.className = "tag-weight"
nbr.value = 0
nbr.hidden = true
insertAfter(nbr,chk)
})
buttonContainer.querySelector("[name='select_all']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked = true;
}
};
buttonContainer.querySelector("[name='select_none']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked = false;
}
};
buttonContainer.querySelector("[name='invert_select']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked == true ? items[i].checked = false : items[i].checked = true;
}
};
buttonContainer.querySelector("[name='export']").onclick = function () {
exportTags(`[name=${target}s]:checked`)
};
}
function insertButtonsGelbooru(target){
let head = document.querySelector(`.${target}`)
if(!head) return;
head = head.previousSibling;
let buttonContainer = Container.cloneNode(true)
buttonContainer.id = `${target}-buttons`
insertAfter(buttonContainer, head)
document.querySelectorAll(`.${target}`).forEach((e) => {
let chk = document.createElement('input');
chk.type = "checkbox"
chk.name = `${target}s`
chk.value = e.querySelector(':scope>a').innerText;
e.insertBefore(chk, e.firstChild)
let nbr = document.createElement('input');
nbr.type = "number"
nbr.name = `${target}s-weight`
nbr.className = "tag-weight"
nbr.value = 0
nbr.hidden = true
insertAfter(nbr,chk)
})
buttonContainer.querySelector("[name='select_all']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked = true;
}
};
buttonContainer.querySelector("[name='select_none']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked = false;
}
};
buttonContainer.querySelector("[name='invert_select']").onclick = function () {
var items = document.getElementsByName(`${target}s`);
for (var i = 0; i < items.length; i++) {
items[i].checked == true ? items[i].checked = false : items[i].checked = true;
}
};
buttonContainer.querySelector("[name='export']").onclick = function () {
exportTags(`[name=${target}s]:checked`)
};
}
["artist-tag","character-tag","copyright-tag","general-tag"].forEach((t)=>insertButtons(t));
["tag-type-artist","tag-type-character","tag-type-copyright","tag-type-metadata","tag-type-general"].forEach((t)=>insertButtonsGelbooru(t));
Container.querySelector("[name='select_all']").onclick = function () {
var items = document.querySelectorAll("#tag-list input[type='checkbox']")
for (var i = 0; i < items.length; i++) {
items[i].checked = true;
}
};
Container.querySelector("[name='select_none']").onclick = function () {
var items = document.querySelectorAll("#tag-list input[type='checkbox']")
for (var i = 0; i < items.length; i++) {
items[i].checked = false;
}
};
Container.querySelector("[name='invert_select']").onclick = function () {
var items = document.querySelectorAll("#tag-list input[type='checkbox']")
for (var i = 0; i < items.length; i++) {
items[i].checked == true ? items[i].checked = false : items[i].checked = true;
}
};
Container.querySelector("[name='export']").onclick = function () {
exportTags(`#tag-list input[type='checkbox']:checked`)
};
document.getElementById("set-weight").onchange = function (e){
if(e.target.checked){
document.querySelectorAll("#tag-list input[type='number']").forEach((e)=>e.hidden=false)
}else{
document.querySelectorAll("#tag-list input[type='number']").forEach((e)=>e.hidden=true)
}
}
})();