Retrieving a document's content URL in Java


If you have a published document, its contents can be viewed by fetching the DocumentListEntry object's <content> src URL:
List<DocumentListEntry> entries = resultFeed.getEntries();
for (DocumentListEntry entry : entries) {
  MediaContent content = (MediaContent)entry.getContent();
  System.out.println("View '" + entry.getTitle().getPlainText() + "' at " + content.getUri());        
}

Geo-Tagging a Picasa Photo in PHP


Assuming that $gp is a Zend_Gdata_Photos object, this will tag the $photoEntry with the specified latitude and longitude. (Note you still have to insert or update the $photoEntry.)
$gp->registerPackage('Zend_Gdata_Geo');
$gp->registerPackage('Zend_Gdata_Geo_Extension');
$where = $gp->newGeoRssWhere();
$position = $gp->newGmlPos('37.0 -122.0');
$where->point = $gp->newGmlPoint($position);
$photoEntry->setGeoRssWhere($where);

Constructing unsupported XML elements using the PHP client library


When a new XML element is introduced, client library support needs to be added. At times, the services move a bit faster than the client libraries. This means that (as per the AtomPub spec) clients must store all unknown elements returned from the server. Clients may also wish to be able to use new functionality which isn't explicitly supported yet in the libraries, so clients can allow you to create arbitrary XML elements and attach them to entries.

The PHP client library accomplishes this using extension elements, represented as instances of Zend_Gdata_App_Extension_Element. Each time the server returns an element that is unknown to the client library, the client creates an instance of that class and stores it in the extensionElements array of the class representing the parent element. In order to send arbitrary XML, you can also construct a new Zend_Gdata_App_Extension_Element and place it in the extensionElements array.

As an example, Google Base added a publishing priority option, specified by adding a <gm:publishing_priority> element. At the time of this post, the element isn't supported by a class in the PHP client library, so here's how you can add it.

<?php
require_once 'Zend/Gdata/Gbase.php';
require_once 'Zend/Gdata/App/Extension/Element.php';

$base = new Zend_Gdata_Gbase();
$entry = $base->newItemEntry();

// Constructing a Zend_Gdata_App_Extension_Control
$control = $base->newControl(); 

// Constructing the extension element, and placing it into the array
// of extension owned by the class representing the parent app:control element.
// Arguments: 
//   element name (including prefix)
//   namespace prefix
//   namespace URI
//   text node of the new element
$control->extensionElements = array(
  new Zend_Gdata_App_Extension_Element('gm:publishing_priority', 'gm', 'http://base.google.com/ns-metadata/1.0', 'high')
);
$entry->control = $control;

Of course, if you discover missing elements, please feel free to file an issue in the Zend Framework issue tracker and, since it's open source, you can also contribute a fix back to the project. More information on contributing can be found on the Zend Framework wiki.

Using the JavaScript Client Library w/ non-supported Services


The JavaScript client library has helper methods for Calendar, Contacts, Blogger, and Google Finance. However, you can use it with just about any Google Data API to access authenticated/private feeds. This example uses the DocList API.
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load('gdata', '1.x');
google.setOnLoadCallback(initialize);

function initialize() {
  var scope = 'http://docs.google.com/feeds/';
  if (google.accounts.user.checkLogin(scope)) {   
    var service = new google.gdata.client.GoogleService('writely', 'DocList-App-v1.0'); 
    service.getFeed(scope + 'documents/private/full/', handleFeed, handleError);
  } else {
    var token = google.accounts.user.login(scope); // can ignore returned token
  }
};

var handleFeed = function(response) {
  var entries = response.feed.entry;
  if (!entries.length) {
    alert('You have no entries!');
    return;
  }
  var html = [];
  for (var i = 0, entry; entry = entries[i]; i++) {
    var title = entry.title.$t;
    html.push('<li>' + title + '</li>');
  }
  document.getElementById('data').innerHTML = html.join('');
};

var handleError = function(e) {
  alert('Error: ' + e.cause ? e.cause.statusText : e.message);
};
</script>

<div id="data"><!-- dynamically filled --></div>

2 Legged OAuth in Python


Google Apps Premier/Education administrators can take advantage of 2 legged OAuth to communicate with the Google Data APIs. If you're using the Google Data Python client library 1.2.3+: An updated sample is here available here. Otherwise, if you're stuck with an older version of the library (< 1.2.3), you can use the Python OAuth library from oauth.net.
import urllib
import oauth
import gdata.contacts
import gdata.contacts.service

CONSUMER_KEY = 'yourdomain.com'
CONSUMER_SECRET = 'YOUR_CONSUMER_SECRET'
CONTACTS_URL = 'http://www.google.com/m8/feeds/contacts/default/full'

# Setup 2 legged OAuth consumer based on our admin "credentials"
consumer = oauth.OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET)

user = 'any.user@yourdomain.com'
params = {'max-results': 50, 'xoauth_requestor_id': user}

# Construct the request manually and sign it using HMAC-SHA1
# Note: The params dictionary needs to be passed in separately from the base URL
request = oauth.OAuthRequest.from_consumer_and_token(
   consumer, http_method='GET', http_url=CONTACTS_URL, parameters=params)
request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None)

# See patch @ http://code.google.com/p/oauth/issues/detail?id=31
headers = request.to_header()

client = gdata.contacts.service.ContactsService()

# Query the user's contacts and print their name & email
uri = '%s?%s' % (request.http_url, urllib.urlencode(params))
feed = client.GetFeed(uri, extra_headers=headers, converter=gdata.contacts.ContactsFeedFromString)
for entry in feed.entry:
 print '%s, %s' % (entry.title.text, entry.email[0].address)

Paging Through Feeds in Python


If you have a feed object you use

feed.GetNextLink().href

to find the URL of the next page of results. Then you can use that to query for more like so:

nextPageFeed = service.Query(feed.GetNextLink().href) 

Dealing with YouTube videos that you can't embed


If you are using the YouTube Player APIs you will notice that some videos will refuse to load on your site. This is because the owner of that video has requested that embedding be disabled. You can tell on the video watch page because it will say "Embedding disabled by request" in place of the standard embed code:

http://www.youtube.com/watch?v=juPxfHO50oo

If you are retrieving videos to display using the Data API you should use the format parameter set to 5 in order to filter out non-embeddable videos:

http://gdata.youtube.com/feeds/api/videos?v=2&format=5

The Data API also has the <yt:noembed> tag included in the video entry when the video cannot be embedded. A video entry can be retrieved using:

http://gdata.youtube.com/feeds/api/videos/VIDEO_ID

If you are using the Player JavaScript or AS2 API you should also handle the onError event.