There are 8 previous versions of this script.
// ==UserScript==
// @name Netflix Rating Granulizer
// @description allows half star user ratings on Netflix
// @author mabuse
// @include http://*netflix.com/*
// ==/UserScript==
var document = unsafeWindow.document;
/* setting "overflow: visible" _dramatically_ improves performance; netflix's "overflow: hidden" isn't necessary */
GM_addStyle('.stbrIl li a, .stbrOl li a, .stbrStc li a { overflow: visible; }');
var ratingStrings = [];
ratingStrings[1.5] = "Craptastic";
ratingStrings[2.5] = "Mediocre";
ratingStrings[3.5] = "Pretty pretty good";
ratingStrings[4.5] = "The shit, for reals";
var ratingWidths = [];
ratingWidths[1.5] = 27;
ratingWidths[2.5] = 46;
ratingWidths[3.5] = 65;
ratingWidths[4.5] = 84;
var niOffset = 17; /* rating width offset when not interested button is to the left */
/**
* Patches the sbHandler javascript object which netflix still uses on a few pages (instead of the
* more accessible HTML/CSS approach).
*/
function patchSbHandler()
{
var sbHandler = unsafeWindow.sbHandler;
if (!sbHandler)
return;
sbHandler.sbOffsets = [18,27,37,46,56,65,75,84,94];
sbHandler.displayStrings[1.5] = ratingStrings[1.5];
sbHandler.displayStrings[2.5] = ratingStrings[2.5];
sbHandler.displayStrings[3.5] = ratingStrings[3.5];
sbHandler.displayStrings[4.5] = ratingStrings[4.5];
for (var i=2; i<11; i++)
{
sbHandler.sbImages[i/2] = new Image();
sbHandler.sbImages[i/2].src = sbHandler.imageRoot+"stars_2_"+(Math.floor(i/2))+(i%2?"5":"0")+".gif";
}
sbHandler.getStarCount=function(evt)
{
var x = unsafeWindow.getElementMouseCoordinate(evt,this.element);
for (var i=0; i<10; i++)
if (x <= this.sbOffsets[i])
return (i+2)/2;
return 0;
};
}
/**
* Patches UL elements having the given class name by adding LI child elements with half-star
* rating widths among the existing elements.
*/
function patchUls(className, offset)
{
var uls = document.getElementsByClassName(className);
var hrefRegex = new RegExp('value=.');
for (var i=uls.length-1; i >=0; i--)
{
var ul = uls[i];
var lis = ul.childNodes;
if (ul.childNodes.length <= 6) /* only do once */
{
for (var j=4; j > 0; j--)
{
var rating = (5-j)+0.5;
var currentElement = lis[j];
var containsAnchors = (currentElement.tagName == 'A');
var oldAnchor = currentElement;
if (!containsAnchors)
oldAnchor = currentElement.childNodes[0];
var newAnchor = document.createElement('a');
newAnchor.href = oldAnchor.href.replace(hrefRegex, 'value='+rating);
newAnchor.rel = 'nofollow';
newAnchor.title = 'Click to rate the movie "'+ratingStrings[rating]+'"';
newAnchor.innerHTML = 'Rate '+rating+' stars';
newAnchor.setAttribute('style', 'width:'+(ratingWidths[rating]+offset)+'px');
var newElement = newAnchor;
if (!containsAnchors)
{
newElement = document.createElement('li');
newElement.appendChild(newAnchor);
}
newElement.setAttribute('class', 'rv'+rating); /* some netflix javascript parses this class name */
ul.insertBefore(newElement, currentElement);
}
}
}
}
/**
* Patches elements displaying your current rating by setting half-star rating widths.
*/
function patchRated()
{
var maskFgs = document.getElementsByClassName('stbrMaskFg');
for (var i = maskFgs.length-1; i >= 0; i--)
{
var maskFg = maskFgs[i];
if (maskFg.childNodes.length)
{
var text = maskFg.childNodes[0].data;
if (text.indexOf('You') == 0)
{
var rating = text.replace(/.*: ([.0-9]+)/, '$1')*1.0;
if (~~rating != rating)
{
var offset = 0;
if (maskFg.parentNode.className.indexOf('stbrMaskBgIlNi') >= 0)
offset = niOffset;
maskFg.style.width = (ratingWidths[rating]+offset)+'px';
}
}
}
}
}
if (unsafeWindow.sbHandler)
patchSbHandler();
var startTime = new Date();
patchUls('stbrIlNi', niOffset);
patchUls('stbrIl', 0);
patchUls('stbrOl', 0);
patchUls('stbrStc', 0);
var endTime = new Date();
if (unsafeWindow.console)
unsafeWindow.console.log('patch time = ' + (endTime-startTime) + 'ms');
/* let DOM changes render before patching rated elements */
setTimeout(patchRated, 0);
