Google Reader just launched a “Send to Twitter” feature that allows you to share bit.ly links to interesting items in your reader with your Twitter friends. First, awesome!
Second, Google Reader has been getting lots of product development attention lately, and with all the awesome stuff they are adding, I spend all of my time there as opposed to twitter.com/home, facebook.com/home, or Tumblr Dashboard. One thing I miss about Tumblr dashboard was easy reblogging.
How to Create Custom Send To Links in Google Reader
There is a “Send to Tumblr” link as one of the defaults, but it doesn’t use bit.ly urls. So, I hacked together a custom “Send to Tumblr” link.
URL: http://tumblr.com/share?v=2&u=&t=Send To Tumblr And Track With Bitly Google Reader Custom Link&s=Send To Tumblr And Track With Bitly Google Reader Custom Link%0Avia%20kortina
Update: This plugin is now hosted by wordpress. click here
/*
Plugin Name: Google Reader Subscription List
Version: 1
Author: Timothy Broder
Description: Lists a users subscribed Google Reader feeds
*/
/* Copyright 2009 Timothy Broder (email : timothy.broder@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
if (!class_exists('GoogleReaderSubList')) {
class GoogleReaderSubList {
var $show_list = 'show-google-reader-sub-list'; //the hook in a page
var $login = '';
var $pass = '';
var $source = 'wordpress-google-reader-sub-list-'; //the source the api sees when logging into Google
var $service = 'reader';
var $login_url = 'https://www.google.com/accounts/ServiceLoginAuth?service=mail'; //URL to login to google
var $subscription_list_url = 'http://www.google.com/reader/api/0/subscription/list'; //URL that holds a users subscriptions
function GoogleReaderSubList() {
$options = $this->get_admin_options();
$this->login = $options['google_login'];
$this->pass = $options['google_pass'];
$this->source = $this->source . $this->login;
}
function show_sub_list() {
$stop = false;
if ($this->login == '' || $this->login == null) {
echo 'Google login not set';
$stop = true;
}
if ($this->pass == '' || $this->pass == null) {
echo 'Google password not set';
$stop = true;
}
//check to see if the zend plugin has been installed and activated
//http://wordpress.org/extend/plugins/zend-framework/
if (!(defined('WP_ZEND_FRAMEWORK') && WP_ZEND_FRAMEWORK)) {
echo 'The Zend Framework Plugin is not active. Please install and activate it.';
$stop = true;
}
if ($stop) {
return;
}
$client = new Zend_Http_Client($this->login_url);
//connect, authenticate, and handshake with Google
$client->setCookieJar()
->setMethod(Zend_Http_Client::POST)
->setParameterPost(array(
'continue' => $this->subscription_list_url,
'service' => 'reader',
'niu' => 1,
'hl' => 'en',
'Email' => $this->login,
'Passwd' => $this->pass,
'PersistentCookie' => 'yes',
'asts' => ''
));
//$error_level = error_reporting();
//error_reporting(1);
$response = $client->request('POST');
$client->setUri($this->subscription_list_url)->setMethod(Zend_Http_Client::GET);
$response = $client->request()->getBody();
if ($client->request()->getStatus() == 400) {
?>Unable to login with supplied Google login/password< ?
return;
}
//error_reporting($error_level);
//got the feed, parse it
$feed = simplexml_load_string($response);
$hashmap = array();
//organize the feeds by tag
foreach ($feed->list->object as $e) {
$url = $e->string[0];
$title = $e->string[1];
$cat = $e->list->object->string[1];
//make sure a feed is filed somewhere
if ($cat == '') {
$cat = 'unfiled';
}
$t = $hashmap["$cat"];
//a category hasn't been used before
if ($t == null) {
$t = array($e);
$hashmap["$cat"] = $t;
}
//category has been used before
else {
array_push($t, $e);
$hashmap["$cat"] = $t;
}
}
//sort the categories
ksort($hashmap);
//output
?>
Tags:
< ?
$endKey = end(array_keys($hashmap));
foreach ($hashmap as $cat=>$t) {
echo "$cat";
if ($cat != $endKey) {
echo ', ';
}
}
?>
< ?
foreach ($hashmap as $cat=>$t) {
echo "";
echo "$cat";
foreach ($t as $e) {
list($feed, $url) = split('feed/', $e->string[0]);
$title = $e->string[1];
echo "$title";
}
echo '';
}
}
function addContent($content) {
// Only do this if this is a page and it has the appropriate custom field
if (is_page()) {
$cust_field_values = get_post_custom_values($this->show_list);
if ($cust_field_values != NULL) {
if (defined('WP_ZEND_FRAMEWORK') && WP_ZEND_FRAMEWORK) {
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Http_Client');
}
$content = $this->show_sub_list();
}
}
return $content;
}
function init() {
$this->get_admin_options();
}
function get_admin_options() {
$admin_options = array('google_login' => '',
'google_pass' => '',
'use_accordion' => 'true');
$options = get_option($this->adminOptionName);
if (!empty($options)) {
foreach ($options as $key => $option) {
$admin_options[$key] = $option;
}
}
update_option($this->admin_optionsName, $admin_options);
return $admin_options;
}
function printAdminPage() {
$options = $this->get_admin_options();
if (isset($_POST['update_greader_sub_list_settings'])) {
if (isset($_POST['greader_sub_list_login'])) {
$options['google_login'] = $_POST['greader_sub_list_login'];
}
if (isset($_POST['greader_sub_list_pass'])) {
$options['google_pass'] = $_POST['greader_sub_list_pass'];
}
update_option($this->admin_optionsName, $options);
echo '
It’s now less “bubble” looking. I’m wondering if its pulling from my gmail theme, but I unfortunately can’t check that from work. I really like being able to hide the stats in the upper left. The only one I ever look at is how many total unread items I have.
As I said earlier, Quite a few presentations from Google I/O have been posted for your viewing pleasure. I’ll be glued to these this weekend while I’m on call.
Topics include
Ajax
KML
Sketchup
Android
OpenSocial
Appengine
Data APIs
Theory Talks
Youtube
Gears
Mashups
Maps
and more!
Blogger in draft added 2 new features today: a blogroll page element, and post scheduling. Post scheduling is pretty useful, you can write up your post, set the time (in the future) that you want it to post, and Blogger will do it automatically.
The second feature, a blogroll, I would like a lot more if it was done better. The main thing I like about it is that it integrates with Google Reader so if I’m linking to my friend’s blogs, I just scroll to my ‘Friends’ Tag and add them. The thing I don’t like however is that it does not support XFN or FOAF therefore not getting picked up by the SocialGraph API. For example, if I linked to my girlfriend’s blog, the blogroll just lists this as
...and get picked up but the SocialGraph as having a relationship to me. Blogger is great and I love using it, but the features of wordpress are blowing it out of the water.
First, Techcrunch came up with a list of the top blogs that users subscribe to using Google Reader. The top 3 on the list were BBC with 202,463, Google News wih 192,100, and ESPN with 189,274 . Remember, these are only the stats if the subscriber is using Google Reader, obviously there are blogs with a higher subscription count, such as the Official Google Blog (They still haven’t moved over to blogs.google.com eh?) with over 669,000 subscribers as reported by FeedBurner.
It was all well and good that Google Reader showed high stats for these blogs, but…. we were apparently duped…
In his article Google Reader Stats are BullSh*t (With Proof), Pete Cashmore goes into his explanation of the “default feed effect.” A default feed is a feed that comes already subscribed in a news aggregator , or is part of a default group (like say Digg, Engadget, and Gizmodo being in the Technology group on Google Reader). Being in these groups is a major traffic boost.
However the system has some flaws
There is subscription data for feeds that don’t exist
Google Reader does not check to see if a subscriber is active or not. (Someone signs up for Reader, adds a feed, and never touches Reader again, they count as a subscriber)
Feedburner pulls some stats from Google Reader
This problem is not limited to Google Reader. It includes many feed readers and start pages
Tune in next time after I do some research into how out wack FeedBurner statistics are.
I’ve been wanting to share what I subscribe to in Google Reader and using the functions I wrote I was able to do just that. Check out the article for the full run down on the unofficial Google Reader API. This is written in python but should be easily portable to php. If i get around to it, I want to make a WordPress plugin so bloggers can share what they read with their readers. This will be followed (or in parallel depending on my mood) with a Javascript version so Blogspot users can do the same in the sidebar. On to the code!
To start off we’ll just copy the functions we need from last time. Generally this is the login and SID token functions, as well as the feed list function.
from django.shortcuts import render_to_response
from django.template import Library
from elementtree import ElementTree
import urllib
import urllib2
import re
login = 'timothy.broder@gmail.com'
password = '***'
source = 'gPowered'
google_url = 'http://www.google.com'
reader_url = google_url + '/reader'
login_url = 'https://www.google.com/accounts/ClientLogin'
token_url = reader_url + '/api/0/token'
subscription_list_url = reader_url + '/api/0/subscription/list'
#login / get SED
def get_SID():
header = {'User-agent' : source}
post_data = urllib.urlencode({ 'Email': login, 'Passwd': password, 'service': 'reader', 'source': source, 'continue': google_url, })
request = urllib2.Request(login_url, post_data, header)
try :
f = urllib2.urlopen( request )
result = f.read()
except:
print 'Error logging in'
return re.search('SID=(\S*)', result).group(1)
#get results from url
def get_results(SID, url):
header = {'User-agent' : source}
header['Cookie']='Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID
print url
request = urllib2.Request(url, None, header)
try :
f = urllib2.urlopen( request )
result = f.read()
except:
print 'Error getting data from %s' % url
return result
#get a specific feed. It works for any feed, subscribed or not
def get_feed(SID, url):
return get_results(SID, get_feed_url + url.encode('utf-8'))
#get a token, this is needed for modifying to reader
def get_token(SID):
return get_results(SID, token_url)
#get a list of the users subscribed feeds
def get_subscription_list(SID):
return get_results(SID, subscription_list_url)
Then we’ll want to get rid off all the information in the feed that we don’t want and load what we do into a data dictionary. After its in the dictionary, feed names and links (and the folders they are in) are ready to be displayed. As usual, I use Django to display my pages, but everything is the same up to the final return in the Feeds method. Below is an example of what each subscription looks like in the Google Reader Feed, and below that is how to process it
class myFeed:
def __init__(self, name, link):
self.name = name
self.link = link
def Feeds(request):
SID = get_SID()
feeds = get_subscription_list(SID)
tree = ElementTree.fromstring(feeds)
d = dict()
#loop through each feed
for object in tree.findall('list')[0].findall('object'):
strings = object.findall('string')
key = object.findall('list')[0].findall('object')[0].findall('string')[1].text
#tag already exists, add to the list
try:
d[key].append(myFeed(strings[1].text, strings[0].text.replace('feed/', '')))
#tag doesn't exist, create list
except KeyError:
d[key] = [myFeed(strings[1].text, strings[0].text.replace('feed/', ''))]
return render_to_response('pages/feeds.html', {
'feeds': d,
})
For those of you that use django or are just curious how I end up displaying the feeds, this is what i have in my view:
Finally!! No more using Yahoo Pipes to search the feeds!
I’m sitting here waiting for my friend Eli to pick me up from his apartment for a nice lunch over at dreamworks, glancing over a few feeds (I have a LOT to catch up on when I get back to NY), and one jumped out at me, the Google Reader Team has finally added a search box to Google reader.
This box will search all of your feeds! Also included in this release are:
- Ability to hide side navigation (I just tried it, it’s very well done)
- Unread count is now 1,000+ rather then 100+ (this is going to be good for me when I get back)
- Forward and Back buttons now have more responsiveness when moving between folders and feeds