e621 Page Result Grabber

Adds buttons below the tag searchbar to copy queries for the page result post ID's to the clipboard.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu betiği yüklemek için bir betik yöneticisi eklentisi yüklemeniz gerekecektir.

(Zaten bir betik yöneticim var, hadi yükleyelim!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         e621 Page Result Grabber
// @namespace    https://greasyfork.org/users/1582013
// @version      1.03
// @description  Adds buttons below the tag searchbar to copy queries for the page result post ID's to the clipboard.
// @author       FreekyCreep
// @license      GNU GPLv3
// @match        https://e621.net/posts?*
// @match        https://e926.net/posts?*
// @grant        GM_addStyle
// ==/UserScript==
(function () {
    "use strict";
    //site elements
    const TAGS = document.getElementById("tags");
    const SEARCH_CONTROLS = document.querySelector(".search-controls");
    const THUMBNAILS = document.querySelectorAll(".posts-container > .thumbnail");

    //queries
    const tagLimit = 40;
    const queryCount = Math.ceil(THUMBNAILS.length / tagLimit);
    const queries = new Array(queryCount).fill("");

    //functions
    function buttonClickHandler(e) {
        let button = e.target;
        let queryIndex = Number(button.dataset.index);
        button.disabled = true;
        if (!queries[queryIndex]) {
            const start = queryIndex * tagLimit;
            const end = (queryIndex + 1 === queryCount) ? THUMBNAILS.length : start + tagLimit;
            for (let i = start; i < end; i++) queries[queryIndex] += "~id:" + THUMBNAILS[i].dataset.id + " ";
        }
        navigator.clipboard.writeText(queries[queryIndex])
            .then(() => {
                button.classList.add("active");
                button.textContent = getRandomRjSmiley();
            }).catch(err =>
                console.error("Failed to copy query:", err)
            );
        setTimeout(() => {
            button.disabled = false;
            button.classList.remove("active");
            button.textContent = buttonText + (queryIndex + 1);
        }, 1500);
    }
    function thumbnailClickHandler(e) {
        if (!e.ctrlKey || !e.shiftKey || e.button || e.target === e.currentTarget || e.target.tagName === "HR") return;
        e.preventDefault();
        let target = e.target;
        while (target.parentNode !== e.currentTarget) target = target.parentNode;
        TAGS.value += " -id:" + target.dataset.id;
        const scrollY = window.scrollY;
        TAGS.style.height = 0;
        TAGS.style.height = TAGS.scrollHeight + "px";
        window.scrollBy(0, scrollY - window.scrollY);
    }
    function getRandomRjSmiley() {
        if (Math.random() < 0.000001) return "(':}',"; //signal for help (1/1,000,000, 0.0001%)
        let smiley = "";
        smiley += (Math.random() < 0.01) ? "'," : ",'"; //ears (1% chance to be reversed)
        smiley += (Math.random() < 0.05) ? "}" : "{"; //face pattern (5% chance to be devil horns)
        smiley += (Math.random() < 0.05) ? ">" : ""; //eyebrows (5% chance to add anger brows)
        switch (Math.random() * 10 | 0) { //eyes
            default: //0,1,2
                smiley += ":"; //30%
                break;
            case 3:
            case 4:
                smiley += ";"; //20%
                break;
            case 5:
            case 6:
                smiley += "B"; //20%
                break;
            case 7:
            case 8:
                smiley += "x"; //20%
                break;
            case 9:
                smiley += "="; //10%
                break;
        }
        smiley += (Math.random() < 0.001) ? "*" : "'"; //nose (0.1% chance to be star)
        switch (Math.random() * 10 | 0) { //mouth
            default: //0,1
                smiley += "D"; //20%
                break;
            case 2:
            case 3:
                smiley += "3"; //20%
                break;
            case 4:
                smiley += "))"; //10%
                break;
            case 5:
                smiley += "]"; //10%
                break;
            case 6:
                smiley += "P"; //10%
                break;
            case 7:
                smiley += "o"; //10%
                break;
            case 8:
                smiley += "v"; //10%
                break;
            case 9:
                smiley += "|"; //10%
                break;
        }
        smiley += (Math.random() < 0.05) ? "c" : ""; //chin paw (5% chance)
        return smiley;
    }

    //DOM+events
    const buttonText = (queryCount < 4) ? ",'{:') " : "";
    for (let i = 0; i < queryCount; i++) {
        let button = document.createElement("button");
        button.className = "st-button freeky-button";
        button.textContent = buttonText + (i + 1);
        button.title = "Copy query " + (i + 1);
        button.dataset.index = i;
        button.addEventListener("click", buttonClickHandler);
        SEARCH_CONTROLS.append(button);
    }
    for (let i = tagLimit; i < THUMBNAILS.length; i += tagLimit) THUMBNAILS[i].before(document.createElement("hr"));
    document.querySelector(".posts-container").addEventListener("click", thumbnailClickHandler);

    //styles
    GM_addStyle(`
        .freeky-button {
            height: auto;
            width: auto;
            padding: 0 0 2px 0 !important;
            display: flex;
            justify-content: center;
            align-items: center;
            min-width: 34px;
            font-size: 13.6px;
            letter-spacing: -1px;
            line-height: 0;
        }
        .posts-container > hr {
            grid-column: 1 / -1;
            margin: 12px;
            border-style: dashed;
        }
        body[data-st-fullscreen='true'] .posts-index-stats {
            margin-right: ${43 * queryCount + 120}px !important;
        }
    `);
    if (queryCount < 4) return;
    GM_addStyle(`
        body[data-st-fullscreen='false'] .search-controls {
            gap: ${8 - queryCount}px !important;
        }
        body[data-st-fullscreen='false'] .freeky-button {
            min-width: ${48 - 4 * queryCount}px !important;
        }
    `);
})();