YouTube Thumbnails - Full Video Thumbnails for YouTube

Shows complete video thumbnails for YouTube videos

Versione datata 25/07/2015. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name        YouTube Thumbnails - Full Video Thumbnails for YouTube
// @namespace   driver8.net
// @description Shows complete video thumbnails for YouTube videos
// @match		*://*.youtube.com/watch?*
// @version     0.3.2
// @require     https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @grant       GM_addStyle
// @grant		unsafeWindow
// @grant		GM_registerMenuCommand
// @grant		GM_getValue
// @grant		GM_setValue
// ==/UserScript==

var AND_BUTTS = false;
var LOAD_DELAY_START = 200;
var LOAD_DELAY_FACTOR = 50;
var LOAD_DELAY_MAX = 500;
var TIMEOUT_DELAY = 2000;
var DIV_PADDING = 10;
var TD_PADDING = 2;
var DISABLE_SPF = GM_getValue('ytDisableSPF', false);
var LOGGING = false;
var MIN_WIDTH = 4;
var MAX_IMAGES = 30;

var $thumbDiv, $thumbHeader, storyboard_spec, storyboard, best_size_idx, best_size, len_seconds, videoId, tries;

function log(msg) {
	LOGGING && console.log(msg);
}
log("Hi");

setUp();
function setUp() {

	AND_BUTTS && $('#eow-title').text($('#eow-title').text() + " and Butts");

	// See if waiting will help w/spf bullshit (it won't)
	tries = 0;
	(function trySb() {
		try {
			storyboard_spec = unsafeWindow.ytplayer.config.args.storyboard_spec;
		} catch (e) {
			log("oops " + e);
			try {
				storyboard_spec = window.ytplayer.config.args.storyboard_spec;
			} catch (e2) {
				log("oops2 " + e2);
				if (tries++ < 2) {
					window.setTimeout(trySb, TIMEOUT_DELAY);
				}
			}
		}
	})();

	storyboard = parseStoryboardSpec(storyboard_spec);
	best_size_idx = chooseBestStoryboardSize(storyboard);
	best_size = storyboard.sizes[best_size_idx];
	log(best_size);
	len_seconds = parseInt(unsafeWindow.ytplayer.config.args.length_seconds);
	log("len: " + len_seconds);

	var $titleDiv = $('#watch-header');
	$thumbDiv = $('<div id="thumbDiv" class="yt-card"></div>');
	$thumbHeader = $('<h1 width="100%">Thumbs</h1>');
	$thumbDiv.append($thumbHeader);
	$titleDiv.after($thumbDiv);

	$thumbDiv.click(showThumbs);

	log("Script done");

	styleIt();
}

function showThumbs(event) {
	var duration = best_size.duration / 1000;
	var num_thumbs = 1;
	if (duration > 0) {
		num_thumbs = Math.ceil(len_seconds / duration / best_size.cols / best_size.rows);
	} else {
		duration = len_seconds / best_size.cols / best_size.rows;
	}
	log("Thumb header clicked. Loading " + num_thumbs + " images.");
	var total_width = best_size.width * best_size.cols + DIV_PADDING * 2;
	var parent_diff = $thumbDiv.parent().innerWidth() - total_width;
	parent_diff < 0 && $thumbDiv.css({'left': + parent_diff + 'px'});
	$thumbDiv.css({'position': 'relative', 'width': total_width + 'px'});

//	Grab the youtube sessionlink ID for time links
	var sessionlink = $('#logo-container').data("sessionlink");

	var badImage = false;
	(function loadImage(imgNum) {
		if (badImage === false && imgNum < num_thumbs && imgNum < MAX_IMAGES) {
			// EX: https:\/\/i.ytimg.com\/sb\/2XY3AvVgDns\/storyboard3_L$L\/$N.jpg
			// EX: https://i.ytimg.com/sb/k4YRWT_Aldo/storyboard3_L2/M0.jpg?sigh=RVdv4fMsE-eDcsCUzIy-iCQNteI
			var link = storyboard.baseUrl.replace('\\', '');
			link = link.replace('$L', best_size_idx);
			link = link.replace('$N', best_size.img_name);
			link = link.replace('$M', imgNum);
			link += '?sigh=' + best_size.sigh;

			log(link);

			// Create a table for the timestamps over the image
			var $newTable = $('<table>');
			$newTable.addClass('imgTable');
			var x = imgNum * duration * best_size.rows * best_size.cols; // the starting time for this table
			var innerStr = '';
			var doclocation = document.location.href.replace(/\#.*/, '');
			for (var i = 0; i < best_size.rows; i++) {
				if (x <= len_seconds + 1) { // if we haven't reached the end of the video
					innerStr += '<tr>';
					for (var j = 0; j < best_size.cols; j++) {
						innerStr += '<td><a class="yt-uix-sessionlink" href="' + doclocation + '#t=' + x + '">';
						if (x <= len_seconds + 1) {
							var hrs = Math.floor(x / 3600);
							var mins = Math.floor((x % 3600) / 60);
							var secs = Math.round(x % 60);
							innerStr += hrs > 0 ? hrs + ':' : ''; // hrs
							innerStr += ( hrs > 0 && mins < 10 ? "0" + mins : mins ) + ':'; // mins
							innerStr += secs < 10 ? "0" + secs : secs; // secs
						}
						innerStr += '</a></td>';
						x += duration;
					}
					innerStr += '<tr>';
				}
			}
			$newTable.html(innerStr);
			$newTable.error(function() {
				badImage = true;
				$(this).remove();
				log("Hid bad image");
			});
			//$newTable.load(function() {
			//	loadImage(imgNum + 1);
			//});
			$newTable.css({'background-image': 'url(' + link + ')', 'width': best_size.width * best_size.cols});

			$thumbDiv.append($newTable);

			setTimeout(loadImage, Math.min(LOAD_DELAY_START + imgNum * LOAD_DELAY_FACTOR, LOAD_DELAY_MAX), imgNum + 1);
		}
	})(0);

	log("Done making thumb div");
	$thumbDiv.off('click');
	$thumbDiv.click(hideThumbs);
}

function hideThumbs(event) {
	if ($(event.target).is('#thumbDiv, #thumbDiv h1')) {
		$thumbDiv.children('table').hide();
		$thumbDiv.off('click');
		$thumbDiv.click(showThumbsAgain);
	} else {
		$('html, body').scrollTop(0);
	}
}

function showThumbsAgain(event) {
	if ($(event.target).is('#thumbDiv, #thumbDiv h1')) {
		$thumbDiv.children('table').show();
		$thumbDiv.off('click');
		$thumbDiv.click(hideThumbs);
	}
}

function parseStoryboardSpec(spec) {
	// EX: https:\/\/i.ytimg.com\/sb\/Pk2oW4SDDxY\/storyboard3_L$L\/$N.jpg|48#27#100#10#10#0#default#vpw4l5h3xmm2AkCT6nMZbvFIyJw|80#45#90#10#10#2000#M$M#hCWDvBSbgeV52mPYmOHjgdLFI1o|160#90#90#5#5#2000#M$M#ys1MKEnwYXA1QAcFiugAA_cZ81Q
	var sections = spec.split('|');
	log(sections);
	var sb = {
		sizes: [],
		baseUrl: sections.shift()
	};

	// EX: 80#45#90#10#10#2000#M$M#hCWDvBSbgeV52mPYmOHjgdLFI1o
	// EX: 160#		90#		90#		5#		5#		2000#	M$M#			ys1MKEnwYXA1QAcFiugAA_cZ81Q
	sections.forEach(function(value, idx) {
		var data = value.split('#');
		log(data);
		var new_size = {
			width : +data[0],
			height : +data[1],
			qual : +data[2], // image quality???
			cols : +data[3],
			rows : +data[4],
			duration : +data[5], // duration of each snapshot in milliseconds
			img_name : data[6],
			sigh : data[7]
		};
		sb.sizes[idx] = new_size;
	});
	log(sb);
	return sb;
}

function chooseBestStoryboardSize(sb) {
	var sizes = sb.sizes;
	var widest = 0;
	var widest_idx = -1;
	for (var i = 0; i < sizes.length; i++) {
		if (widest < sizes[i].width  || (widest == sizes[i].width && sizes[widest_idx].cols < sizes[i].cols)) {
			if (sizes[i].cols >= MIN_WIDTH) {
				widest = sizes[i].width;
				widest_idx = i;
			}
		}
	}
	return widest_idx;
}


function styleIt() {
	var userStyles0 =
		"table.imgTable { border-collapse: collapse; background-repeat: no-repeat; cursor: auto; !important } " +
		".imgTable td { width: " + (best_size.width - 2 * TD_PADDING) + "px;" +
		" height: " + (best_size.height - 2 * TD_PADDING) + "px;" +
		" padding: " + TD_PADDING + "px;" +
		" border-width: 0px;" +
		" vertical-align: top;" +
		"	color: white;" +
		"	    text-shadow:" +
		"			-1px -1px 0 #000, " +
		"			1px -1px 0 #000, " +
		"			-1px 1px 0 #000, " +
		"			1px 1px 0 #000;  " +
		" 	!important}" +
		".imgTable a { text-decoration: none; color: white; display: block; width: 100%; height: 100%; !important }" +
		"#thumbDiv {padding: " + DIV_PADDING + "px; cursor: pointer; }";
	GM_addStyle(userStyles0);

	if (DISABLE_SPF) {
		$('a.spf-link').each(function () {
			var $link = $(this);
			$link.removeClass('spf-link');
			$link.off();
		});
	}

	GM_registerMenuCommand( "Toggle SPF", function toggleSpf() {
		DISABLE_SPF = !DISABLE_SPF;
		GM_setValue('ytDisableSPF', DISABLE_SPF);
	}, 's' );
	log("DONE");
}


/// TRYING TO DEAL WITH YOUTUBE'S STUPID SPF SHIT WITHOUT DISABLING IT. BLAHH! ///

//window.addEventListener('spfrequest', function() { log("SPF WUT? spfrequest"); });
//window.addEventListener('spfpartprocess', function() { log("SPF WUT? spfpartprocess"); });
//window.addEventListener('spfpartdone', function() { log("SPF WUT? spfpartdone"); });
//window.addEventListener('spfprocess', function() { log("SPF WUT? spfprocess"); });
//window.addEventListener('spfdone', function() { log("SPF WUT? spfdone"); });
//window.addEventListener('spferror', function() { log("SPF WUT? spferror"); });
//window.addEventListener('spfreload', function() { log("SPF WUT? spfreload"); });
//window.addEventListener('spfjsbeforeunload', function() { log("SPF WUT? spfjsbeforeunload"); });

//window.addEventListener('spfdone', spfWut);

//function spfWut(a) {
//	log(a);
//	var parts = a.detail.response.parts;
//	var good_part = null;
//	parts.forEach(function(val, idx) {
//		good_part = good_part || (val.data && val.data.swfcfg);
//	});
//	log(good_part);
//	// var storyboard_spec = a.data.swfcfg.args.storyboard_spec;
//	storyboard_spec = good_part.args.storyboard_spec;
//	log("sbSpec: " + sb_spec);
//	best_size_idx_idx = chooseBestStoryboardSize(storyboard);
//	best_size = storyboard.sizes[best_size_idx_idx];
//	log(best_size);
//	len_seconds = parseInt(good_part.args.length_seconds);
//	log("len: " + len_seconds);
//	setUp();
//	log("BOOM");
//}
//
//(function transitionCheck() {
//	$('body').on('transitionend', function(event) {
//		log("transitioned prog");
//		if (event.target.id != 'progress') return false;
//		log("transitioned event");
//		setUp();
//		log("BOOM");
//		transitionCheck();
//	});
//})();