Danbooru Ajax Interface

New interface to search images on Booru-style sites.

30.04.2017 itibariyledir. En son verisyonu görün.

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

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 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.

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

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

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.

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

// ==UserScript==
// @name           Danbooru Ajax Interface
// @namespace      http://danbooru.donmai.us
// @description    New interface to search images on Booru-style sites.

// @include        http://danbooru.donmai.us/
// @include        http://danbooru.donmai.us/#*
// @include        http://www.donmai.us/
// @include        http://www.donmai.us/#*
// @include        http://donmai.us/
// @include        http://donmai.us/#*

// @include        https://gelbooru.com/
// @include        https://gelbooru.com/#*
// @include        http://www.gelbooru.com/
// @include        http://www.gelbooru.com/#*

// @include        http://konachan.com/
// @include        http://konachan.com/#*
// @include        http://konachan.net/
// @include        http://konachan.net/#*

// @include        https://yande.re/post
// @include        https://yande.re/post#*

// @version        3.14159265358
// @grant          GM_addStyle
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_deleteValue
// @grant          GM_xmlhttpRequest
// ==/UserScript==

// CONSTANTS
const ratio = ((1 + Math.sqrt(5)) / 2);
const d = document;

// NEW SITES CAN BE ADDED NOW
var sites = [
    {
        name    :   "Danbooru",                                 // Site name
        site    :   "donmai\.us",                               // Regular expression check on current url
        post    :   "/posts.xml",                               // Relative url to xml post API
        note    :   "/notes.xml",                               // Relative url to xml note API
        list    :   "/posts/",                                  // Relative url to post listing
        page    :   "/posts/",                                  // Relative url to post page
        query   :   function(tags, images, page, postid) {      // Query passed to API
                        return (postid ? "?group_by=note&limit=99999&search[post_id]=" + postid : "?tags=" + tags + (page ? "&page=" + page + "&limit=" + images : ""));
                    }
    },
    {
        name    :   "Gelbooru",
        site    :   "(www\.)?gelbooru\.",
        post    :   "/index.php?page=dapi&s=post&q=index",
        note    :   "/index.php?page=dapi&s=note&q=index&post_id=",
        list    :   "/index.php?page=post&s=list",
        page    :   "/index.php?page=post&s=view&id=",
        query   :   function(tags, images, page, postid) {
                        return (postid ? postid : "&tags=" + tags + "&limit=" + images + "&pid=" + (page - 1));
                    }
    },
    {
        name    :   "Konachan",
        site    :   "konachan\.",
        post    :   "/post.xml",
        note    :   "/note.xml?post_id=",
        list    :   "/post/",
        page    :   "/post/show/",
        query   :   function(tags, images, page, postid) {
                        return (postid ? postid : "?tags=" + tags + "&limit=" + images + "&page=" + page);
                    }
    },
    {
        name    :   "Yande.re",
        site    :   "yande\.re",
        post    :   "/post.xml",
        note    :   "/note.xml?post_id=",
        list    :   "/post/",
        page    :   "/post/show/",
        query   :   function(tags, images, page, postid) {
                        return (postid ? postid : "?tags=" + tags + "&limit=" + images + "&page=" + page);
                    }
    }
];

var booru;
for(var i = 0; i < sites.length; i++)
    if(new RegExp(sites[i].site).test(window.location.hostname))
        booru = sites[i];

var alltags = GM_getValue("tags", setDefaults("alltags", sites.length));
var allpage = GM_getValue("page", setDefaults("allpage", sites.length));
var allimages = GM_getValue("images", setDefaults("allimages", sites.length));
var allrating = GM_getValue("rating", setDefaults("allrating", sites.length));

// PAGE CLEANING
while(d.documentElement.firstChild)
    d.documentElement.removeChild(d.documentElement.firstChild);

d.documentElement.appendChild(d.createElement("HEAD"));
d.documentElement.appendChild(d.createElement("BODY"));
d.documentElement.firstChild.appendChild(title = d.createElement("TITLE"));
title.appendChild(d.createTextNode(booru.name));

GM_addStyle("* { transition: all 2s ease-in-out 0s; } body { margin: 4px; } a { text-decoration: none; color: #0000EE; } img { border: 0px; } .thumb { border: 1px solid WhiteSmoke; min-width: 150px; min-height: 150px; max-width: 150px; max-height: 150px; margin: -1px 0px 0px -1px; padding: 1px; display: flex; justify-content: center; align-items: center; font-size: small; overflow: hidden; } .yellow { background-color: LightYellow; } .red { background-color: MistyRose; } .trans { border: 1px solid Black; background-color: LightYellow; position: absolute; }");
GM_deleteValue("columns");

// SCRIPT STARTS HERE
var tags = getValue("alltags", alltags);
var page = getValue("allpage", allpage);
var images = getValue("allimages", allimages);
var rating = getValue("allrating", allrating);

var searchTable, searchTr, searchTd, searchForm, aLink, aTags, aReply, aTableBar, aLeftBar, aCenterBar, aRightBar, aTable, aTr1, aTr2, aTr3, aTd1, aTd2, aTd3, aTd4, aTd5, aTd6, aPage, aRS, aRQ, aRE, aFIT, aSD, aLS, aLQ, aLE, aLF, aLD, aImages, aPrev, aSearch, aNext, aTagsDisplay, imagesLayer, overlay, display, innerDisplay, sampleRate = 1;
var cache = [];
var cacheID = [];
var domParser = new DOMParser();
var xsltText = "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'><xsl:template match='posts'><xsl:copy><xsl:copy-of select='@*'/><xsl:apply-templates/></xsl:copy></xsl:template><xsl:template match='post'><post><xsl:for-each select='*'><xsl:attribute name='{name()}'><xsl:value-of select='text()'/><xsl:if test='@nil'>false</xsl:if></xsl:attribute></xsl:for-each></post></xsl:template></xsl:stylesheet>";

d.body.appendChild(searchTable = d.createElement("TABLE"));
searchTable.appendChild(searchTr = d.createElement("TR"));
searchTr.setAttribute("style", "vertical-align: top;");
searchTr.appendChild(searchTd = d.createElement("TD"));
searchTd.setAttribute("style", "text-align: center;");

searchForm = d.createElement("FORM");
searchForm.addEventListener("submit", function(event) {
    tags = aTags.value;
    page = Math.max(1, parseInt(aPage.value, 10));
    images = Math.max(1, Math.min(parseInt(aImages.value, 10), 100));
    rating = (aRS.checked ? "s" : "") + (aRQ.checked ? "q" : "") + (aRE.checked ? "e" : "") + (aFIT.checked ? "f" : "") + (aSD && aSD.checked ? "d" : "");

    allimages = setValue("images", allimages, images);
    allrating = setValue("rating", allrating, rating);

    search(tags, page);
    event.preventDefault();
}, false);

searchForm.appendChild(aLink = d.createElement("A"));
aLink.setAttribute("href", booru.list);
aLink.setAttribute("tabindex", "1");
aLink.appendChild(d.createTextNode(booru.name));

searchForm.appendChild(d.createElement("BR"));

searchForm.appendChild(aTags = d.createElement("INPUT"));
aTags.setAttribute("type", "text");
aTags.setAttribute("cols", 25);
aTags.setAttribute("value", tags);
aTags.setAttribute("tabindex", "2");
aTags.addEventListener("change", function(event) {
    aPage.value = 1;
}, false);

searchForm.appendChild(d.createElement("P"));

searchForm.appendChild(aReply = d.createElement("SPAN"));
aReply.appendChild(d.createTextNode("Nobody here but us chickens!"));

searchForm.appendChild(d.createElement("P"));

// Slider
aTableBar = d.createElement("TABLE");
aTableBar.appendChild(d.createElement("TR"));
aTableBar.setAttribute("style", "border-collapse: collapse; border: 1px solid Black; width: 100%; padding: 0px");
aLeftBar = d.createElement("TD");
aLeftBar.setAttribute("style", "padding: 0px;");
aTableBar.firstChild.appendChild(aLeftBar);
aCenterBar = d.createElement("TD");
aCenterBar.setAttribute("style", "border: 1px solid Black; padding: 1.5px 0px; background-color: WhiteSmoke; width: 25%; min-width: 1px;");
aTableBar.firstChild.appendChild(aCenterBar);
aRightBar = d.createElement("TD");
aRightBar.setAttribute("style", "padding: 0px; width: 100%;");
aTableBar.firstChild.appendChild(aRightBar);
searchForm.appendChild(aTableBar);

// Search options
aTable = d.createElement("TABLE");
aTr1 = d.createElement("TR");

aTd1 = d.createElement("TD");
aTd1.appendChild(d.createTextNode("Page:"));
aTr1.appendChild(aTd1);

aTd2 = d.createElement("TD");
aPage = d.createElement("INPUT");
aPage.setAttribute("type", "text");
aPage.setAttribute("size", "1");
aPage.setAttribute("value", page);
aPage.setAttribute("tabindex", "3");
aTd2.appendChild(aPage);
aTr1.appendChild(aTd2);

aTd3 = d.createElement("TD");
aTd3.setAttribute("style", "text-align: left;");
aTd3.setAttribute("rowspan", "3");

aRS = d.createElement("INPUT");
aRS.setAttribute("type", "checkbox");
if(/s/.test(rating)) aRS.setAttribute("checked", "checked");
aLS = d.createElement("LABEL");
aLS.appendChild(aRS);
aLS.appendChild(d.createTextNode("Safe"));

aTd3.appendChild(aLS);
aTd3.appendChild(d.createElement("BR"));

aRQ = d.createElement("INPUT");
aRQ.setAttribute("type", "checkbox");
if(/q/.test(rating)) aRQ.setAttribute("checked", "checked");
aLQ = d.createElement("LABEL");
aLQ.appendChild(aRQ);
aLQ.appendChild(d.createTextNode("Questionable"));

aTd3.appendChild(aLQ);
aTd3.appendChild(d.createElement("BR"));

aRE = d.createElement("INPUT");
aRE.setAttribute("type", "checkbox");
if(/e/.test(rating)) aRE.setAttribute("checked", "checked");
aLE = d.createElement("LABEL");
aLE.appendChild(aRE);
aLE.appendChild(d.createTextNode("Explicit"));

aTd3.appendChild(aLE);
aTd3.appendChild(d.createElement("BR"));

if(booru.name == "Danbooru") {
    aSD = d.createElement("INPUT");
    aSD.setAttribute("type", "checkbox");
    if(/d/.test(rating)) aSD.setAttribute("checked", "checked");
    aLD = d.createElement("LABEL");
    aLD.appendChild(aSD);
    aLD.appendChild(d.createTextNode("Show deleted"));

    aTd3.appendChild(aLD);
    aTd3.appendChild(d.createElement("BR"));

    aSD.addEventListener("change", function(event) {
        for(var i in cache)
            d.getElementById("content").insertBefore(cache[i], d.getElementById("content").childNodes[cache[i].style.getPropertyValue("order")]);

        setTimeout(function() { // transitions are stupid
            deletedlist = d.evaluate("//DIV[contains(@class, 'red')]", d, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
            if(aSD.checked) {
                for(var n = 0, deleted = null; deleted = deletedlist.snapshotItem(n++); n) {
                    deleted.style.setProperty("opacity", "1", "");
                    deleted.style.setProperty("padding", "1px", "");
                    deleted.style.setProperty("margin", "-1px 0px 0px -1px", "");
                    deleted.style.setProperty("border-width", "1px", "");
                    deleted.style.setProperty("min-width", "150px", "");
                    deleted.style.setProperty("max-width", "150px", "");
                }
            } else {
                cache.length = 0;
                for(var n = 0, deleted = null; deleted = deletedlist.snapshotItem(n++); n) {
                    deleted.style.setProperty("opacity", "0", "");
                    deleted.style.setProperty("padding", "0px", "");
                    deleted.style.setProperty("margin", "0px", "");
                    deleted.style.setProperty("border-width", "0px", "");
                    deleted.style.setProperty("min-width", "0px", "");
                    deleted.style.setProperty("max-width", "0px", "");
                    cache.push(deleted);
                }
            }
        }, 25);
    }, false);
} else {
    rating.replace("d", "");
}
aTr1.appendChild(aTd3);

aTr2 = d.createElement("TR");

aTd4 = d.createElement("TD");
aTd4.appendChild(d.createTextNode("Images:"));
aTr2.appendChild(aTd4);

aTd5 = d.createElement("TD");
aImages = d.createElement("INPUT");
aImages.setAttribute("type", "text");
aImages.setAttribute("size", "1");
aImages.setAttribute("value", images);
aImages.setAttribute("tabindex", "4");
aTd5.appendChild(aImages);
aTr2.appendChild(aTd5);

aTr3 = d.createElement("TR");

aTd6 = d.createElement("TD");
aTd6.setAttribute("colspan", "2");
aFIT = d.createElement("INPUT");
aFIT.setAttribute("type", "checkbox");
aFIT.setAttribute("tabindex", "5");
if(/f/.test(rating)) aFIT.setAttribute("checked", "checked");
aLF = d.createElement("LABEL");
aLF.appendChild(aFIT);
aLF.appendChild(d.createTextNode("Fit width"));

aTd6.appendChild(aLF);
aTr3.appendChild(aTd6);

aTable.appendChild(aTr1);
aTable.appendChild(aTr2);
aTable.appendChild(aTr3);
searchForm.appendChild(aTable);

searchForm.appendChild(d.createElement("HR"));

searchForm.appendChild(aPrev = d.createElement("INPUT"));
aPrev.setAttribute("type", "button");
aPrev.setAttribute("value", "<");
aPrev.setAttribute("disabled", "disabled");
aPrev.addEventListener("click", function(event) {
    search(tags, --page);
}, false);

searchForm.appendChild(aSearch = d.createElement("INPUT"));
aSearch.setAttribute("type", "submit");
aSearch.setAttribute("value", "Search");

searchForm.appendChild(aNext = d.createElement("INPUT"));
aNext.setAttribute("type", "button");
aNext.setAttribute("value", ">");
aNext.setAttribute("disabled", "disabled");
aNext.addEventListener("click", function(event) {
    search(tags, ++page);
}, false);

searchForm.appendChild(d.createElement("HR"));

searchForm.appendChild(aTagsDisplay = d.createElement("DIV"));
aTagsDisplay.setAttribute("style", "overflow-x: hidden;");

searchTd.appendChild(searchForm);
searchTr.appendChild(imagesLayer = d.createElement("TD"));

fixsize = (searchTd.getBoundingClientRect().right - searchTd.getBoundingClientRect().left) + "px";
searchTd.style.setProperty("min-width", fixsize, "important");
searchTd.style.setProperty("max-width", fixsize, "important");

// "Lightbox"
overlay = d.createElement("DIV");
overlay.setAttribute("style", "display: none; position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; background-color: Black; opacity: 0.8;");
innerDisplay = d.createElement("DIV");
innerDisplay.setAttribute("id", "innerDisplay");
innerDisplay.setAttribute("style", "background-color: White; display: inline-block; padding: 10px; min-width: 200px; min-height: 200px; border-radius: 10px;");
display = d.createElement("TABLE");
display.setAttribute("style", "display: none; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; text-align: center; vertical-align: middle;");
display.appendChild(d.createElement("TR"));
display.firstChild.appendChild(d.createElement("TD"));
display.firstChild.firstChild.appendChild(innerDisplay);

d.body.insertBefore(display, d.body.firstChild);
d.body.insertBefore(overlay, d.body.firstChild);

overlay.addEventListener("click", function(event) {
    if(event.target.id || d.evaluate("ancestor-or-self::div[contains(@id, 'bodynote')]", event.target, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue) return;
    overlay.style.setProperty("display", "none", "");
    display.style.setProperty("display", "none", "");
}, false);

display.addEventListener("click", function(event) {
    if(event.target.id || d.evaluate("ancestor-or-self::div[contains(@id, 'bodynote')]", event.target, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue) return;
    overlay.style.setProperty("display", "none", "");
    display.style.setProperty("display", "none", "");
}, false);

display.addEventListener("dblclick", function(event) {
    overlay.style.setProperty("display", "none", "");
    display.style.setProperty("display", "none", "");
}, false);

// CTRL+S to save image
var keylistener = function(event) {
    if(display.style.getPropertyValue("display") == "none")
        return
    else
    if(event.ctrlKey && event.keyCode == 83) { // CTRL+S
        event.preventDefault();
        event.stopPropagation();
    } else
    if(aFIT.checked && event.keyCode == 37) { // LEFT KEY
        next = openimage.parentNode.previousElementSibling || openimage.parentNode.parentNode.lastChild;
        next.firstChild.firstChild.click();
    } else
    if(aFIT.checked && event.keyCode == 39) { // RIGHT KEY
        next = openimage.parentNode.nextElementSibling || openimage.parentNode.parentNode.firstChild;
        next.firstChild.firstChild.click();
    }
};
var saveimage = function(event) {
    if(event.ctrlKey && event.keyCode == 83) { // CTRL+S
        var sauce = openimage.href.match(/[^\/]+$/)[0];
        if(/%/.test(sauce)) sauce = decodeURIComponent(sauce);
        var imgdown = d.createElement("A");
        imgdown.setAttribute("download", sauce);
        imgdown.setAttribute("href", openimage.href);
        d.body.appendChild(imgdown);
        imgdown.click();
        imgdown.remove();
    }
};
window.addEventListener("keydown", keylistener, false);
window.addEventListener("keyup", saveimage, false);

if(!window.location.origin)
    window.location.origin = (window.location.protocol + "//" + window.location.host);

if(window.location.hash)
    search(window.location.hash.split("#")[1], 1);

var requestPost, requestNote, requestCount, requestCache;

function search(newtags, newpage) {
    if(requestPost)
        requestPost.abort();
    if(requestNote)
        requestNote.abort();
    if(requestCount)
        requestCount.abort();
    if(requestCache)
        requestCache.abort();

    aTags.value = tags = newtags;
    aPage.value = page = newpage;
    aImages.value = images;

    alltags = setValue("tags", alltags, tags);
    allpage = setValue("page", allpage, page);

    aPrev.disabled = (newpage < 2);
    aRS.checked = /s/.test(rating);
    aRQ.checked = /q/.test(rating);
    aRE.checked = /e/.test(rating);

    if(/^sf?d?$/.test(rating))
        newtags += " rating:safe";
    if(/^qf?d?$/.test(rating))
        newtags += " rating:questionable";
    if(/^ef?d?$/.test(rating))
        newtags += " rating:explicit";
    if(/^qef?d?$/.test(rating))
        newtags += " -rating:safe";
    if(/^sef?d?$/.test(rating))
        newtags += " -rating:questionable";
    if(/^sqf?d?$/.test(rating))
        newtags += " -rating:explicit";

    if(imagesLayer.hasChildNodes())
        imagesLayer.removeChild(imagesLayer.firstChild);

    imagesLayer.appendChild(d.createTextNode("Loading..."));
    requestPost = GM_xmlhttpRequest({
        method : "GET",
        url : window.location.origin + booru.post + booru.query(encodeURIComponent(newtags), images, page),
        headers : {
            "Accept" : "application/xml",
            "Cookie" : d.cookie
        },
        overrideMimeType : "application/xml; charset=utf-8",
        onload : function(response) {
            getContent(domParser.parseFromString(response.responseText, "application/xml"), newtags);
        }
    });
}

function showContent(xmldoc) {
    if(imagesLayer.hasChildNodes())
        imagesLayer.removeChild(imagesLayer.firstChild);

    aReply.textContent = "Nobody here but us chickens!";

    var posts = xmldoc.evaluate("posts", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    if(!posts) {
        reason = xmldoc.evaluate("response/@reason", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        if(reason)
            imagesLayer.textContent = reason.nodeValue;
        else
            imagesLayer.textContent = "Something broke.";
        return;
    }
    var post = xmldoc.evaluate("posts/post", xmldoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    if(((parseInt(posts.getAttribute("offset"), 10) + 1) > posts.getAttribute("count")) & posts.getAttribute("count") > 0) {
        search(tags, Math.ceil(parseInt(posts.getAttribute("count"), 10) / images));
        return;
    }

    if(posts.getAttribute("count") > 0) aReply.textContent = "Found " + posts.getAttribute("count") + ", showing " + (parseInt(posts.getAttribute("offset"), 10) + 1) + "-" + (Math.min(posts.getAttribute("count"), parseInt(posts.getAttribute("offset"), 10) + images));
    aLeftBar.style.setProperty("width", (posts.getAttribute("offset") / posts.getAttribute("count") * 100) + "%");
    aCenterBar.style.setProperty("width", (images / posts.getAttribute("count") * 100) + "%");

    aNext.disabled = (page >= Math.ceil(posts.getAttribute("count") / images));

    imagesLayer.appendChild(content = d.createElement("DIV"));
    content.setAttribute("style", "display: flex; flex-flow: row wrap;");
    content.setAttribute("id", "content");
    cache.length = 0;

    for(var i = 0; i < images; i++) {
        data = post.snapshotItem(i);
        if(data) {
            if(!data.getAttribute("preview-file-url")) {
                checkCache(data);
            }
            content.appendChild(thumb = d.createElement("DIV"));
            if(!!data.getAttribute("last-noted-at") && data.getAttribute("last-noted-at") != "false") data.setAttribute("has_notes", "true");

            var image = d.createElement("IMG");
            image.setAttribute("width", (data.getAttribute("preview_width") || "auto"));
            image.setAttribute("height", (data.getAttribute("preview_height") || "auto"));
            image.setAttribute("src", data.getAttribute("preview_url") || data.getAttribute("preview-file-url"));
            image.setAttribute("id", data.getAttribute("id"));
            image.setAttribute("alt", data.getAttribute("tag-string") || data.getAttribute("tags").trim());
            image.setAttribute("title", (data.getAttribute("tag-string") || data.getAttribute("tags").trim()) + " rating:" + data.getAttribute("rating").replace(/e$/, "Explicit").replace(/s$/, "Safe").replace(/q$/, "Questionable") + " score:" + data.getAttribute("score"));

            if(/\.zip$/.test(data.getAttribute("file_url")) || /\.zip$/.test(data.getAttribute("file-url"))) {
                data.setAttribute("file_url", (data.getAttribute("preview_url") || data.getAttribute("preview-file-url")).replace("preview/", "sample/sample-").replace(/\..+$/, ".webm"));
                data.setAttribute("file-url", data.getAttribute("file_url"));
            }
            image.setAttribute("fullsize", data.getAttribute("file_url") || data.getAttribute("file-url"));
            image.setAttribute("fullwidth", data.getAttribute("width") || data.getAttribute("image-width"));
            image.setAttribute("fullheight", data.getAttribute("height") || data.getAttribute("image-height"));
            image.setAttribute("notes", data.getAttribute("has_notes"));
            image.setAttribute("md5", data.getAttribute("md5"));

            // Show tags on sidebar
            image.addEventListener("click", function(event) {
                if(aTagsDisplay.hasChildNodes())
                    aTagsDisplay.removeChild(aTagsDisplay.firstChild);
                aTagsDisplay.appendChild(d.createElement("DIV"));

                var tagnames = this.getAttribute("alt").split(" ");
                for(var t = 0; t < tagnames.length; t++) {
                    var taglink = d.createElement("A");
                    taglink.appendChild(d.createTextNode(tagnames[t]));
                    taglink.setAttribute("href", "#" + tagnames[t]);
                    taglink.addEventListener("click", function(event) {
                        aTags.value = this.textContent;
                        aPage.value = 1;
                        aSearch.click();
                        event.preventDefault();
                    }, false);
                    aTagsDisplay.firstChild.appendChild(taglink);
                    aTagsDisplay.firstChild.appendChild(document.createElement("BR"));
                }

                // CTRL + click to show only the tags
                if(event.ctrlKey) return;

                // "Lightbox" by VIPPER ("How do I jQuery?")
                while(innerDisplay.hasChildNodes())
                    innerDisplay.removeChild(innerDisplay.firstChild);

                if(/\.swf$/.test(this.getAttribute("fullsize"))) {
                    fullsize = d.createElement("EMBED");
                } else if(/\.webm$|\.zip$/.test(this.getAttribute("fullsize"))) {
                    fullsize = d.createElement("VIDEO");
                    fullsize.setAttribute("controls", true);
                    fullsize.setAttribute("loop", true);
                    fullsize.setAttribute("autoplay", true);
                    if(/\.zip$/.test(this.getAttribute("fullsize")))
                        this.setAttribute("fullsize", this.getAttribute("fullsize").replace("data/", "data/sample/sample-").replace(".zip", ".webm"));
                } else {
                    fullsize = d.createElement("IMG");
                    fullsize.addEventListener("click", function(event) {
                        noteDivs = d.evaluate("./DIV[starts-with(@id, 'note')]", innerDisplay, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
                        for(var n = 0, note = null; note = noteDivs.snapshotItem(n++); n) {
                            if(note.style.getPropertyValue("visibility") == "visible")
                                note.style.setProperty("visibility", "hidden", "");
                            else
                                note.style.setProperty("visibility", "visible", "");
                        }
                    }, false);
                }
                fullsize.setAttribute("src", this.getAttribute("fullsize"));
                fullsize.setAttribute("width", this.getAttribute("fullwidth"));
                fullsize.setAttribute("height", this.getAttribute("fullheight"));
                fullsize.setAttribute("id", this.getAttribute("id"));
                fullsize.setAttribute("notes", this.getAttribute("notes"));
                fullsize.setAttribute("md5", this.getAttribute("md5"));
                fullsize.style.setProperty("transition-property", "none", "");

                if(fullsize.getAttribute("notes") == "true") {
                    requestNote = GM_xmlhttpRequest({
                        method : "GET",
                        url : window.location.origin + booru.note + booru.query(null, null, null, fullsize.getAttribute("id")),
                        headers : {
                            "Accept" : "application/xml",
                            "Cookie" : d.cookie
                        },
                        overrideMimeType : "application/xml; charset=utf-8",
                        onload : function(response) {
                            getNotes(domParser.parseFromString(response.responseText, "application/xml"), response.finalUrl);
                        }
                    });
                }

                var pagelink = d.createElement("A");
                pagelink.setAttribute("href", booru.page + fullsize.getAttribute("id"));
                pagelink.appendChild(d.createTextNode(fullsize.getAttribute("id")));

                innerDisplay.appendChild(fullsize);
                innerDisplay.appendChild(d.createElement("BR"));
                innerDisplay.appendChild(pagelink);

                overlay.style.setProperty("display", "", "");
                display.style.setProperty("display", "", "");

                sampleRate = 1;
                var clientwidth = Math.min(d.documentElement.clientWidth, d.body.clientWidth) - 22;
                if(aFIT.checked && this.getAttribute("fullwidth") > clientwidth) {
                    sampleRate = clientwidth / this.getAttribute("fullwidth");
                    fullsize.setAttribute("width", clientwidth);
                    fullsize.setAttribute("height", this.getAttribute("fullheight") * sampleRate);
                }
            }, false);

            var link = d.createElement("A");
            link.setAttribute("href", data.getAttribute("file_url") || data.getAttribute("file-url"));
            link.setAttribute("alt", data.getAttribute("id"));
            link.appendChild(image);
            link.addEventListener("click", function(event) {
                openimage = this;
                event.preventDefault();
            }, false);

            thumb.classList.add("thumb");
            if(booru.name == "Danbooru") thumb.style.setProperty("order", i, "");
            thumb.appendChild(link);
            if(/true/.test(data.getAttribute("has_notes")))
                thumb.classList.add("yellow");
            if(/deleted/.test(data.getAttribute("status")) || /true/.test(data.getAttribute("is-deleted"))) {
                thumb.classList.add("red");
                thumb.addEventListener("transitionend", function() { if(!aSD.checked) this.remove(); }, false);
                if(!aSD.checked) {
                    thumb.style.setProperty("opacity", "0", "");
                    thumb.style.setProperty("padding", "0", "");
                    thumb.style.setProperty("margin", "0", "");
                    thumb.style.setProperty("border-width", "0px", "");
                    thumb.style.setProperty("min-width", "0px", "");
                    thumb.style.setProperty("max-width", "0px", "");
                    cache.push(thumb);
                    thumb.remove();
                }
            }
        }
    }
}

function getContent(xmldoc, newtags) {
    if(booru.name == "Danbooru") { // Inject the count where it should be by default...
        requestCount = GM_xmlhttpRequest({
            method : "GET",
            url : window.location.origin + "/counts/posts.xml" + booru.query(encodeURIComponent(newtags)),
            headers : {
                "Accept" : "application/xml",
                "Cookie" : d.cookie
            },
            overrideMimeType : "application/xml; charset=utf-8",
            onload : function(response) {
                newxmldoc = domParser.parseFromString(response.responseText, "application/xml");
                posts = xmldoc.evaluate("posts", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                count = newxmldoc.evaluate("counts/posts", newxmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                if(posts) {
                    posts.setAttribute("count", count ? count.textContent.trim() : "0");
                    posts.setAttribute("offset", (page - 1) * images);
                }

                // processing of new XML back to legacy format
                var xsltProcessor = new XSLTProcessor();
                xsltProcessor.importStylesheet(domParser.parseFromString(xsltText, "text/xml"));
                xmldoc = xsltProcessor.transformToDocument(xmldoc);
                showContent(xmldoc);
            }
        });
    } else {
        showContent(xmldoc);
    }
}

function checkCache(data) {
    cached = false;
    for(var i in cacheID)
        if(data.getAttribute("id") == cacheID[i].id) { // insert the cached url directly to data
            cached = true;
            data.setAttribute("md5", cacheID[i].md5)
            data.setAttribute("file-url", cacheID[i].url)
            data.setAttribute("preview-file-url", "/data/preview/" + cacheID[i].md5 + ".jpg");
            break;
        }
    if(!cached) requestCache = GM_xmlhttpRequest({ // change the thumbnails and cache the entry
        method : "GET",
        url : window.location.origin + "/posts/" + data.getAttribute("id"),
        headers : {
            "Accept" : "text/html",
            "Cookie" : d.cookie
        },
        onload : function(response) {
            parsedPage = domParser.parseFromString(response.responseText, "text/html");
            parsed = parsedPage.getElementById("image-container");
            id = parsed.getAttribute("data-id");
            md5 = parsed.getAttribute("data-md5");
            url = parsed.getAttribute("data-file-url");
            cacheID.push({ id : id, md5 : md5, url : url });
            image = d.getElementById(id);
            if(!image)
                for(var i in cache)
                    if(cache[i].firstChild.firstChild.getAttribute("id") == id)
                        image = cache[i].firstChild.firstChild;
            if(!image) return;
            image.setAttribute("md5", md5);
            image.setAttribute("fullsize", url);
            image.setAttribute("src", "/data/preview/" + md5 + ".jpg");
            image.parentNode.setAttribute("href", url);
        }
    });
}

function showNotes(note, id) {
    var offsetx = fullsize.getBoundingClientRect().left + (d.documentElement.scrollLeft || d.body.scrollLeft);
    var offsety = fullsize.getBoundingClientRect().top + (d.documentElement.scrollTop || d.body.scrollTop);
    var vp_bottom = Math.max(window.innerHeight, innerDisplay.getBoundingClientRect().bottom - innerDisplay.getBoundingClientRect().top);

    for(var i = 0, ndata = null; ndata = note.snapshotItem(i++); i) {
        if(id.match(/[0-9]+$/)[0] != fullsize.getAttribute("id")) continue;
        if(d.getElementById("note" + ndata.getAttribute("id"))) continue;

        var noteDiv = d.createElement("DIV");
        noteDiv.setAttribute("id", "note" + ndata.getAttribute("id"));
        noteDiv.setAttribute("class", "trans");
        noteDiv.setAttribute("style", "opacity: 0.4; transition: none !important;");
        noteDiv.style.setProperty("left", ndata.getAttribute("x") * sampleRate + offsetx + "px", "");
        noteDiv.style.setProperty("top", ndata.getAttribute("y") * sampleRate + offsety + "px", "");
        noteDiv.style.setProperty("width", ndata.getAttribute("width") * sampleRate + "px", "");
        noteDiv.style.setProperty("height", ndata.getAttribute("height") * sampleRate + "px", "");
        noteDiv.addEventListener("mouseover", function(event) {
            noteclear = setTimeout(function() { d.getElementById("body" + this.getAttribute("id")).style.setProperty("display", "", ""); }.bind(this), 100);
        }, false);
        noteDiv.addEventListener("mouseout", function(event) {
            noteclear = setTimeout(function() { d.getElementById("body" + this.getAttribute("id")).style.setProperty("display", "none", ""); }.bind(this), 200);
        }, false);
        innerDisplay.appendChild(noteDiv);

        var noteBody = d.createElement("DIV");
        noteBody.innerHTML = ndata.getAttribute("body");
        noteBody.setAttribute("id", "bodynote" + ndata.getAttribute("id"));
        noteBody.setAttribute("class", "trans");
        noteBody.setAttribute("style", "color: Black; text-align: left; padding: 4px; z-index: 1" + i + ";");
        noteBody.addEventListener("mouseover", function(event) {
            clearTimeout(noteclear);
            this.style.setProperty("display", "", "");
        }, false);
        noteBody.addEventListener("mouseout", function(event) {
            this.style.setProperty("display", "none", "");
        }, false);
        innerDisplay.appendChild(noteBody);

        // this sucks, find another method!
        var w = ndata.getAttribute("width") * sampleRate;
        var h = ndata.getAttribute("height") * sampleRate;
        if(w < h) { w ^= h; h ^= w; w ^= h; } // FUCK YEAH XOR SWAP
        while(w / h > ratio) {
            w -= ratio;
            h += ratio;
        }

        noteBody.style.setProperty("min-width", "-moz-min-content", "");
        noteBody.style.setProperty("min-width", "-webkit-min-content", "");
        noteBody.style.setProperty("max-width", w + "px", "");

        ntop = (ndata.getAttribute("y") * sampleRate) + (ndata.getAttribute("height") * sampleRate) + offsety + 5;
        nheight = noteBody.getBoundingClientRect().bottom - noteBody.getBoundingClientRect().top;
        if(ntop + nheight > vp_bottom)
            noteBody.style.setProperty("top", vp_bottom - nheight + "px", "");
        else
            noteBody.style.setProperty("top", ntop + "px", "");

        noteBody.style.setProperty("left", ndata.getAttribute("x") * sampleRate + offsetx + "px", "");
        noteBody.style.setProperty("display", "none", "");
    }
}

function getNotes(xmldoc, id) {
    if(booru.name == "Danbooru") { // Parses the nodes as attributes for each note
        notes = xmldoc.evaluate("notes/note/is-active[text() = 'true']/..", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
        for(var i = 0, note = null; note = notes.snapshotItem(i++); i) {
            while(note.firstChild) {
                if(note.firstChild.nodeName != "#text")
                    note.setAttribute(note.firstChild.nodeName, note.firstChild.textContent);
                note.removeChild(note.firstChild);
            }
        }
        showNotes(xmldoc.evaluate("notes/note[@is-active = 'true']", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), id);
    } else {
        showNotes(xmldoc.evaluate("notes/note[@is_active = 'true']", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), id);
    }
}

function getValue(name, values) {
    for(var i = 0; i < sites.length; i++)
        if(new RegExp(sites[i].site).test(window.location.hostname)) {
            if(eval(values)[i] != "" && !eval(values)[i]) {
                values = setValue(name.replace(/all/, ""), values, setDefaults(name, 1));
            }
            return eval(values)[i];
        }
}

function setValue(name, values, newvalue) {
    for(var i = 0; i < sites.length; i++)
        if(new RegExp(sites[i].site).test(window.location.hostname)) {
            oldvalue = eval(values);
            oldvalue[i] = (newvalue == "" ? "" : newvalue || oldvalue[i]);
            GM_setValue(name, JSON.stringify(oldvalue));
            return(JSON.stringify(oldvalue));
        }
}

function setDefaults(name, all) {
    var def, string = "[";
    for(var i = 0; i < all; i++) {
        if(name == "alltags")
            def = "\"\"";
        if(name == "allpage")
            def = "1";
        if(name == "allimages")
            def = "20";
        if(name == "allrating")
            def = "\"s\"";
        string += (def) + (i < sites.length - 1 ? ", " : "]");
    }
    return (all > 1 ? string : eval(def));
}