Gelbooru Image Viewer

Adds a fullscreen image view option when you click on images

Fra og med 25.11.2016. Se den nyeste version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

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.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @id             gelbooru-slide
// @name           Gelbooru Image Viewer
// @version        1.1.1
// @namespace      intermission
// @author         intermission
// @license        CC0; https://wiki.creativecommons.org/wiki/CC0
// @description    Adds a fullscreen image view option when you click on images
// @include        http://gelbooru.com/index.php?*
// @include        https://gelbooru.com/index.php?*
// @run-at         document-start
// @grant          GM_registerMenuCommand
// ==/UserScript==

(function(){
	"use strict";
	var d = document, array = a => [].slice.call(a), observer, request, mouseUp, slideEl, slider, slidin, base = a => a.split("/").pop().split(".")[0].split("_").pop(), keyDown, find, current, preload, stor = localStorage, l, toggle = stor["gelbooru-slide"] == "true";
	
	if (!stor["gelbooru-slide"]) stor["gelbooru-slide"] = "false";
	
	GM_registerMenuCommand("Current image mode: " + (toggle ? "Always original size" : "Sample only"), () => {
		stor["gelbooru-slide"] = toggle ? "false" : "true";
		location.reload();
	});
	
	l = toggle ? ["ul>li>a[style*='font-weight:']", "href"] : ["#image", "src"];
	
	current = a => d.querySelector("img.preview[src*='" + base(slideEl.src) + "']").parentNode;
	
	mouseUp = e => e.button == 0 && (e.preventDefault(), e.stopPropagation(), slider(e.target.parentNode));
	
	find = function(el, method) {
		var a;
		el = el.parentNode;
		do {
			try {
				el = el[(method ? "next" : "previous") + "ElementSibling"];
				a = el.querySelector`a[data-full]`;
			} catch(err) {
				return false;
			}
			if (a) break;
			a = false;
		} while(!a);
		return a;
	};
	
	preload = function() {
		var curr = current(), a = find(curr, true), b = find(curr, false);
		a && request(a);
		b && request(b);
		return;
	};
	
	keyDown = function(e) {
		var move;
		switch(e.keyCode) {
			case 32:
			case 39:
				move = true;
				break;
			case 37:
				move = false;
				break;
			case 38:
				window.location = current().href;
				break;
			case 40:
				e.preventDefault();
				slideEl.click();
				break;
		}
		if (typeof move != "undefined") {
			e = find(current(), move);
			if (e) slideEl.slide(e.firstElementChild.src);
			preload();
		}
	};
	
	slider = function(a) {
		var list;
		list = array(d.querySelectorAll`body > *`);
		if (slidin) {
			let center;
			slidin = false;
			a = current();
			slideEl.remove();
			slideEl = null;
			list.forEach(a => a.dataset.slide = "false");
			a.classList.add`outlined`;
			d.removeEventListener("keydown", keyDown, false);
			center = a.offsetTop + a.offsetHeight / 2 - window.innerHeight / 2;
			window.scrollTo(0, center < 0 ? 0 : center);
		} else {
			slidin = true;
			list.forEach(a => a.dataset.slide = "true");
			array(d.querySelectorAll`span>a.outlined`).map(a => a.classList.remove`outlined`);
			slideEl = d.createElement`img`;
			slideEl.id = "slide";
			slideEl.alt = "Loading...";
			Object.defineProperty(slideEl, "slide", {
				value: function(src) {
					var data;
					this.src = src;
					data = current().dataset.full;
					if (data == "loading") request(current());
					else this.src = data;
				}
			});
			slideEl.onclick = _ => slider(a);
			d.body.appendChild(slideEl);
			slideEl.slide(a.firstElementChild.src);
			d.addEventListener("keydown", keyDown, false);
			preload();
		} return;
	};
	
	request = function(node) {
		if (node.dataset.alreadyLoading) return;
		node.dataset.alreadyLoading = "true";
		return fetch(node.href)
			.then(x => x.text().then(text => {
				var doc = d.createElement`div`, img, _base;
				doc.innerHTML = text;
				if (img = doc.querySelector(l[0])) {
					_base = base(img[l[1]]);
					node.dataset.full = img[l[1]];
					if (slideEl.src.indexOf(_base) > -1)
						slideEl.src = img[l[1]];
				} else {
					node.removeAttribute`data-already-loading`;
					fetch`/intermission.php`.then(x2 => request(node))
				}
			})).catch(err => {
				console.error("Failed HTTP request\nDo you have an internet connection?\n", err);
				node.removeAttribute`data-already-loading`;
			});
	};
	
	observer = new MutationObserver(function(mutations) {
		function process(node) {
			let a;
			try {
				if (node.matches`span.thumb[id^='s']` && (a = node.firstElementChild) && !a.dataset.full) {
					if (node.querySelector`img[alt*='webm']`) return;
					a.dataset.full = "loading";
					a.onclick = mouseUp;
				}
			} catch(e) {}
		};
		mutations.forEach(function(mutation) {
			array(mutation.addedNodes).forEach(process);
		}); 
	});
	observer.observe(d, {
		childList: true,
		subtree: true
	});
	
	d.addEventListener("animationend", e => e.animationName == 'Outlined' && e.target.classList.remove`outlined`, false);
	
	{
		let css = d.createElement`style`;
		css.textContent =
		`@keyframes Outlined{
			0% {
				outline: 6px solid orange
			}
			60% {
				outline: 6px solid orange
			}
			100% {
				outline: 6px solid transparent
			}
		}
		[data-slide="true"] {
			display: none ! important
		}
		#slide {
			width: 100vw;
			height: 100vh;
			object-fit: contain
		}
		.outlined {
			outline: 6px solid transparent;
			animation-duration: 4s;
			animation-name: Outlined
		}`;
		d.head.appendChild(css);
	}
}())