Home     Blogs     Copyright 2021, Randy Strauss

Google Folder Contents

// This lists all files in and below a folder into a spreadsheet.
// It will avoid loops caused by a link to an already-visited folder.
// Create this in your Google Drive:  New > More > Google Apps Script
// NOTE:  You must set the TOP_FOLDER_NAME in line 7...

function listAllFiles() {
  var foldername = 'TOP_FOLDER_NAME';  // set the TOP_FOLDER_NAME
  var spreadsheetName = 'listing-of-folder-' + foldername;
  
  var folder = getFolder(foldername);
  sheet = getOrCreateSpreadsheet(folder, spreadsheetName);

  // The top row (should really be frozen...)
  sheet.appendRow(['link','type','name','--generated by a script--']);

  hash = new Map();  // put listed urls inside, to avoid loops
  hash.set(folder.getUrl(), true);

  var numRows = 1;  
  numRows = listFilesInFolder(numRows, sheet, 0, folder);
  numRows = listFoldersInFolder(numRows, hash, sheet, 0, folder);
  sheet.appendRow([ "###" ]);

  deleteUnsedRows(sheet, numRows);
};


// Returns the named folder, or null if there are none or more than one
function getFolder(foldername) {
  var folders = DriveApp.getFoldersByName(foldername)
  if (!folders.hasNext()) {
      Logger.log("Named folder does not exist: "+foldername);
      return null;
  }
  var folder = folders.next();
  if (folders.hasNext()) {  // has at least 2
    var num = 2;
    folder = folders.next();
    while (folders.hasNext()) {
      folder = folders.next();
      num++;
    }
    Logger.log("There are "+num+" folders named: "+foldername);
    return null;
  }
  return folder;
}


// I'm not sure this works...  But the initial clear() worked...
function deleteUnsedRows(numRows) {
  var lastNum = sheet.getLastRow();
  if (numRows < lastNum) {
    sheet.deleteRows(numRows+1, lastNum-numRows);
  }
}


// If the spreadsheet exists, its contents are overwritten. Else it's created in the folder.
// The active sheet in the spreadsheet is returned
function getOrCreateSpreadsheet(folder, spreadsheetName) {
  var files = DriveApp.getFilesByName(spreadsheetName);
  var sheet, ss = null;
  if (!files.hasNext()) {
    ss = SpreadsheetApp.create(spreadsheetName);
    file = DriveApp.getFilesByName(spreadsheetName);
    folder.moveTo(folder);
    sheet = ss.getActiveSheet();
  } else {
    ss = SpreadsheetApp.open(files.next());
  }
  sheet = ss.getActiveSheet();
  sheet.clear();
  return sheet;
}


// If the spreadsheet exists, its contents are overwritten. Else it's created in the folder.
// The active sheet in the spreadsheet is returned, cleared of data.
function listFilesInFolder(n, sheet, nblanks, folder) {
  var contents = folder.getFiles();
  while(contents.hasNext() && n < 10000) {
    var file = contents.next();
    var link = file.getUrl();
    hash.set(link, true);
    var name = file.getName();
    var type = getFileType("" + file.getMimeType(), n, nblanks, name);
    var list = [link, type];
    for (i = 0;  i < nblanks;  i++) {
      list.push('.');
    }
    list.push(name);
    sheet.appendRow(list);
    n++;
  }
  return n;
}


// This isn't complete-unrecognized ones are printed so can be added...
function getFileType(type, n, nblanks, name) {
  if (type == 'application/vnd.google-apps.shortcut') {
    return "Link";
  } else if (type == 'application/vnd.google-apps.spreadsheet') {
    return "Sheet";
  } else if (type == 'application/vnd.google-apps.presentation') {
    return "Pres";
  } else if (type == 'application/vnd.google-apps.document') {
    return "Doc";
  } else if (type == 'application/zip') {
    return "zip";
  } else if (type == 'application/x-zip-compressed') {
    return "zip";
  } else if (type == 'application/pdf') {
    return "zip";
  } else if (type == 'image/png') {
    return "image";
  } else if (type == 'image/jpg') {
    return "image";
  } else if (type == 'image/jpeg') {
    return "image";
  } else if (type == 'audio/x-m4a') {
    return "audio";
  } else if (type == 'text/html') {
    return "html";
  } else if (type == 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
    return "xlsx";
  } else if (type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
    return "xlsx";
  } else if (type == 'application/vnd.google-apps.form') {
    return "g-form";
  } else {
    Logger.log("?: " + n + "-" + nblanks + "/" + type + " - " + name);
    return "?";
  }
}


function listFoldersInFolder(n, hash, sheet, nblanks, folder) {
  var contents = folder.getFolders();
  while(contents.hasNext() && n < 10000) {
    var subfolder = contents.next();
    var link = subfolder.getUrl();
    if (hash.get(link)) {
      //Logger.log("SKIPPING REDUNDANT " + n + "-" + nblanks + "/" + type + " - " + name);
      continue;
    }
    hash.set(link, true);
    var name = subfolder.getName();
    var type = "f";
    var list = [link, type];
    for (i = 0;  i < nblanks;  i++) {
      list.push(".");
    }
    list.push(name);
    sheet.appendRow(list);
    n = listFilesInFolder(++n,       sheet, nblanks+1, subfolder);
    n = listFoldersInFolder(n, hash, sheet, nblanks+1, subfolder);
  }
  return n;
}
// ###