The best kittens, technology, and video games blog in the world.

Sunday, March 08, 2009

Use Greasemonkey to vote for hotter girls

The Thinker... by law_keven from flickr (CC-SA)

Tell me - are there any websites that you enjoy a lot, except you're really pissed about some tiny quirks? I mean, other than ads, you already know how to fix those. Don't even think about contacting website author, that almost never works. Better take the matter in your own hands, and write a Greasemonkey script to fix the problem.

Greasemonkey scripting is not too popular, because nobody knows how to do it. There's a manual online, but if I publicly mention what I think about it, Mark Pilgrim will never speak to me again, and that would be bad.
Fortunately you don't have to rely on it any more - taking advantage of immense popularity that this blog occasionally has (hey there programming reddit! vote buttons under post), I want to singlehandedly empower all of you - and tell you in easy and zero-bullshit way how to make the Internet a better place with Greasemonkey.

Preparations


First, you'll need Firefox obviously. Install and enable Greasemonkey and Firebug. Restarted Firefox? Great!

Now open Error Console. Yes, I know you have Firebug, but it won't catch errors in your Greasemonkey scripts, you need Error Console for that.

Go to website you want to fix, let's say hotornot, right click on the monkey, select "New User Script...", fill in name, namespace, description, and URLs on which it should be executed (usually http://www.domain.com/* - remember about the *) add alert("im in ur greasemonkey, makin internets better"); below the comments block, something like that:
// ==UserScript==
// @name           My new script
// @namespace      http://hi-thats-me.blogspot.com/
// @description    Increases general awesomeness levels
// @include        http://www.hotornot.com/*
// ==/UserScript==
alert("im in ur greasemonkey, makin internets better");


Now close text editor and reload the page. If you've done it right, you should see the alert box. Congratulations, you've just written your first Greasemonkey script!

The secret step preceeding profit


Now here's my problem with Greasemonkey and its documentation. Do you remember how hard it was to do anything useful with Javascript in 2000? Now multiply that by current value of Dow Jones Industrial Average because of security sandbox and no control over HTML, and that's about how hard it is to write Greasemonkey scripts official style.

Fortunately you can almost use modern Javascript within Greasemonkey. What you need to do is get jQuery source and copy and paste the entire file just under your Greasemonkey script's initial comment block.

We're almost there. Now the second part of the secret step:
unsafeWindow.jQuery = jQuery;


For security reasons Greasemonkey scripts execute within a sandbox. So jQuery which you just included won't be available to script on the page. That's not normally a problem because they're someone else's script, except that Firebug executes it their context, not Greasemonkey context. So if you want to develop your scripts with help of Firebug, you need this line.

The unsafe part suggests there's a security risk involved, and there might be some. Javascript on the page is not supposed to be able to manipulate Javascript within your Greasemonkey script, but now it has limited access to your sandbox. There's probably some way of abusing this access and owning your machine, so just comment this line out after you're done developing.

Profit!

And now profit time. All photo voting websites want you to click on numbers or photos to vote. That's outrageously bad usability, and even in Web 1.0 you should be using keyboard for that. So let's fix it.

Right click on the monkey, select "Manage User Scripts...", select your script for editing. It should look something like this:
// ==UserScript==
// @name           Hotornot vote by keyboard
// @namespace      http://t-a-w.blogspot.com/
// @description    Use 1-0 to vote
// @include        http://www.hotornot.com/*
// ==/UserScript==

// Content of http://jquery.com/src/jquery-latest.pack.js goes here

// Use only for development:
unsafeWindow.jQuery = jQuery;

// and here's out script
Now we need to intercept keypresses on the entire window. We should return true if we want propagation or false if we intercept.
jQuery(window).keypress(function(ev){
// logic here
return true;
});


For hotornot we want to use keys 1 to 0 (0 being 10).
jQuery(window).keypress(function(ev){
var cc = ev.charCode;
if(cc >= 48 && cc <= 57) {
// vote here
return false;
}
return true;
});


Now let's vote. hotornot's HTML isn't the prettiest ever, but we can handle it. We're interested in form named voteForm, votes are checkboxes located in divs r1 to r10.

jQuery(window).keypress(function(ev){
var cc = ev.charCode;
if(cc >= 48 && cc <= 57) {
var vote = cc - 48;
if(vote < 1) vote = 10;
var check_box = jQuery("form[name='voteForm'] div.rateval#r"+vote+" input");
var form = jQuery("form[name='voteForm']");
return false;
}
return true;
});


Unfortunately due to security sandbox we cannot use all of jQuery power, so we'll have to use a mix of jQuery and DOM scripting. It would be brilliant if Greasemonkey, jQuery, and Firebug all worked together, but so would be peace in the Middle East.

jQuery(window).keypress(function(ev){
var cc = ev.charCode;
if(cc >= 48 && cc <= 57) {
var vote = cc - 48;
if(vote < 1) vote = 10;
jQuery("form[name='voteForm'] div.rateval#r"+vote+" input")[0].checked = true;
jQuery("form[name='voteForm']")[0].submit();
return false;
}
return true;
});

Done.

BabeVsBabe


BabeVsBabe is a less popular photo voting site, but girls there are much prettier than on hotornot, and selecting if left or right are hotter involves much less thinking than selecting a number vote.

Let's start with the same skeleton:
// ==UserScript==
// @name           BabeVsBabe vote by keyboard
// @namespace      http://t-a-w.blogspot.com/
// @description    Use left and right arrows to vote
// @include        http://www.babevsbabe.com/*
// ==/UserScript==

// Content of http://jquery.com/src/jquery-latest.pack.js goes here

// Use only for development:
unsafeWindow.jQuery = jQuery;

jQuery(window).keypress(function(ev){
// code goes here
return true;
});


The main difference is that we want to intercept left arrow (key code 37) and right arrow (key code 39) keys, and both possible votes are conveniently located in separate forms named frmLeftBabe and frmRightBabe.

jQuery(window).keypress(function(ev){
var kk = ev.keyCode;
if(kk == 37) {
jQuery("form[name='frmLeftBabe']")[0].submit()
return false;
}
if(kk == 39) { // right
jQuery("form[name='frmRightBabe']")[0].submit()
return false;
}
return true;
});


Save, reload, and spend as much time enjoying Greasemonkey usability improvements we just did as you want.

Upload your script to userscripts.org


Writing a great script is only half of it. After you have written it, you should share it on userscripts.org.

Full scripts described in this post are here: hotornot script, babevsbabe script.

Moar!


There's plenty of things you can do with Greasemonkey scriping. If you just need something to train on, I recommend Kitten War. If there's enough interest in this, I'll write more posts explaing how to deal with, I'm open to suggestion what to improve next.

6 comments:

Wayne Khan said...

Great post! I always wanted to explore Greasemonkey, but never found sufficient motivation to do, till now.

I've written my own script for NBA.com, thanks to you.

taw said...

Wayne Khan: Great! That's what I wrote this blog post for.

Johan Sundström said...

Is there data available on what parts of jQuery's functionality breaks when subjected to the Greasemonkey sandbox -- like a run of its test suite?

taw said...

Johan: As far as I know, in spite of so many people seem to be using Greasemonkey in combination with jQuery, there's neither official support, nor any systemic data about anything. Part of the problem is that Firefox throws those silly sandbox violation exceptions instead of something more useful.

If you want to research it, it would be awesome!

Johan Sundström said...

I guess I'll probably have to look at it sooner or later anyway. At least the jQuery test suite seems to be a fairly fine-grained one -- hopefully there won't be all that many issues coming up. (Or people probably would not be using jQuery under/on Greasemonkey much at all.)

Mozilla's javascript sandbox is a painfully harsh environment to do anything nice in. I hope Chromium will prove to be somewhat nicer.

Haywood said...

I wish I understood 1 word of that!