NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name MrSkin Ratings in IMDb // @namespace mrskin.com // @description Display an actress' MrSkin Rating and a link to her MrSkin page // @include http://*.imdb.com/name/nm* // @include http://*.imdb.com/title/tt* // @version 1.24 // // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @connect imdb.com // @connect mrskin.com // // @history 1.24 Fixed Title pages. Found new data on MrSkin pages to extract info from as backup and to provide additional info in tooltip where available. Quick workaround to have better looking stars on new design title pages (reuse imdb's own stars) // @history 1.23 Fixed support for New IMDB Title Design. Edited line break for rating on new design so only occurs on name and not title pages. Stars look ugly on New design Title Page, will modify later. // @history 1.22 Fixed some missing semicolons. Added line break for rating on new design so it doesn't truncate. // @history 1.21 Fixed regex for 'new design' IMDB, apparently they updated the code at some point. Thanks derjanb. // @history 1.20 Removed native Chrome support (as Chrome doesn't allow 3rd party scripts anymore anyway). Bringing back compatibility for Firefox. To use with Chrome, this scripts must be used with TamperMonkey now. // @history 1.19 Changes to try to comply to TM 4.0 update // @history 1.18 As MrSkin no longer stipulates Best Matches, it's not 100% if the MrSkin results are the correct actress/title. Now prompts if search results doesn't 100% match, might show for slightly different spellings or grammar. // @history 1.17 MrSkin redesign rewrite. Remove autoupdater (all clients should do this automaticlly with greasemonkey and tampermonkey now). // @history 1.16 Fix for current iterations of IMDB and MrSkin. // @history 1.15 MrSkin removed search landing page. Also Fix of formatting of code with last version. // @history 1.14 Fix clickable rating link for new mrskin exact-match search skips. // @history 1.13 Title check to ensure MrSkin results match. // @history 1.12 MrSkin integration with IMDB Title pages. (Option) // @history 1.11 Fix for MrSkin site change: skip search results on popular match. // @history 1.10 Fix for missing MrSkin star resources // @history 1.09 Google Chrome support. Fix for nudity roles in tooltip. // @history 1.08 New IMDB design support. Fix for checking underage actresses. // @history 1.07 Bug fix (search results url restored). // @history 1.06 User requested option for opening links in new tab // @history 1.05 Fixed bug with script not working with unique names that have no similarities to other actresses. // @history 1.04 Removed unecessary regex line // @history 1.03 Made actress comparison case insensitive e.g: Clea DuVall. Fixed search url for when actress isn't found. // @history 1.02 Added option to add google image search link // @history 1.01 Fix for update of site and fixed mistaken use of constant rating image // @history 1.00 Initial release // @license GPL-3.0-or-later // @updateURL https://openuserjs.org/meta/nascent/MrSkin_Ratings_in_IMDb.meta.js // @downloadURL https://openuserjs.org/install/nascent/MrSkin_Ratings_in_IMDb.user.js // ==/UserScript== //Based on http://userscripts.org/scripts/2273 //Settings var googleLink; //Show link to google image search var openInNewTab; //Open created links in new tab var mrSkinInTitlePages; //Integrate MrSkin ratings into IMDB title pages. var mrskinDiscrepancy = ""; //Boolean variable to flag if MrSKin doesn't find an exact match for IMDB Acterss/Title (this will allow for UI notice on IMDB) var isTitle = false; //Temporary global variable to check if current page is actress or title var imdbNewDesign = false; //Check if current page is loaded in reference/classic design or new design (function() { //Settings (As no settings interface is displayed, just edit the settings directly from about:config) googleLink = GM_getValue("googleLink", true); openInNewTab = GM_getValue("openInNewTab", false); mrSkinInTitlePages = GM_getValue("mrSkinInTitlePages", false); /* Check for actress */ /* Below code checks age of acctress to save lookup as MrSkin only has 18+ actresses in database */ isTitle = document.URL.lastIndexOf("\/title\/tt") >= 0; //IMDB Title page or Name page? if (!isTitle && document.URL.lastIndexOf("\/name\/nm") >= 0) { // IMDB Name page (not Title page) if ( //Check if actress in IMDB classic design document.evaluate( '//h5/a[text()=\'Actress:\']', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotLength == 0 ) { /* Returned not an actress. */ if ( //Check if actress in IMDB new 2012 design document.evaluate( //'//a[.=\'Actress\']', document, null, '//div[@class=\'infobar\']/a[@href=\'#actress\']', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotLength == 0 ) { /* This isn't an actress, ignore. */ return; } } // Check for legal age // Get year var now = new Date(); var years = document.evaluate( "//a[contains(@href,'birth_year')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ); if (years.snapshotLength > 0) { var href = new String(years.snapshotItem(0)); var bornYear = href.substring(href.length - 4); if ((now.getFullYear() - bornYear) < 18) { // Too young return; } if ((now.getFullYear() - bornYear) == 18) { // Might still be too young var dates = document.evaluate( "//a[contains(@href,'OnThisDay')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ); if (dates.snapshotLength > 0) { href = new String(dates.snapshotItem(0)); var dateindex = href.indexOf('day='); var monthindex = href.indexOf('month='); var day = href.substring(dateindex + 4, monthindex - 1); var month = href.substring(monthindex + 6); // convert month into a number switch (month) { case 'January': month = 0; break; case 'February': month = 1; break; case 'March': month = 2; break; case 'April': month = 3; break; case 'May': month = 4; break; case 'June': month = 5; break; case 'July': month = 6; break; case 'August': month = 7; break; case 'September': month = 8; break; case 'October': month = 9; break; case 'November': month = 10; break; case 'December': month = 11; break; } if (month > now.getMonth()) { // Too young return; } if (month == now.getMonth()) { if (day > now.getDate()) { // Too young return; } } } } } } /* end of check of actress age on name pages */ /* IMDB parsing and MrSkin Lookup */ //Lookup Actress/Title on Classic/Reference Design var s = document.evaluate( 'id(\'tn15title\')/h1', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0); //IMDB new (2012) design support //This could be replaced by extracting info from the Title tag, but I like this as it ensures the pages are as expected, may change in future if (s == null) { //classic design not working (check s is empty) //Check for Actress s = document.evaluate( //'//td[@id=\'overview-top\']/h1', document, null, '//td [contains(@id,"overview-top")] //span [contains(@itemprop,"name")]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0); imdbNewDesign = true; } if (s === null) { //classic design and new design actress not working (check s is empty) //Check for Title s = document.evaluate( '//div [contains(@class,"title_wrapper")] //h1 [contains(@itemprop,"name")]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0); imdbNewDesign = true; } if (s !== null) { //Found elements, continuing lookup on MrSkin (check s is not empty) var span = document.createElement("span"); span.setAttribute("style", "font-size:small"); s.parentNode.insertBefore(span, s.nextSibling); span.appendChild(document.createTextNode(" ")); var actressname = trim(s.childNodes.item(0).data.replace(/ \(I+\)$/, "").replace(/ /g, " ")); if (actressname.length === 0) console.log("Warning, " + "MrSkin Ratings in IMDb script unable to parse Actress from IMDB - has there been a redesign?"); //alert("http://www.mrskin.com/search/search?term=" +escape(trim(s.childNodes.item(0).data.replace(/ \(I+\)$/, "").replace(/ /g, "+")))); //findActress(span,s,actressname,"http://www.mrskin.com/search/search?term=" +escape(trim(s.childNodes.item(0).data.replace(/ \(I+\)$/, "").a(/ /g, "+")))); findActress(span,s,actressname,"http://www.mrskin.com/search/api.json?term=" +escape(trim(s.childNodes.item(0).data.replace(/ \(I+\)$/, "")))); //alert(escape(trim(s.childNodes.item(0).data.replace(/ \(I+\)$/, "")))); } else { //Cant find on New (2012) Design either console.log("Warning, " + "MrSkin Ratings in IMDb script unable to parse IMDB - has there been a redesign?"); } //Save settings GM_setValue('googleLink', googleLink); GM_setValue('openInNewTab', openInNewTab); GM_setValue('mrSkinInTitlePages', mrSkinInTitlePages); })(); function trim(stringToTrim) { return stringToTrim.replace(/^\s+|\s+$/g,""); } function findActress(span,s,actressname,link){ var MrSkinJSON; GM_xmlhttpRequest({ method: "GET", url: link, synchronous: true, headers: { //GET /search/celebs?term=jennifer+aniston+ HTTP/1.1\r\n 'Host': 'www.mrskin.com', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36', 'DNT': '1', 'Accept-Encoding': 'gzip, deflate, sdch', 'Accept-Language': "en-US,en;q=0.8,en-GB;q=0.6" }, onload:function(result) { if (!result.responseJSON) { MrSkinJSON = JSON.parse(result.responseText); } var actress; //(ALL,url,name) //var rating; //(ALL,ratingNumber,ratingSummary,"Node rules:",nudeRolesNumber) //(Rating, Nudity summary, #Nude roles) //Search MrSkin if (MrSkinJSON.results.length > 0) { var movieTitle = actress = MrSkinJSON.results[0].name; //movieTitle is just assigned to actress to act as an alias. //Compare IMDB Actress/Title with MrSkin Actress/Title result var tmpTitle = ""; //Temporary variable for comparing title of MrSkin page against IMDB page if (MrSkinJSON.results[0].type == "title"){ //if MrSkin page is a movie title page rather than actress page // Uses reverse regex to remove the last brackets in case a title has brackets in \([^\(]*$ //Uses standard regex to remove first set of brackets found (could cause issues if title has brackets within it) \([0-9]+\) tmpTitle = trim(movieTitle.replace(/\([^\(]*$/, "")); //extract the (YYYY) backets and year info from title } else //returned page is an actress page and not a movie title { tmpTitle = actress; //store actress name in temp comparison variable instead to avoid comparison issues in next query } //alert("IMDB: " + actressname + ", MrSkin: " + MrSkinJSON.results[0].name); if(actressname.toLowerCase() == tmpTitle.toLowerCase()){ //Results match perfectly. } else { //Results don't match, could be spelling discrepancy but could be correct result. console.log("Info, " + "MrSkin actress/title result differs from IMDB actress/title\nThis could be the correct result with spelling discrepnancy, or could be that MrSkin search can't find actress/title.\n" + "IMDB: " + actressname + ", MrSkin: " + tmpTitle); mrskinDiscrepancy = actress; //Code to go here to cycle through array and compare all MrSkin results to see if better match exists. } //Get MrSkin Rating/Nudity info and display getRating(span,s,MrSkinJSON.results[0].name,"http://www.mrskin.com" + MrSkinJSON.results[0].url); } else { console.log("Warning, " + "No MrSkin Search Results for Actress/Title"); } } }); } function getRating(span,s,actressname,link){ GM_xmlhttpRequest({ method: "GET", url: link, synchronous: true, headers: { //GET /search/celebs?term=jennifer+aniston+ HTTP/1.1\r\n 'Host': 'www.mrskin.com', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36', 'DNT': '1', 'Accept-Encoding': 'gzip, deflate, sdch', 'Accept-Language': "en-US,en;q=0.8,en-GB;q=0.6" }, onload: function(result) { var actress; //(ALL,url,name) // ratingArray; //(ALL,ratingNumber,ratingSummary,"Nude roles:",nudeRolesNumber) //(Rating, Nudity summary, #Nude roles) //(Rating, Nudity summary, "Nude roles:", #Nude roles) - Rating, Type of nudity and how many nude roles var ratingArray = result.responseText.match(/<span class='detail-type'>Keywords:<\/span>[\s\S].+?rating=(.+?)">(.+?)<\/a>/); //This works for actress pages var rating; var ratingSummary; var nudeRoles; var fakeBreasts; var breastSize; var bodyType; var hairColor; //nudeAppearancesCount = Nude Roles // starRating/titleNudityRating = rating if (!(ratingArray)){ //No result, possibly Title page ratingArray = result.responseText.match(/<div class='object-rating'>[\s\S]+?star-rating[\s\S]+?rating-string'>(.+)<\/span>/); if (ratingArray){ //result found //Try counting the active star images rating = (ratingArray[0].match(/"fa fa-star active"/g) || []).length; //Counts stars ratingSummary = ratingArray[1]; //Summary of nudity such as "Brief Nudity" //Try extracting the info from the "_track_page" script in header //Clear no longer needed array ratingArray.length = 0; //<div class='object-rating'>[\s\S]+?star-rating([\s\S])+?<\/div> ratingArray = result.responseText.match(/<script>[\s\S]+?titleNudityRating":([\s\S]+?),[\s\S]+?nudeAppearancesCount":([\s\S]+?)}[\s\S]+?<\/script>/); if (ratingArray){ //Not Empty if (!(rating)){ //Empty rating = ratingArray[1]; //titleNudityRating } nudeRoles = ratingArray[2]; //nudeAppearancesCount //Clear no longer needed array ratingArray.length = 0; } // var _track_page = {"titleType":"Movie","titleId":15414,"titleName":"The Break-Up","titleYear":"(2006)","titleNudityRating":2,"titleGenres":["Comedy","Romance"],"nudity":true,"mediaCount":11,"sceneCount":3,"picCount":8,"nudeSceneCount":1,"nudePicCount":5,"appearancesCount":1,"nudeAppearancesCount":1}; } } else { rating = ratingArray[1]; //rating value from MrSkin Actress page ratingSummary = ratingArray[2]; //Summary of nudity such as "Brief Nudity" //(Rating, Nudity summary) - The rating and type of nudity //Clear no longer needed array ratingArray.length = 0; } //Try extracting the info from the "_track_page" script in header ratingArray = result.responseText.match(/<script>[\s\S]+?starRating":([\s\S]+?),[\s\S]+?breastSize":"([\s\S]+?)",[\s\S]+?bodyType":"([\s\S]+?)",[\s\S]+?fakeBreasts":([\s\S]+?),[\s\S]+?hairColor":"([\s\S]+?)"[\s\S]+?nudeAppearancesCount":([\s\S]+?)}[\s\S]+?<\/script>/); if (ratingArray){//Not Empty if (!(rating)){ //Empty rating = ratingArray[1]; //titleNudityRating } nudeRoles = ratingArray[6]; //nudeAppearancesCount fakeBreasts = ratingArray[4]; breastSize = ratingArray[2]; bodyType = ratingArray[3]; hairColor = ratingArray[5]; //Clear no longer needed array ratingArray.length = 0; } //window.prompt("responseText", result.responseText); if (!(nudeRoles)){ //If we don't already have nudeRoles from _track_page then get it from body var nudeRolesArray = result.responseText.match(/<div class='pedigree-wrapper'>[\s\S]+?<span class='detail-type'>Nude Roles:<\/span>[\s\S]+?detail-info'>(.+)<\/span>/); if (!(nudeRolesArray)){ //nudeRoles information not available (probably a Title page, or a redesign) console.log("Info, " + "Nude Roles information not available (probably a Title page, possibly just lacking for this actress, or a redesign)"); } else { nudeRoles = nudeRolesArray[1]; //Number of roles Actress appeared nude //Clear no longer needed array nudeRolesArray.length = 0; } } //alert("rating: " + rating + "\nratingSummary: " + ratingSummary + "\nnudeRoles: " + nudeRoles); //Add linebreak in 'new design' IMDb so that rating is under actress name instead of alongside. if (imdbNewDesign) { if (!isTitle) { var lineBR = document.createElement("br"); span.appendChild(lineBR); } } //Display rating var newLink = document.createElement("a"); newLink.setAttribute("href", link); if (openInNewTab) {newLink.setAttribute("target", "_blank");} var sknImg = document.createElement("img"); //http://img-p.mrskin.com/assets/images/rating_2.png //alert("summary: " + ratingSummary); if(rating.length > 0 && ratingSummary.length > 0 && typeof nudeRoles !== 'undefined' && nudeRoles.length > 0){ sknImg.title = ratingSummary + " (Nude Roles: " + nudeRoles + ")"; } else if(ratingSummary.length > 0) { sknImg.title = ratingSummary; } if (typeof fakeBreasts !== 'undefined') { //if (fakeBreasts) //Variable contains data if (fakeBreasts == "false") { sknImg.title = "\n" + sknImg.title + " - Real Breasts (" + breastSize + "), Body Type: " + bodyType + ", Hair Color: " + hairColor; } else { sknImg.title = "\n" + sknImg.title + " - Fake Breasts (" + breastSize + "), Body Type: " + bodyType + ", Hair Color: " + hairColor; } } var ratingImage = ""; if (rating == 1) { if (imdbNewDesign && isTitle) { ratingImage = "http://i.imgur.com/djcu3e0.png"; } else { ratingImage = "http://i.imgur.com/bh7FS.png"; } } else if (rating == 2){ if (imdbNewDesign && isTitle) { ratingImage = "https://i.imgur.com/MR5MHi4.png"; } else { ratingImage = "http://i.imgur.com/OnETx.png"; } } else if (rating == 3){ if (imdbNewDesign && isTitle) { ratingImage = "https://i.imgur.com/LYVWRK3.png"; } else { ratingImage = "http://i.imgur.com/nUxuM.png"; } } else if (rating == 4){ if (imdbNewDesign && isTitle) { ratingImage = "https://i.imgur.com/VkCui3R.png"; } else { ratingImage = "http://i.imgur.com/q0Ldw.png"; } } //sknImg.src = "http://img-p.mrskin.com/assets/images/rating_" + rating[1] + ".png"; sknImg.src = ratingImage; newLink.appendChild(sknImg); span.appendChild(newLink); //MrSkin Actress/Title doesn't exactly match IMDb actress/Title if (mrskinDiscrepancy.length > 0) { //Notify in tooltip sknImg.title = "Please note this rating might be for the incorrect Actress/Title as MrSkin didn't return an exact match.\n" + "Results returned were for " + mrskinDiscrepancy + '\n' + sknImg.title; //Add astrix to rating span.style.fontSize = "18px"; //Increase the fontsize so that it shows a bit more clearly var t = document.createTextNode("*"); span.appendChild(t); } //Google if (googleLink){ var gglLink = document.createElement("a"); gglLink.setAttribute("href", "http://google.com/images?q=" + actressname); if (openInNewTab) {gglLink.setAttribute("target", "_blank");} var gglImg = document.createElement("img"); gglImg.src = "http://www.google.com/favicon.ico"; gglImg.height = height="21"; gglImg.width = width="21"; //Add padding span.appendChild(document.createTextNode('\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0' + '\xa0')); gglLink.appendChild(gglImg); span.appendChild(gglLink); } //reset Variable mrskinDiscrepancy = ""; } }); }