- // ==UserScript==
- // @id gelbooru-endless-scroll
- // @name Gelbooru Endless Scroll
- // @version 1.6.9
- // @namespace intermission
- // @author intermission
- // @description Adds endless scroll function to various boorus
- // @match *://gelbooru.com/index.php?*
- // @match *://rule34.xxx/index.php?*
- // @match *://e621.net/post/index/*
- // @match *://*.booru.org/index.php?*
- // @match *://rule34.paheal.net/post/list*
- // @match *://yande.re/post*
- // @match *://lolibooru.moe/*
- // @match *://konachan.com/*
- // @match *://atfbooru.ninja/*
- // @match *://safebooru.org/*
- // @match *://hypnohub.net/*
- // @match *://tbib.org/*
- // @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, url, host = location.hostname.match(/[^\.]+\.[^\.]+$/)[0],
- 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, myImuoto = ~["yande.re", "lolibooru.moe", "konachan.com", "hypnohub.net"].indexOf(host),
- page = function(doc) {
- try {
- var images, pageNo = d.createElement("paheal.net" === host ? "div" : "span"), frag = d.createDocumentFragment(), container,
- fn = (e) => {
- (e = e.target.parentNode.parentNode).style.overflow = "";
- if (!e.getAttribute("style")) e.removeAttribute("style");
- };
- images = [...doc.querySelectorAll(myImuoto ? "li[id^='p'][class*='creator-id-']" : 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");
- a.style.overflow = "hidden";
- img.addEventListener("load", fn, { once : true });
- frag.appendChild(a);
- }
- container = d.querySelector(v).parentNode;
- if (container.lastElementChild.tagName === "SPAN") container.appendChild(frag);
- else container.insertBefore(frag, container.querySelector(v + ":last-of-type + *"));
- target().classList.remove("loadingu");
- if (paginator.go) paginator();
- if (list.length > 0) {
- events(true);
- process();
- } return;
- } catch(err) { console.error(err); }
- }, req = _ => fetch(url.href).then(
- x => x.text().then(
- text => page((new DOMParser()).parseFromString(text, "text/html"))
- )
- ).catch(err => {
- target().classList.remove("loadingu");
- if (typeof err !== "undefined") {
- if (_.attempt < 10) {
- console.error(`An error occured, ${~_.attempt + 11} retries left\n`, err.message, err.stack);
- ++_.attempt;
- setTimeout(req, 5000, _);
- } else
- console.error("Maximum number of retries reached\n", err.message, err.stack);
- }
- }), process = function(_override) {
- if ((!d.hidden && vis()) || (typeof _override === "boolean" ? _override : false)) {
- target().classList.add("loadingu");
- events();
- url = list.shift();
- return req({attempt: 0});
- }
- }, events = function(_on) {
- var name = _on ? "addEventListener" : "removeEventListener", obj = { passive : true };
- ["scroll", "resize", "visibilitychange"].forEach(evt => window[name](evt, process, obj));
- }, list = [], r = /(page=|pid=|index\/)([0-9]+)|(list\/(?:[^\/]+\/)?)([0-9]+)$/, paginator = function() {
- var el = target(), rect1 = d.querySelector(".thumb:last-of-type"),
- el2 = d.querySelector(location.href.startsWith("https://gelbooru.com/") ? ".hidden-xs" : ".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;
- }
- };
- const target = () => d.querySelector("div.pagination") || d.querySelector("div#paginator") || d.querySelector("section#paginator");
- {
- let style = d.createElement("style");
- style.appendChild(d.createTextNode(`.loadingu {
- position: relative;
- }
- .loadingu::after {
- content: "" ! important;
- display: block;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- min-width: 34px;
- min-height: 34px;
- background: rgba(0,0,0,.5) no-repeat center center url(data:image/svg+xml,%3Csvg%20width%3D%2234px%22%20height%3D%2234px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20100%20100%22%20preserveAspectRatio%3D%22xMidYMid%22%20class%3D%22uil-ring-alt%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%22%20height%3D%22100%22%20fill%3D%22none%22%20class%3D%22bk%22%3E%3C%2Frect%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2240%22%20stroke%3D%22%23b4b197%22%20fill%3D%22none%22%20stroke-width%3D%2210%22%20stroke-linecap%3D%22round%22%3E%3C%2Fcircle%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2240%22%20stroke%3D%22%23f4efcc%22%20fill%3D%22none%22%20stroke-width%3D%226%22%20stroke-linecap%3D%22round%22%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20from%3D%220%22%20to%3D%22502%22%3E%3C%2Fanimate%3E%3Canimate%20attributeName%3D%22stroke-dasharray%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20values%3D%22150.6%20100.4%3B1%20250%3B150.6%20100.4%22%3E%3C%2Fanimate%3E%3C%2Fcircle%3E%3C%2Fsvg%3E);
- }`));
- d.head.appendChild(style);
- }
- if (target() && /\/post\/?|page=post/.test(location.href)) {
- let pid = location.href.match(r),
- p = ((pid && pid[1] === "index/" || myImuoto) ? target().lastElementChild.previousElementSibling : target().lastElementChild).href,
- n = d.querySelectorAll(v).length,
- start_index, end_index, increment = 1, index = 0;
- 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 "booru.org":
- start_index = pid ? pid[2] / n : 0;
- increment = n;
- end_index = p.match(r)[2] / n;
- index = 1;
- break;
- case "e621.net":
- start_index = pid ? +pid[2] : 2;
- end_index = +p.match(r)[2];
- break;
- case "yande.re":
- case "lolibooru.moe":
- case "konachan.com":
- case "hypnohub.net":
- start_index = pid ? +pid[2] : 1;
- end_index = +p.match(r)[2];
- break;
- case "paheal.net":
- start_index = pid ? +pid[4] : 1;
- end_index = +p.match(r)[4];
- break;
- default:
- start_index = pid ? pid[2] / n : 0;
- increment = n;
- end_index = p.match(r)[2] / n;
- index = 1;
- paginator.go = true;
- break;
- }
- while(start_index < end_index)
- list.push({
- href: p.replace(r, (host === "paheal.net" ? "$3" : "$1") + ++start_index * increment),
- index: start_index + index
- });
- total = end_index + index;
- } else
- throw Error("*shrug*");
- if (paginator.go) paginator();
- window.addEventListener("keypress", e => {
- if (typeof url !== "object" && vis()) process();
- }, { once : true });
- d.addEventListener("gelbooru-slide", e => {
- if (list.length > 0)
- events(e.detail);
- }, false);
- d.addEventListener("gelbooru-slide-next", e => {
- if (list.length > 0) {
- clearTimeout(e.detail);
- d.querySelector(".loadingu").classList.remove("loadingu");
- process(true);
- }
- }, false);
- events(true);
- if (vis()) process();
- }());