Gelbooru Image Viewer

Adds a fullscreen image view option when you click on images

Version au 08/12/2016. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @id             gelbooru-slide
// @name           Gelbooru Image Viewer
// @version        1.4.2
// @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:
				return window.location = current().href;
			case 40:
				e.preventDefault();
				return slideEl.click();
		}
		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;
			slideEl.onmouseup = e => e.button === 1 && keyDown({keyCode:38});
			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 => {
				let 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);
	}
}())