IMDB works#

Shows number of credited works after names on IMDB site

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==//
// @name           IMDB works#
// @description    Shows number of credited works after names on IMDB site
// @match          *://*.imdb.com/*
// @version        1.0.7
// @author         wOxxOm
// @namespace      wOxxOm.scripts
// @license        MIT License
// @grant          GM_addStyle
// @run-at         document-start
// @require        https://greatest.deepsurf.us/scripts/12228/code/setMutationHandler.js
// ==/UserScript==

var SELECTOR = 'a[href^="/name/nm"]';
var CACHE_FRESH_DURATION = 30 * 24 * 3600 * 1000; // 1 month
var CACHE_STALE_DURATION = CACHE_FRESH_DURATION * 2; // keep stale data another 2 months, then kill

GM_addStyle(
	'.number-of-works, .number-of-works span { opacity: 0.5; transition: opacity .25s ease-in-out .25s; }' +
	'.number-of-works span:before { content: "/"; }' +
	'.number-of-works:hover { opacity: 1.0; }' +
	'.number-of-works:hover span { opacity: 1.0; }' +
	'.number-of-works:before { content: " ["; opacity: 0.5; }' +
	'.number-of-works:after { content: "]"; opacity: 0.5; }'
);

process(document.querySelectorAll(SELECTOR));
setMutationHandler(document, SELECTOR, process);

if (location.pathname.match(/\/name\/nm\d+\/?$/)) {
	document.addEventListener('DOMContentLoaded', function() {
		parseNamePage(document, {cacheKey: 'works#' + location.pathname.match(/\/name\/nm(\d+)\/?$/)[1]});
	});
}

function process(links) {
	var now = Date.now();
	for (var link, i = 0; (link = links[i++]); ) {
		if (link.querySelector('img') ||
			!link.textContent.trim() ||
			link.children[0] && link.textContent.trim() != link.children[0].textContent.trim() ||
			link.nextElementSibling && link.nextElementSibling.matches('.number-of-works'))
			continue;
		var id = (link.pathname.match(/\/name\/nm(\d+)\/?$/) || [])[1];
		if (!id)
			continue;
		var cacheKey = 'works#' + id;
		var cache = (localStorage[cacheKey] || '').split('\t');
		if (cache.length == 2 && +cache[0] && cache[1]) {
			showWorksNum(link, cache[1]);
			var isFresh = +cache[0] > now;
			if (isFresh)
				continue;
		}
		doXHR({
			url: link.pathname,
			link: link,
			cacheKey: cacheKey,
			onload: parseNamePage,
		});
	}
}

function showWorksNum(link, num) {
    num = num.toString().replace(/\/(\d+)/, '<span>$1</span>');
	if (link.nextElementSibling && link.nextElementSibling.matches('.number-of-works')) {
		link.nextElementSibling.innerHTML = num;
	} else {
		link.insertAdjacentHTML('afterend', '<span class="number-of-works">' + num + '</span>');
	}
}

function parseNamePage(doc, options) {
	var credits = [].map.call(doc.querySelectorAll('#filmography .head'), function(e) {
		return {
			num: +(e.textContent.match(/\((\d+) credits?\)/i) || [])[1],
			type: (e.querySelector('a[name]') || {name: ''}).name,
		};
	});
	if (!credits.length)
		return;
	var creditsSum = credits.reduce(function(sum, e) { return sum + e.num; }, 0);
	var rxIgnore = /^(self|archive_footage|thanks)$/;
	var creditsSorted = credits.sort(function(a, b) {
		if (rxIgnore.test(a.type))
			return 1;
		else if (rxIgnore.test(b.type))
			return -1;
		else
			return b.num - a.num || (a.type == 'actor' ? -1 : b.type == 'actor' ? 1 : 0);
	});
	var worksNum = rxIgnore.test(creditsSorted[0].type) ? creditsSum : creditsSorted[0].num + (credits.length > 1 ? '/' + creditsSum : '');
	localStorage[options.cacheKey] = '' + (Date.now() + CACHE_FRESH_DURATION) + '\t' + worksNum;
	if (options.link)
		showWorksNum(options.link, worksNum);
}

function doXHR(options) {
	if (document.readyState == 'complete') {
		sendRequest(options);
		return;
	}
	if (!doXHR.queue)
        initQueue();
    if (!isDupe()) {
        doXHR.queue.push(options);
        doXHR.queuedUrl[options.url] = options;
    }

	function sendRequest(options) {
		var xhr = new XMLHttpRequest();
		xhr.open('GET', options.url);
		xhr.responseType = 'document';
		xhr.onload = function(e) {
			options.onload(xhr.response, options);
            doXHR.activeRequests--;
            poolQueue();
		};
        doXHR.activeRequests++;
		xhr.send();
	}

	function initQueue() {
		doXHR.queue = [];
		doXHR.queuedUrl = {};
        doXHR.activeRequests = 0;
		document.addEventListener('DOMContentLoaded', function() {
			cleanupStorage();
            poolQueue();
		});
    }

	function isDupe() {
        var dupe = doXHR.queuedUrl[options.url];
        if (!dupe)
            return false;
        if (dupe.link == options.link)
            return true;
        // this request's link element will use the will-be-cached data from the earlier queued request
        options.url = '';
        var _onload = dupe.onload;
        dupe.onload = function() {
            _onload.apply(null, arguments);
            showWorksNum(options.link, localStorage[options.cacheKey].split('\t')[1]);
        };
        return true;
    }

    function poolQueue() {
        while (doXHR.queue.length && doXHR.activeRequests < 16) {
            sendRequest(doXHR.queue.shift());
        }
    }
}

function cleanupStorage() {
	setTimeout(function doCleanup() {
		var now = Date.now(), i = 0;
		for (var k in localStorage) {
			if (k.lastIndexOf('works#', 0) === 0 && (+localStorage[k].split('\t')[0]) + CACHE_STALE_DURATION < now) {
				delete localStorage[k];
			}
			if (++i % 100 === 0 && Date.now() - now > 10) {
				setTimeout(doCleanup, 1000);
				return;
			}
		}
	}, 1000);
}