Google Reader Favicon ++

By Yamamaya Last update Oct 28, 2009 — Installed 6,471 times. Daily Installs: 14, 23, 120, 141, 74, 29, 48, 44, 30, 66, 31, 49, 40, 34, 44, 33, 15, 29, 19, 16, 12, 15, 19, 12, 13, 16, 23, 14, 17, 17, 13, 10

There are 32 previous versions of this script.

// ==UserScript==
// @name          Google Reader Favicon ++
// @description   Adds favicons to feeds and entries
// @namespace     Yamamaya
// @version       4.0.3
// @include       http://*google.tld/reader/view*
// @include       https://*google.tld/reader/view*
// ==/UserScript==

/*************************************************
 This script is based on 
  Ultimate GReader favicons
   http://userscripts.org/scripts/show/27739
  Google Reader - Colorful List View
   http://userscripts.org/scripts/show/8782
***************************************************/

(function(){
	var GOOGLE_READER_INFO = eval(GM_getValue('googleReaderInformation')) || {};
	var FAVICON = GOOGLE_READER_INFO.favicon || (GOOGLE_READER_INFO.favicon = {});
	var FAVICON_URL = ['http://getfavicon.appspot.com/http://', ''];
	var FAVICON_DEFAULT_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABdUExURa2z+H6CrWtwpnN5uWNopejp9Pf3/6+08Kes6G50uePm/qSr+MTG6ZSZzbW4593e93R4qs3R/JOWu5Oa8dbZ/ISJvJ6l9Ovs/sXJ+amszL3C9/P0/7W6+J+izP////fbRfQAAAEbSURBVHjaYpCTFYICOTAACCAGWT5pNml+QQkpPlGwAEAAMcgKCvKLy7FKsXMISAKBHEAAMchKychIyYjLSbAzioiI8EgCBBCDLIO4HJsMg7i0jCgbUKcsQAAxyMpIMAKBAAjIiUjIAgQQUIsoh7i0uAhQpywTm6AsQAABDRWVkhARl5OWYOBmkRORBQggBlkRUQYxMQYZaTkpMRZpVkmAAGLgZRcV45KTlhGTluZg4ZKWBAggBjleUTEZCS45GRk5KRZ+VkmAAGKQkxNlEBYWE5cWE+dnkuKRBAggkICEtLiwhJywCCsT0KUAAQQSEJSTE5YS55bgZwL6BSCAgAKMYlLsYsJAIAsSAAggoIAcMycnMzMQCYB8CxBgAB2IFJeOuyn5AAAAAElFTkSuQmCC';

	var COLORFUL_FLAG = GOOGLE_READER_INFO.colorfulViewFlag || false;
	var COLORFUL_BUTTON_TEXT = GOOGLE_READER_INFO.colorfulViewText || 'Colorful View On';
	var COLORFUL_BUTTON_CLASS_CONTENT = GOOGLE_READER_INFO.colorfulViewButtonContentClass || '';
	var COLORFUL_BUTTON_CLASS_POS = GOOGLE_READER_INFO.colorfulViewButtonPosClass || '';
	var COLORFUL_BUTTON_CLASS_TOP_SHADOW = GOOGLE_READER_INFO.colorfulViewButtonTopShadowClass || '';
	var COLORFUL_BUTTON_CLASS_INNER_BOX = GOOGLE_READER_INFO.colorfulViewButtonInnerBoxClass || '';

	var RSS = $X('id("sub-tree-item-0-main")/ul/li/ul/li').length;
	var FOLDER = $X('id("sub-tree-item-0-main")/ul/li').length;
	var RSS_NUMBERS = GOOGLE_READER_INFO.rssNumber || null;
	var FOLDER_NUMBERS = GOOGLE_READER_INFO.folderNumber || null;
			
 
	var googleReader = {
		init: function(){ 
			(RSS_NUMBERS === null || FOLDER_NUMBERS === null || RSS !== RSS_NUMBERS || FOLDER !== FOLDER_NUMBERS) ?
				this.noCacheAddFavicon(): this.addFavicon();

			this.addBaseCss();
			
			if(COLORFUL_FLAG == false) 
				this.addNoColorfulListViewCss();
		 
			GM_registerMenuCommand('GoogleReaderFavicon++ - clear cache', clearCache); 
	   
			GOOGLE_READER_INFO.rssNumber = RSS;
			GOOGLE_READER_INFO.folderNumber = FOLDER;
			setValue();
		},
		noCacheAddFavicon: function(){
			var xhr = new XMLHttpRequest();
	   
			xhr.open('get', '/reader/subscriptions/export', true);

			xhr.onload = function(){
				var responseXML = xhr.responseXML;
				Array.forEach(responseXML.getElementsByTagName('outline'), function(outline){
					if (!outline.hasAttribute('htmlUrl')) return;
					var title = outline.getAttribute('title');
					var url = outline.getAttribute('htmlUrl');
					var favicon;
					url = url.split(/\/|\?/)[2];
					(title.length > 24) ? 
						FAVICON[title.substr(0, 21) + '...'] = FAVICON_URL.join(url):
						FAVICON[title] = FAVICON_URL.join(url);
				});	
					
				googleReader.addFavicon();
			
				setValue();	
			};

			xhr.send(null);		
		},
		addFavicon: function(){
			entryFaviconNoDOMNodeInserted();
			if(COLORFUL_FLAG == true)
				this.colorfulListView.setColor();
			this.colorfulListView.button();
			this.entryFavicon();		
			this.sideBarFavicon();
			
			
			function entryFaviconNoDOMNodeInserted(){
				$X('.//span[@class="entry-source-title"] | .//a[@class="entry-source-title"]').forEach(function(title){
					var match = title.textContent;
					if(match.length > 24) 
						match = match.substr(0,21) + '...';
					var favicon = document.createElement('img');
					favicon.className = 'entry-favicon';
					
					if(COLORFUL_FLAG == true){
						var target;
						(title.tagName === 'SPAN') ? 
							target = title.parentNode.parentNode.parentNode:
							target = title.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
						if(target.getAttribute('color') === null)
							target.setAttribute('color',match.replace(/"/g,''));
					}	
					
					if(FAVICON.hasOwnProperty(match)){
						favicon.src = FAVICON[match]
					}	
					else{
						favicon.src = FAVICON_DEFAULT_IMG;
					}	
					
					if(title.tagName !== 'SPAN'){
						title = title.parentNode.parentNode.getElementsByTagName('a')[0];
					}
					
					title.parentNode.insertBefore(favicon,title);	
					
					favicon.removeEventListener('error',revertFavicon,false);
					favicon.addEventListener('error',revertFavicon,false);
				});			
			};			
		},
		entryFavicon: function(){
			document.addEventListener('DOMNodeInserted', function(e){
				var target = e.target;
				entry(target);
				sideBar(target);
			}, false);		
			
			function entry(target){
				if(/^entry\s/i.test(target.className) && target.tagName === 'DIV'){
					var point, match;
					var favicon = document.createElement('img');
					favicon.className = 'entry-favicon';
										
					if(target.firstChild.className === 'collapsed'){ // リスト表示 .//span[contains(@class,'entry-source-title')]
						point = target.getElementsByTagName('span')[0];
						match = point.textContent;
					}
					else{// 前文表示 .//span[@class='entry-source-title-parent'], 検索, コメント共有
						point = target.getElementsByClassName('entry-title-link')[0] || target.getElementsByClassName('comment-entry-title')[0];
						var title = target.getElementsByClassName('entry-source-title')[0]; 
						match = title.textContent;
					}				
						
					if(match.length > 24) 
						match = match.substr(0,21) + '...';			
					
					if(target.getAttribute('color') === null)
						target.setAttribute('color',match.replace(/"/g,''));
						
					if(FAVICON.hasOwnProperty(match)){
						favicon.src = FAVICON[match];
					}
					else{ // popular items | recommended sources
						var fs = target.getElementsByClassName('entry-original')[0] || target.getElementsByClassName('entry-title-link')[0];
						if(fs){
							fs = FAVICON_URL.join(fs.href.split(/\/|\?/)[2]);
							favicon.src = fs;
						}
						else{
							favicon.src = FAVICON_DEFAULT_IMG;
						}
					} 
					
					point.parentNode.insertBefore(favicon, point);
					favicon.removeEventListener('error', revertFavicon, false);
					favicon.addEventListener('error', revertFavicon, false);			
				}				
			};
				
			function sideBar(target){
				if(target.nodeName.toLowerCase() === 'li' && target.className.match(/^folder/))
					googleReader.sideBarFavicon();						
			};
		
		},
		sideBarFavicon: function(){
			$X('id("sub-tree")//span[contains(@class,"sub-icon")]').forEach(function(e){
				if(e.parentNode.firstChild.nodeName.toLowerCase() === 'img') return;
				var title = e.nextSibling;
				var match = title.firstChild.textContent;
				if(match.length > 24) match = match.substr(0,21) + '...';
				title.style.paddingLeft = '7px';			
				var favicon = document.createElement('img');
				e.parentNode.insertBefore(favicon,e);
				e.parentNode.removeChild(e);
					
				if(FAVICON.hasOwnProperty(match)){
					favicon.src = FAVICON[match];
				}
				else{
					favicon.src = FAVICON_DEFAULT_IMG;
				}
				favicon.removeEventListener('error',revertFavicon,false);
				favicon.addEventListener('error',revertFavicon,false);
			});		
		},
		addBaseCss: function(){
			GM_addStyle(<><![CDATA[  
				img.entry-favicon {
					width: 16px !important;
					height: 16px !important;					
					border: none !important;
					margin-right: 5px;
				}
				.collapsed img.entry-favicon {
					position: absolute !important;	
					top: 3px !important;
					left: 1.6em !important;
					margin-right: 0px !important;
					vertical-align: baseline !important;			
				}
				#entries.list .collapsed .entry-main .entry-source-title {
					left: 3.25em !important;
					width:9em !important;
				}
				#sub-tree ul ul li a {
					padding-left:22px !important;
				}
				#sub-tree a img {
					width:16px;
					height:16px;
					border:none;
					vertical-align:middle;
				}
				#entries.list .collapsed .entry-secondary {
					margin: 0 8.5em 0 14em !important;
				}
				#entries.single-source .collapsed .entry-source-title {
					display:block !important;
				}
				.colorful-view-content {
					color: #EEEEEE !important;
				}
				.colorful-view-base-top-shadow {
					background-color:#999999 !important;
					border-bottom-color:#888888 !important;
				}
				.colorful-view-inner-box {
					background-color:#777777 !important;
					background:#F9F9F9 none repeat scroll 0 0 !important;
					border-color:#888888 !important;
				}
				.colorful-view-base-pos {
					background-color:#777777 !important;
					border-color:#888888 !important;
				}
			]]></>);		
		},
		addNoColorfulListViewCss: function(){
			GM_addStyle(<><![CDATA[
				#entries.list .read .collapsed {
					opacity:0.6;
				}
				#entries.list .entry .collapsed:hover {
					background:#C2CFF1;
				}
				#entries.list .read .collapsed:hover {
					opacity:1.0;
					background:#C2CFF1;
				}		
			]]></>);
		},
		/*----------------------------------------------------------------------------------
			Google Reader - Colorful List View / http://userscripts.org/scripts/show/8782 
		-----------------------------------------------------------------------------------*/	
		colorfulListView: {
			button: function(){
				var insert = document.getElementById('stream-prefs-menu');
				var div = document.createElement('div');
				var divStyle = div.style;
				divStyle.marginLeft = '0.5em';
				div.className = 'goog-button goog-button-base unselectable goog-inline-block goog-button-float-left goog-menu-button goog-button-tight scour-disabled';
				div.setAttribute('tabindex','0');
				div.setAttribute('role','wairole:button');
				div.innerHTML = '<div class="goog-button-base-outer-box goog-inline-block">\
								 <div class="goog-button-base-inner-box '+COLORFUL_BUTTON_CLASS_INNER_BOX+'">\
								 <div class="goog-button-base-pos '+COLORFUL_BUTTON_CLASS_POS+'">\
								 <div class="goog-button-base-top-shadow '+COLORFUL_BUTTON_CLASS_TOP_SHADOW+'">&nbsp;</div>\
								 <div class="goog-button-base-content '+COLORFUL_BUTTON_CLASS_CONTENT+'">\
								 <div class="goog-button-body">'+COLORFUL_BUTTON_TEXT+'</div>\
								 </div>\
								 </div>\
								 </div>\
								 </div>';
				insert.parentNode.insertBefore(div,insert.nextSibling);
	
				div.addEventListener('click',function(e){
					var buttonBody = $X('.//div[contains(@class,"goog-button-body")]',div)[0];
					var buttonPos = $X('.//div[contains(@class,"goog-button-base-pos")]',div)[0];
					var buttonTopShadow = $X('.//div[contains(@class,"goog-button-base-top-shadow")]',div)[0];
					var buttonInnerBox = $X('.//div[contains(@class,"goog-button-base-inner-box")]',div)[0];
			  
					if(buttonBody.textContent.match(/on/igm)){
						buttonClickEvent(true);
					} 
					else{
						buttonClickEvent(false);
					} 
				
					function buttonClickEvent(flag){	
						var head = document.getElementsByTagName('head')[0];
						var style = head.getElementsByTagName('style');
						if(flag === true){
							buttonBody.parentNode.className = 'goog-button-base-content colorful-view-content';			
							buttonTopShadow.className = 'goog-button-base-top-shadow colorful-view-base-top-shadow';
							buttonPos.className = 'goog-button-base-pos colorful-view-base-pos';			
							buttonInnerBox.className = 'goog-button-base-inner-box goog-inline-block colorful-view-inner-box';
				 
							buttonBody.innerHTML = 'Colorful View Off';
							GOOGLE_READER_INFO.colorfulViewFlag = flag;		
							GOOGLE_READER_INFO.colorfulViewButtonContentClass = 'colorful-view-content';
							GOOGLE_READER_INFO.colorfulViewButtonTopShadowClass = 'colorful-view-base-top-shadow';
							GOOGLE_READER_INFO.colorfulViewButtonPosClass = 'colorful-view-base-pos';
							GOOGLE_READER_INFO.colorfulViewButtonInnerBoxClass = 'colorful-view-inner-box';
					
							GOOGLE_READER_INFO.colorfulViewText = buttonBody.textContent;
							setValue();															
						}
						else{
							buttonBody.parentNode.className = 'goog-button-base-content';
							buttonTopShadow.className = 'goog-button-base-top-shadow';						
							buttonPos.className = 'goog-button-base-pos';
							buttonInnerBox.className = 'goog-button-base-inner-box goog-inline-block';

							buttonBody.innerHTML = 'Colorful View On';
							GOOGLE_READER_INFO.colorfulViewFlag = flag;		
							GOOGLE_READER_INFO.colorfulViewButtonContentClass = '';
							GOOGLE_READER_INFO.colorfulViewButtonTopShadowClass = '';
							GOOGLE_READER_INFO.colorfulViewButtonPosClass = '';
							GOOGLE_READER_INFO.colorfulViewButtonInnerBoxClass = '';
					
							GOOGLE_READER_INFO.colorfulViewText = buttonBody.textContent;
							setValue();		
						}	
					};			  
				},false);	
			},
			setColor: function(){
				var style = '.card {background-color: transparent !important;}'
						  +	'.collapsed {border-color: transparent !important;}'
						  + '#entries.list #current-entry .collapsed {border: 2px solid #8181DC !important;}'
						  + '#entries.list #current-entry.expanded .collapsed {border-bottom-color: transparent !important;border-width: 2px 0 !important;}';
									
				for(var i in FAVICON){
					var title = i.replace(/"/g,'');
					var c = 0;
					var l = parseInt(title.length);
					c += title.charCodeAt(0);
					c = Math.floor(l*c);
					c = Math.floor(c%270);
					style += 'div[color="'+title+'"] .collapsed{background: hsl('+c+', '+(l+70)+'%, 70%) !important;}'
						  +	 'div[color="'+title+'"]:hover .collapsed {background: hsl('+c+', '+(l+80)+'%, 60%) !important;}'
						  +	 'div.read[color="'+title+'"] .collapsed {background: hsla('+c+', '+(l+80)+'%, 85%, 0.9) !important;}'
						  +	 'div.read[color="'+title+'"]:hover .collapsed {background: hsla('+c+', '+(l+70)+'%, 70%, 1.0) !important;}'
						  +	 'div[color="'+title+'"] .card{background: hsl('+c+', '+(l+70)+'%, 75%) !important;}'
						  +	 'div[color="'+title+'"]:hover .card {background: hsl('+c+', '+(l+80)+'%, 65%) !important;}'
						  +  'div.read[color="'+title+'"] .card {background: hsl('+c+', '+(l+85)+'%, 88%) !important;}'
						  +  'div.read[color="'+title+'"]:hover .card {background: hsl('+c+', '+(l+70)+'%, 80%) !important;}'
						  +  'div.read[color="'+title+'"] .collapsed .entry-title {color: #8F8F8F !important;}'
						  +  'div.read[color="'+title+'"] .collapsed .entry-source-title {color: #8F8F8F !important;}'
						  +  'div.read[color="'+title+'"] .collapsed .entry-secondary {color: #8F8F8F !important;}'
						  +  'div.read[color="'+title+'"]:hover .collapsed .entry-title {color: #000000 !important;}'
						  +  'div.read[color="'+title+'"]:hover .collapsed .entry-source-title {color: #555555 !important;}'
						  +  'div.read[color="'+title+'"]:hover .collapsed .entry-secondary {color: #777777 !important;}';
				};
				// set color is error
				style += '#entries.list .collapsed {background: hsl(180, 70%, 70%);}'
					  +	 '#entries.list .collapsed:hover {background: hsl(180, 80%, 60%);}'
			          +  '#entries.list .read .collapsed {background: hsl(180, 80%, 85%); opacity:1.0;}'
			          +  '#entries.list .read .collapsed:hover {background: hsl(180, 70%, 70%);}'
			          +	 'div .card {background: hsl(180, 70%, 70%);}'
			          +	 'div .card:hover {background: hsl(180, 80%, 60%);}'
			          +  'div .read .card {background: hsl(180, 85%, 90%);}'
			          +  'div .read .card:hover {background: hsl(180, 70%, 85%);}'
				GM_addStyle(style);
			}	
		}
	};
 
	googleReader.init();
  

	function revertFavicon(event){
		this.src = FAVICON_DEFAULT_IMG;
	};
 
	function setValue(){
		GM_setValue('googleReaderInformation',uneval(GOOGLE_READER_INFO));
	};
 
	function clearCache(){
		GM_setValue('googleReaderInformation','');
	};
 
	function $X(exp, ctx){
		var xp = (ctx && ctx.ownerDocument || document).evaluate(exp, ctx || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null),
		r = [];
		for (var i = 0;i < xp.snapshotLength;++i) r.push(xp.snapshotItem(i));
		return r;
	};
	
})();