02 May 2009

Greasemonkey Index of /images

After I posted the Yahoo Baseball Greasemonkey script, I remembered another script that I have that's worth sharing. Not my Yahoo Football Greasemonkey script which does the same as the baseball (shows in-game stats on tab title) but another more useless useful script.

Have you ever been searching for an image or been Stumbling around and came across a page like the one to the left?

I see them quite often actually because I'm nosy and like to poke around on web sites. If I see a picture of interest, I wonder if the web site owner has others that aren't being displayed.

But here's the rub. We have a nice list but we have to click each one to see it.

Greasemonkey to the rescue.

I wrote a quick script that replaces the little icon to the left of each link with the link src. And since loading these images may be time consuming, you don't want to do this on every "Index of /" page that you come across. So we wrap that function up in a "Show Images" link at the top of the page when it completes loading.

I've uploaded the script to userscripts.org where you can check it out. Install it and go to a page where you can see for yourself how it works.

Google around for "index of /images" and see what treasures abound.

I find lots of pages like this by "going up" a level on a URL. For example (not real, this is not a valid location) if you are looking at a photo:

http://somewhere.good/images/138028.jpg

Then see what's at:

http://somewhere.good/images

Either by editing the URL in the address bar or use the "up one level on this web site" button in Firefox. What, you don't know about that button? Right-Click an empty spot the tool bar and select "Customize...". Drag the icon that looks like the one I've circled below to your tool bar. Use it and discover lots of stuff.


What do you think? Leave a comment.

Baseball Better - Yahoo Greasemonkey Script

I love baseball. But you gotta admit that it can be boring "watching" a game on the web. If not watching it in person or on tv, it's kinda slow. I'm sorta ADD when cruising the web. I usually have 6 or more Firefox tabs open at once. I'm reading something, writing something, searching for something all at the same time. It's a wonder that I get anything done at all, but amazingly it works out.

So if a good game is on at the same time that I'm on-line, I like to have a tab tuned into the Yahoo Sport MLB game. But the problem is that I have to keep clicking to that tab to see what's going on. I have Greasemonkey installed and have written a few other scripts to customize my viewing pleasure so hacking the box score page should be pretty easy.

Here's what the regular game looks like. Usually there's an advertisement over on the right side above the "series at glance" table. I guess times are tough at Yahoo and advertising is slow because no ad is being displayed on this screen shot.

Notice a few other things. The Firefox tab says "MLB - Kansas City Royals/M...". I'd like this to display something useful like the current in-progress game stats. Also see the Inning Summary table at the bottom. Below that is a Scoring Summary that can't be seen unless you scroll down.

So my typical game "watching" experience is every 5-10 minutes, click the tab, look at the score. If different than last time I looked, grab the scroll bar and go way down to see what happened. Way too much work.

After some quick Greasemonkey hacking, I've come up with a better experience. As the page loads, I grab the team names, current score, inning, ball-strike count, runners on-base, and last play. Sounds like a lot but really it's not. Yahoo has everything in nice tables and getting it is like butter. Not really but I just felt like using that term. Just like buddah.

I take all those stats and format them into the tab so I can see the game info without having to click the tab. This alone has probably saved years of wear and tear on my mouse button.

I then replaced the advertisement block (yahoo isn't currently using it anyway) with the scoring summary so no painful scrolling occurs.

For those that also want to enjoy baseball a little better, I've uploaded the script to Greasemonkey script haven.

For those that don't trust me and want to see what I've done, here's a view in the sausage factory. It ain't pretty but it works.

It's just basically screen scraping by searching for classes and then parsing data. Every time Yahoo makes a tweak, it breaks the script. I don't mind, it's usually minor.

Here we go.

Yahoo sets the page to a fixed width of 974 pixels. I run in 1280 mode so this wastes lots of valuable screen space and causes unsightly white gutters. This must be changed:
function changeWidth() {
var node = document.evaluate('//table[@width="974"]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);

node.snapshotItem(0).width="100%";
}
Here's a big part of the magic. Find the table that wraps the team name and score and parse it out. The team names are long and we need shorten them so they fit it the tab nicely.
function getScore() {
var scoreNode = document.evaluate(
'//td[@class="yspsctnhdln"]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
scoreNode = (scoreNode.snapshotItem(0));

// this is ugly but I want to shorten the team so all the info displays nice on the tab
var str = scoreNode.textContent;
str = str.replace(/\n/g, "");
str = str.replace(/ /g, "");
str = str.replace(/,/g, "");
str = str.replace("Arizona", "AZ");
str = str.replace("Atlanta", "Atl");
str = str.replace("Baltimore", "Bal");
str = str.replace("Boston", "Bos");
str = str.replace("Chi Cubs", "Cub");
str = str.replace("Chi White Sox", "CWS");
str = str.replace("Cincinnati", "Cin");
str = str.replace("Cleveland", "Cle");
str = str.replace("Colorado", "Col");
str = str.replace("Detroit", "Det");
str = str.replace("Florida", "FL");
str = str.replace("Houston", "Hou");
str = str.replace("Kansas City", "KC");
str = str.replace("Minnesota", "Min");
str = str.replace("Milwaukee", "Mil");
str = str.replace("LA Angels", "LAA");
str = str.replace("LA Dodgers", "LAD");
str = str.replace("NY Mets", "Met");
str = str.replace("NY Yankees", "NYY");
str = str.replace("Oakland", "Oak");
str = str.replace("Philadelphia", "Phi");
str = str.replace("Pittsburgh", "Pit");
str = str.replace("San Diego", "SD");
str = str.replace("San Francisco", "SF");
str = str.replace("Seattle", "Sea");
str = str.replace("St. Louis", "SL");
str = str.replace("Tampa Bay", "Tam");
str = str.replace("Toronto", "Tor");
str = str.replace("Texas", "Tex");
str = str.replace("Washington", "Was");
str = str.replace(/ /g, "");

// get inning and shorten
var inning = getInning();
inning = inning.replace(/\n/g, "");
inning = inning.replace(/ /g, "");
inning = inning.replace(/Bot /g, "B");
inning = inning.replace(/Top /g, "T");
inning = inning.replace(/End /g, "E");

document.title = str + ' ' + inning + ' ' + getOut();
}
In the above code, I didn't put a comment on this line but this is where the Firefox tab gets the in-game stats:
document.title = str + ' ' + inning + ' ' + getOut();
And more parsing. And then some really ugly if-else code. Kinda embarrassing that I did this. But I did and I'm too lazy to re-write.
function getOut() {
var balls = document.evaluate("//*[contains(.,'O:')]/b",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

var count = "";
if (balls) {
var n= balls.nextSibling;
var strikes = n.nextSibling;
n = strikes.nextSibling;
var outs= n.nextSibling;
count = balls.innerHTML + '-' + strikes.innerHTML + ' O:'+ outs.innerHTML;
}

// find how many men are on base.
// do this by looking at what image is being displayed.
// yeah, I need to clean this up but it works and I don't have time. go for it
var men = document.evaluate("//img[contains(@src,'tr_empty.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "empty";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

if (men) {
men = "1b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_2b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "2b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b2b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "1b2b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "1b3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_2b3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "2b3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_full.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "full";
}
else {
men = "";
}
}
}
}
}
}
}
}
return count + ' ' + men;
}
And that's about it. Take a look at the file at userscripts.org and give it a try. Let me know if you've improved and found some bugs.

What do you think? Leave a comment.