Gelbooru Tag Copyer

Quickly copy tags from gelbooru's post so you can use thoes tags to generate AI images.

Από την 01/01/2023. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         Gelbooru Tag Copyer
// @namespace    https://greasyfork.org/zh-CN/scripts/439308
// @version      1.2
// @description  Quickly copy tags from gelbooru's post so you can use thoes tags to generate AI images.
// @author       3989364
// @include      *://gelbooru.com/index.php*
// @icon         https://gelbooru.com/favicon.ico
// @grant        none
// @license MIT

// ==/UserScript==

(function () {
  "use strict";
  const tagListEle = document.querySelector("#tag-list");

  const DEFAULT_CHECKED_TAGS = ["general", "copyright", "character"];
  const DEFAULT_QUALITY_TAG = `((masterpiece)), (((best quality))), ((ultra-detailed)), ((illustration)), (an extremely delicate and beautiful), `;

  const attriTags = ["hair", "eyes", "dress", "sleeves", "bow"];

  const EXCLUDED_TAGS = ["censor", "out-of-frame", "speech bubble"];

  function initUI(tagListEle, defultCheckedTags) {
    /**
     * @param tagListEle
     * @returns [String, ...]
     */
    function parseTags(tagListEle) {
      const tags = Object.create(null);

      tagListEle
        .querySelectorAll('li[class^="tag-type"]')
        .forEach((tagItem) => {
          const tagEle = tagItem.querySelector(".sm-hidden + a");
          const tag = tagEle.textContent;

          const tagCount = parseInt(tagEle.nextElementSibling.textContent) || 0;

          const tagType = tagItem.className.replace("tag-type-", "");
          if (!tags[tagType]) {
            tags[tagType] = [];
          }

          tags[tagType].push({ tag, tagCount });
        });

      // sort general tags by count
      if ("general" in tags) {
        tags["general"].sort((a, b) => b.tagCount - a.tagCount);
      }

      for (const key in tags) {
        tags[key] = tags[key].map((item) => item.tag);
      }

      // add attr tag
      tags["attrTag"] = [];
      return tags;
    }

    function createTagCheckbox(tagType, checked = false) {
      const el = document.createElement("div");

      el.innerHTML = `
        <input
        type="checkbox"
        name="${tagType}"
        ${checked ? "checked" : ""}>${tagType}
    `;

      el.style.marginBottom = "0.15rem";
      el.style.display = "flex";
      el.style.alignItems = "center";

      return [el, el.querySelector("input")];
    }

    const tagCheckboxList = [];
    const tagsObj = parseTags(tagListEle);

    // emphasis character
    if ("character" in tagsObj) {
      tagsObj["character"] = tagsObj["character"].map(
        (character) => `(${character}:1.2)`
      );
    }

    // exclude special tags & resort tag
    if ("general" in tagsObj) {
      tagsObj["attrTag"] = tagsObj["general"].filter((tag) =>
        attriTags.some((attrTag) => tag.includes(attrTag))
      );

      tagsObj["general"] = tagsObj["general"]
        .filter(
          (name) => !EXCLUDED_TAGS.some((exTags) => name.includes(exTags))
        )
        .filter((tag) => !attriTags.some((attrTag) => tag.includes(attrTag)));
    }

    const tagCheckboxContainer = document.createElement("li");

    for (const tagType in tagsObj) {
      if (tagType === "attrTag") {
        continue;
      }

      const [wrapper, ckbox] = createTagCheckbox(
        tagType,
        defultCheckedTags.includes(tagType)
      );

      tagCheckboxContainer.appendChild(wrapper);
      tagCheckboxList.push(ckbox);
    }

    const copyBtn = document.createElement("button");

    copyBtn.innerText = "Copy";
    tagCheckboxContainer.appendChild(copyBtn);
    tagListEle.insertBefore(tagCheckboxContainer, tagListEle.firstChild);

    return {
      copyBtn,
      tagCheckboxList,
      tagsObj,
    };
  }

  const ui = initUI(tagListEle, DEFAULT_CHECKED_TAGS);

  const tagTypeOrderMap = {
    character: 1,
    copyright: 1,
    artist: 1,
    attrTag: 1,
    general: 2,
  };

  ui.copyBtn.addEventListener("click", () => {
    const checkedTagsType = ui.tagCheckboxList
      .filter((item) => item.checked)
      .map((item) => item.name);

    checkedTagsType.push("attrTag");

    // sort tags type
    checkedTagsType.sort((a, b) => {
      return tagTypeOrderMap[a] - tagTypeOrderMap[b];
    });

    const tags =
      DEFAULT_QUALITY_TAG +
      "\n" +
      checkedTagsType
        .map((type) => {
          return ui.tagsObj[type].join(", ");
        })
        .join(",\n");

    prompt("copied tags:", tags);
  });
})();