Access Google Photo API with Python using google-api-python-client

Thanks to Ido Ran's and brillb's examples, I finally got my problem solved too. Some of the documentation links given above are not valid any more. Trying to enhance above examples, I found the page Google Photos APIs most useful. It not only documents the API, but also allows you to test your requests interactively - I probably never had gotten it to work without that testing capability. After entering your request, you can see your coding example in cURL, HTTP or JAVASCRIPT - but nothing for Python.

Besides producing a list of my albums, I was also interested in

  • link to each album,
  • list of images (in albums or not),
  • link to each my media items and the URL to find them

In order to get the link to the albums, you can extend the above examples simply by retrieving item['productUrl']. However, many times the URL did not work for me in Firefox, IE nor Edge (error 404 after showing the album very briefly), but it did in Chrome and Opera (who knows why).

Much more reliable seems to be the URL of the album's cover photo: item['coverPhotoMediaItemId'] and there you'll find links to the album(s) under Info.

Instead of using the albums method, you can also access sharedAlbums (and specify results.get('sharedAlbums', []). I was hoping to be able to get the shareableUrl, but never found the ShareInfo resource as part of the results.

For the list of images, you have the choice of two methods: mediaItems.list and mediaItems.search. I don't consider the former useful since it returns a long list of all your images, while the search allows for limiting the results by the date, the picture was taken (not uploaded!). There is also a get and batchGet, I never tried because you need to know item ID given to the image by Google photos.

Each method has a limit (pageSize) for the maximum of entries to be returned. If there are more than that, it also sends a pageToken, you can use to request the next part.

I finally came up with this example:

from os.path import join, dirname
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
SCOPES = 'https://www.googleapis.com/auth/photoslibrary.readonly'

store = file.Storage(join(dirname(__file__), 'token-for-google.json'))
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets(join(dirname(__file__), 'client_id.json', SCOPES))
    creds = tools.run_flow(flow, store)
google_photos = build('photoslibrary', 'v1', http=creds.authorize(Http()))

day, month, year = ('0', '6', '2019')  # Day or month may be 0 => full month resp. year
date_filter = [{"day": day, "month": month, "year": year}]  # No leading zeroes for day an month!
nextpagetoken = 'Dummy'
while nextpagetoken != '':
    nextpagetoken = '' if nextpagetoken == 'Dummy' else nextpagetoken
    results = google_photos.mediaItems().search(
            body={"filters":  {"dateFilter": {"dates": [{"day": day, "month": month, "year": year}]}},
                  "pageSize": 10, "pageToken": nextpagetoken}).execute()
    # The default number of media items to return at a time is 25. The maximum pageSize is 100.
    items = results.get('mediaItems', [])
    nextpagetoken = results.get('nextPageToken', '')
    for item in items:
            print(f"{item['filename']} {item['mimeType']} '{item.get('description', '- -')}'"
                      f" {item['mediaMetadata']['creationTime']}\nURL: {item['productUrl']}")

I didn't find any example so I took the Drive API v3 example and adapted it to Photos v1 API.

You can see and use the example.

The gist is:

from apiclient.discovery import build

service = build('photoslibrary', 'v1', http=creds.authorize(Http()))
results = service.albums().list(
    pageSize=10, fields="nextPageToken,albums(id,title)").execute()

The API is a bit less capable than indicated in the example above, it doesn't support "fields". But it does work:

from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
SCOPES = 'https://www.googleapis.com/auth/photoslibrary.readonly'

store = file.Storage('token-for-google.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_id.json', SCOPES)
    creds = tools.run_flow(flow, store)
gdriveservice = build('photoslibrary', 'v1', http=creds.authorize(Http()))

results = gdriveservice.albums().list(
    pageSize=10).execute()
items = results.get('albums', [])
for item in items:
        print(u'{0} ({1})'.format(item['title'].encode('utf8'), item['id']))