// ==UserScript==
// @name          RSS Reader on Google Search
// @namespace     http://blog.fkoji.com/
// @description	  Add feed items to Google search result
// @include       http://*.google.*/search*q=*
// ==/UserScript==

(function() {
 function parseRSS10(xml) {
  var feed = {"item":[]};
  var matchNum = 0;
  xml.match(/<\/channel>/);
  xml = RegExp.rightContext;
  while(xml.match(/<item/)) {
   xml = RegExp.rightContext;
   matchNum++;
   xml.match(/<title.*?>(.+?)<\/title>/);
   var title = RegExp.$1;
   xml.match(/<link.*?>(.+?)<\/link>/);
   var link = RegExp.$1;
   feed.item.push({"title":title,"link":link});
   if(matchNum == 5) break;
  }
  return feed;
 }
 function parseRSS20(xml) {
  var feed = {"item":[]};
  var matchNum = 0;
  while(xml.match(/<item>/)) {
   xml = RegExp.rightContext;
   matchNum++;
   xml.match(/<title.*?>(.+?)<\/title>/);
   var title = RegExp.$1;
   xml.match(/<link.*?>(.+?)<\/link>/);
   var link = RegExp.$1;
   feed.item.push({"title":title,"link":link});
   if(matchNum == 5) break;
  }
  return feed;
 }
 function parseAtom(xml) {
  var feed = {"item":[]};
  var matchNum = 0;
  xml.match(/<entry>/);
  xml = RegExp.rightContext;
  while(xml.match(/<title>/)) {
   matchNum++;
   xml.match(/<title.*?>(.+?)<\/title>/);
   var title = RegExp.$1;
   xml.match(/<link.+?href="(.+?)"/);
   var link = RegExp.$1;
   xml = RegExp.rightContext;
   feed.item.push({"title":title,"link":link});
   if(matchNum == 5) break;
  }
  return feed;
 }

 function showFeed(feed, link) {
  var ul = document.createElement("ul");
  with(ul.style) {
   listStyleType = 'circle';
   margin = '3px';
   paddingLeft = '18px';
  }
  if (feed.item.length == 0) return false;
  for (var i = 0; i < feed.item.length; i++) {
   feed.item[i].title = feed.item[i].title.replace(/^<!\[CDATA\[/, "");
   feed.item[i].title = feed.item[i].title.replace(/\]\]>$/, "");
   feed.item[i].link = feed.item[i].link.replace(/^<!\[CDATA\[/, "");
   feed.item[i].link = feed.item[i].link.replace(/\]\]>$/, "");
   var a = document.createElement("a");
   a.href = feed.item[i].link;
   a.style.color = 'f60';
   a.appendChild(document.createTextNode(feed.item[i].title));
   var li = document.createElement("li");
   li.appendChild(a);
   ul.appendChild(li);
  }
  var div = document.createElement("div");
  with (div.style) {
   marginTop = '5px';
   marginBottom = '5px';
   fontSize = '0.8em';
  }
  div.appendChild(ul);
  link.parentNode.insertBefore(div, link.nextSibling);
 }

 function getFeed(feedUrl, type, link) {
  GM_xmlhttpRequest({method: "GET", url: feedUrl, onload: function(res) {
   xml = res.responseText;
   var str512 = xml.substr(0, 512);
   var feed = undefined;
   if (type == "RSS") {
    if (str512.match(/<rss/)) {
     feed = parseRSS20(xml);
    }
    else if (str512.match(/<rdf:RDF/)) {
     feed = parseRSS10(xml);
    }
   }
   else if (type == "Atom") {
    feed = parseAtom(xml);
   } else {
    if (str512.match(/<rss/)) {
     feed = parseRSS20(xml);
    }
    else if (str512.match(/<feed/)) {
     feed = parseAtom(xml);
    }
    else if (str512.match(/<rdf:RDF/)) {
     feed = parseRSS10(xml);
    }
   }
   if (feed) {
    showFeed(feed, link);
   }
  }});
 }

 function getPage(link) {
  GM_xmlhttpRequest({method: "GET", url: link.href, onload: function(res) {
   body = res.responseText;
   var linkTags = body.match(/<link *?.+?\/?>/g);
   if (!linkTags) return;
   for (var i = 0; i < linkTags.length; i++) {
    var elem = linkTags[i];
    if (elem.match(/rel="alternate"/) && elem.match(/type="application\/(.*?)xml"/)) {
     switch (RegExp.$1) {
      case "rss+": type = "RSS"; break;
      case "atom+": type = "Atom"; break;
      default: type = "Feed";
     }
     if (elem.match(/href="(.+?)"/)) {
      getFeed(RegExp.$1, type, link);
      break;
     }
    }
   }
  }});
 }

 if (!location.search.match(/site(%3A|:)/)) {
  var links = document.evaluate('//a[@class="l"]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  if (!links.snapshotLength) return;
  for (var i = 0; i < links.snapshotLength; i++) {
   var link = links.snapshotItem(i);
   getPage(link);
  }
 }
})();

