// ==UserScript==
// @id gelbooru-endless-scroll
// @name Gelbooru Endless Scroll
// @version 1.6
// @namespace intermission
// @author intermission
// @license WTFPL; http://www.wtfpl.net/about/
// @description Adds endless scroll function to Gelbooru
// @include http://gelbooru.com/index.php?*
// @include https://gelbooru.com/index.php?*
// @include http://rule34.xxx/index.php?*
// @include https://rule34.xxx/index.php?*
// @include http://*.booru.org/index.php?*
// @include https://*.booru.org/index.php?*
// @include http://e621.net/post/index/*
// @include https://e621.net/post/index/*
// @include http://rule34.paheal.net/post/list/*
// @include https://rule34.paheal.net/post/list/*
// @run-at document-end
// @grant none
// ==/UserScript==
/* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details. */
(function(){
"use strict";
var d = document, _on = false, url,
v = ".thumb",
vis = function() {
var rect = target().getBoundingClientRect();
return rect.x === 0 && rect.y === 0 ? false : (
rect.top + rect.height >= 0 &&
( document.documentElement.clientHeight - rect.bottom ) + rect.height >= 0
);
}, total,
page = function(doc) {
var images, pageNo = d.createElement("paheal.net" == host ? "div" : "span"), frag = d.createDocumentFragment(), container,
fn = (e) => {
e.target.onload = null;
e.target.parentNode.style.overflow = "";
}, base = a => a.match(r2);
images = [...doc.querySelectorAll(v)];
if (images.length === 0)
throw Error("API error");
pageNo.innerHTML = '<span style="height:' + ("paheal.net" == host ? "180px" : "inherit") + ';display:flex;flex-direction:column;">Page ' + url.index + '~<span style="margin:auto 0 30px">out of ' + total + "</span></span>";
pageNo.className = "thumb";
if ("paheal.net" == host)
pageNo.setAttribute("style", "transform: translateY(-180px); margin-bottom: -180px");
frag.appendChild(pageNo);
for (let a of images) {
let img = a.querySelector("img");
if (d.querySelector("img[src*='" + base(img.src) + "']")) continue;
a.style.overflow = "hidden";
img.onload = fn;
frag.appendChild(a);
};
container = d.querySelector(v).parentNode;
if (container.lastElementChild.matches("span")) container.appendChild(frag);
else container.insertBefore(frag, container.querySelector(".thumb:last-of-type + *"));
if (paginator.go) paginator();
if (list.length > 0) {
events();
process();
} return;
}, req = _ => fetch(url.href).then(
x => x.text().then(
text => page((new DOMParser()).parseFromString(text, "text/html"))
)
).catch(err => {
if (typeof err != "undefined") {
console.error("Something unexpected happened\n", err);
setTimeout(() => req(), 5000);
}
}), process = function() {
if (vis()) {
events();
url = list.shift();
return req();
}
}, events = function() {
var name = (_on = !_on) ? "addEventListener" : "removeEventListener";
window[name]("scroll", process);
window[name]("resize", process);
window[name]("visibilitychange", process);
}, list = [], r = /(pid=|index\/|list\/)([0-9]+)/, r2 = /[a-f0-9]{32}/, paginator = function() {
var el = target(), rect1 = d.querySelector(".thumb:last-of-type"),
el2 = d.querySelector(".sidebar"), rect2;
if (el.classList.contains("pagination")) el = el.parentNode;
rect1 = rect1.offsetTop + rect1.offsetHeight;
rect2 = el2.offsetTop + el2.offsetHeight - 9;
if (rect2 >= rect1) {
el.style.position = "absolute";
el.style.top = rect1 + "px";
el.style.left = "calc(50vw + " + (el2.getBoundingClientRect().width / 2) + "px)";
el.style.transform = "translateX(-50%)";
} else {
el.style.position = "";
el.style.top = "";
el.style.left = "";
el.style.transform = "";
paginator.go = false;
}
}, host = location.hostname.match(/[^\.]+\.[^\.]+$/)[0];
const target = () => (d.querySelector("div.pagination") || d.querySelector("div#paginator") || d.querySelector("section#paginator"));
if (target() && /\/post\/|page=post/.test(location.href)) {
let pid = location.href.match(r),
p = ((pid && pid[1] == "index/") ? target().lastElementChild.previousElementSibling : target().lastElementChild).href,
n = d.querySelectorAll(v).length,
start_index, end_index, increment, index = 1;
if (host == "paheal.net") {
let ayy = target().children[0].children;
p = ayy[[...ayy].indexOf([...ayy].find(el => !!~el.textContent.indexOf("Random"))) + 2].href;
}
if (!p) return;
switch(host) {
case "gelbooru.com": case "rule34.xxx":
start_index = pid ? pid[2] / n : 0;
increment = n;
end_index = p.match(r)[2] / n;
paginator.go = true;
break;
case "booru.org":
start_index = pid ? pid[2] / n : 0;
increment = n;
end_index = p.match(r)[2] / n;
break;
case "e621.net": case "paheal.net":
start_index = pid ? +pid[2] : 2;
increment = 1;
index = 0;
end_index = +p.match(r)[2];
break;
case "paheal.net":
start_index = pid ? +pid[2] : 1;
increment = 1;
index = 0;
end_index = +p.match(r)[2];
break;
}
while(start_index < end_index)
list.push({
href: p.replace(r, "$1" + (++start_index * increment)),
index: start_index + index
});
total = end_index + index;
}
if (paginator.go) paginator();
d.addEventListener("gelbooru-slide", _ => {
if (list.length > 0)
events();
}, false);
d.addEventListener("gelbooru-slide-next", _ => {
if (list.length > 0)
events();
}, false);
events();
if (vis()) process();
}());