Greasy Fork is available in English.

Bovverzoom

My take of (pre)viewing images and animations on Reddit by mouse hovering on their thumbnail or text link. Work in progress. Rewrite pending. Yes, the name is a Yak-tribute.

Från och med 2015-08-27. Se den senaste versionen.

// ==UserScript==
// @name        Bovverzoom
// @description My take of (pre)viewing images and animations on Reddit by mouse hovering on their thumbnail or text link. Work in progress. Rewrite pending. Yes, the name is a Yak-tribute.
// @namespace   raina
// @include     /^https?:\/\/(www\.)?reddit\.com\//
// @version     1.3
// @done        Avoided mixed content issues by stripping out explicit protocol.
// @done        Handle Imgur ad hoc collection images
// @done        Handle Imgur "gifv"
// @todo        Handle DOM mutations.
// @todo        Handle Imgur albums and galleries somehow.
// @todo        Keyboard navigation?
// @grant       none
// ==/UserScript==
(function() {
	"use strict";

	var i, j;
	var doc = document;
	var thumbs = doc.getElementsByClassName("thumbnail");
	var userText = doc.getElementsByClassName("usertext-body");
	var show = function() {
			this.style.display = "block";
		};
	var hide = function() {
			this.style.display = "none";
		};
	var img = doc.createElement("img");
		img.className = "bovverzoom";
		img.cache = "";
		img.show = show;
		img.hide = hide;

	var clip = doc.createElement("video");
		clip.className = "bovverzoom";
		clip.autoplay = "autoplay";
		clip.muted = "muted";
		clip.loop = "loop";
		clip.cache = "";
		clip.show = show;
		clip.hide = hide;

	var style = doc.createElement("style");
		style.type = "text/css";
		style.textContent = ".bovverzoom {" +
			"background-color: rgba(0,0,0,.01);" +
			"position: fixed;" +
			"right: 0;" +
			"top: 0;" +
			"z-index: 100;" +
			"max-width: 100%;" +
			"max-height: 100%;" +
			"pointer-events: none;" +
			"border-radius: 3px;" +
			"display: none;" +
			"}"+
 			".glow {" +
			"box-shadow: rgba(255, 255, 255, .5) 0 0 8px" +
 			"}";

	var fetchGFY = function(url, e) {
		img.hide();
		if (url != clip.cache) {
			var xhr = new XMLHttpRequest();
			xhr.addEventListener("load", showGFY, false);
			xhr.open("GET", url, true);
			xhr.send();
			clip.cache = url;
		} else {
			clip.show();
		}
	};

	var showGFY = function() {
		clip.show();
		var gfyItem = JSON.parse(this.responseText).gfyItem;
		var newClip = clip.cloneNode(false);

		var webmSrc = doc.createElement("source");
		webmSrc.src = gfyItem.webmUrl.replace(/^https?:/, "");
		webmSrc.type = "video/webm";
		newClip.appendChild(webmSrc);

		var mp4Src = doc.createElement("source");
		mp4Src.src = gfyItem.mp4Url.replace(/^https?:/, "");
		mp4Src.type = "video/mp4";
		newClip.appendChild(mp4Src);

		document.body.replaceChild(newClip, clip);
		newClip.hide = clip.hide;
		newClip.show = clip.show;
		clip = newClip;
		clip.show();
	};

	var showGIFV = function(url) {
		clip.show();
		var newClip = clip.cloneNode(false);

		var webmSrc = doc.createElement("source");
		webmSrc.src = url.replace(".gifv", ".webm").replace(/^https?:/, "");
		webmSrc.type = "video/webm";
		newClip.appendChild(webmSrc);

		var mp4Src = doc.createElement("source");
		mp4Src.src = url.replace(".gifv", ".mp4").replace(/^https?:/, "");
		mp4Src.type = "video/mp4";
		newClip.appendChild(mp4Src);

		document.body.replaceChild(newClip, clip);
		newClip.hide = clip.hide;
		newClip.show = clip.show;
		clip = newClip;
		clip.show();
	};

	var imgMe = function(src, e) {
		src = src.replace(/^https?:/, "");
		clip.hide();
		if (src != img.cache) {
			img.src = "";
			img.src = src;
			img.cache = src;
		}
		img.show();
	};
	
	var killMe = function() {
		clip.hide();
		img.hide();
	};
	
	var rigMe = function(src, el) {
		el.addEventListener("mouseover", swapper, false);
		el.addEventListener("mouseout", swapper, false);
		el.className = el.className + " glow";
	};

	var clipFunc = rigMe;
	var imgFunc = rigMe;
	var swapper = function(e) {
		var obj;
		if (undefined !== this) {
			obj = this;
			clipFunc = obj.href.match(/gfycat/) ? fetchGFY : showGIFV;
			imgFunc = imgMe;
		} else {
			obj = e;
		}
		if ("mouseover" === e.type || "" === e.type) {
			if (obj.href.match(/^https?:\/\/(.*\.)?gfycat\.com\/.{1,}$/i)) { // gfycat.com, HTML5 video even for direct .gif links
//				console.log("3 " + obj.href.replace(/^.*\.com\//, ""));
				clipFunc("//gfycat.com/cajax/get/" + obj.href.replace(/^.*\.com\//, ""), e);
			} else if (obj.href.match(/^https?:\/\/((i|m|www)\.)?imgur\.com\/[^\/]{1,}\.gifv$/)) { // imgur.com HTML5 video
//				console.log("1 " + obj.href);
				clipFunc(obj.href, e);
			} else if (obj.href.match(/\.(bmp|gif|jpg|png|svg)(\?.*)?$/i)) { // images, any domain
//				console.log("1 " + obj.href);
				imgFunc(obj.href, e);
			} else if (obj.href.match(/^https?:\/\/((www|m)\.)?imgur\.com(\/r\/[^\/]*)?\/[^\/]{1,}#[0-9]{1,}$/)) { // imgur.com ad hoc collections
				var imgList = obj.href.slice(obj.href.lastIndexOf("/") + 1, obj.href.lastIndexOf("#")).split(",");
				var index = obj.href.slice(obj.href.lastIndexOf("#") + 1);
				imgFunc("//i.imgur.com/" + imgList[index] + ".jpg", e);
			} else if (obj.href.match(/^https?:\/\/((www|m)\.)?imgur\.com(\/r\/[^\/]*)?\/[^\/]{1,}$/)) { // imgur.com, nonhotlinked single images
//				console.log("2 " + obj.href);
				imgFunc(obj.href.replace(/\/([^\/]*\.)?imgur\.com(\/r\/[^\/]*)?/, "/i.imgur.com") + ".jpg", e);
			} else { // not a recognized image/clip link
				killMe();
			}
		} else { // mouseout
			killMe();
		}
	};

	doc.head.appendChild(style);
	doc.body.appendChild(clip);
	doc.body.appendChild(img);

	for (i = 0; i < thumbs.length; i++) {
		swapper(thumbs[i]);
	}

	for (i = 0; i < userText.length; i++) {
	var textLinks = userText[i].getElementsByClassName("md")[0].getElementsByTagName("a");
		if (textLinks.length) {
			for (j = 0; j < textLinks.length; j++) {
				swapper(textLinks[j]);
			}
		}
	}
}());