google-apps-scriptgoogle-photosgoogle-photos-api

Google photos api adding photos not working, upload seems to work


Trying to use Google Apps Script and Google Photos API to add photos to Google Photos. Upload seems to work / returns a token, but then adding the photo to the library fails. The process consists of two steps: 1. Upload the photo data as described here, then 2. Add the photo to photo library as described here.

Step 1. works for me, as I get an upload token, but step 2 with source code below, throws an error, but my call has the one media item it needs.

{
  "error": {
    "code": 400,
    "message": "Request must have at least one newMediaItem.",
    "status": "INVALID_ARGUMENT"
  }
}

My code after the upload step below. I have tried to stringify request body and have passed it to payload instead of body, but nothing worked. As the error seems specific enough, I've the feeling I'm just overlooking a tiny thing, but what??? Who has a working piece of code, preferably in apps script that I can have a look at?

    requestHeader = {
      "authorization": "Bearer " + photos.getAccessToken(),
      "Content-Type": "application/json"
    }

    var requestBody = {
      "newMediaItems": [
        {
          "description": "Photo description",
          "simpleMediaItem": {
            "fileName": fileName,
            "uploadToken": uploadToken
          }
        }
      ]
    }

    var options = {
      "muteHttpExceptions": true,
      "method" : "post",
      "headers": requestHeader,
      "body" : requestBody
    };


      var response = UrlFetchApp.fetch("https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate", options);

      Logger.log("raw: " + response);

Solution

  • If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.

    Usage:

    1. Linking Cloud Platform Project to Google Apps Script Project:

    About this, you can see the detail flow at here.

    2. Add scope:

    In this case, please addt the scope of https://www.googleapis.com/auth/photoslibrary to the manifest file (appsscript.json).

    Although I think that from your question, above step 1 and 2 have already been done, I added them because I thought that this might be useful for other users.

    3. Sample script:

    In your script, I cannot see the detail of uploadToken. But in your question, I could confirm that you have alredy retrieved the value of uploadToken. So when you want to use your script for retrieving uploadToken, please replace uploadToken to yours. As the modification point of your script, 1. Include the album ID. 2. There is no body property of UrlFetchApp. 3. Please use JSON.stringify() to the payload.

    function getUplaodToken_(imagefileId) {
      var headers = {
        "Authorization": "Bearer " + ScriptApp.getOAuthToken(),
        "X-Goog-Upload-File-Name": "sampleFilename",
        "X-Goog-Upload-Protocol": "raw",
      };
      var options = {
        method: "post",
        headers: headers,
        contentType: "application/octet-stream",
        payload: DriveApp.getFileById(imagefileId).getBlob()
      };
      var res = UrlFetchApp.fetch("https://photoslibrary.googleapis.com/v1/uploads", options);
      return res.getContentText()
    }
    
    // Please run this.
    function myFunction() {
      var imagefileId = "###";  // Please set the file ID of the image file.
      var albumId = "###";  // Please set the album ID.
      var uploadToken = getUplaodToken_(imagefileId);
    
      var requestHeader = {Authorization: "Bearer " + ScriptApp.getOAuthToken()};
      var requestBody = {
        "albumId": albumId,
        "newMediaItems": [{
          "description": "Photo description",
          "simpleMediaItem": {
          "fileName": "sampleName",
          "uploadToken": uploadToken
        }}]
      };
      var options = {
        "muteHttpExceptions": true,
        "method" : "post",
        "headers": requestHeader,
        "contentType": "application/json",
        "payload" : JSON.stringify(requestBody)
      };
      var response = UrlFetchApp.fetch("https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate", options);
      Logger.log(response);
    }
    

    Note:

    References:

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