// ==UserScript==
// @name Show Metacritic.com ratings
// @description Show metacritic metascore and user ratings on: Bandcamp, Apple Itunes (Music), Amazon (Music,Movies,TV Shows), IMDb (Movies), Google Play (Music, Movies), TV.com, Steam, Gamespot (PS4, XONE, PC), Rotten Tomatoes, Serienjunkies, BoxOfficeMojo, allmovie.com, movie.com, Wikipedia (en), themoviedb.org, letterboxd
// @namespace cuzi
// @oujs:author cuzi
// @grant GM_xmlhttpRequest
// @grant GM_getResourceURL
// @grant GM_setValue
// @grant GM_getValue
// @grant unsafeWindow
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @resource global.min.css http://www.metacritic.com/css/global.min.1446760484.css
// @resource base.min.css http://www.metacritic.com/css/search/base.min.1446760407.css
// @license GNUGPL
// @version 4
// @include https://*.bandcamp.com/*
// @include https://itunes.apple.com/*/album/*
// @include https://play.google.com/store/music/album/*
// @include https://play.google.com/store/movies/details/*
// @include http://www.amazon.com/*
// @include https://www.amazon.com/*
// @include http://www.amazon.co.uk/*
// @include https://www.amazon.co.uk/*
// @include http://www.amazon.fr/*
// @include https://www.amazon.fr/*
// @include http://www.amazon.de/*
// @include https://www.amazon.de/*
// @include http://www.amazon.es/*
// @include https://www.amazon.es/*
// @include http://www.amazon.ca/*
// @include https://www.amazon.ca/*
// @include http://www.amazon.in/*
// @include https://www.amazon.in/*
// @include http://www.amazon.it/*
// @include https://www.amazon.it/*
// @include http://www.amazon.co.jp/*
// @include https://www.amazon.co.jp/*
// @include http://www.amazon.com.mx/*
// @include https://www.amazon.com.mx/*
// @include http://www.amazon.com.au/*
// @include https://www.amazon.com.au/*
// @include http://www.imdb.com/title/*
// @include https://www.imdb.com/title/*
// @include http://store.steampowered.com/app/*
// @include https://store.steampowered.com/app/*
// @include http://www.gamespot.com/*
// @include https://www.gamespot.com/*
// @include http://www.serienjunkies.de/*
// @include https://www.serienjunkies.de/*
// @include http://www.tv.com/shows/*
// @include http://www.rottentomatoes.com/m/*
// @include https://www.rottentomatoes.com/m/*
// @include http://www.rottentomatoes.com/tv/*
// @include https://www.rottentomatoes.com/tv/*
// @include http://www.boxofficemojo.com/movies/*
// @include http://www.allmovie.com/movie/*
// @include https://en.wikipedia.org/*
// @include http://www.movies.com/*/m*
// @include https://www.themoviedb.org/movie/*
// @include https://www.themoviedb.org/tv/*
// @include http://letterboxd.com/film/*
// @include https://letterboxd.com/film/*
// @downloadURL none
// ==/UserScript==
var baseURL = "http://www.metacritic.com/";
var baseURL_music = "http://www.metacritic.com/music/";
var baseURL_movie = "http://www.metacritic.com/movie/";
var baseURL_pcgame = "http://www.metacritic.com/game/pc/";
var baseURL_ps4 = "http://www.metacritic.com/game/playstation-4/";
var baseURL_xone = "http://www.metacritic.com/game/xbox-one/";
var baseURL_tv = "http://www.metacritic.com/tv/";
var baseURL_search = "http://www.metacritic.com/search/{type}/{query}/results";
var baseURL_autosearch = "http://www.metacritic.com/autosearch";
var mybrowser = "other";
if(~navigator.userAgent.indexOf("Chrome")) {
mybrowser = "chrome";
}
// http://www.designcouch.com/home/why/2013/05/23/dead-simple-pure-css-loading-spinner/
var CSS = "#mcdiv123 .grespinner{height:16px;width:16px;margin:0 auto;position:relative;-webkit-animation:rotation .6s infinite linear;-moz-animation:rotation .6s infinite linear;-o-animation:rotation .6s infinite linear;animation:rotation .6s infinite linear;border-left:6px solid rgba(0,174,239,.15);border-right:6px solid rgba(0,174,239,.15);border-bottom:6px solid rgba(0,174,239,.15);border-top:6px solid rgba(0,174,239,.8);border-radius:100%}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(359deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(359deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(359deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(359deg)}}#mcdiv123searchresults .result{font:12px arial,helvetica,serif;border-top-width:1px;border-top-color:#ccc;border-top-style:solid;padding:5px}#mcdiv123searchresults .result .result_type{display:inline}#mcdiv123searchresults .result .result_wrap{float:left;width:100%}#mcdiv123searchresults .result .has_score{padding-left:42px}#mcdiv123searchresults .result .basic_stats{height:1%;overflow:hidden}#mcdiv123searchresults .result h3{font-size:14px;font-weight:700}#mcdiv123searchresults .result a{color:#09f;font-weight:700;text-decoration:none}#mcdiv123searchresults .metascore_w.game.seventyfive,#mcdiv123searchresults .metascore_w.positive,#mcdiv123searchresults .metascore_w.score_favorable,#mcdiv123searchresults .metascore_w.score_outstanding,#mcdiv123searchresults .metascore_w.sixtyone{background-color:#6c3}#mcdiv123searchresults .metascore_w.forty,#mcdiv123searchresults .metascore_w.game.fifty,#mcdiv123searchresults .metascore_w.mixed,#mcdiv123searchresults .metascore_w.score_mixed{background-color:#fc3}#mcdiv123searchresults .metascore_w.negative,#mcdiv123searchresults .metascore_w.score_terrible,#mcdiv123searchresults .metascore_w.score_unfavorable{background-color:red}#mcdiv123searchresults a.metascore_w,#mcdiv123searchresults span.metascore_w{display:inline-block}#mcdiv123searchresults .result .metascore_w{color:#fff!important;font-family:Arial,Helvetica,sans-serif;font-size:17px;font-style:normal!important;font-weight:700!important;height:2em;line-height:2em;text-align:center;vertical-align:middle;width:2em;float:left;margin:0 0 0 -42px}#mcdiv123searchresults .result .more_stats{font-size:10px;color:#444}#mcdiv123searchresults .result .release_date .data{font-weight:700;color:#000}#mcdiv123searchresults ol,#mcdiv123searchresults ul{list-style:none}#mcdiv123searchresults .result li.stat{background:0 0;display:inline;float:left;margin:0;padding:0 6px 0 0;white-space:nowrap}#mcdiv123searchresults .result .deck{margin:3px 0 0}#mcdiv123searchresults .result .basic_stat{display:inline;float:right;overflow:hidden;width:100%}";
function name2metacritic(s) {
return s.normalize('NFKD').replace(/\//g,"").replace(/[\u0300-\u036F]/g, '').replace(/&/g,"and").replace(/\W+/g, " ").toLowerCase().trim().replace(/\W+/g,"-");
}
function minutesSince(time) {
var seconds = ((new Date()).getTime() - time.getTime()) / 1000;
return seconds>60?parseInt(seconds/60)+" min ago":"now";
}
function randomStringId() {
var id10 = () => Math.floor((1 + Math.random()) * 0x10000000000).toString(16).substring(1);
return id10()+id10()+id10()+id10()+id10()+id10();
}
function fixMetacriticURLs(html) {
return html.replace(/= 75) {
fg = "white";
bg = "#6c3";
t = parseInt(score);
} else if(score < 40) {
fg = "white";
bg = "#f00";
t = parseInt(score);
} else {
fg = "white";
bg = "#fc3";
t = parseInt(score);
}
return ''+t+'';
}
function filterUniversalUrl(url) {
url = url.match(/http.+/)[0].replace(/https?:\/\/(www.)?/,"");
if(url.startsWith("somehost")) {// TODO
return url; // Do not remove parameters
} else {
return url.split("?")[0].split("&")[0]; // Remove parameters
}
}
function addToMap(url, metaurl) {
var data = JSON.parse(GM_getValue("map","{}"));
var url = filterUniversalUrl(url);
var metaurl = metaurl.replace(/^http:\/\/(www.)?metacritic\.com\//,"");
data[url] = metaurl;
GM_setValue("map", JSON.stringify(data));
(new Image()).src = "http://123.net23.net/whitelist.php?docurl="+encodeURIComponent(url)+"&metaurl="+encodeURIComponent(metaurl)+"&ref="+encodeURIComponent(randomStringId());
}
function addToBlacklist(url, metaurl) {
var data = JSON.parse(GM_getValue("black","{}"));
var url = filterUniversalUrl(url);
var metaurl = metaurl.replace(/^http:\/\/(www.)?metacritic\.com\//,"");
data[url] = metaurl;
GM_setValue("black", JSON.stringify(data));
(new Image()).src = "http://123.net23.net/blacklist.php?docurl="+encodeURIComponent(url)+"&metaurl="+encodeURIComponent(metaurl)+"&ref="+encodeURIComponent(randomStringId());
}
function isBlacklistedUrl(docurl, metaurl) {
docurl = docurl.replace(/https?:\/\/(www.)?/,"");
metaurl = metaurl.replace(/^http:\/\/(www.)?metacritic\.com\//,"");
metaurl = metaurl.replace(/\/\//g,"/").replace(/\/\//g,"/");; // remove double slash
var data = JSON.parse(GM_getValue("black","{}"));
if(docurl in data) {
if(data[docurl] == metaurl) {
return true;
}
}
return false;
}
function isBlacklisted(metaurl) {
return isBlacklistedUrl("" + document.location.host.replace(/^www\./,"") + document.location.pathname + document.location.search, metaurl);
}
function listenForHotkeys(code, cb) {
// Call cb() as soon as the code sequence was typed
var i = 0;
$(document).bind("keydown.listenForHotkeys",function(ev) {
if(document.activeElement == document.body) {
if(ev.key != code[i]) {
i = 0;
} else {
i++;
if(i == code.length) {
ev.preventDefault();
$(document).unbind("keydown.listenForHotkeys");
cb();
}
}
}
});
}
function metacritic_hoverInfo(url, cb, errorcb) {
// Get the metacritic hover info. Requests are cached.
var handleresponse = function(response, cached) {
if(response.status == 200 && cb) {
if(~response.responseText.indexOf('"jsonRedirect"')) { // {"viewer":{},"mixpanelToken":"6e219fd....","mixpanelDistinctId":"255.255.255.255","omnitureDebug":0,"jsonRedirect":"\/movie\/national-lampoons-vacation"}
var j = JSON.parse(response.responseText);
current.url = baseURL + j["jsonRedirect"];
metacritic_hoverInfo(baseURL + j["jsonRedirect"], cb, errorcb);
} else {
cb(response.responseText, new Date(response.time));
}
} else if(response.status != 200 && errorcb) {
errorcb(response.responseText, new Date(response.time));
if(!cached)
console.log("Show metacritic ratings: Error:"+response.status+"\n"+url);
}
};
var cache = JSON.parse(GM_getValue("hovercache","{}"));
for(var prop in cache) {
// Delete cached values, that are older than 2 hours
if((new Date()).getTime() - (new Date(cache[prop].time)).getTime() > 2*60*60*1000) {
delete cache[prop];
}
}
if(url in cache) {
handleresponse(cache[url], true);
} else {
GM_xmlhttpRequest({
method: "POST",
url: url,
data: "hoverinfo=1",
headers: {
"Referer" : url,
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
"Host" : "www.metacritic.com",
"User-Agent" : "MetacriticUserscript "+navigator.userAgent,
"X-Requested-With" : "XMLHttpRequest"
},
onload: function(response) {
response.time = (new Date()).toJSON();
cache[url] = response;
GM_setValue("hovercache",JSON.stringify(cache));
handleresponse(response, false);
}
});
}
}
function metacritic_searchResults(url, cb, errorcb) {
// Get metacritic search results. Requests are cached.
var handleresponse = function(response, cached) {
if(response.results.length && cb) {
cb(response.results, new Date(response.time));
} else if(response.results.length == 0 && errorcb) {
errorcb(response.results, new Date(response.time));
}
};
var cache = JSON.parse(GM_getValue("searchcache","{}"));
for(var prop in cache) {
// Delete cached values, that are older than 2 hours
if((new Date()).getTime() - (new Date(cache[prop].time)).getTime() > 2*60*60*1000) {
delete cache[prop];
}
}
if(url in cache) {
handleresponse(cache[url], true);
} else {
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: {
"Referer" : url,
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
"Host" : "www.metacritic.com",
"User-Agent" : "MetacriticUserscript "+navigator.userAgent,
},
onload: function(response) {
var results = [];
if(!~response.responseText.indexOf("No search results found.")) {
var d = $('').html(response.responseText);
d.find("ul.search_results.module .result").each(function() {
results.push(this.innerHTML);
});
}
response = {
time : (new Date()).toJSON(),
results : results,
};
cache[url] = response;
GM_setValue("searchcache",JSON.stringify(cache));
handleresponse(response, false);
},
onerror: function(response) {
alert(response.responseText);
console.log("Show metacritic ratings: Search error: "+response.status+"\n"+url);
handleresponse({
time : (new Date()).toJSON(),
results : [],
}, false);
}
});
}
}
function metacritic_showHoverInfo(url) {
if(!url) {
return;
}
metacritic_hoverInfo(url,
// On Success
function(html, time) {
$("#mcdiv123").remove();
var div = $('').appendTo(document.body);
div.css({
position:"fixed",
bottom :0,
left: 0,
minWidth: 300,
backgroundColor: "#fff",
border: "2px solid #bbb",
borderRadius:" 6px",
boxShadow: "0 0 3px 3px rgba(100, 100, 100, 0.2)",
color: "#000",
padding:" 3px",
zIndex: "5010001",
});
// Functions for communication between page and iframe
// Mozilla can access parent.document
// Chrome can use postMessage()
var functions = {
"other" : {
"parent": function() {},
"frame" : function sizecorrection() {
var f = parent.document.getElementById('mciframe123');
for(var i =0; f.clientHeight < document.body.scrollHeight && i < 100; i++) {
f.style.width = parseInt(f.style.width)+10+"px";
}
if(f.clientHeight < document.body.scrollHeight) {
f.style.height = parseInt(f.style.height)+15+"px";
f.style.width = "300px";
sizecorrection();
}
}
},
"chrome" : {
"parent" : function() {
var f = parent.document.getElementById('mciframe123');
window.addEventListener("message", function(e){
if("mcimessage1" in e.data) {
f.style.width = parseInt(f.style.width)+10+"px";
} else if("mcimessage2" in e.data) {
f.style.height = parseInt(f.style.height)+15+"px";
f.style.width = "300px";
} else {
return;
}
f.contentWindow.postMessage({
"mcimessage3" : true,
"mciframe123_clientHeight" : f.clientHeight,
"mciframe123_clientWidth" : f.clientWidth,
},'*');
});
},
"frame" : function() {
var i = 0;
window.addEventListener("message", function(e){
if(!("mcimessage3" in e.data)) return;
if(e.data.mciframe123_clientHeight < document.body.scrollHeight && i < 100) {
parent.postMessage({"mcimessage1":1},'*');
i++;
}
if(i >= 100) {
parent.postMessage({"mcimessage2":1},'*')
i = 0;
}
});
parent.postMessage({"mcimessage1":1},'*');
}
}
};
var framesrc = 'data:text/html,';
framesrc += encodeURIComponent('\
\
\
\