Sleazy Fork is available in English.

Gelbooru Image Viewer

Adds a fullscreen image view option when you click on images

נכון ליום 07-12-2016. ראה הגרסה האחרונה.

// ==UserScript==
// @id             gelbooru-slide
// @name           Gelbooru Image Viewer
// @version        1.4.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, slideEl, slider, slidin, base = a => a.split("/").pop().split(".")[0].split("_").pop(), keyDown, find, current, preload, stor = localStorage, l, ns = "gelbooru-slide", toggle = stor[ns] == "true", cache;
	
	if (!stor[ns]) stor[ns] = "false";
	
	GM_registerMenuCommand("Current image mode: " + (toggle ? "Always original size" : "Sample only"), _ => {
		stor[ns] = toggle ? "false" : "true";
		return location.reload();
	});
	
	l = toggle ? ["ul>li>a[style*='font-weight:']", "href"] : ["#image", "src"];
	
	current = _ => d.querySelector("img.preview[src*='" + base(slideEl.src) + "']").parentNode;
	
	cache = (a, b) => {
		let id = a.href.match(/id=([0-9]+)/)[1], val = toggle ? "original" : "sample";
		if (!b) {
			let ret;
			try { ret = JSON.parse(stor[ns + id])[val] } catch(e) {}
			if (ret)
				if (!/[0-9a-f]/.test(ret[0])) return "loading"; // BC for pre 1.3 version
				else ret = "http://gelbooru.com//images/" + ret.substr(0,2) + "/" + ret.substr(2,2) + "/" + ret;
			else ret = "loading";
			return ret;
		} else {
			let obj, temp;
			try { temp = JSON.parse(stor[ns + id]) } catch(e) {}
			obj = temp || {};
			obj[val] = base(b) + "." + b.split(".").pop();
			stor[ns + id] = JSON.stringify(obj);
			return b;
		}
	};
	
	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();
		} return;
	};
	
	slider = function(a) {
		if (slidin) {
			let center;
			slidin = !(a = current());
			slideEl = slideEl.remove();
			d.querySelector`#paginator`.hidden = true;
			d.body.classList.remove`sliding`;
			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);
			d.querySelector`#paginator`.hidden = false;
		} else {
			slidin = true;
			d.body.classList.add`sliding`;
			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;
			d.body.appendChild(slideEl);
			slideEl.slide(a.firstElementChild.src);
			d.addEventListener("keydown", keyDown, false);
			preload();
		} return;
	};
	
	request = function(node) {
		if (node.dataset.alreadyLoading || node.dataset.full != "loading" ) return;
		node.dataset.alreadyLoading = "true";
		return fetch(node.href)
			.then(x => x.text().then(text => {
				var doc = (new DOMParser()).parseFromString(text, "text/html"), img, _base;
				if (img = doc.querySelector(l[0])) {
					_base = base(img[l[1]]);
					node.dataset.full = cache(node, img[l[1]]);
					if (slideEl && slideEl.src.indexOf(_base) > -1)
						slideEl.slide(img[l[1]]);
					return;
				} else {
					node.removeAttribute`data-already-loading`;
					fetch`/intermission.php`.then(_ => request(node));
					throw undefined;
				}
			})).catch(err => {
				if (typeof err == "undefined") return;
				console.error("Failed HTTP request\nDo you have an internet connection?\n", err);
				return node.removeAttribute`data-already-loading`;
			});
	};
	
	observer = new MutationObserver(function(mutations) {
		function process(node) {
			var 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 = cache(a);
					a.onclick = e => e.button === 0 && (e.preventDefault(), e.stopPropagation(), slider(e.target.parentNode));
				}
			} catch(e) {} return;
		}
		return mutations.forEach(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);
	
	window.addEventListener("keypress", e => (e.target.matches`span.thumb>a[data-full]` && (e.key === "Enter" || e.keyCode === 13)) && (e.preventDefault(), slider(e.target)), false);
	
	window.addEventListener("wheel", e => slidin && keyDown({keyCode: e.deltaY > 0 ? 39 : e.deltaY < 0 ? 37 : 0}), 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
			}
		}
		body.sliding > *:not(#slide) {
			display: none ! important
		}
		#slide {
			width: 100vw;
			height: 100vh;
			object-fit: contain
		}
		.outlined {
			outline: 6px solid transparent;
			animation-duration: 4s;
			animation-name: Outlined
		}
		span.thumb {
			max-width: 180px;
			max-height: 180px;
		}`;
		return d.head.appendChild(css);
	}
}())