GoogleReaderGrowl

By brian dunnington Last update Aug 28, 2009 — Installed 7,676 times.

There are 2 previous versions of this script.

// ==UserScript==
// @name        GoogleReaderGrowl
// @namespace   http://www.growlforwindows.com
// @description Get Growl notifications for Google Reader updates
// @include     http://google.com/reader/*
// @include     http://*.google.com/reader/*
// @author      Brian Dunnington
// @credit      Based on Fluid script by Todd Ditchendorf
// @credit      Based on Fluid script by Tanguy de Courson <tanguy@0x7a69.net>
// @version     1.0.1 - fixed a bug that didnt always handle individual notifications properly
// ==/UserScript==


GoogleReaderGrowl = function(){
    var unreadText = "";
    var unread = 0;
	var old_unread = 0;

    var focused = true;
    window.addEventListener('focus', function(){focused=true;}, false);
    window.addEventListener('blur', function(){focused=false;}, false);
    
    function doUpdates(firstTime) {
        var title = document.title;
        old_unread = unread || 0;

        if (title && title.length) {
            var start = title.indexOf("(");
            var end = title.indexOf(")");
            if (start > -1 && end > -1) {
                start++;
                unreadText = title.substring(start, end);
                unread = parseInt(unreadText);
            } else {
                unread = 0;
            }
        }

        //growl if there are more unread items than last time
        if ((unread || 0) > old_unread) 
		{
		    // send out a generic 'you have unread items' notification
		    GrowlMonkey.notify(GoogleReaderGrowl.appname, 'newitems', 'Google Reader', (unreadText || "") + " unread item(s)");

            // send out a notification for each unread item individually
            if(!firstTime){
		        var items = getElementsByClassName('entry');
		        if(items && items.length){
		            for(i=0; i < ((unread/1)-(old_unread/1)); i++)
		            {
		                var item = items[i];
		                if(item.className.indexOf('read') < 0){
    			            var feed = item.getElementsByClassName('entry-source-title')[0].innerHTML;
    			            var preview = item.getElementsByClassName('entry-title')[0].innerHTML;

        			        GrowlMonkey.notify(GoogleReaderGrowl.appname, 'individual', feed, preview);
        			    }
		            }
		        }
		    }
        }

		if(!firstTime && !focused) refresh();        
        waitAndCheckAgain();
    }
    
    function waitAndCheckAgain(){
        window.setTimeout(function(){doUpdates();}, 10 * 1000); // Check for new messages every 10 seconds
    }

	function refresh()
	{
		var refreshelm = document.getElementById('viewer-refresh');
		if(refreshelm)
		{
			var e = document.createEvent('MouseEvents');
			e.initMouseEvent("click", true, true, window,
			    0, 0, 0, 0, 0, false, false, false, false, 0, null);
			refreshelm.dispatchEvent(e);
			return true;
		}
		else
			return false;
	}

    return {
        appname : "Google Reader",

        init : function(){
            GoogleReaderGrowl.register();
            doUpdates(true);
        },

        register :  function(){
            var ntNewItems = {};
            ntNewItems.name = "newitems";
            ntNewItems.displayName = "New Unread Items";
            ntNewItems.enabled = true;

            var ntIndividual = {};
            ntIndividual.name = "individual";
            ntIndividual.displayName = "New Individual Item";
            ntIndividual.enabled = true;

            var types = [ntNewItems, ntIndividual];

            GrowlMonkey.register(GoogleReaderGrowl.appname, "http://growlforwindows.com/gfw/images/plugins/googlereader.png", types);
        }
    }
}();


/* === GETELEMENTSBYCLASSNAME ===
   Developed by Robert Nyman, http://www.robertnyman.com
   Code/licensing: http://code.google.com/p/getelementsbyclassname/
   ============================== */


var getElementsByClassName = function(className, tag, elm) {
    if (document.getElementsByClassName) {
        getElementsByClassName = function(className, tag, elm) {
            elm = elm || document;
            var elements = elm.getElementsByClassName(className),
            nodeName = (tag) ? new RegExp("\\b" + tag + "\\b", "i") : null,
            returnElements = [],
            current;
            for (var i = 0, il = elements.length; i < il; i += 1) {
                current = elements[i];
                if (!nodeName || nodeName.test(current.nodeName)) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    else if (document.evaluate) {
        getElementsByClassName = function(className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
            classesToCheck = "",
            xhtmlNamespace = "http://www.w3.org/1999/xhtml",
            namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace) ? xhtmlNamespace: null,
            returnElements = [],
            elements,
            node;
            for (var j = 0, jl = classes.length; j < jl; j += 1) {
                classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
            }
            try {
                elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
            }
            catch(e) {
                elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
            }
            while ((node = elements.iterateNext())) {
                returnElements.push(node);
            }
            return returnElements;
        };
    }
    else {
        getElementsByClassName = function(className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
            classesToCheck = [],
            elements = (tag === "*" && elm.all) ? elm.all: elm.getElementsByTagName(tag),
            current,
            returnElements = [],
            match;
            for (var k = 0, kl = classes.length; k < kl; k += 1) {
                classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
            }
            for (var l = 0, ll = elements.length; l < ll; l += 1) {
                current = elements[l];
                match = false;
                for (var m = 0, ml = classesToCheck.length; m < ml; m += 1) {
                    match = classesToCheck[m].test(current.className);
                    if (!match) {
                        break;
                    }
                }
                if (match) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    return getElementsByClassName(className, tag, elm);
};

/* === //GETELEMENTSBYCLASSNAME === */


// initialize the whole works
window.addEventListener("load", function(e) {
     GoogleReaderGrowl.init();
}, false);


// -- GrowlMonkey stuff below here - do not edit
GrowlMonkey = function(){
    function fireGrowlEvent(type, data){
        var element = document.createElement("GrowlEventElement");
        element.setAttribute("data", JSON.stringify(data));
        document.documentElement.appendChild(element);

        var evt = document.createEvent("Events");
        evt.initEvent(type, true, false);
        element.dispatchEvent(evt);
    }
    
    return {
        register : function(appName, icon, notificationTypes){
            var r = {};
            r.appName = appName;
            r.icon = icon;
            r.notificationTypes = notificationTypes;
            fireGrowlEvent("GrowlRegister", r);
        },
        
        notify : function(appName, notificationType, title, text, icon){
            var n = {};
            n.appName = appName;
            n.type = notificationType;
            n.title = title;
            n.text = text;
            n.icon = icon;
            fireGrowlEvent("GrowlNotify", n);
        }
    }
}();

/* json2.js 
 * 2008-01-17
 * Public Domain
 * No warranty expressed or implied. Use at your own risk.
 * See http://www.JSON.org/js.html
*/
if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
return'['+a.join(',')+']';}
if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
return'{'+a.join(',')+'}';}}
return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
return filter(k,v);}
if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
throw new SyntaxError('parseJSON');}};}();}