6

I have many albums in Google Photos. (Maybe 200). I want to get a list of these albums along with their urls. How can I do this?

To put it in context, I want to send an email listing many of these albums to friends. As a workaround I can, in principle, click into each album in the Google Photos web interface. Then click "More options" then click "Sharing options" then click "COPY". Then I can paste this url somewhere. But that's an absolute best case of 5 or 6 clicks times 200. It's probably much higher.

Surely there is an API I can use in a hacky one-time sort of way to get a list of all of my albums. No? It seems like this should be simple. Can someone point me to the documentation that I'm not finding? I don't even see where in the world of Google to ask this question. I have found a similar question, but it's unanswered. It seems that today (2016-03-05) the Picasa Web Albums Data API is probably what I need. But I'm not sure.

My ideal solution is probably to have a simple script in a Google Sheet to grab a list of all Albums: Names in one column and public url (if it exists) in another column. But I'll settle for ANY way of getting a list of all my albums with their urls.

UPDATE: Sally, raised the possibility of screen scraping to get the answer. I love this idea! But I'm unable to use her idea, so I'm adding this angle to the question to provoke a clearer answer.

I'm able to list all of my shared albums at this url: https://photos.google.com/shared

I would like to obtain the public url for all of these albums. But the public url, which has this form: https://goo.gl/photos/Rw5gpSaD4ikadj6M9, is not found in the source code for the page. I must click into each album and then click "Share" to find the public url.

In short: obtaining the complete list of my shared albums with their public urls via API, screen scraping, or any other means would meet my requirement.

4 Answers 4

3

The Google Photos interface is very minimal even for humans, let alone applications. The best way I found to get a list of album names and URLs is to parse the page source using the browser console.

The list of all albums

Executed on the page https://photos.google.com/albums, this script returns a string that can be copy-pasted to a Google Sheet, creating a table of names and URLs.

var links = document.getElementsByTagName('A'); 
var s = ''; 
for (var i = 0; i< links.length; i++) {
  if (/\b(album|share)\b/.test(links[i].href)) {
    var albumName = links[i].children[3].children[0].innerText;
    s = s + albumName + '\t' + links[i].href + '\n';
  }
}

The list of shared albums

Executed on the page https://photos.google.com/shared, this script returns the list of album names and URLs.

var links = document.getElementsByTagName('A'); 
var s = ''; 
for (var i = 0; i< links.length; i++) {
  if (/\b(album|share)\b/.test(links[i].href)) {
    s = s + links[i].innerText + '\t' + links[i].href + '\n';
  }
}

The URLs are in the long format: https://photos.google.com/share/...?key=..., not in the short format https://goo.gl/photos/... that you would get by clicking the share button. But they are functionally equivalent: the latter redirects to the former after going through Google's URL shortening service goo.gl. If length is a concern, you can shorten them yourself within Google Sheets by using an Apps Script for generating goo.gl URLs.

3
  • I cannot see the public urls in the shared albums page. So I don't think this approach can work on that page. Is there a different page I should be using? (I can see the links into each album... but those links aren't right for the rest of the world.
    – mdahlman
    Commented Mar 6, 2016 at 17:19
  • I think those links are right for the rest of the world: see my expanded answer. If you open a "share" link in an incognito window of the browser, you'll see it directing to one of those long links that you see on the page.
    – user79865
    Commented Mar 6, 2016 at 17:59
  • Ahh... I'll test tomorrow. If the long urls are functionally equivalent, then that's certainly good enough. I'll accept after testing.
    – mdahlman
    Commented Mar 7, 2016 at 5:24
3

I found the google API can provide a list of albums and provides an online way to run the command and print results using your live data.

https://developers.google.com/photos/library/reference/rest/v1/albums/list

Set excludeNonAppCreatedData to false.

Note the next page token required for further pages (next 50 items max, 20 items listed by default), it is provided at the end of the json data of the last page you requested.

2

Here's an update (for the current state of Google Photos) to user79865's answer ...

The list of all albums

Executed on the page https://photos.google.com/albums, this script returns a string that can be copy-pasted to a Google Sheet, creating a table of names and URLs.

var links = document.getElementsByTagName('A');
var s = '';
for (var i = 0; i < links.length; i++) {
  let link = links[i];
  if (/\b\d+ items\b/.test(link.innerText)) {
    let divs = link.getElementsByTagName('DIV');
    for (var j = 0; j < divs.length; j++) {
      let div = divs[j];
      let text = div.innerText;
      if (text != "" && div.childElementCount == 0 && ! /\b\d+ items\b/.test(text)) {
        s = s + text + '\t' + link.href + '\n';
        break;
      }
    }
  }
}
s;

The list of shared albums

Executed on the page https://photos.google.com/shared, this script returns the list of album names and URLs.

var links = document.getElementsByTagName('A');
var s = '';
for (var i = 0; i < links.length; i++) {
  let link = links[i];
  if (/\bLink shared\b/.test(link.innerText)) {
    let spans = link.getElementsByTagName('SPAN');
    for (var j = 0; j < spans.length; j++) {
      let span = spans[j];
      let text = span.innerText;
      if (text != "") {
        let spanParent = span.parentElement;
        if (spanParent.hasAttribute('aria-label')) {
          parentLabel = spanParent.getAttribute('aria-label');
          if (/\bShared album$/.test(parentLabel)) {
            s = s + text + '\t' + link.href + '\n';
          }
        }
      }
    }
  }
}
s;

To get the short URL of albums, you've to do an authenticated API request, there's no other way. https://developers.google.com/photos/library/reference/rest/v1/albums/share

0

If your code is running as part of a Chrome extension, you can use the Picasa API to get the list of albums, and upload images. Not sure if it works in webpage code. (I don't think it does, because of cross-origin restrictions)

As far as I can tell, despite the name it lets you access all Google Photos albums/images, not just those created through Picasa.

async function GetAlbums(token, retriesLeft = 2) {
    var response = await fetch("https://picasaweb.google.com/data/feed/api/user/default?alt=json", {
        method: "GET",
        headers: new Headers({
            Authorization: "Bearer " + token, 
        }),
    });
    //var responseJSON = await response.json();
    let responseText = await response.text();
    try {
        var responseJSON = JSON.parse(responseText);
    } catch (ex) {
        console.error("Error converting text into JSON: " + responseText);
        throw ex;
    }

    let albums = responseJSON.feed.entry;
    for (let album of albums) {
        album.name = album.title.$t;
        album.id = album.gphoto$id.$t;
    }
    return albums;
}

async function UploadImageToAlbum(token: string, albumID: string, fileName: string, imageDataBlob: Blob, retriesLeft = 2) {
    var response = await fetch("https://picasaweb.google.com/data/feed/api/user/default/albumid/" + albumID + "?alt=json", {
        method: "POST",
        body: imageDataBlob,
        headers: new Headers({
            Authorization: "Bearer " + token,
            Slug: fileName,
        }),
    });
    //var responseJSON = await response.json();
    let responseText = await response.text();
    try {
        var responseJSON = JSON.parse(responseText);
    } catch (ex) {
        console.error("Error converting text into JSON: " + responseText);
        throw ex;
    }

    var viewLink = responseJSON.entry.link.find(a=>a.rel == "alternate");
    if (viewLink) {
        //chrome.tabs.create({url: viewLink.href});
        window.open(viewLink.href, "_blank");
    }
}

And here is an example usage: (this example must run in a background-script because of chrome.identity usage, although I think there is a webpage/client equivalent)

async function PostImageAndMessageToGooglePlus(imageDataURI: string) {
    chrome.identity.getAuthToken({interactive: true}, token=> {
        let albums = await GetAlbums(token);
        let targetAlbum = albums.find(a=>a.name == "MyAlbum");
        if (targetAlbum == null) throw new Error(`Could not find album titled "MyAlbum".`);
        console.log("Found album:" + JSON.stringify(targetAlbum));

        let imageDataBlob = dataURItoBlob(imageDataURI);
        await UploadImageToAlbum(token, targetAlbum.id, "Graph", imageDataBlob);
    });
}

function dataURItoBlob(dataURI) {
    var byteString = atob(dataURI.split(",")[1]);
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
         ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], {type: "image/png"});
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.