Send To Tumblr And Track With Bitly Google Reader Custom Link

Testing the "send to blogger" button... Send To Tumblr And Track With Bitly Google Reader Custom Link: "

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](http://labs.kortina.ne t/files/2009/08/2009-08-13_2354-300x173.png)

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`

Icon URL: http://assets.tumblr.com/images/favicon.gif?2

[![Custom Send to Tumblr with Bitly Link from Google Reader Link](http://labs. kortina.net/files/2009/08/2009-08-13_2351-300x170.png)](http://labs.kortina.ne t/files/2009/08/2009-08-13_2351.png)

Custom Send to Tumblr with Bitly Link from Google Reader Link

Possibly related posts:

  1. I Want “Read Flare” — Plugins for Sharing in Google Reader
  2. Business Cards Have Google Maps Now
  3. How To Make a Fixed Link to Twitter That’s Always Visible on Your Webpage

[![](http://feeds.feedburner.com/~ff/kortina- essays?d=yIl2AUoC8zA)](http://feeds.feedburner.com/~ff/kortina- essays?a=o2hn6f5JGDQ:skeQbrLiUSU:yIl2AUoC8zA) [![](http://feeds.feedburner.com/~ff/kortina- essays?i=o2hn6f5JGDQ:skeQbrLiUSU:D7DqB2pKExk)](http://feeds.feedburner.com/~ff /kortina-essays?a=o2hn6f5JGDQ:skeQbrLiUSU:D7DqB2pKExk) [![](http://feeds.feedburner.com/~ff/kortina- essays?d=qj6IDK7rITs)](http://feeds.feedburner.com/~ff/kortina- essays?a=o2hn6f5JGDQ:skeQbrLiUSU:qj6IDK7rITs) [![](http://feeds.feedburner.com/~ff/kortina- essays?i=o2hn6f5JGDQ:skeQbrLiUSU:gIN9vFwOqvQ)](http://feeds.feedburner.com/~ff /kortina-essays?a=o2hn6f5JGDQ:skeQbrLiUSU:gIN9vFwOqvQ) [![](http://feeds.feedburner.com/~ff/kortina- essays?d=7Q72WNTAKBA)](http://feeds.feedburner.com/~ff/kortina- essays?a=o2hn6f5JGDQ:skeQbrLiUSU:7Q72WNTAKBA) [![](http://feeds.feedburner.com/~ff/kortina- essays?d=c-S6u7MTCTE)](http://feeds.feedburner.com/~ff/kortina- essays?a=o2hn6f5JGDQ:skeQbrLiUSU:c-S6u7MTCTE)

Wordpress Plugin: Displaying your Google Reader RSS subscriptions

I've been meaning to write this code for a while, and I really wanted to take a stab at writing a wordpress plugin so here it goes.

The following takes in Google user credentials, and allows the user to display what RSS feeds they subscribe to on their wordpress blog

Example: The RSS that I read
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<br />';
    $stop = true;
   }
   if ($this->pass == '' || $this->pass == null) {
    echo 'Google password not set<br />';
    $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 <a href="http://wordpress.org/extend/plugins/zend-framework/" target="_blank">Zend Framework Plugin</a> 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
   ?>
   <p>Tags:
    < ?
    $endKey = end(array_keys($hashmap));
    foreach ($hashmap as $cat=>$t) {
     echo "<a href='#$cat'>$cat</a>";
     if ($cat != $endKey) {
      echo ', ';
     }
    }
    ?>
   </p>< ?

   foreach ($hashmap as $cat=>$t) {
    echo "<a name='$cat'></a>";
    echo "<b>$cat</b><br />";    
    foreach ($t as $e) {
     list($feed, $url) = split('feed/', $e->string[0]);
     $title = $e->string[1];

     echo "<a href='$url' target='_blank'>$title</a><br />";

    }
    echo '<br />';
   }
  }

  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 '<div class="updated"><p><strong>' .  _e('Settings Updated.', 'GoogleReaderSubList'). '</strong></p></div>';

   }
   //$submit = _e('Update Settings', 'GoogleReaderSubList');

   echo "<div class='wrap'>    <form method='post' action='" . $_SERVER['REQUEST_URI'] . "'>     <h2>Google Reader Subscription List</h2>     <h3>Google Login</h3>     <input type='text' name='greader_sub_list_login' value='";
   echo _e(apply_filters('format_to_edit', $options['google_login']), 'GoogleReaderSubList');
   echo "' />
     <h3>Google Password</h3>     <input type='password' name='greader_sub_list_pass' value='";
   echo _e(apply_filters('format_to_edit', $options['google_pass']), 'GoogleReaderSubList');
   echo "' />
     <div class='submit'>      <input type='submit' name='update_greader_sub_list_settings' value='";
   echo _e('Update Settings', 'GoogleReaderSubList');
   echo "'/>
     </div>    </form>   </div>";
  }
}
}

if (class_exists('GoogleReaderSubList')) {
$greader_sub_list = new GoogleReaderSubList();
}

if (!function_exists('greader_sub_list_ap')) {
function greader_sub_list_ap() {
  global $greader_sub_list;
  if (!isset($greader_sub_list)) {
   return;
  }
  if (function_exists('add_options_page')) {
   add_options_page('gReader Subscriptions', 'gReader Subscriptions', 9, basename(__FILE__), array(&$greader_sub_list, 'printAdminPage'));
  }
}
}

if (isset($greader_sub_list)) {
add_action('admin_menu', 'greader_sub_list_ap');
add_action('activate_google-raeder-list/google-reader-list.php', array(&$greader_sub_list, 'init'));
add_filter('the_content', array(&$greader_sub_list, 'addContent'), '7');
}

Google Reader gets a facelift

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.

Blogger adds bloggroll

[Blogger](http://buzz.blogger.com/2008/04/blog-list-scheduled-post-publishing- on.html) 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

<a href='http://maybe-not.net/' target='_blank'>Maybe-Not</a>

A better link, for example from a wordpress blogroll would look something like

<a href="http://maybe-not.net/" rel="friend sweetheart" title="Laura&#8217;s blog">Maybe-Not</a>< 

...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.

Google Reader stats out of Wack

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.

Displaying what you read from Google Reader

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

<object>
    <string name="id">feed/http://www.ubuntu.com/rss.xml</string>
    <string name="title">Ubuntu</string>
    <list name="categories">

        <object>
            <string name="id">user/16162999404522159936/label/dev</string>
            <string name="label">dev</string>
        </object>
    </list>
    <number name="firstitemmsec">1186137757794</number>
</object>
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:


### My Reading {% for item in feeds.items %} {{ item.0 }} {% for feed in item.1 %} [{{ feed.name }}]({{ feed.link }}) {% endfor %} {% endfor %}

Again, too see what I subscribe to, click here

Google Reader adds Search Box!!

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

Check out Google Blog Search for more blog searching.

HOWTO: Google Reader API Functions

I've been wanting an API for Google reader since I started using it, and especially since i started gPowered so I could display a list of the feeds I read on the site. The official word on an API for reader is "It's coming in a few weeks," but that was back in late 2005. The reason being that at the time, the URLs the API would use were going to change a lot. So, after a bit of research and coding I came up with some python functions to do the job.

The first step was authenticating against Google accounts without using the client library. The Python Gdata Library makes login very easy but Reader isn't part of the Client Library yet (maybe I'll try to add it, we'll see...) but this was the method I was using for gdata and python pre-Client Library, and the principles still hold true for working with Reader. Thankfully, most of the research for working with the 'Reader API' was done for me already by Niall Kennedy. This is an unofficial, unsupported API and the URLs for some of the queries have changed since the writing of that article. Here we go...

We're going to use urllib(2) to handle the communication with this one. I rather would have used httplib, but I was having trouble with the authentication cookie. Each retrieval has its own URL to query against

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'
reading_url = reader_url + '/atom/user/-/state/com.google/reading-list'
read_items_url = reader_url + '/atom/user/-/state/com.google/read'
reading_tag_url = reader_url + '/atom/user/-/label/%s'
starred_url = reader_url + '/atom/user/-/state/com.google/starred'
subscription_url = reader_url + '/api/0/subscription/edit'
get_feed_url = reader_url + '/atom/feed/'

When we authenticate against Google Reader with a gmail account and password in the browser, a cookie is stored. We'll have to recreate the values in this cookie. The static values are the Domain (.google.com), the Path (/), and Expires (we'll use 160000000000). The unique value, based on the current login session, is the SID (Session ID?), which we will need to retrieve. We'll do the login and retrieval in the same function:

#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)

We'll also need a function that can handle any of those URLs, create the header, attach a cookie to it, and retrieve the data from Google. I left the return as a raw data string so you could use whatever XML parsing library you want. I personally like using [ElementTree](http://effbot.org/zone/element- index.htm).

#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

    request = urllib2.Request(url, None, header)

    try :
        f = urllib2.urlopen( request )
        result = f.read()

    except:
        print 'Error getting data from %s' % url

    return result

The following methods are the calls that I've gotten working so far; I'm going to keep working on the 'edit' functions, like adding, removing feeds, changing tags, etc. See the comments for what they do. Note: Any edit against the API needs to send over a changing token as part of the call

#get a token, this is needed for modifying to reader
def get_token(SID):
    return get_results(SID, token_url)

#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 list of the users subscribed feeds
def get_subscription_list(SID):
    return get_results(SID, subscription_list_url)

#get a feed of the users unread items
def get_reading_list(SID):
    return get_results(SID, reading_url)

#get a feed of the users read items
def get_read_items(SID):
    return get_results(SID, read_items_url)

#get a feed of the users unread items of a given tag
def get_reading_tag_list(SID, tag):
        tagged_url = reading_tag_url % tag
        return get_results(SID, tagged_url.encode('utf-8'))

#get a feed of a users starred items/feeds
def get_starred(SID):
    return get_results(SID, starred_url)

#subscribe of unsubscribe to a feed
def modify_subscription(SID, what, do):
    url = subscription_url + '?client=client:%s&ac;=%s&s;=%s&token;=%s' % ( login, do.encode('utf-8'), 'feed%2F' + what.encode('utf-8'), get_token(SID) )
    print url
    return get_results(SID, url)

#subscribe to a feed
def subscribe_to(SID, url):
    return modify_subscription(SID, url, 'subscribe')

#unsubscribe to a feed
def unsubscribe_from(SID, url):
    return modify_subscription(SID, url, 'unsubscribe')

Example usage:

SID = get_SID()
print get_subscription_list(SID)
#print get_reading_list(SID)
#print get_read_items(SID)
#print get_reading_tag_list(SID, 'me')
#print get_reading_tag_list(SID, 'nada-mas')
#print get_starred(SID)
#print get_token(SID)

#test_feed = 'http://picasaweb.google.com/data/feed/base/user/timothy.broder/albumid/5101347429735335089?kind=photo&alt;=rss&hl;=en_US'

#print subscribe_to(SID, test_feed)
#returns ok but I don't see the feed in reader?

#print get_feed(SID, test_feed)

Like I said, I'd like to keep going with this and get the edit functionality to work better. I'm also going to take a look into the Client Library and see if I could set this up as a patch that people could use if they wanted to use the API.

View Google Groups posts in Reader

I don't know why I never noticed this before but you can subscribe to the mail sent to Google Groups through an RSS feed at the bottom of each group. I'm trying it out for a few groups, I might like it better then reading through the mail. I wonder if there is a way to subscribe to the rolled up versions of the posts...