1
votes

I'm trying to use an Apps script in Google drive to search for image files in company shared drive. The file list is held in a spreadsheet and the script searches for and either makes a copy of the file (if it's already a jpg or a png file) or exports a png file if it's a google drawing.

This is the code I have so far...

function load_list_of_images(course_workbook) {
  var image_list_sheet = course_workbook.getSheetByName("image_list");
  // Get list of image names from spreadsheet
  var list_of_images = [];
  var images = image_list_sheet.getRange(1,1,1000).getValues();
  for (var row in images) {
    for (var col in images[row]) {
      var image = images[row][col];
      if (image == "") {
        return(list_of_images);
      }
      list_of_images.push(image);
    }
  }
}

function download_google_images() {
  var course_workbook_name = "NAME"; // Title of spreadsheet with file list
  var dst_folder_id = "FOLDER_ID"; // ID of destination folder

  // There may be more than one!
  var course_workbooks = DriveApp.getFilesByName(course_workbook_name);
  // Try to access the spreadsheet
  try{
    var course_workbook_id = course_workbooks.next();
    Logger.log("Spreadsheet ID : " + course_workbook_id);    
  } catch(error) {
    Logger.log("Spreadsheet doesn't exist... exiting...");
    return(null);
  }
  var course_workbook = SpreadsheetApp.open(course_workbook_id);
  var list = load_list_of_images(course_workbook);
  // This will hold a list of missing images
  var missing = [];
  // What if the list is empty?
  if (list == null){
    Logger.log("Errr... no images to find - check the sheet!");
    return(null);
  }
  // Set up handle to destination folder
  var dst_folder = DriveApp.getFolderById(dst_folder_id);

  // Now look for each image in the list
  for (var row in list){
    // Get the name of the image to look for
    var image_name = list[row];
    Logger.log("Looking for : " + image_name);
    // Get all the files which match this name
    // This line ONLY finds images that are owned by me
    // MOST of the images are owned by other users
    var image_exists = DriveApp.getFilesByName(image_name);
    // The list of images is empty
    if (!image_exists.hasNext()){
      Logger.log("  Can't find image : " + image_name);
      missing.push([image_name]);
    }
    // I found some images!
    else{
      while (image_exists.hasNext()){
        var image = image_exists.next()
        var drive_mime_type = image.getMimeType();
        // I'll tell you which type of file I've found
        Logger.log("  I've found a '" + drive_mime_type + "' file.");
        // Deal with file types
        switch (drive_mime_type) {
          // Existing JPG file
          case "image/jpeg":
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name);
            if (!already_exists.hasNext()){
              Logger.log("  Creating image : " + image_name);          
              var copy = image.makeCopy(dst_folder);
            }
            else{
              Logger.log("  It's already in the destination so I won't create another one.");
            }
            break;
          // Existing PNG file
          case "image/png":
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name);
            if (!already_exists.hasNext()){
              Logger.log("  Creating image : " + image_name);
              var copy = image.makeCopy(dst_folder);
            }
            else{
              Logger.log("  It's already in the destination so I won't create another one.");
            }
            break;
          // Google drawing - Convert to PNG!
          case "application/vnd.google-apps.drawing":
            var exportUrl = "https://www.googleapis.com/drive/v3/files/" + image.getId() + "/export?mimeType=image/png";
            var urlFetchOptions = {
              headers: {Authorization : "Bearer " + ScriptApp.getOAuthToken()}
            }
            try{
              var blob = UrlFetchApp.fetch(exportUrl, urlFetchOptions).getBlob();
            }
            catch(err){
              Logger.log("  There is an error getting the image : " + image_name);
              Logger.log(err);
              return(null);
            }
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name + ".png");
            if (!already_exists.hasNext()){
              Logger.log("  Creating image : " + image_name);
              DriveApp.getFolderById(dst_folder_id).createFile(blob).setName(image_name + ".png");
            }
            else {
              Logger.log("  There is already a png version in the destination so I won't create another one.");
            }
            break;
          }
      } 
    }
  }
  // Populate the missing images list
  var missing_images_sheet = course_workbook.getSheetByName("missing_images");
  missing_images_sheet.getRange(1,1,1000).clear();
  var missing_images_range = missing_images_sheet.getRange(1,1,missing.length);
  missing_images_range.setValues(missing);
}

All the image files are in a Shared Google Drive. I'm a full member on all the drives. The behaviour at the moment is that ONLY files owned by me are located from the SHARED drive and copied into the destination folder whereas most of the images were created by another user of the drive.

How do I change the script so that it finds files owned by ANYONE?

The appscript.json file which is with the script looks like this...

{
  "timeZone": "Europe/London",
  "dependencies": {
    "enabledAdvancedServices": []
  },
  "oauthScopes": [
    "https://www.googleapis.com/auth/drive.readonly",
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/drive.file",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/drive.metadata"
  ],
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

Thank you for your help!

1
Unfortunately, I cannot understand about your question. I apologize for this. Can I ask you about your current issue? And also, can you explain about your current script? And, when you run the script, does an error occur?Tanaike
Thanks you for your response @tanaike - the files that the script tries to download are in a shared drive. The script will only download the files that I own but most of the files I want to download are owned by another user in the company - the script does not even find them. There are no errors.Mark Mills
I've added more comments to the script. It is this line... var image_exists = DriveApp.getFilesByName(image_name); which ONLY finds images owned by me but most of the images are owned by other users. How can I change the script so that it finds ALL files irrespective of owner?Mark Mills
Thank you for replying. From your replying, I proposed a modified script as an answer. Could you please confirm it? If that was not the direct solution of your issue, I apologize.Tanaike

1 Answers

1
votes

In that case, how about using Drive API instead of Drive service? When your script is modified, it becomes as follows.

The main modification is as follows.

From:

var image_exists = DriveApp.getFilesByName(image_name);

To:

var image_exists = Drive.Files.list({corpora: "drive", driveId: "###DriveID###", includeItemsFromAllDrives: true, supportsAllDrives: true, maxResults: 1000, q: `title='${image_name}'`}).items;

Modified script:

In this case, please modify download_google_images() as follows. Please set your Drive ID of the shared Drive to ###DriveID### of var image_exists = Drive.Files.list({corpora: "drive", driveId: "###DriveID###", includeItemsFromAllDrives: true, supportsAllDrives: true, maxResults: 1000, q: title='${image_name}'}).items;. And please enable Drive API at Advanced Google services.

function download_google_images() {
  var course_workbook_name = "NAME"; // Title of spreadsheet with file list
  var dst_folder_id = "FOLDER_ID"; // ID of destination folder

  // There may be more than one!
  var course_workbooks = DriveApp.getFilesByName(course_workbook_name);
  // Try to access the spreadsheet
  try{
    var course_workbook_id = course_workbooks.next();
    Logger.log("Spreadsheet ID : " + course_workbook_id);    
  } catch(error) {
    Logger.log("Spreadsheet doesn't exist... exiting...");
    return(null);
  }
  var course_workbook = SpreadsheetApp.open(course_workbook_id);
  var list = load_list_of_images(course_workbook);
  // This will hold a list of missing images
  var missing = [];
  // What if the list is empty?
  if (list == null){
    Logger.log("Errr... no images to find - check the sheet!");
    return(null);
  }
  // Set up handle to destination folder
  var dst_folder = DriveApp.getFolderById(dst_folder_id);

  // Now look for each image in the list
  for (var row in list){
    // Get the name of the image to look for
    var image_name = list[row];
    Logger.log("Looking for : " + image_name);
    // Get all the files which match this name
    // This line ONLY finds images that are owned by me
    // MOST of the images are owned by other users

    var image_exists = Drive.Files.list({corpora: "drive", driveId: "###DriveID###", includeItemsFromAllDrives: true, supportsAllDrives: true, maxResults: 1000, q: `title='${image_name}'`}).items;  // <--- Modified

    // The list of images is empty
    if (image_exists.length == 0) {  // <--- Modified
      Logger.log("  Can't find image : " + image_name);
      missing.push([image_name]);
    }
    // I found some images!
    else {
      image_exists.forEach(e => {  // <--- Modified
        var image = DriveApp.getFileById(e.id);  // <--- Modified
        var drive_mime_type = image.getMimeType();
        // I'll tell you which type of file I've found
        Logger.log("  I've found a '" + drive_mime_type + "' file.");
        // Deal with file types
        switch (drive_mime_type) {
          // Existing JPG file
          case "image/jpeg":
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name);
            if (!already_exists.hasNext()) {
              Logger.log("  Creating image : " + image_name);
              var copy = image.makeCopy(dst_folder);
            }
            else {
              Logger.log("  It's already in the destination so I won't create another one.");
            }
            break;
          // Existing PNG file
          case "image/png":
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name);
            if (!already_exists.hasNext()) {
              Logger.log("  Creating image : " + image_name);
              var copy = image.makeCopy(dst_folder);
            }
            else {
              Logger.log("  It's already in the destination so I won't create another one.");
            }
            break;
          // Google drawing - Convert to PNG!
          case "application/vnd.google-apps.drawing":
            var exportUrl = "https://www.googleapis.com/drive/v3/files/" + image.getId() + "/export?mimeType=image/png";
            var urlFetchOptions = {
              headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() }
            }
            try {
              var blob = UrlFetchApp.fetch(exportUrl, urlFetchOptions).getBlob();
            }
            catch (err) {
              Logger.log("  There is an error getting the image : " + image_name);
              Logger.log(err);
              return (null);
            }
            var already_exists = DriveApp.getFolderById(dst_folder_id).getFilesByName(image_name + ".png");
            if (!already_exists.hasNext()) {
              Logger.log("  Creating image : " + image_name);
              DriveApp.getFolderById(dst_folder_id).createFile(blob).setName(image_name + ".png");
            }
            else {
              Logger.log("  There is already a png version in the destination so I won't create another one.");
            }
            break;
        }
      });  // <--- Modified
    }
  }
  // Populate the missing images list
  var missing_images_sheet = course_workbook.getSheetByName("missing_images");
  missing_images_sheet.getRange(1,1,1000).clear();
  var missing_images_range = missing_images_sheet.getRange(1,1,missing.length);
  missing_images_range.setValues(missing);
}

Note:

  • In this case, when you have no permission of reader or writer of the shared Drive, above modified script cannot be used. So please be careful this.
  • In the current stage, it seems that the files in the shared Drive cannot be retrieved using DriveApp.getFilesByName(filename) with the filename. On the other hand, when the file ID is used, DriveApp.getFileById(fileId) returns the file object from the shared Drive. From this situation, I proposed to use the method of files.list in Drive API for retrieving the file metadata from the filename. This is from Iamblichus's comment.

Reference: