Danbooru tags buttons

Return +/- buttons to Danbooru

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Danbooru tags buttons
// @namespace    danbooru
// @version      0.5
// @description  Return +/- buttons to Danbooru
// @author       Jallot
// @include      http*://*danbooru.donmai.us/posts*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    let currentTags = document.getElementById("tags").value.split(" ").filter(String);

    function addTagToSearch(tag, negative=false){
        var newTags = [...currentTags]
        if (negative){
            tag = "-" + tag;
        }
        newTags.push(tag);
        return newTags.join("+");
    };


    const tagList = document.querySelectorAll('ul li[class*="tag-type-"]');
    for (const tag of tagList) {
        const tagLinks = tag.querySelectorAll("a");
        const tagNameNode = tagLinks[1];
        const tagUrl = new URLSearchParams(tagNameNode.href.split('?')[1]);
        const tagName = tagUrl.get("tags");
        var plusLink = document.createElement('a');
        plusLink.href = '/posts?tags=' + addTagToSearch(tagName);
        plusLink.textContent = '+';
        var minusLink = document.createElement('a');
        minusLink.href = '/posts?tags=' + addTagToSearch(tagName, true);
        minusLink.textContent = '-';
        tagNameNode.parentNode.insertBefore(plusLink, tagNameNode);
        tagNameNode.parentNode.insertBefore(document.createTextNode(" "), tagNameNode);
        tagNameNode.parentNode.insertBefore(minusLink, tagNameNode);
        tagNameNode.parentNode.insertBefore(document.createTextNode(" "), tagNameNode);
    };

    const tagBox = document.getElementById("tag-box");
    if (tagBox) {
        const ageSection = document.createElement("section");
        ageSection.id = "age-filter-box";

        const heading = document.createElement("h2");
        heading.textContent = "Age Filter";
        ageSection.appendChild(heading);

        const customDiv = document.createElement("div");
        customDiv.style.cssText = "display:flex;flex-direction:column;gap:4px;";

        const rangeRow = document.createElement("div");
        rangeRow.style.cssText = "display:flex;align-items:center;gap:4px;";

        const fromLabel = document.createElement("span");
        fromLabel.textContent = "from";

        const fromInput = document.createElement("input");
        fromInput.type = "number";
        fromInput.min = "0";
        fromInput.placeholder = "0";
        fromInput.style.cssText = "width:50px;";

        const toLabel = document.createElement("span");
        toLabel.textContent = "to";

        const toInput = document.createElement("input");
        toInput.type = "number";
        toInput.min = "0";
        toInput.placeholder = "0";
        toInput.style.cssText = "width:50px;";

        rangeRow.appendChild(fromLabel);
        rangeRow.appendChild(fromInput);
        rangeRow.appendChild(toLabel);
        rangeRow.appendChild(toInput);

        const unitSelect = document.createElement("select");
        for (const [val, label] of [["d","days"],["w","weeks"],["mo","months"],["y","years"]]) {
            const opt = document.createElement("option");
            opt.value = val;
            opt.textContent = label;
            unitSelect.appendChild(opt);
        }

        // Restore saved age filter state
        const savedAge = sessionStorage.getItem("age-filter");
        if (savedAge) {
            const m = savedAge.match(/^age:(\d+)(\w+)\.\.(\d+)(\w+)$/);
            if (m) {
                fromInput.value = m[1];
                toInput.value = m[3];
                unitSelect.value = m[2];
            }
        }

        const addBtn = document.createElement("button");
        addBtn.textContent = "Search";
        addBtn.addEventListener("click", function() {
            const from = fromInput.value;
            const to = toInput.value;
            const unit = unitSelect.value;
            if (from === "" || to === "") return;
            const ageTag = "age:" + from + unit + ".." + to + unit;
            sessionStorage.setItem("age-filter", ageTag);
            const tagsWithoutAge = currentTags.filter(t => !t.startsWith("age:"));
            tagsWithoutAge.push(ageTag);
            window.location.href = "/posts?tags=" + tagsWithoutAge.join("+");
        });

        customDiv.appendChild(rangeRow);
        customDiv.appendChild(unitSelect);
        customDiv.appendChild(addBtn);
        ageSection.appendChild(customDiv);

        // Shift buttons — only shown when age filter is active
        if (savedAge) {
            const shiftDiv = document.createElement("div");
            shiftDiv.style.cssText = "display:flex;flex-wrap:wrap;gap:4px;margin-top:4px;";

            function shiftAge(direction) {
                const from = parseInt(fromInput.value);
                const to = parseInt(toInput.value);
                const unit = unitSelect.value;
                if (isNaN(from) || isNaN(to)) return;
                const span = to - from;
                const newFrom = Math.max(0, from + direction * span);
                const newTo = newFrom + span;
                const ageTag = "age:" + newFrom + unit + ".." + newTo + unit;
                sessionStorage.setItem("age-filter", ageTag);
                const tagsWithoutAge = currentTags.filter(t => !t.startsWith("age:"));
                tagsWithoutAge.push(ageTag);
                window.location.href = "/posts?tags=" + tagsWithoutAge.join("+");
            }

            const shiftLabel = document.createElement("span");
            shiftLabel.textContent = "Date shifting";
            shiftLabel.style.cssText = "width:100%;";
            shiftDiv.appendChild(shiftLabel);

            const prevBtn = document.createElement("button");
            prevBtn.textContent = "-1";
            prevBtn.addEventListener("click", () => shiftAge(-1));

            const nextBtn = document.createElement("button");
            nextBtn.textContent = "+1";
            nextBtn.addEventListener("click", () => shiftAge(+1));

            shiftDiv.appendChild(prevBtn);
            shiftDiv.appendChild(nextBtn);
            ageSection.appendChild(shiftDiv);
        }

        tagBox.after(ageSection);
    }
})();