How to use Google Photos API Method: mediaItems.search in Google apps script for a spreadsheet

雨燕双飞 提交于 2020-11-29 09:04:27

问题


I really tried to figure this out on my own...

I am trying to load photo metadata from google photos into a sheet using the Google Photos API and google apps script.

I was able to make some progress after a lot of help on a previous question

Is it possible to load google photos metadata into google sheets?

I now have two functions.

function photoAPI_ListPhotos() - Uses Method: mediaItems.list and gives me all my photos that are not archived function photoAPI_ListAlbums() - Uses Method: albums.list and gives me all my albums

What I want to do is retrieve all photos from a specific album. Method: mediaItems.search should do this but it uses the POST protocol and the previous working examples I found only use GET. Looking at the examples available on that page, there is a javascript portion but it does not work in apps script.

The documentation for UrlFetchApp tells me how to format a POST request but not how to add the parameters for authentication.

The external APIs also is not giving me the examples I am looking for.

I feel like I'm missing some essential tiny piece of info and I hope I'm not wasting everyone's time asking it here. Just a solid example of how to use POST with oauth in apps script should get me where I need to go.

Here is my working function for listing all non-archived photos.

function photoAPI_ListPhotos() {
  /*
  This function retrieves all photos from your personal google photos account and lists each one with the Filename, Caption, Create time (formatted for Sheet), Width, Height, and URL in a new sheet.
  it will not include archived photos which can be confusing if you happen to have a large chunk of archived photos some pages may return only a next page token with no media items.

  Requires Oauth scopes. Add the below line to appsscript.json
  "oauthScopes": ["https://www.googleapis.com/auth/spreadsheets.currentonly", "https://www.googleapis.com/auth/photoslibrary", "https://www.googleapis.com/auth/photoslibrary.readonly", "https://www.googleapis.com/auth/script.external_request"]

  Also requires a standard GCP project with the appropriate Photo APIs enabled.
  https://developers.google.com/apps-script/guides/cloud-platform-projects
  */

  //Get the spreadsheet object
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  //Check for presence of target sheet, if it does not exist, create one.
  var photos_sh = ss.getSheetByName("photos") || ss.insertSheet("photos", ss.getSheets().length); 
  //Make sure the target sheet is empty
  photos_sh.clear();
  var narray = []; 

  //Build the request string. Max page size is 100. set to max for speed.
  var api = "https://photoslibrary.googleapis.com/v1/mediaItems?pageSize=100";
  var headers = { "Authorization": "Bearer " +  ScriptApp.getOAuthToken() };
  var options = { "headers": headers, "method" : "GET", "muteHttpExceptions": true };

  //This variable is used if you want to resume the scrape at some page other than the start. This is needed if you have more than 40,000 photos.
  //Uncomment the line below and add the next page token for where you want to start in the quotes.
  //var nexttoken="";

  var param= "", nexttoken;
  //Start counting how many pages have been processed.
  var pagecount=0;

  //Make the first row a title row
  var data = [
    "Filename",
    "description",
    "Create Time",
    "Width",
    "Height",
    "ID",
    "URL",
    "NextPage"
  ];
  narray.push(data);

  //Loop through JSON results until a nextPageToken is not returned indicating end of data
  do {
    //If there is a nextpagetoken, add it to the end of the request string
    if (nexttoken)
      param = "&pageToken=" + nexttoken; 

    //Get data and load it into a JSON object
    var response = UrlFetchApp.fetch(api + param, options);
    var json = JSON.parse(response.getContentText());

    //Check if there are mediaItems to process.
    if (typeof json.mediaItems === 'undefined') {
      //If there are no mediaItems, Add a blank line in the sheet with the returned nextpagetoken

      //var data = ["","","","","","","",json.nextPageToken];
      //narray.push(data);
    } else {
      //Loop through the JSON object adding desired data to the spreadsheet.
      json.mediaItems.forEach(function (MediaItem) {

        //Check if the mediaitem has a description (caption) and make that cell blank if it is not present.
        if(typeof MediaItem.description === 'undefined') {
            var description = "";
          } else {
            var description = MediaItem.description;
          }

        //Format the create date as appropriate for spreadsheets.
        var d = new Date(MediaItem.mediaMetadata.creationTime);

        var data = [
          MediaItem.filename,
          "'"+description, //The prepended apostrophe makes captions that are dates or numbers save in the sheet as a string. 
          d,
          MediaItem.mediaMetadata.width,
          MediaItem.mediaMetadata.height,
          MediaItem.id,
          MediaItem.productUrl,
          json.nextPageToken
        ];
        narray.push(data);
      });
    }

    //Get the nextPageToken
    nexttoken = json.nextPageToken;    

    pagecount++;
    //Continue if the nextPageToaken is not null
    //Also stop if you reach 400 pages processed, this prevents the script from timing out. You will need to resume manually using the nexttoken variable above.
  } while (pagecount<4 && nexttoken);

    //Continue if the nextPageToaken is not null (This is commented out as an alternative and can be used if you have a small enough collection it will not time out.)
  //} while (nexttoken);

  //Save all the data to the spreadsheet.
  photos_sh.getRange(1, 1, narray.length, narray[0].length).setValues(narray);
}

回答1:


  • You want to retrieve all photos of the specific album using Google Photo API.
  • You want to know how to use the method of mediaItems.search using Google Apps Script.
  • You have already been able to retrieve the data using Google Photo API.

If my understanding is correct, how about this sample script? Please think of this as just one of several answers.

Sample script 1:

var albumId = "###"; // Please set the album ID.

var headers = {"Authorization": "Bearer " + ScriptApp.getOAuthToken()};
var url = "https://photoslibrary.googleapis.com/v1/mediaItems:search";
var mediaItems = [];
var pageToken = "";
do {
  var params = {
    method: "post",
    headers: headers,
    contentType: "application/json",
    payload: JSON.stringify({albumId: albumId, pageSize: 100, pageToken: pageToken}),
  }
  var res = UrlFetchApp.fetch(url, params);
  var obj = JSON.parse(res.getContentText());
  Array.prototype.push.apply(mediaItems, obj.mediaItems);
  pageToken = obj.nextPageToken || "";
} while (pageToken);
Logger.log(mediaItems)
  • At the method of mediaItems.search, albumId, pageSize and pageToken are included in the payload, and the values are sent as the content type of application/json.

Sample script 2:

When your script is modified, how about the following modified script?

function photoAPI_ListPhotos() {
  var albumId = "###"; // Please set the album ID.

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var photos_sh = ss.getSheetByName("photos") || ss.insertSheet("photos", ss.getSheets().length); 
  photos_sh.clear();
  var narray = []; 
  var api = "https://photoslibrary.googleapis.com/v1/mediaItems:search";
  var headers = { "Authorization": "Bearer " +  ScriptApp.getOAuthToken() };
  var nexttoken = "";
  var pagecount = 0;
  var data = ["Filename","description","Create Time","Width","Height","ID","URL","NextPage"];
  narray.push(data);
  do {
    var options = {
      method: "post",
      headers: headers,
      contentType: "application/json",
      payload: JSON.stringify({albumId: albumId, pageSize: 100, pageToken: nexttoken}),
    }
    var response = UrlFetchApp.fetch(api, options);
    var json = JSON.parse(response.getContentText());
    if (typeof json.mediaItems === 'undefined') {
      //If there are no mediaItems, Add a blank line in the sheet with the returned nextpagetoken

      //var data = ["","","","","","","",json.nextPageToken];
      //narray.push(data);
    } else {
      json.mediaItems.forEach(function (MediaItem) {
        if(typeof MediaItem.description === 'undefined') {
            var description = "";
          } else {
            var description = MediaItem.description;
          }
        var d = new Date(MediaItem.mediaMetadata.creationTime);
        var data = [
          MediaItem.filename,
          "'"+description,
          d,
          MediaItem.mediaMetadata.width,
          MediaItem.mediaMetadata.height,
          MediaItem.id,
          MediaItem.productUrl,
          json.nextPageToken
        ];
        narray.push(data);
      });
    }
    nexttoken = json.nextPageToken || "";
    pagecount++;
  } while (pagecount<4 && nexttoken);
  photos_sh.getRange(1, 1, narray.length, narray[0].length).setValues(narray);
}

Note:

  • This script supposes as follows.
    • Google Photo API is enabed.
    • The scope of https://www.googleapis.com/auth/photoslibrary.readonly or https://www.googleapis.com/auth/photoslibrary are included in the scopes.

Reference:

  • Method: mediaItems.search

If I misunderstood your question and this was not the result you want, I apologize.



来源:https://stackoverflow.com/questions/57192192/how-to-use-google-photos-api-method-mediaitems-search-in-google-apps-script-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!