Home>

I'm trying to create a BOT using the Twitter API from Google Apps Script, but I'm having trouble posting an image file.
We would appreciate it if you could teach us how to deal with the following errors and how to post image files.

Execution environment

■ Google Apps Script
■ Twitter API
■ Google Spreadsheet
■ Google Drive

Implementation content

The script that acquires the ID of the image file described in the Google spreadsheet and automatically tweets it on Twitter is described.
The target image file has already been uploaded to Google Drive.

Script for Twitter API authentication
// Get authentication URL
function getOAuthURL () {
  Logger.log (getService (). Authorize ());
}
// Get service
function getService () {
  return OAuth1.createService ('Twitter')
      .setAccessTokenUrl ('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl ('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl ('https://api.twitter.com/oauth/authorize')
      // Set the set authentication information
      .setConsumerKey (PropertiesService.getScriptProperties (). GetProperty ("CONSUMER_API_KEY"))
      .setConsumerSecret (PropertiesService.getScriptProperties (). GetProperty ("CONSUMER_API_SECRET"))
      .setCallbackFunction ('authCallback')
      // Set the credentials in the property store (this eliminates the need for re-authentication until deauthorized)
      .setPropertyStore (PropertiesService.getUserProperties ());
}
// Define the process to be called when authentication is successful
function authCallback (request) {
  var service = getService ();
  var authorized = service.handleCallback (request);
  if (authorized) {
    return HtmlService.createHtmlOutput ('success !!');
  } else {
    return HtmlService.createHtmlOutput ('failed');}
}
I get an error when I try to execute a function in testBot2
Spreadsheet image file, for getting tweet content
function testBot2 () {
  const activeSheet = SpreadsheetApp.getActiveSheet ();
  const lastRow = activeSheet.getLastRow ();
  for (let i = 2;i<= lastRow;i ++) {
// Check the value of the target cell with getValue ()
    // False if the cell is empty, true if the string is 1 or more
    var sell = activeSheet.getRange (i, 5);
    if (! sell.getValue ()) {
      sell.setValue (true);
      // Body and image variables
      var tweetBot = activeSheet.getRange (i, 4) .getValue ();
// Below, error cause line 1
// The file ID is listed in the spreadsheet cell (i, 3), and we are trying to get that value and store it in a variable.
      var tweetCapture = DriveApp.getFileById (activeSheet.getRange (i, 3) .getValue ());
      // Get image
// Error cause line 2
// Specify tweetCapture in the argument of UrlFetchApp.fetch below. An error occurs here
      var imgUrl = UrlFetchApp.fetch (tweetCapture) .getBlob ();
      var imgCapture = Utilities.base64Encode (imgUrl.getBytes ());
      // Passing the argument of the variable that stores the message and image file to the function for tweet
      toTweet (tweetBot, imgCapture);
      if (i>= lastRow) {
        activeSheet.getRange (2,5, lastRow --1) .clearContent ();
      }
      break;
    }
  }
}
A function that invokes the API for tweets
function toTweet (tweetBot, imgCapture) {
  var endPointStatus ='https://api.twitter.com/1.1/statuses/update.json';
  var endPointMedia ='https://upload.twitter.com/1.1/media/upload.json';
  var twitterService = getService ();
  if (twitterService.hasAccess ()) {// Post
    var twMethod = {method: "POST"};
    twMethod.payload = {status: tweetBot};
    // Twitter API is getting the file in JSON
    var img_option = {
    'method': "POST",
    'payload': {
      'media_data': imgCapture
    }
  };
    // Parse JSON and get ready for use with GAS
    var image_upload = JSON.parse (twitterService.fetch (endPointMedia, img_option));
    var sendoption = {
    'status': tweetBot,
    'media_ids': image_upload [media_id_string]
    };
    //twitterService.fetch (endPointStatus, {method:'post', payload: sendoption});
    Twitter.api ('statuses/update', sendoption);
    Logger.log (response.getContentText ());
  } else {
    Logger.log (twitterService.getLastError ());
  }
}
error contents

Exception: DNS error: http: // filename.png (line 99, file "code")

Line 99 code

// in the testBoxt2 function
var tweetCapture = DriveApp.getFileById (activeSheet.getRange (i, 3) .getValue ());
var imgUrl = UrlFetchApp.fetch (tweetCapture) .getBlob ();

It is recognized that the URL is confirmed from the ID of the target file, and the URL is incorrect, so
I think that an error has occurred.

I think that the part that should get https ~ may have an error because it is trying to get it with http.

Sorry for your inconvenience, but I don't understand how to deal with the above error, and if possible, the above Twitter API script.
We would appreciate it if you could also teach us the script for posting image files.

Nice to meet you

  • Answer # 1

    [1]
    First
    Exception: DNS error: http: // filename.png (line 99, file "code")

    Is the cause of the error,

    In the testBot2 function

    var tweetCapture = DriveApp.getFileById (activeSheet.getRange (i, 3) .getValue ());
    var imgUrl = UrlFetchApp.fetch (tweetCapture) .getBlob ();


    About the two lines ...

    DriveApp.getFileById (id) the function is,Get the file object with the file ID specified in the argumentWhile it is something to do
    UrlFetchApp.fetch (url) the function is,Download the resource of the URL specified in the argumentIt is a function that comes.
    (Reference: Google Official Manual 1 2)

    So if you put the above two lines of code together,Specify the file object obtained from the file ID in the URL and downloadBecause it has become the process, an error will occur.

    UrlFetchApp.fetch (url) Function argumentsurlYou need to specify the URL for downloading the image.

    If you refer to the contents of the answer to the questioner's python version of another question, you will understand.
    The URL for downloading files from Google Drive is

    "Https://drive.google.com/uc?export=view&id="File ID"

    Since it is in the format, you can pass the URL in this format.

    [2]
    I will post the full-text code that was organized as a whole and worked at my hand below. (Since there is no space, the procedure around authentication is omitted.)

    I personally made comments that were redundant and easy to understand. (Actually, there is a tendency that it is better to write so that you can understand it only with the code without adding comments as much as possible, but it is just for learning)

    I myself have only touched GAS for about 4-5 hours in my life, so it may be a poor code for those who are familiar with it, but I hope it will be useful for the questioner's learning.

    As a point of understanding this script, or rather Twitter specifications, what is "tweet with image"?
    ・ Upload image
    When
    ・ Posting a tweet with the uploaded image added
    It may be a little easier to see if you keep in mind that it is a combination of these two different functions.

    function getOAuthURL () {
      Logger.log (getService (). Authorize ());
    }
    // Get service
    function getService () {
      return OAuth1.createService ('Twitter')
          .setAccessTokenUrl ('https://api.twitter.com/oauth/access_token')
          .setRequestTokenUrl ('https://api.twitter.com/oauth/request_token')
          .setAuthorizationUrl ('https://api.twitter.com/oauth/authorize')
          // Set the set authentication information
          .setConsumerKey (PropertiesService.getScriptProperties (). GetProperty ("CONSUMER_API_KEY"))
          .setConsumerSecret (PropertiesService.getScriptProperties (). GetProperty ("CONSUMER_API_SECRET"))
          .setCallbackFunction ('authCallback')
          // Set the credentials in the property store (this eliminates the need for re-authentication until deauthorized)
          .setPropertyStore (PropertiesService.getUserProperties ());
    }
    // Define the process to be called when authentication is successfulfunction authCallback (request) {
      var service = getService ();
      var authorized = service.handleCallback (request);
      if (authorized) {
        return HtmlService.createHtmlOutput ('success !!');
      } else {
        return HtmlService.createHtmlOutput ('failed');
      }
    }
    function testBot2 () {
      // Get active sheet
      const activeSheet = SpreadsheetApp.getActiveSheet ();
      // Get the bottom line
      const lastRow = activeSheet.getLastRow ();
      for (let i = 2;i<= lastRow;i ++) {
        // Get the contents of the cell in the i-th row and 5th column.
        var sell = activeSheet.getRange (i, 5);
        // If the cell in row i and column 5 is empty, write True to that cell.
        if (! sell.getValue ()) {
          sell.setValue (true);
          // Get the message body from cell i row 4 column.
          var tweetBot = activeSheet.getRange (i, 4) .getValue ();
          Logger.log (tweetBot);
    // Get the image file ID from the cell in the i-th row and 3rd column.
          var fileId = activeSheet.getRange (i, 3) .getValue ();
          // Assemble the image acquisition URL from the image file ID.
          var imgUrl = "https://drive.google.com/uc?export=view&id="+ fileId;
          // Get the image data via the image acquisition URL and encode it to Base64.
          var imgBlob = UrlFetchApp.fetch (imgUrl) .getBlob ();
          var imgCapture = Utilities.base64Encode (imgBlob.getBytes ());
          Logger.log (imgCapture);
          // Pass the message body and image data to the tweet function
          toTweet (tweetBot, imgCapture);
          if (i>= lastRow) {
            activeSheet.getRange (2,5, lastRow --1) .clearContent ();
          }
          break;
        }
      }
    }
    / ***************************************************** ** **
      Function to tweet a message with an image
      argument:
       tweetBot: Message bodyimgCapture: Base64 encoded image data
    ****************************************************** ** /
    function toTweet (tweetBot, imgCapture) {
      // Endpoint for posting tweets.
      var endPointStatus ='https://api.twitter.com/1.1/statuses/update.json';
      // Endpoint for uploading images.
      var endPointMedia ='https://upload.twitter.com/1.1/media/upload.json';
      // Get the service object to operate twitter.
      var twitterService = getService ();
      // If the approval has been obtained, start the process of posting a tweet with an image.
      if (twitterService.hasAccess ()) {
        // Assemble the option for image upload.
        var img_option = {
        'method': "POST",
        'payload': {
          'media_data': imgCapture
          }
        };
        // Upload the image and parse the returned JSON (to get the media_id in the JSON)
        var image_upload = JSON.parse (twitterService.fetch (endPointMedia, img_option));
        Logger.log (image_upload);
        // Assemble options for posting tweets with images.
        var sendoption = {
          'status': tweetBot,
          'media_ids': image_upload ['media_id_string']
        };
        // Post a tweet with an image. The response is stored in the response variable.
        response = twitterService.fetch (endPointStatus, {method:'post', payload: sendoption});
        // Log the contents of the response.
        Logger.log (response.getContentText ());
      } else {
        // Record the latest error log because it has not been approved.
        Logger.log (twitterService.getLastError ());
      }
    }


    Others:
    -Variable names such as tweetBot and imgCapture may be difficult to understand.
    For example, tweet_text, img_64, etc. may be easy to understand.

    Referenced sites:
    https://developer.twitter.com/ja/docs/
    https://lookbackmargin.blog/2019/08/11/img-tweet-via-gas/
    Initial setting
    https://tech-cci.io/archives/4228

  • Answer # 2

    var imgUrl = UrlFetchApp.fetch (tweetCapture) .getBlob ();
    Please try to output LOG whether imgUrl is normal.