Picasa Web Albums allows client applications to view and update albums, photos, and comments in the form of Google Data API feeds. Your client application can use the Picasa Web Albums Data API to create new albums, upload photos, add comments, edit or delete existing albums, photos, and comments, and query for items that match particular criteria.
In addition to providing some background on the capabilities of the Picasa Web Albums Data API, this guide provides examples for interacting with the API using the Python Google Data APIs Client Library. For help setting up the client library, see the Getting Started Guide.
If you're interested in understanding more about the underlying protocol used by the Python client library to interact with the Picasa Web Albums API, please see the protocol guide.
This document is intended for programmers who want to write client applications using the Google Data APIs Python client library that can interact with Picasa Web Albums.
Picasa Web Albums uses Google Accounts for authentication, so if you have a Google account you are all set. Otherwise, you can create a new account.
For help setting up the client library, see the Getting Started Guide. To use the Python client library, you'll need Python 2.2 or higher and the modules for Element Tree (which are included in Python 2.5 and higher). After downloading the client library, you will need to install the gdata and atom packages or copy them to your working directory so that they can be found by the interpreter when the modules are imported.
To run the examples in this document, you'll need the following import statements:
import gdata.photos.service import gdata.media import gdata.geo
The PhotosService class represents a client connection (with authentication) to the Picasa Web Albums web service.
The Python client library can be used to work with either public or private feeds. Public feeds are read-only, but do not require any authentication. Private feeds require that you authenticate to the Picasa Web Albums servers. This can be done via ClientLogin username/password authentication or AuthSub proxy authentication.
Please see the Google Data APIs authentication documentation for more information on AuthSub and ClientLogin.
To use ClientLogin (also called "Authentication for Installed Applications"), invoke the ProgrammaticLogin method of PhotosService, specifying the ID and password of the user on whose behalf your client is sending the query. For example:
gd_client = gdata.photos.service.PhotosService() gd_client.email = email gd_client.password = password gd_client.source = 'exampleCo-exampleApp-1' gd_client.ProgrammaticLogin()
Once the ClientLogin token has been received, it will be used to authenticate each request made using this service object.
Note that the service name for the Picasa Web Albums API is "lh2".
For more information about Google's authentication systems, see the Google Account Authentication documentation.
AuthSub proxy authentication is used by web applications which need to authenticate their users to Google accounts. The operator does not need access to the username and password for the user - only special AuthSub tokens are required.
When the user first visits your application, they have not yet been authenticated. In this case, you need to print some text and and a link directing the user to Google to authenticate your request for access to their photos. The Python Google Data APIs client library provides a function to generate this URL. The code below sets up a link to the AuthSubRequest page.
def GetAuthSubUrl(): next = 'http://www.example.com/welcome.pyc' scope = 'http://picasaweb.google.com/data/' secure = False session = True gd_client = gdata.photos.service.PhotosService() return gd_client.GenerateAuthSubURL(next, scope, secure, session); authSubUrl = GetAuthSubUrl(); print '<a href="%s">Login to your Google account</a>' % authSubUrl
Notice the parameters sent to the GenerateAuthSubURL method:
The URL looks something like this:
https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fpicasaweb.google.com%2Fdata%2F&session=1&secure=0&next=http%3A%2F%2Fwww.example.com%2Fwelcome.pyc
The user can then follow the link to Google's site and authenticate to their Google account.
After the user authenticates, they will be redirected back to the next URL. The URL will have a single-use token value appended to it as a query parameter. The URL looks something like this:
http://www.example.com/welcome.pyc?token=14a87fe98219731acd516
For security, this token is single-use only, so now you need to exchange this single-use token for a session token. This process is described in the AuthSub documentation. The following code snippet shows how to upgrade the token.
gd_client = gdata.photos.service.PhotosService() gd_client.auth_token = authsub_token gd_client.UpgradeToSessionToken()
In this snippet, the authsub_token variable contains the value from the token query parameter in the URL. There are several ways to retrieve this value, for example:
import cgi parameters = cgi.FieldStorage() authsub_token = parameters['token']
This token value represents a single-use AuthSub token. Since session = True was specified above, this token can be exchanged for an AuthSub session token using the UpgradeToSessionToken method, which calls the AuthSubSessionToken service.
Albums are the way Picasa Web Albums groups photos into useful sets. These albums can be public or unlisted, and have their own properties such as a geographic location, a description, or a date.
You do not have to authenticate to retrieve data about public albums, but in order to create, update, or delete content you must authenticate using one of the methods discussed in the authentication section.
You can retrieve all of a user's albums by using the GetUserFeed method.
If you do not specify a username, the string 'default' will be used and the server will use the username of the user whose credentials were used to create the auth token used in the request.
albums = gd_client.GetUserFeed(user=username)
for album in albums.entry:
print 'title: %s, number of photos: %s, id: %s' % (album.title.text,
album.numphotos.text, album.gphoto_id.text)
The above code retrieves all of the user's albums and prints out a list of them. It also prints the number of photos inside of each album, and the album's unique identifier.
The unique identifier is important, as it allows you to identify the album in future requests.
Albums can also be created using the API. If you want to create a new album for the authenticated user, then you can use the following:
album = gd_client.InsertAlbum(title='New album', summary='This is an album')
This code will create a new album named "New album" with the description of "This is an album."
Once an album entry is retrieved, it can be easily modified using the Put method.
album.title.text = 'new album title';
updated_album = gd_client.Put(album, album.GetEditLink().href,
converter=gdata.photos.AlbumEntryFromString)
Retrieved entries can also be deleted using the Delete method.
gd_client.Delete(album)
When uploading, modifying, or removing photos, you will have to authenticate using one of the methods discussed in the Authentication section.
There are different ways to retrieve photos. The most common is to get a list of all of the photos in an album, but you can also retrieve recent photos from a user, or search photos from the public albums of other users.
This is the basic query to retrieve all of the photos belonging to username in the albumname album. The title of each photo is then printed out to the console.
You may use the string 'default' for the username instead of a user's email address. When 'default' is used, the server will use the username of the user who is authenticated in the request. This code assumes that 'album' is an entry that represents an album, as shown previously.
photos = gd_client.GetFeed(
'/data/feed/api/user/%s/albumid/%s?kind=photo' % (
username, album.gphoto_id.text))
for photo in photos.entry:
print 'Photo title:', photo.title.text
It is also possible to retrieve the photos associated with a user, but without specifying any particular album. The following example retrieves the last 10 photos uploaded by username and prints their titles.
photos = gd_client.GetUserFeed(kind='photo', limit='10') for photo in photos.entry: print 'Recently added photo title:', photo.title.text
With the API, you can search photos uploaded by other users, as long as they are in a public album. The following code retrieves 10 photos matching a search for 'puppy' and prints out their titles.
photos = gd_client.SearchCommunityPhotos('puppy', limit='10')
for photo in photos.entry:
print 'Community photo title:', photo.title.text
In previous examples, only the title of a photo was printed out. However, there is a lot of different data that can be retrieved about a photo such as Exif information, thumbnail URLs, the ID of the album it is a part of, and more.
print 'AlbumID:', photo.albumid.text print 'PhotoID:', photo.gphoto_id.text if photo.exif.make and photo.exif.model: camera = '%s %s' % (photo.exif.make.text, photo.exif.model.text) else: camera = 'unknown' print 'Camera:', camera print 'Content URL:', photo.content.src print 'First Thumbnail:', photo.media.thumbnail[0].url
The above example prints out different pieces of information from a PhotoEntry. The thumbnail and image URLs are taken from the MediaRSS elements inside of the entry. The camera data, if available, is found inside of the Exif namespace.
You can upload a photo to Picasa Web Albums using the InsertPhotoSimple method of the PhotosService object. The following demonstrates an example with a few assumptions: username is the name of the user who owns the album and that we have authenticated as (you can also use 'default'), album is an album object that represents the album to upload the photo to, filename is the path to the file on the local disk, gd_client is an authenticated PhotosService object, and 'image/jpeg' is the valid MIME type of the file to be uploaded.
album_url = '/data/feed/api/user/%s/albumid/%s' % (username, album.gphoto_id.text)
photo = gd_client.InsertPhotoSimple(album_url, 'New Photo',
'Uploaded using the API', filename, content_type='image/jpeg')
Notice that you did not specify tags or any other sort of meta-data about the photo when it was uploaded. To do this, you can either use InsertPhoto and pass in a PhotoEntry or you can add the meta-data after the photo has been created by update the entry you received back from the server, which leads into the Update a photo section. A call to InsertPhoto might look something like this:
photo = gd_client.InsertPhoto(album_url, new_entry, filename,
content_type='image/jpeg')
For an example of how metadata can be added to the new_entry, see the next section describing how to Update a photo.
If you want to post a photo, but don't want the hassle of requiring the user of your app to choose an album, you can post the photo to the 'Drop Box.' This special album will automatically be created the first time it is used to store a photo. To post to the 'Drop Box,' use an albumid value of 'default'. In the Python client library, your code would look like:
photo = gd_client.InsertPhotoSimple(
'/data/feed/api/user/default/albumid/default', 'New Photo',
'Uploaded using the API', filename, content_type='image/jpeg')
Usually, you want to set up some meta-data when you are uploading photos. This example will give the photo a title, a caption, some tags, and geographic location. Notice that we are adding three tags (foo, bar, and baz) all at the same time using the <media:keywords> element.
photo.title.text = 'edited title'
photo.summary.text = 'edited summary'
if not photo.media:
photo.media = gdata.media.Group()
if not photo.media.keywords:
photo.media.keywords = gdata.media.Keywords()
photo.media.keywords.text = 'foo, bar, baz'
if not photo.geo:
photo.geo = gdata.geo.Where()
if not photo.geo.Point:
photo.geo.Point = gdata.geo.Point()
photo.geo.Point.pos = gdata.geo.Pos(text='%s %s' % ('45', '-45'))
updated_entry = gd_client.UpdatePhotoMetadata(entry)
Deleting a photo is done by using the Delete method.
gd_client.Delete(photo)
Tags are a convenient way to label and organize your photos. By associating photos with descriptive strings, it makes searching through large quantities of photos easier.
Your program can retrieve a list of tags that are used by a user, in a particular album, or that are associated with a particular photo.
The following code will print out all of the tags that username has used in photos in their albums.
The string 'default' can be used in place of a real username, in which case the server will use the username of the user credentials used to authenticate the request.
tags = gd_client.GetFeed('/data/feed/api/user/%s?kind=tag' % username)
for tag in tags.entry:
print 'Tag', tag.title.text
The following code will print out all of the tags that username has tagged photos with in the album album.
tags = gd_client.GetFeed('/data/feed/api/user/%s/albumid/%s?kind=tag' % (username, album.gphoto_id.text))
for tag in tags.entry:
print 'Tag', tag.title.text
The following code will print out all of the tags that username has tagged the photo photo with in the album album. See the Accessing photo information section for information on obtaining a reference to a photo.
tags = gd_client.GetFeed('/data/feed/api/user/%s/albumid/%s/photoid/%s?kind=tag' % (username, album.gphoto_id.text, photo.gphoto_id.text))
for entry in feed.entry:
print 'Tag', entry.title.text
Note that this same information is available inside of the <media:keywords> element of the photo itself in a comma separated format.
The following code uses the tag parameter to search for all photos belonging to username that are tagged with both "foo" and "bar".
photos = gd_client.GetTaggedPhotos('foo,bar', user=username)
for photo in photos.entry:
print 'Title of tagged photo:', photo.title.text
Note you could search for photos in a particular album by using GetFeed with a URL that looks like this: '/data/feed/api/user/%s/albumid/%s?kind=photo&tag=%s' % (username, album.gphoto_id.text, tag.lower()).
The following code adds the tag "foo" to the photo, in the album which is owned by username.
url = '/data/feed/api/user/%s/albumid/%s/photoid/%s' % (username, album.gphoto_id.text, photo.gphoto_id.text) tag = gd_client.InsertTag(url, 'foo')
Note that this can also be done in bulk as described in the Update a photo section using the <media:keywords> element.
Deleting a tag is done by using the Delete method.
gd_client.Delete(tag)
Comments are short text snippets attached to photos by Picasa Web Albums users.
The following example prints out the 10 most recent comments on a username's photos.
The string 'default' can be used in place of a real username, in which case the server will use the username of the user credentials used to authenticate the request.
comments = gd_client.GetFeed('/data/feed/api/user/%s?kind=comment&max-results=10' % username)
for comment in comments.entry:
print 'Comment', comment.content.text
You can also retrieve all of the comments associated with a particular photo. The following example prints out all of the comments on the photo identified by photo, inside of the album album, owned by the username user.
comments = gd_client.GetFeed(
'/data/feed/api/user/%s/albumid/%s/photoid/%s?kind=comment&max-results=10' % (
username, album.gphoto_id.text, photo.gphoto_id.text))
for comment in comments.entry:
print 'Comment', comment.content.text
The following code adds the comment "great photo!" to the photo identified by photo in the album owned by username.
url = '/data/feed/api/user/%s/albumid/%s/photoid/%s' % (username, album.gphoto_id.text, photo.gphoto_id.text) comment = gd_client.InsertComment(url, 'great photo!')
Deleting a comment is done by using the Delete method.
gd_client.Delete(comment)
This complete example code demonstrates retrieving all the albums for the currently authenticated user, iterating through the photos in each album, displaying the photo's title, and any associated tags and comments.
#!/usr/bin/python2.5
import gdata.photos.service
import gdata.media
import gdata.geo
gd_client = gdata.photos.service.PhotosService()
gd_client.email = '=change=' # Set your Picasaweb e-mail address...
gd_client.password = '=change=' # ... and password
gd_client.source = 'api-sample-google-com'
gd_client.ProgrammaticLogin()
albums = gd_client.GetUserFeed()
for album in albums.entry:
print 'Album: %s (%s)' % (album.title.text, album.numphotos.text)
photos = gd_client.GetFeed('/data/feed/api/user/default/albumid/%s?kind=photo' % (album.gphoto_id.text))
for photo in photos.entry:
print ' Photo:', photo.title.text
tags = gd_client.GetFeed('/data/feed/api/user/default/albumid/%s/photoid/%s?kind=tag' % (album.gphoto_id.text, photo.gphoto_id.text))
for tag in tags.entry:
print ' Tag:', tag.title.text
comments = gd_client.GetFeed('/data/feed/api/user/default/albumid/%s/photoid/%s?kind=comment' % (album.gphoto_id.text, photo.gphoto_id.text))
for comment in comments.entry:
print ' Comment:', comment.content.text