IMDB for TPB

By perbanan Last update Jun 7, 2009 — Installed 1,620 times. Daily Installs: 1, 0, 4, 1, 2, 8, 7, 6, 3, 4, 4, 3, 3, 6, 7, 1, 1, 1, 3, 1, 7, 4, 3, 8, 5, 3, 4, 8, 5, 6, 2, 2

There are 5 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           IMDB for TPB
// @namespace      http://example.com
// @include        http://thepiratebay.org/*
// ==/UserScript==
var nfo = $X("//div[@class='nfo']");

var details = document.getElementById('details');
if(nfo && details)
{
	var col1, dt;

	var str = $X("string(//div[@id='details']/dl/dd/a/text())");
	if(str.match(/Movies|Filmer|Filmar|Film|Elokuvat|Kvikmyndir|Films|Filme|Películas|Filmes|Filmy|Filmek|Filmler|Pel.lícules|Filmid|Filmi|Wayang|Filma|Ταινίες|Фильмы|סרטים| 映画|Филми|افلام|电影|Фільми|চলচ্চিত্র/))
	{
		col1 = details.childNodes[1];
		
		dt = document.createElement('dt');
		dt.textContent = 'More info:';
		col1.appendChild(dt);
		
		dt = document.createElement('dd');
		dt.textContent = 'Loading...';
		col1.appendChild(dt);
		
		findImdbId(function(ids)
		{
			col1.removeChild(dt);
		
			if(ids)
			{
				var imdbId = ids[0];
				var shortImdbId = ids[1];
					
				var dd = document.createElement('dd');
				var a = document.createElement('a');
				a.href = "#imdb";
				a.textContent = "Show IMDB section";
				dd.appendChild(a);
				col1.appendChild(dd);
		
				var dd = document.createElement('dd');
				a = document.createElement('a');
				a.href = "#rotten-tomatoes";
				a.textContent = "Show Rotten Tomatoes";
				dd.appendChild(a);
				col1.appendChild(dd);
					
				var poster = document.createElement("img");
				poster.style.cssFloat = 'left';
					
		
				generateImdb(ids, poster);
				generateRottenTomatoes(ids, poster);
			}
		});
	}
}

function findImdbId(callback)
{
	var nfo = $X("string(//div[@class='nfo'])");
	if(nfo)
	{
		var result = nfo.match(/imdb.com\/title\/(tt([0-9]+))/);

		if(result)
		{
			callback([ result[1], result[2] ]);

			return;;
		}
	}
	
	// Go through comments to check for IMDB-urls
	var urls = $x("//div[@class='comment']/a");

	for(var i in urls)
	{
		var link = urls[i];
		

		var result = link.href.match(/imdb.com\/title\/(tt([0-9]+))/);

		if(result)
		{
			callback([ result[1], result[2] ]);

			return;;
		}
	}

	// We need to perform a search for movies
	var str = $X("string(//div[@id='details']/dl/dd/a/text())");
	if(str.match(/Movies|Filmer|Filmar|Film|Elokuvat|Kvikmyndir|Films|Filme|Películas|Filmes|Filmy|Filmek|Filmler|Pel.lícules|Filmid|Filmi|Wayang|Filma|Ταινίες|Фильмы|סרטים| 映画|Филми|افلام|电影|Фільми|চলচ্চিত্র/))
	{
		var stopwords = [ "VOB", "CAM", "DVDRIP", "TS", "KVCD" ];

		// This is a movie
		var title = $X("string(//div[@id='title'])");
		title = title
		.replace(/^\s+/, '')
		.replace(/\s+$/, '')
		.replace(/\./g, ' ')
		.replace(/\s+/g, ' ')
		.replace(/\_/g, ' ')
		.replace(/\[.*?\]/g, '')
		.replace(/vob(-[a-z0-9]+)?/gi, '')
		.replace(/cam(-[a-z0-9]+)?/gi, '')
		.replace(/dvdrip(-[a-z0-9]+)?/gi, '')
		.replace(/dvdscr(-[a-z0-9]+)?/gi, '')
		.replace(/dvd(-[a-z0-9]+)?/gi, '')
		.replace(/r5(-[a-z0-9]+)?/gi, '')
		.replace(/ts(-[a-z0-9]+)?/gi, '')
		.replace(/kvcd(-[a-z0-9]+)?/gi, '')
		.replace(/xvid(-[a-z0-9]+)?/gi, '')
		.replace(/divx(-[a-z0-9]+)?/gi, '')
		.replace(/x264(-[a-z0-9]+)?/gi, '')
		.replace(/ts(-[a-z0-9]+)?/gi, '')
		.replace(/ws(-[a-z0-9]+)?/gi, '')
		.replace(/proper(-[a-z0-9]+)?/gi, '')
		.replace(/BluRay(-[a-z0-9]+)?/gi, '')
		.replace(/HD-DVD(-[a-z0-9]+)?/gi, '')
		.replace(/screener(-[a-z0-9]+)?/gi, '')
		.replace(/\S+-[a-z0-9]+/gi, '')
		.replace(/[0-9]{3,4}p(-[a-z0-9]+)?/gi, '')
		.replace(/\s[A-Z]+SUB/gi, '')
		.replace(/\([0-9]{4}\)/g, '')
		.replace(/[0-9]{4}/g, '');

		// http://www.imdb.com/find?s=all&q=The+Dark+Knight&x=4&y=10
		var link = "http://www.imdb.com/find?s=all&q=" + URLEncode(title) + "&x=4&y=10";
		wget(link, function(dom)
		{
			var parts = title.toLowerCase().split(" ");
			var bestCandidate = ""; var bestCount = 0;
			
			var links = $x("//a", dom);
			for(var i in links)
			{
				var link = links[i];

				var linkParts = link.textContent.toLowerCase().split(" ");

				var currentCount = 0;
				for(var j in parts)
				{
					for(var x in linkParts)
					{
						if(parts[x] == linkParts[j])
						{
							currentCount++;
							break;
						}
					}
				}

				if(currentCount > bestCount
					&& link.href.match(/title\/(tt([0-9]+))/))
				{
					bestCount = currentCount;
					bestCandidate = link.href;
				}
			}

			var result = bestCandidate.match(/title\/(tt([0-9]+))/);

			if(result)
			{
				callback([ result[1], result[2], true ]);
	
				return;
			}
			
			callback();
		});
	}

	return;
}

function generateImdb(ids, poster)
{
	var imdbId = ids[0];

	// Create the info-box
	var imdb = document.createElement("div");
	imdb.id = "imdb";
	var header = document.createElement("div");
	header.id = "title";
	header.textContent = "IMDB ";
	imdb.appendChild(header);

	nfo.parentNode.insertBefore(imdb, nfo.nextSibling);

	if(ids[2])
	{
		var potential = document.createElement("font");
		potential.color = "white";
		potential.textContent = " (potential match)";
		header.appendChild(potential);
	}

	var loading = document.createElement("font");
	loading.color = "white";
	loading.textContent = " Loading...";
	header.appendChild(loading);

	var t = "http://www.imdb.com/title/" + imdbId + "/";

	imdb.appendChild(poster);

	/*var img = document.createElement("img");
	imdb.appendChild(img);
	
	var poster = "http://posters.motechnet.com/covers/" + imdbId + "_smallCover.jpg";
	img.src = poster;*/

	// Request data from IMDB
	wget(t, function(dom, url, xhr)
	{
		// We now have information from IMDB
		header.removeChild(loading);
		
		var container = document.createElement("div");
		container.style.paddingLeft = "150px";
		imdb.appendChild(container);

		var c1 = document.createElement("dl");
		container.appendChild(c1);

		var title = $x("//div[@id='tn15title']/h1/text()", dom);
		add(c1, "Title", title);

		var year = $x("//div[@id='tn15title']/h1/span/a/text()", dom);
		add(c1, "Year", year);


		var rating = $x("//div[@class='general rating']/div/b/text()", dom);
		add(c1, "Rating", rating);

		var tagline = $x("//div[@class='info']/h5[.='Runtime:']/following-sibling::text()", dom);
		add(c1, "Runtime", tagline);


		var dt = document.createElement('dt');
		dt.textContent = 'Link:';
		c1.appendChild(dt);

		var dd = document.createElement('dd');
		var a = document.createElement('a');
		
		a.href = t;
		a.textContent = t;
		dd.appendChild(a);

		c1.appendChild(dd);

		var c2 = document.createElement("dl");
		container.appendChild(c2);

		var director = $x("//div[@class='info']/h5[.='Director:']/following-sibling::a/text()", dom);
		if(! director[0])
		{
			director = $x("//div[@class='info']/h5[.='Directors:']/following-sibling::a/text()", dom);
			add(c2, "Directors", director);
		}
		else
		{
			add(c2, "Director", director);
		}

		var tagline = $x("//div[@class='info']/h5[.='Tagline:']/following-sibling::text()", dom);
		add(c2, "Tagline", tagline);

		var genre = $x("//div[@class='info']/h5[.='Genre:']/following-sibling::a/text()", dom);
		add(c2, "Genre", genre);

		var cast = $x("//table[@class='cast']//td[@class='nm']/a/text()", dom);
		add(c2, "Cast", cast);

		var c3 = document.createElement("dl");
		container.appendChild(c3);

		var tagline = $x("//div[@class='info']/h5[.='Plot:']/following-sibling::text()", dom);
		add(c3, "Plot", tagline);
		
		var d = document.createElement("div");
		d.style.clear = 'both';
		imdb.appendChild(d);
	});
}

function generateRottenTomatoes(ids, poster)
{
	var imdbId = ids[1];

	// Create the info-box
	var box = document.createElement("div");
	box.id = "rotten-tomatoes";
	var header = document.createElement("div");
	header.id = "title";
	header.textContent = "Rotten Tomatoes ";
	header.style.clear = 'both';
	box.appendChild(header);

	nfo.parentNode.insertBefore(box, nfo.nextSibling.nextSibling);

	if(ids[2])
	{
		var potential = document.createElement("font");
		potential.color = "white";
		potential.textContent = " (potential match) ";
		header.appendChild(potential);
	}

	var loading = document.createElement("font");
	loading.color = "white";
	loading.textContent = " Loading...";
	header.appendChild(loading);

	var rottenImg = document.createElement("img");
	rottenImg.style.verticalAlign = 'middle';
	header.appendChild(rottenImg);

	var t = "http://www.rottentomatoes.com/alias?type=imdbid&s=" + imdbId;

	// Request data from Rotten Tomatoes
	wget(t, function(dom, url, xhr)
	{
		header.removeChild(loading);

		
		
		var c1 = document.createElement("dl");
		box.appendChild(c1);

/*		var title = $x("string(//div[@id='tn15title']/h1)", dom);
		add(c1, "Title", title);*/

		var dt = document.createElement('dt');
		dt.textContent = 'Link:';
		c1.appendChild(dt);

		var dd = document.createElement('dd');
		var a = document.createElement('a');
		
		a.href = t;
		a.textContent = t;
		dd.appendChild(a);

		c1.appendChild(dd);

		var img = $x("//div[@class='movie_tools_area']//img/@src", dom);

		if(! img[0])
		{
			poster.src = 'http://images.rottentomatoes.com/images/poster_default.gif';
			return;
		}
		
		poster.src = img[0].nodeValue;

		var c1 = document.createElement("dl");
		box.appendChild(c1);

		var percentage = $x("//span[@class='percent']/text() | //span[@class='perfect']/text()", dom);
		add(c1, "Rating", percentage[0].nodeValue + "%");

		rottenImg.src = getRottenImage(percentage[0].nodeValue);

		var consensus = $x("//*[@id='consensus']/text()", dom);
		add(c1, "Consensus", consensus);

		var c1 = document.createElement("dl");
		box.appendChild(c1);

		var synopsis = $x("//span[@id='movie_synopsis_blurb']/text()", dom);
		add(c1, "Synopsis", synopsis, "rt-synopsis-blurb");

		
	});
}

function add(root, header, content, id)
{
	if(! content || ! content[0])
	{
		return;
	}

	var dt = document.createElement('dt');
	dt.textContent = header + ':';
	root.appendChild(dt);

	var dd = document.createElement('dd');
	if(id)
	{
		dd.id = id;
	}

	var con = "";
	if(typeof content != 'string')
	{	
		for(var c in content)
		{
	
			var trimmed = !! content[c].nodeValue ? content[c].nodeValue : content[c];
			trimmed = trimmed.replace(/^\s+/, '').replace(/\s+$/, '');
	
			if(trimmed != "more" && trimmed != "" && trimmed != "|")
			{
				if(con != "")
				{
					con += ", ";
				}
	
				con += trimmed;
			}
			
		}
	}
	else
	{
		con = content;
	}

	if(con == "")
	{
		con = "Unknown";
	}

	dd.textContent = con;

	root.appendChild(dd);
}

function getRottenImage(percentage)
{
	if (percentage >= 60) { // it's fresh
					return 'data:image/png;base64,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';
				}
				else { // it's rotten
					return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gHGAQ2MyTxzz0AAAMSSURBVDjLhZPra1tlHMe/z7nk0nPSpklz2WKTrra1J7Ht3FoliGJ1MMS51g3xnXgDwf0dDuYLwaHgfQr6SjfpXKkIKjjsVqKburZZ0NUu7Zo0adpkzTkn5zznPI8vpCLTzc+77w9+X35XglsYPirtj4W9x1zGjPWa8+7CF/RX3AHyT6FNyJ7RTLJ45MBzMcZcnPnmw/qlxVIyP0W3b2cg3aJ7wsH2mGXrAIBdXbGgsbE2BGBWm5AJgGEAAQBz+SlK/zbY+7Q8Gg2pz2w2jIvX14p5rXddEwUZ1Vod1avuljYhK1pv/PTQwOCjrmOKsz/npvPAYQCQMpOyNpq563ymb8S3Vik557679Hyoffb1+9IjkUpZLxs1XuhQybHsyNBBv08F0In+nt2Hbjyxendhml4TJInsj0cCPsZbiEc6pWiXV7vy+/WTLbuOZE9QHn8x8HJ/z+4XBJHBojdh0ZsggkO2SywFAESbkCN702runj3dKb+3A41tw7KpbUfDnQHOOWxKIcsyOHfhuBYazS3Mfl+y5740e10bNwgAaAc9w7Go5710OjiWTMQJEURQx4RNdQhEhEdWcOHiMvtt3ig2626psuS+Y+v8YwAQAAA+vlCYNx8/f2HjOOUmONEBwYTHK0DycDCio1ym3263nMcCveThnWQAINln1T5tIPSRqsi72vxSKBbxBwn5975blovaZqvW1J3V9apx7tofjTd/+bxVlgb7w8ezY4kH8T8oChAOBcIAwozxkctXKk/ZtDgmlCvGNCCxtjY/VlZM5OaqtiB6oKoKVFWBZRF89umSsVGjdCfW3q4ie38qLQpkXFou1j859f583NHJKwu5rRmryd/uekM9m30g2Q0A5XUTP/1QPSx2sH19fdHXfN6/jtcwKPQaU6T8FHWBzRMATuyUazsspyj+bgC4N5NAap8vsVzcOjmXW33ywPjAQy7jOHtmka3mnKvSf/X74+WVDzJaYjIWCQhfzRT44tdGqdXglrGxMDlzeunV5qajrRVap6iJ239qZFB8pDMlvCV5yUt3Gu6fwOFaILXvWhsAAAAASUVORK5CYII=';
				}
}

function URLEncode (clearString) {
  var output = '';
  var x = 0;
  clearString = clearString.toString();
  var regex = /(^[a-zA-Z0-9_.]*)/;
  while (x < clearString.length) {
    var match = regex.exec(clearString.substr(x));
    if (match != null && match.length > 1 && match[1] != '') {
    	output += match[1];
      x += match[1].length;
    } else {
      if (clearString[x] == ' ')
        output += '+';
      else {
        var charCode = clearString.charCodeAt(x);
        var hexVal = charCode.toString(16);
        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
      }
      x++;
    }
  }
  return output;
}

// Utility methods from http://ecmanaut.googlecode.com/svn/trunk/lib/gm/wget.js

// list nodes matching this expression, optionally relative to the node `root'
function $x( xpath, root ) {
  var doc = root ? root.evaluate ? root : root.ownerDocument : document, next;
  var got = doc.evaluate( xpath, root||doc, null, 0, null ), result = [];
  switch (got.resultType) {
    case got.STRING_TYPE:
      return got.stringValue;
    case got.NUMBER_TYPE:
      return got.numberValue;
    case got.BOOLEAN_TYPE:
      return got.booleanValue;
    default:
      while (next = got.iterateNext())
	result.push( next );
      return result;
  }
}

function $X( xpath, root ) {
  var got = $x( xpath, root );
  return got instanceof Array ? got[0] : got;
}


// Fetches url, $x slices it up, and then invokes cb(nodes, url, dom, xhr).
// If runGM is set to true and the url is on the same domain as location.href,
// the loaded document will first be processed by all GM scripts that apply. If
// div is set to true and runGM is not, the DOMization will be via a div instead
// of a frame (which munges the html, head and body tags), but saves resources.
// Note when using div: use xpath expressions starting in "./", not "/", as the
// root node is not connected. Also, the document passed to cb will be the div.
function wget$x( url, cb/*( [DOMNodes], url, dom, xhr )*/, xpath, runGM, div ) {
  wget(url, function(xml, url, xhr) {
    cb( $x( xpath, xml ), url, xml, xhr );
  }, runGM, div);
}

// Fetches url, $X slices it up, and then invokes cb(node, url, dom, xhr).
// If runGM is set to true and the url is on the same domain as location.href,
// the loaded document will first be processed by all GM scripts that apply.  If
// div is set to true and runGM is not, the DOMization will be via a div instead
// of a frame (which munges the html, head and body tags), but saves resources.
// Note when using div: use xpath expressions starting in "./", not "/", as the
// root node is not connected. Also, the document passed to cb will be the div.
function wget$X( url, cb/*( DOMNode, url, dom, xhr )*/, xpath, runGM, div ) {
  wget(url, function(xml, url, xhr) {
    cb( $X( xpath, xml ), url, xml, xhr );
  }, runGM, div);
}

// Fetches url, turns it into an HTML DOM, and then invokes cb(dom, url, xhr).
// If runGM is set to true and the url is on the same domain as location.href,
// the loaded document will first be processed by all GM scripts that apply.  If
// div is set to true and runGM is not, the DOMization will be via a div instead
// of a frame (which munges the html, head and body tags), but saves resources.
function wget( url, cb/*( dom, url, xhr )*/, runGM, div ) {
  //console.log("Loading %x", url);
  if (html2dom[url]) // cache hit?
    return html2dom(null, cb, url, null, runGM);
  var xhr = { method:'GET', url:url, onload:function( xhr ) {
    if (xhr.responseXML)
      cb( xhr.responseXML, url, xhr );
    else
      html2dom( xhr.responseText, cb, url, xhr, runGM, div );
  }};
  if (wget.xhr)
    wget.xhr(xhr);
  else
    GM_xmlhttpRequest(xhr);
}

function mayCommunicate(url1, url2) {
  function beforePath(url) {
    url = url.match(/^[^:]+:\/*[^\/]+/);
    return url && url[0].toLowerCase();
  }
  return beforePath(url1) == beforePath(url2);
}

// Well-behaved browers (Opera, maybe WebKit) could use this simple function:
// function html2dom( html, cb/*( xml, url, xhr )*/, url, xhr ) {
//   cb( (new DOMParser).parseFromString(html, "text/html"), url, xhr );
// }

// Firefox doesn't implement (new DOMParser).parseFromString(html, "text/html")
// (https://bugzilla.mozilla.org/show_bug.cgi?id=102699), so we need this hack:
function html2dom( html, cb/*( xml, url, xhr )*/, url, xhr, runGM, div ) {
  function loaded() {
    doc = cached.doc = iframe.contentDocument;
    iframe.removeEventListener("load", loaded, false);
    doc.removeEventListener("DOMContentLoaded", loaded, false);
    var callbacks = cached.onload;
    delete cached.onload;
    //console.log("DOMContentLoaded of %x: cb %x", url, callbacks);
    setTimeout(function() { // avoid racing with GM's DOMContentLoaded callback
      //console.log("Running %x callbacks", url);
      callbacks.forEach(function(cb,i) { cb( doc, url, xhr ); });
    }, 10);
  };
  function wipeJavascript(html) {
    var x = html.replace(/[\n\r]+/g, " "). // needed not freeze up(?!)
      replace(/<script.*?<\/script>/ig, ""). // no code execution on injection!
      replace(/<noscript.*?<\/noscript>/ig, ""). // no code execution on injection!
      replace(/<iframe.*?<\/iframe>/ig, ""). // no code execution on injection!
      replace(/<body(\s+[^="']*=("[^"]*"|'[^']*'|[^'"\s]\S*))*\s*onload=("[^"]*"|'[^']*'|[^"']\S*)/ig, "<body$1");
// 	console.log(x);
	return x;
  };

  if (div && !runGM) {
    var parent = document.createElement("div");
    parent.innerHTML = wipeJavascript(html);
    return setTimeout(cb, 10, parent, url); // hopefully render it first
  }

  var cached = html2dom[url]; // cache of all already loaded and rendered DOM:s
  if (cached)
    if (cached.onload)
      return cached.onload.push(cb);
    else
      return cb(cached.doc, url, cached.xhr);

  var iframe = document.createElement("iframe");
  iframe.style.height = iframe.style.left = "0";
  iframe.style.width = (innerWidth - 32)+"px";
  iframe.style.visibility = "hidden";
  iframe.style.position = "absolute";
  document.body.appendChild(iframe);

  iframe.addEventListener("load", loaded, false);
  html2dom[url] = cached = { onload:[cb], xhr:xhr };
  if (runGM && mayCommunicate(url, location.href))
    return iframe.src = url; // load through GM (should be cached due to xhr)

  //console.log("May not communicate / GM scripts unwanted! (%x)", runGM);
  html = wipeJavascript(html);
  iframe.contentWindow.location.href = location.href; // for cross domain issues
  var doc = iframe.contentDocument;
  doc.open("text/html");
  doc.addEventListener("DOMContentLoaded", loaded, false);
  doc.write(html); // this may throw weird errors we can't catch or silence :-|
  doc.close();
}

html2dom.destroy = function() {
  for (var url in html2dom)
    if (html2dom.hasOwnProperty(url)) {
      var cache = html2dom[url];
      cache.doc = cache.onload = cache.xhr = null;
      delete html2dom[url];
    }
};

// functionally belongs to html2dom above (see location.href line for details)
try { // don't run this script recursively on wget() documents on other urls
  if (window.frameElement &&
      window.parent.location.href.replace(/#.*/, "") == location.href)
    throw (new Error("wget.js: Avoiding double firing on " + location.href));
} catch(e) {
  //console.error("Double fire check error: %x", e);
}

window.addEventListener("unload", html2dom.destroy, false);