YouTube Fullscreen Bookmarklet

I find it incredibly annoying when an embedded YouTube video can’t be made fullscreen, and I have to switch to YouTube.com just to watch it.

So, I wrote this simple little bookmarklet which modifies the embed code for any YouTube videos to allow fullscreen. It could also easily be made into a user script for GreaseMonkey, etc, to perform the modifications automatically.

Bookmarklet

Source:

var os = document.getElementsByTagName("object");
for (var i = 0; i < os.length; i++)
{
    var o = os[i].cloneNode(true);
    o.innerHTML = ‘<param name="allowFullScreen" value="true"></param>’ + o.innerHTML;
    for (var j = 0; j < o.childNodes.length; j++)
    {
        if (o.childNodes[j].name == "movie")
            o.childNodes[j].value += "&fs=1";
        else if (o.childNodes[j].nodeName.toUpperCase() == "EMBED") {
            o.childNodes[j].src += "&fs=1";
            o.childNodes[j].setAttribute("allowfullscreen", "true");
        }
    }
    os[i].parentNode.replaceChild(o, os[i]);
}

Try it out on this page (I’m too lazy to actually make it fullscreen).

Note that currently it doesn’t actually check to make sure it’s a YouTube video that it’s modifying, so it might stomp all over other types of embeds.

A simple Google Charts API "framework"

The Google Charts API is a useful little tool for generating charts. The “API” is actually just a set of parameters you pass to a single URL endpoint: http://chart.apis.google.com/chart

sample chart

It’s a very capable API, and you could write an entire framework around it (as some people have), but I don’t think it’s necessary. A few little helper functions and Google’s documentation is all you really need. Here’s the heart of my “framework” in JavaScript:

function gchart_build(options)
{
    var params = [];
    for (option in options)
        params.push(option + "=" + options[option]);
    return "http://chart.apis.google.com/chart?" + params.join("&");
}

And PHP:

function gchart_build($options)
{
    $params = array();
    foreach ($options as $option => $value)
        $params[] = $option . "=". $value;
    return "http://chart.apis.google.com/chart?" . implode("&", $params);
}

And here’s a simple bar chart example in PHP:

$chart_url = gchart_build(array(
    "cht"   => "bvs",
    "chs"   => "400×250",
    "chbh"  => "14,2,0",
    "chd"   => "t:3,4,4,1,3,2,2,0,1,3,11,5,7,5,5,7,7,5,3,2,3,3,6,6",
    "chds"  => "0,11"
));

The nice thing about this “frameworks” is it takes 30 seconds to implement in many languages, and the actual API is identical across every language, since it just uses a hash object and the original API as a very simple domain-specific language.

This could be improved with a few more helper functions for different parts of the Google Chart API, but this function remains the most important.

Here’s a simple testbed for trying out the JavaScript version. Simple edit the JavaScript and click “Update!” to see the results:
gchart_tester.html

Adding Growl Notifications to Facebook

Yesterday Facebook added the “Live Feed”, which is like the existing News Feed, but automatically updates the page without requiring the user to refresh. It simply polls Facebook’s servers every few seconds, rather than the slightly fancier “comet”-style long-polling they do for Facebook chat:

Live Feed vs Facebook Chat

Polling is perfectly sufficient for this sort of updating (it’s not particularly latency sensitive), but none of this is relevant to the rest of this post anyhow.

As neat as it is, I’m not going to sit around all day watching Facebook, waiting for updates. I want to be notified of updates unobtrusively, at which point I can decide if I want to ignore them or check it out. Growl is perfect for this.

Many OS X apps use Growl to display notifications to the user. They use either Distributed Objects or a UDP protocol called GrowlTalk to post the notifications, neither of which is suitable for a client-side web app. Google Gears promises to provide NotificationAPI at some point, but it’s not currently ready. Fluid also has a notification API, but we need Firefox’s Greasemonkey plugin to inject some JavaScript.

Brian Dunnington wrote a version of Growl for Windows, which adds one neat feature: an HTTP interface. This lets the browser (or anything else the speaks HTTP) post notifications directly. Unfortunately the OS X version of Growl doesn’t have this interface built in, but it’s nearly trivial to create a bridge to the GrowlTalk protocol in Python:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from socket import AF_INET, SOCK_DGRAM, socket
from urlparse import urlparse
from cgi import parse_qs
import simplejson
import netgrowl

class GrowlBridgeHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        try:
            # parse url
            u = urlparse(self.path)
            if u.path == "/":
                
                # parse query string
                q = parse_qs(u.query)
                print q
                
                # parse json payload
                j = simplejson.loads(q[‘d’][0])
                print j
                
                # create and send the notification
                p = netgrowl.GrowlNotificationPacket(
                    description=(j.has_key(‘description’) and j[‘description’] or "Description"),
                    title=(j.has_key(‘title’) and j[‘title’] or "Title"),
                    priority=(j.has_key(‘priority’) and j[‘priority’] or 0),
                    sticky=True) #(j.has_key(‘sticky’) and j[‘sticky’] or False))
                growlserver.sendto(p.payload(), addr)
                
                # send a 200 http response
                self.send_response(200)
                self.send_header(‘Content-type’, ‘text/html’)
                self.end_headers()
                return
            
            return
                
        except IOError:
            self.send_error(404, ‘File Not Found: %s’ % self.path)

def main():
    try:
        # prepare the growl socket
        global addr, growlserver
        addr = ("localhost", netgrowl.GROWL_UDP_PORT)
        growlserver = socket(AF_INET,SOCK_DGRAM)
        print "Assembling registration packet like growlnotify’s (no password)"
        p = netgrowl.GrowlRegistrationPacket()
        p.addNotification()
        print "Sending registration packet"
        growlserver.sendto(p.payload(), addr)
        
        # start the http server
        httpserver = HTTPServer((, 9889), GrowlBridgeHandler)
        print ‘started growlbridge…’
        httpserver.serve_forever()
        
    except KeyboardInterrupt:
        print ‘^C received, shutting down server’
        httpserver.socket.close()
        
        growlserver.close()
        print "Done."

if __name__ == ‘__main__’:
    main()

growlbridge.py.gz

Of course this opens up a port on your machine, so you should take the necessary precautions to firewall it. It uses Rui Carmo’s netgrowl and also requires Bob Ippolito’s simplejson.

We can now use Brian’s growl.js library with both Mac OS X and Windows versions of Growl. The next step is to connect it up to Facebook with Greasemonkey:

// ==UserScript==
// @name           Facebook News Feed Notifier
// @namespace      http://tlrobinson.net/
// @description    Notify user of new Facebook News Feed items via Growl
// @include        http://*.facebook.com/home.php
// ==/UserScript==

function GM_init() {
    
    var fbNewsFeedNotification = new Growl.NotificationType("Facebook News Feed", true);
    Growl.register("Facebook", [fbNewsFeedNotification]);
    
    unsafeWindow.HomeFeed.prototype._addStoriesToQueueOriginal = unsafeWindow.HomeFeed.prototype._addStoriesToQueue
    unsafeWindow.HomeFeed.prototype._addStoriesToQueue = function(stories) {
        this._addStoriesToQueueOriginal(stories);
        
        var testDiv = document.createElement("div");
        for (var i = 0; i < stories.length; i++)
        {
            testDiv.innerHTML = stories[i];
            var spans = testDiv.getElementsByTagName("span");
            
            var message = (spans.length > 0) ? spans[0].textContent : "Unknown update";
            
            Growl.notify(fbNewsFeedNotification, "Facebook News Feed", message, Growl.Priority.Normal, false);
        }
    }
}

// Add growl.js
var GM_GROWL = document.createElement(‘script’);
GM_GROWL.src = ‘http://www.tripthevortex.com/growl/growl.js’;
GM_GROWL.type = ‘text/javascript’;
document.getElementsByTagName(‘head’)[0].appendChild(GM_GROWL);

// Check if growl.js’s loaded
function GM_wait() {
    if(typeof unsafeWindow.Growl == ‘undefined’)
    {
        console.log("waiting");
            window.setTimeout(GM_wait, 100);
    }
    else
    {
        Growl = unsafeWindow.Growl;
        GM_init();
    }
}
GM_wait();

This fairly simple userscript loads growl.js, then overwrites one of Facebook’s JavaScript functions that gets called when updating the feed, HomeFeed.prototype._addStoriesToQueue(). The new function should call the original one (so that the feed is still updated), but it should also post a new notification for each new feed story.

That’s about it. Run “python growlbridge.py” if you’re on a Mac (make sure you have netgrowl and simplejson), or Brian Dunnington’s Growl for Windows, install the above Greasemonkey userscript, and open up http://www.new.facebook.com/home.php?tab=2.

Unfortunately, there appears to be some bugs (or new security restrictions) in Firefox 3 that prevents this userscript from working correctly, but it works fine in Firefox 2.

In the future growl.js could be swapped out for the Gears or Fluid notification APIs, or anything else (ideally some standard). Also, hopefully Growl for OS X will have the same HTTP interface built in.