IMDB - add Rottentomatoes info

Adds info from Rottentomatoes to IMDB title pages

目前為 2015-01-17 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name			IMDB - add Rottentomatoes info
// @namespace		https://greasyfork.org/en/users/7864-curtis-gibby
// @description		Adds info from Rottentomatoes to IMDB title pages
// @grant			GM_xmlhttpRequest
// @version			3.5.1
// @include			http://*.imdb.com/title/*/
// @include			http://*.imdb.com/title/*/?*
// @include			http://*.imdb.com/title/*/maindetails
// @include			http://*.imdb.com/title/*/combined
// @include			http://imdb.com/title/*/
// @include			http://imdb.com/title/*/maindetails
// @include			http://imdb.com/title/*/combined
// @require			http://code.jquery.com/jquery-1.11.0.min.js
// ==/UserScript==

// ==Test Cases ==
// http://www.imdb.com/title/tt1375666/ -- Inception (2010) -- RT IMDb Alias API normal (best case scenario)
// http://www.imdb.com/title/tt1375666/combined -- Inception (2010) -- Old IMDb layout -- RT IMDb Alias API normal (best case scenario)
// http://www.imdb.com/title/tt1187064/ -- Triangle (2009) -- Has a Tomatometer rating, but no consensus yet
// http://www.imdb.com/title/tt1762308/ -- Midway to Heaven (2011) -- No Tomatometer rating and no consensus
// http://www.imdb.com/title/tt1126618/ -- Morning Glory (2010) -- RT IMDb Alias API error, works through regular RT API
// http://www.imdb.com/title/tt0386676/ -- The Office (TV Series 2005– ) -- TV show (shouldn't add any RT information)
// http://www.imdb.com/title/tt1848620/ -- "The Office" Search Committee -- TV show episode (shouldn't add any RT information)
// http://www.imdb.com/title/tt1848620/combined -- "The Office" Search Committee -- Old IMDb layout -- TV show episode (shouldn't add any RT information)

// http://www.imdb.com/title/tt1375666/ -- Inception (2010) -- certified fresh
// http://www.imdb.com/title/tt1375666/ -- Inception (2010) -- upright bucket
// http://www.imdb.com/title/tt0121765/ -- Star Wars: Episode II - Attack of the Clones (2002) -- fresh
// http://www.imdb.com/title/tt0105643/ -- Troll 2 (1990) -- rotten
// http://www.imdb.com/title/tt0105643/ -- Troll 2 (1990) -- spilled bucket


// ==User-Defined Variables==

rottenTomatoesApiKey = 'husypbhbxuguyvaa63nbjncu'; // customize for your own Rotten Tomatoes API login details

//showConsensus = false;
showConsensus = true;

//useRottenTomatoesColors = false;
useRottenTomatoesColors = true;

//showAudience = false;
showAudience = true;

// options below are temporarily deprecated until Rotten Tomatoes adds them to their API
	//showAverageRating = false;
	//showAverageRating = true;

	//showReviewCount = false;
	//showReviewCount = true;

	//showFreshReviewCount = false;
	//showFreshReviewCount = true;

	//showRottenReviewCount = false;
	//showRottenReviewCount = true;

// ==/User-Defined Variables==

if (document.getElementById('tn15') != null) {
	oldImdbLayout = true;
}
else {
	oldImdbLayout = false;
}

if (useRottenTomatoesColors == true) {
	var stylesheet = '								\
<style>												\
	#rottenTomatoesResults {						\
		padding: 5px;								\
		margin-top: 5px;							\
		clear: both;								\
		color: #6F6A57;								\
		border: 1px solid #dddddd;					\
		border-radius: 10px;						\
		-moz-box-shadow: 0px 0px 5px #ddd; 			\
		-webkit-box-shadow: 0px 0px 5px #ddd; 		\
		box-shadow: 0px 0px 5px #ddd; 				\
		background-image: -webkit-gradient(			\
			linear,									\
			left top,								\
			left 25,								\
			color-stop(0.1, rgb(255,227,125)),		\
			color-stop(0.3, rgb(255,254,215))		\
		);											\
		background-image: -moz-linear-gradient(		\
			center top,								\
			rgb(255,227,125) 10%,					\
			rgb(255,254,215) 30%					\
		);											\
	}												\
	#rottenTomatoesResults a, #rottenTomatoesResults a:link, #rottenTomatoesResults a:hover {	\
		color: #506A16 !important;					\
		text-decoration: none !important;			\
	}												\
	#rottenTomatoesResults a:hover {				\
		text-decoration: underline !important;		\
	}												\
	#rottenTomatoesResults img {					\
		margin-right: 10px;							\
	}												\
	#rottenTomatoesResults div.rtIcon {				\
		background:url("http://images.rottentomatoescdn.com/images/redesign/icons-v2.png") 0 0;						\
		float: left;								\
		width: 48px;								\
		height: 48px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.fresh {		\
		background-position: 120px 132px;			\
	}												\
	#rottenTomatoesResults div.rtIcon.certified_fresh {		\
		background-position: 120px 84px;			\
	}												\
	#rottenTomatoesResults div.rtIcon.rotten {		\
		background-position: 72px 84px;				\
	}												\
	#rottenTomatoesResults div.rtIcon.upright {		\
		background-position: 280px 52px;			\
		width: 32px;								\
		height: 32px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.spilled {		\
		background-position: 184px 52px;			\
		width: 32px;								\
		height: 32px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.wts {			\
		background-position: 312px 52px;			\
		width: 32px;								\
		height: 32px;								\
	}												\
	#rottenTomatoesResults .floater {				\
		float:left;									\
		padding: 0 3px;								\
	}												\
	#rottenTomatoesResults .rt-credits {			\
		font-size: 11px;							\
	}												\
	#rottenTomatoesTomatoMeterScore, #rottenTomatoesAudience {				\
		font-family: Arial, Helvetica, sans-serif;	\
		font-size: 40px; 							\
		font-weight: 700; 							\
		font-style: normal; 						\
		color: #506A16; 							\
	}												\
	#rottenTomatoesTomatoMeterScore.noScore {		\
		font-size: 26px; 							\
	}												\
	#rottenTomatoesAudience {						\
		font-size: 30px; 							\
	}												\
	#rottenTomatoesConsensus {						\
		width:57%;									\
		font-size:11px;								\
		margin-top:10px;							\
		line-height:1.5em;							\
	}												\
	.rottenClear {									\
		clear: both;								\
	}												\
</style>';


}
else {
	var stylesheet = '								\
<style>												\
	#rottenTomatoesResults {						\
		clear: both;								\
		margin-top: 5px;							\
	}												\
	#rottenTomatoesResults .floater {				\
		float:left;									\
		padding: 0 3px;								\
	}												\
	#rottenTomatoesResults div.rtIcon {				\
		background:url("http://images.rottentomatoescdn.com/images/redesign/icons-v2.png") 0 0;						\
		float: left;								\
		width: 32px;								\
		height: 32px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.fresh {		\
		background-position: 249px 48px;			\
	}												\
	#rottenTomatoesResults div.rtIcon.certified_fresh {		\
		background-position: 152px 48px;			\
	}												\
	#rottenTomatoesResults div.rtIcon.rotten {		\
		background-position: 217px 48px;			\
	}												\
	#rottenTomatoesResults div.rtIcon.upright {		\
		background-position: 24px 152px;			\
		width: 24px;								\
		height: 24px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.spilled {		\
		background-position: 24px 56px;				\
		width: 24px;								\
		height: 24px;								\
	}												\
	#rottenTomatoesResults div.rtIcon.wts {			\
		background-position: 24px 176px;			\
		width: 24px;								\
		height: 24px;								\
	}												\
	#rottenTomatoesConsensus {						\
		width:80%;									\
	}												\
	.rottenClear {									\
		clear: both;								\
	}												\
</style>';
}
$('head').append(stylesheet);

findPattern = "//table[@class='probody']";
results = document.evaluate( findPattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

if (results.snapshotItem(0) != null)
{
	proImdbLayout = true;
}
else {
	proImdbLayout = false;
}

$('head').append(stylesheet);

var insertSelector = "div.star-box";
var labelHtml = 'Rotten Tomatoes:';

if (oldImdbLayout == true) {
	insertSelector = "div.info:first";
}

if (proImdbLayout == true) {
	insertSelector = "table.probody";
}

var spinnerGif = $('<img></img>').
	attr('alt', "...").
	attr('src', 'data:image/gif;base64,'+
		'R0lGODlhEAAQAPYAAP///wAAANTU1JSUlGBgYEBAQERERG5ubqKiotzc3KSkpCQkJCgoKDAwMDY2'+
		'Nj4+Pmpqarq6uhwcHHJycuzs7O7u7sLCwoqKilBQUF5eXr6+vtDQ0Do6OhYWFoyMjKqqqlxcXHx8'+
		'fOLi4oaGhg4ODmhoaJycnGZmZra2tkZGRgoKCrCwsJaWlhgYGAYGBujo6PT09Hh4eISEhPb29oKC'+
		'gqioqPr6+vz8/MDAwMrKyvj4+NbW1q6urvDw8NLS0uTk5N7e3s7OzsbGxry8vODg4NjY2PLy8tra'+
		'2np6erS0tLKyskxMTFJSUlpaWmJiYkJCQjw8PMTExHZ2djIyMurq6ioqKo6OjlhYWCwsLB4eHqCg'+
		'oE5OThISEoiIiGRkZDQ0NMjIyMzMzObm5ri4uH5+fpKSkp6enlZWVpCQkEpKSkhISCIiIqamphAQ'+
		'EAwMDKysrAQEBJqamiYmJhQUFDg4OHR0dC4uLggICHBwcCAgIFRUVGxsbICAgAAAAAAAAAAAACH/'+
		'C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwA'+
		'AAAAEAAQAAAHjYAAgoOEhYUbIykthoUIHCQqLoI2OjeFCgsdJSsvgjcwPTaDAgYSHoY2FBSWAAML'+
		'E4wAPT89ggQMEbEzQD+CBQ0UsQA7RYIGDhWxN0E+ggcPFrEUQjuCCAYXsT5DRIIJEBgfhjsrFkaD'+
		'ERkgJhswMwk4CDzdhBohJwcxNB4sPAmMIlCwkOGhRo5gwhIGAgAh+QQJCgAAACwAAAAAEAAQAAAH'+
		'jIAAgoOEhYU7A1dYDFtdG4YAPBhVC1ktXCRfJoVKT1NIERRUSl4qXIRHBFCbhTKFCgYjkII3g0hL'+
		'UbMAOjaCBEw9ukZGgidNxLMUFYIXTkGzOmLLAEkQCLNUQMEAPxdSGoYvAkS9gjkyNEkJOjovRWAb'+
		'04NBJlYsWh9KQ2FUkFQ5SWqsEJIAhq6DAAIBACH5BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhQkK'+
		'E2kGXiwChgBDB0sGDw4NDGpshTheZ2hRFRVDUmsMCIMiZE48hmgtUBuCYxBmkAAQbV2CLBM+t0pu'+
		'aoIySDC3VC4tgh40M7eFNRdH0IRgZUO3NjqDFB9mv4U6Pc+DRzUfQVQ3NzAULxU2hUBDKENCQTtA'+
		'L9yGRgkbcvggEq9atUAAIfkECQoAAAAsAAAAABAAEAAAB4+AAIKDhIWFPygeEE4hbEeGADkXBycZ'+
		'Z1tqTkqFQSNIbBtGPUJdD088g1QmMjiGZl9MO4I5ViiQAEgMA4JKLAm3EWtXgmxmOrcUElWCb2zH'+
		'kFQdcoIWPGK3Sm1LgkcoPrdOKiOCRmA4IpBwDUGDL2A5IjCCN/QAcYUURQIJIlQ9MzZu6aAgRgwF'+
		'GAFvKRwUCAAh+QQJCgAAACwAAAAAEAAQAAAHjIAAgoOEhYUUYW9lHiYRP4YACStxZRc0SBMyFoVE'+
		'PAoWQDMzAgolEBqDRjg8O4ZKIBNAgkBjG5AAZVtsgj44VLdCanWCYUI3txUPS7xBx5AVDgazAjC3'+
		'Q3ZeghUJv5B1cgOCNmI/1YUeWSkCgzNUFDODKydzCwqFNkYwOoIubnQIt244MzDC1q2DggIBACH5'+
		'BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhTBAOSgrEUEUhgBUQThjSh8IcQo+hRUbYEdUNjoiGlZW'+
		'QYM2QD4vhkI0ZWKCPQmtkG9SEYJURDOQAD4HaLuyv0ZeB4IVj8ZNJ4IwRje/QkxkgjYz05BdamyD'+
		'N9uFJg9OR4YEK1RUYzFTT0qGdnduXC1Zchg8kEEjaQsMzpTZ8avgoEAAIfkECQoAAAAsAAAAABAA'+
		'EAAAB4iAAIKDhIWFNz0/Oz47IjCGADpURAkCQUI4USKFNhUvFTMANxU7KElAhDA9OoZHH0oVgjcz'+
		'rJBRZkGyNpCCRCw8vIUzHmXBhDM0HoIGLsCQAjEmgjIqXrxaBxGCGw5cF4Y8TnybglprLXhjFBUW'+
		'VnpeOIUIT3lydg4PantDz2UZDwYOIEhgzFggACH5BAkKAAAALAAAAAAQABAAAAeLgACCg4SFhjc6'+
		'RhUVRjaGgzYzRhRiREQ9hSaGOhRFOxSDQQ0uj1RBPjOCIypOjwAJFkSCSyQrrhRDOYILXFSuNkpj'+
		'ggwtvo86H7YAZ1korkRaEYJlC3WuESxBggJLWHGGFhcIxgBvUHQyUT1GQWwhFxuFKyBPakxNXgce'+
		'YY9HCDEZTlxA8cOVwUGBAAA7AAAAAAAAAAAA'
	);
	
// try to avoid running on TV series pages
if (document.title.indexOf('TV Series') < 0
	&& document.title.indexOf('TV mini-series') < 0
	&& $("#pagecontent").html().indexOf('<h2 class="tv_header">') < 0
	&& $("#pagecontent").html().indexOf("<h5>TV Series:</h5>") < 0
) {
	getRTFromImdbId();
}

function getRTFromImdbId() {

	var rottenTomatoesResults = $('<div></div>').
		attr('id', "rottenTomatoesResults").
		html("Checking Rotten Tomatoes... ").
		append(spinnerGif);
	$(insertSelector).append(rottenTomatoesResults);

	var rtUrl = 'http://api.rottentomatoes.com/api/public/v1.0/movie_alias.json?type=imdb&id='+getIMDBid()+'&apikey='+rottenTomatoesApiKey;

	GM_xmlhttpRequest({
		method: "GET",
		url: rtUrl,
		onload: function(response) {
			response = JSON.parse(response.responseText);

			if (response.hasOwnProperty("error")) {
				rottenTomatoesResults.html("Got error from Rotten Tomatoes' IMDb Alias API: \"")
					.append(response.error + '"');

				if (response.error != "Account Inactive") {
					rottenTomatoesResults
						.append("\" Trying Rotten Tomatoes Movie API...")
						.append(spinnerGif);

					getRTFromTitle();
				}
			}
			else {
				parseValidResponse(response);
			}
		}
	});
} // end function getRTFromImdbId

function getRTFromTitle() {
	var rtUrl = 'http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey='+rottenTomatoesApiKey+'&q='+getMovieName()+'%20'+getMovieYear();

	GM_xmlhttpRequest({
		method: "GET",
		url: rtUrl,
		onload: function(response) {
			response = JSON.parse(response.responseText);

			if (response.hasOwnProperty("error")) {
				rottenTomatoesResults.html("Got error from Rotten Tomatoes' Movie API: \"").
					append(response.error).
					append("\" Giving up.");
			}
			else {
				if (response.hasOwnProperty("movies")) {
					parseValidResponse(response.movies[0])
				}
				else {
					rottenTomatoesResults.html("Unable to find film in Rotten Tomatoes' Movie API. Giving up.");
				}
			}
		}
	});
}
function parseValidResponse(response) {
	var rottenResults = $('#rottenTomatoesResults');
	
	// add tomato-meter score and icon
	var tomatoMeterScoreImage = '';
	if (response.ratings.critics_score == -1) {
		tomatoMeterScoreText = "No Score Yet...";
		tomatoMeterScoreClass = " noScore";
	}
	else {
		tomatoMeterScoreText = response.ratings.critics_score;
		tomatoMeterScoreClass = "";
		
		critics_rating_text = response.ratings.critics_rating;
		
		if (critics_rating_text == "Certified Fresh") { // it's certified fresh
			critics_rating_image_class = 'certified_fresh';
		}
		else {
			if (critics_rating_text == "Fresh") { // it's fresh
				critics_rating_image_class = 'fresh';
			}
			else { // it's rotten
				critics_rating_image_class = 'rotten';
			}
		}
		tomatoMeterScoreText = response.ratings.critics_score + "%";

		tomatoMeterScoreImage = $('<div></div>').
			attr('class', 'rtIcon ' + critics_rating_image_class).
			attr('title', critics_rating_text + " - "+ tomatoMeterScoreText);

		if (critics_rating_text == "Certified Fresh") { // it's certified fresh
			critics_rating_image_class = 'certified_fresh';
		}
		else {
			if (critics_rating_text == "Fresh") { // it's fresh
				critics_rating_image_class = 'fresh';
			}
			else { // it's rotten
				critics_rating_image_class = 'rotten';
			}
		}

	}

	var tomatoMeterScore = $('<span></span>').
		attr("id", "rottenTomatoesTomatoMeterScore").
		text(tomatoMeterScoreText);

	var tomatoMeter = $('<a></a>').
		attr('href', response.links.alternate).
		attr("id", "rottenTomatoesTomatoMeterScore").
		attr("title", "\""+response.title+"\" on Rotten Tomatoes").
		addClass("floater"+tomatoMeterScoreClass).
		html('<p class="rt-credits">Rotten Tomatoes® Score</p>').
		append(tomatoMeterScoreImage).
		append(tomatoMeterScoreText);
		
	rottenResults.html(tomatoMeter);

	if (showConsensus) {
		if (response.hasOwnProperty("critics_consensus")) {
			var consensusText = response.critics_consensus;
		}
		else {
			var consensusText = "No Consensus Yet";
		}
		rottenResults.append(
			$('<div></div>').
				attr("id", "rottenTomatoesConsensus").
				addClass("floater").
				html("<b>Consensus</b> : ").
				append(consensusText)
		);
	}
	
	if (showAudience) {
		if (response.ratings.hasOwnProperty("audience_rating")) {
			audience_rating_text = response.ratings.audience_rating;
		}
		else {
			audience_rating_text = "No Audience Rating Yet";
		}
		
		audience_rating_label = "Liked It";
		if (audience_rating_text == "Upright") {
			audience_rating_image_class = 'upright';
		}
		else {
			if (audience_rating_text == "Spilled") {
				audience_rating_image_class = 'spilled';
			}
			else {
				audience_rating_label = "Want To See It";
				audience_rating_image_class = 'wts';
			}
		}
		
		AudienceScoreText = response.ratings.audience_score + "%";
		

		AudienceScoreImage = $('<div></div>').
			attr('class', 'rtIcon ' + audience_rating_image_class).
			attr('title', audience_rating_text+" - "+AudienceScoreText+" "+audience_rating_label);

			rottenResults.append(
			$('<a></a>').
				attr("href", response.links.alternate).
				attr("id", "rottenTomatoesAudience").
				attr("title", "\""+response.title+"\" on Rotten Tomatoes").
				addClass("floater").
				append(AudienceScoreImage).
				append(AudienceScoreText)
		);
	}
	
	rottenResults.append(
		$('<div></div>').
			addClass("rottenClear").
			html("&nbsp;")
	);
	
	// TODO add average rating -- currently not implemented in RT API
	
	// TODO add review count -- currently not implemented in RT API
	
	// TODO add fresh review count -- currently not implemented in RT API

	// TODO add rotten review count -- currently not implemented in RT API
	
}

function getIMDBid () {
	var regexImdbNum = /\/title\/tt(\d{7})\//;
	id = regexImdbNum.exec(document.location);
	return id[1];
}

function getMovieYear() {
	var dateMeta = document.evaluate(
			"//meta[@itemprop='datePublished']",
			document,
			null,
			XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
			null);

	return new Date(dateMeta.snapshotItem(0).content).getFullYear();
}

function getMovieName () {
	const $xpath = '//h1/span[@itemprop="name"]/text()';
	var $nodes = document.evaluate($xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
	return escape($nodes.singleNodeValue.data.replace(/[^\w \xC0-\xFF]/g, ''));
}