Saturday, January 25, 2014

Automatically Accepting last.fm Friends

After a bit of a break from working on my projects I've finally got some spare time again so it's time to get back on the saddle. Number 1 on the "kind of annoying thing I should fix" list is related to ScrobbleAlong. I've added a bunch of stations since I first launched the site and I'm now running about 30 different last.fm accounts for those stations. Fans of the stations want to be friends with them on last.fm, and I'm happy about that but there is no API for accepting friends so about once a week I've just been logging into all the accounts and accepting all the friends. Being a software developer, I wanted to find a way to automate this boring and repetitive task.

My first thought was to use PhantomJS, a headless browser which I've used somewhat successfully to accept trade offers for my Steam Trash Bot which allows you to write JavaScript code to visit a website and do various DOM manipulations on it. After a bit of experimentation I realized that it was very fiddly and hard to do sequences of actions, and some web searching revealed that CasperJS was better for what I wanted to do. CasperJS is a wrapper around PhantomJS that allows you to easily write a sequence of navigation and manipulation steps - exactly what I wanted to do!

The sequence of steps I wanted to go through were, for each account I have, log in, go to the friend requests page, accept all the friends, then log out. Logging in and logging out was fairly easy, I just needed to tell CasperJS to go to the log in page, fill out and submit the form, then submit the logout form, the only trick was that I had to tell it to wait for the redirection after the form submission. Accepting friends was another story since there is no easy way of getting CasperJS to do something for each result of a selector, but as usual, StackOverflow had an answer that pointed me in the right direction. The trick is to come up with a CSS selector that will find the first unaccepted request, then click the accept button and wait until it is accepted, then try again until no more unaccepted requests are found. In last.fm, when you click the accept button, the div it is in gets hidden but the HTML is still there, so most selectors will not be able to tell if it's been accepted or not. Thankfully and slightly confusingly, one thing does change with the request, the action of the form changes from nothing to "/ajax/inbox/friendrequest", so the selector "form:not([action='/ajax/inbox/friendrequest']) input[name='accept']" can be used to find unaccepted friend requests.

Putting all this together I've written a nice little script that will save me literally minutes every week. Just think of what I can do with all those minutes!