My script in my spreadsheet on Gdrive for insert link id of file in folders like this:
function listFolders(folder) {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(["Name", "FileId"]); //writes the headers
var folder = DriveApp.getFolderById("XXXXXXXXXX")
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
var name = subfolders.next();
var files = name.getFiles();
var cnt = 0;
var file;
while (files.hasNext()) {
var file = files.next();
cnt++;
data = [
file.getName(),
file.getId()
];
sheet.appendRow(data);
};
}
}
How to resolve this problem?
Thanks in advance.
I believe your goal as follows.
You want to retrieve the file list from the subfolders just under the specific folder using Google Apps Script.
You want to reduce the process cost of your script.
As the additional goal, you want to add "FolderName" to the column.
Modification points:
In your script, appendRow is used in a loop. In this case, the process cost becomes high. Ref In your situation, I thought that when the number of files is large, the process cost will become high. In this answer, this is modified.
It seems that folder of argument is not used.
When above points are reflected to your script, it becomes as follows.
Modified script:
function listFolders() {
var sheet = SpreadsheetApp.getActiveSheet();
var folder = DriveApp.getFolderById("XXXXXXXXXX")
var subfolders = folder.getFolders();
var values = [["Name", "FileId", "FolderName"]]; // Modified
while (subfolders.hasNext()) {
var name = subfolders.next();
var folderName = name.getName(); // Added
var files = name.getFiles();
while (files.hasNext()) {
var file = files.next();
data = [file.getName(), file.getId(), folderName]; // Modified
values.push(data);
}
}
var cnt = values.length;
console.log(cnt); // You can see the total number of files at the log.
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
In this modification, the file list is put to an array and the array including the file list is put to the Spreadsheet using setValues.
Note:
When you want to retrieve the file list from all subfolders under the subfolders in the specific folder, you can also use the following script.
function listFolders() {
const getAllFolders = (id, list = [["Name", "FileId", "FolderName"]]) => { // Modified
const fols = DriveApp.getFolderById(id).getFolders();
let temp = [];
while (fols.hasNext()) {
const fol = fols.next();
const folderName = fol.getName(); // Added
temp.push(fol.getId());
const files = fol.getFiles();
while (files.hasNext()) {
const file = files.next();
list.push([file.getName(), file.getId(), folderName]); // Modified
}
}
temp.forEach(id => getAllFolders(id, list));
return list;
}
const id = "###"; // Please set the top folder ID.
const values = getAllFolders(id);
var cnt = values.length;
console.log(cnt); // You can see the total number of files at the log.
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
When above modification was not the direct solution of your issue, I would like to propose to use Drive API. In this case, I think that this Google Apps Script library can be also used. https://github.com/tanaikech/FilesApp
References:
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
setValues(values)
Added:
About your following replying,
I want to know which folder on my drive this file belonged to. const getAllFolders = (folderName,id, list = [["FolderName","Name", "FileId"]]
Unfortunately, I'm not sure whether I could correctly understand about the output values of your additional question, the following script is what you want?
Sample script:
function sample() {
const getAllFolders = (id, list = [["FolderName", "Name", "FileId"]]) => {
const folder = DriveApp.getFolderById(id);
const folderName = folder.getName();
const fols = folder.getFolders();
let temp = [];
while (fols.hasNext()) {
const fol = fols.next();
temp.push(fol.getId());
const files = fol.getFiles();
while (files.hasNext()) {
const file = files.next();
list.push([folderName, file.getName(), file.getId()]);
}
}
temp.forEach(id => getAllFolders(id, list));
return list;
}
const id = "###"; // Please set the top folder ID.
const values = getAllFolders(id);
var cnt = values.length;
console.log(cnt); // You can see the total number of files at the log.
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
This minor modification runs okay for me:
function listFolders() {
var sh = SpreadsheetApp.getActiveSheet();
sh.appendRow(["Name", "FileId","Count"]);
var folder = DriveApp.getFolderById("insert folder id")
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
var fldr = subfolders.next();
var files = fldr.getFiles();
var cnt = 0;
while (files.hasNext()) {
var file = files.next();
sh.appendRow([file.getName(),file.getId(),++cnt]);
};
}
}
This was my output:
Name
FileId
Count
Slide22.png
Redacted
1
Slide21.png
Redacted
2
Slide20.png
Redacted
3
Slide19.png
Redacted
4
Slide18.png
Redacted
5
Slide17.png
Redacted
6
Slide16.png
Redacted
7
Slide15.png
Redacted
8
Slide14.png
Redacted
9
Slide13.png
Redacted
10
Related
Hello I have a column with a list of Google Drive folder links and I would like to get latest updated date of all the files contained in the folders.
Example
By looking around I was able to build the following scripts which works fine by giving me the list of all the files contained in the folder and their latest update.
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'UpdateCheck', functionName: 'files'},
];
spreadsheet.addMenu('Menu', menuItems);
}
function files() {
var ui = SpreadsheetApp.getUi();
var result = ui.prompt("Paste the ID of Google Drive Folder");
var folderId = result.getResponseText();
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFiles();
var output = [];
while (files.hasNext()) {
var file = files.next();
output.push([file.getName(), file.getLastUpdated()]);
}
output.sort(function(a, b) {
return a[0] == b[0] ? 0 : a[0] < b[0] ? -1 : 1;
});
SpreadsheetApp.getActiveSpreadsheet().insertSheet().getRange(2, 1, output.length, output[0].length).setValues(output);
However I have to use the UI to open each link, copy and paste the ID from the URL in the input field. I would like to just read the column range, get the IDs from the strings without duplicates and run my script and have my result in a new tab. Any help would be great.
I believe your current situation and your goal are as follows.
You have a sheet that the folder links are put to the column "D" in your providing image.
You want to retrieve the folder ID from the links and want to retrieve the filename and the value of getLastUpdated() of all files in the folders.
You want to put the retrieved data on a new sheet.
Modified script:
Please set the sheet names of srcSheetName and dstSheetName.
function myFunction() {
var srcSheetName = "Sheet1"; // Please set the source sheet name.
var dstSheetName = "Sheet2"; // Please set the destination sheet name.
// Retrieve folder links from "D2:D" and check the duplication.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(srcSheetName);
var folderIds = [...new Set(sheet.getRange("D2:D" + sheet.getLastRow()).getRichTextValues().flatMap(([d]) => {
var url = d.getLinkUrl();
if (url && /^https:\/\/drive\.google\.com\/drive\/folders\/.+/.test(url)) {
return [url.split("/")[5].trim()];
}
return [];
}))];
// Create an array for putting to sheet.
var res = folderIds.flatMap(id => {
var folder = DriveApp.getFolderById(id);
var files = folder.getFiles();
var temp = [];
while (files.hasNext()) {
var file = files.next();
temp.push([file.getName(), file.getLastUpdated()]);
}
return temp;
});
// Put the array to the destination sheet.
ss.insertSheet(dstSheetName).getRange(1, 1, res.length, 2).setValues(res);
}
About some unclear points, I guessed as follows.
I couldn't understand the format of folder links in the cells. In this modification, I guessed that the folder link is like https://drive.google.com/drive/folders/###.
I couldn't understand get the IDs from the strings without duplicates. In this modification, the duplication of retrieved folder IDs is checked.
References:
getValues()
insertSheet(sheetName)
setValues(values)
Added:
From the following your replying,
Quick question, when I run it I get an Unexpected error while getting the method or property getFolderById on object DriveApp at line var res = folderIds.flatMap(id => { var folder = DriveApp.getFolderById(id); it's solvable or should I open another thread?
the folder link was indeed incorrect instead of https://drive.google.com/drive/folders/### the format was https://drive.google.com/corp/drive/u/0/folders/####?resourcekey=#### so I correct the code with /^https://drive.google.com/corp/drive/u/0/folders/.+/.test(url)) { return [url.split("/")[8].trim()]; but now I get 1CHKEThZJ0P-ISv0g0MoGjCCqdZuuJJyA?resourcekey=0-1gzYTJvJv1XDwF2Hx4HvEQ and I need to find a way to get rid of everything right before the "?"
For this, I modified my proposed script as follows.
Modified script:
function myFunction() {
var srcSheetName = "Sheet1"; // Please set the source sheet name.
var dstSheetName = "Sheet2"; // Please set the destination sheet name.
// Retrieve folder links from "D2:D" and check the duplication.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(srcSheetName);
var folderIds = [...new Set(sheet.getRange("D2:D" + sheet.getLastRow()).getRichTextValues().flatMap(([d]) => {
var url = d.getLinkUrl();
if (url) {
if (/^https:\/\/drive\.google\.com\/drive\/folders\/.+/.test(url)) {
return [url.split("/")[5].trim()];
} else if (/^https:\/\/drive\.google\.com\/.+\/drive\/u\/0\/folders\/.+/.test(url)) {
return [url.split("/")[8].trim().split("?")[0]];
}
}
return [];
}))];
// Create an array for putting to sheet.
var res = folderIds.flatMap(id => {
try {
var folder = DriveApp.getFolderById(id);
var files = folder.getFiles();
var temp = [];
while (files.hasNext()) {
var file = files.next();
temp.push([file.getName(), file.getLastUpdated()]);
}
return temp;
} catch (e) {
console.log({id, msg: e.message});
}
});
// Put the array to the destination sheet.
ss.insertSheet(dstSheetName).getRange(1, 1, res.length, 2).setValues(res);
}
By this modification, 2 kinds of URLs like https://drive.google.com/drive/folders/### and https://drive.google.com/corp/drive/u/0/folders/####?resourcekey=#### can be used, and when an error occurs when the files are retrieved from the folder, you can see the folder ID at the log. And, the script is not stopped.
So I am a noob in coding but managed to adjust the code a bit to do what I need it to do and that is to list the files inside a folder and its subfolder files.
The issue is that the files total is about 50k or more and keeps increasing each day XD
so now most of the time I get a "Exceeded maximum execution time" and sometimes's I don't. Inside the script, there is a flush function so it should reset the timer if I am correct?
I run the script every day I do not know what to do to fix this?
I think the best would be to have a function that will check if it is already listed and if not updated to skip it to speed up the script but again I just do not know atm ware to start.
If someone could help me to fix the " Exceeded maximum execution time" I would be extremely grateful.
this is the script:
function ListarTodo() {
/* Adapted from Code written by #Andres Duarte in this link:
https://stackoverflow.com/questions/59045664/how-to-list-also-files-inside-subfolders-in-google-drive/63182864#63182864
*/
// List all files and sub-folders in a single folder on Google Drive
// declare the folder name
var foldername = 'Beelden';
// declare this sheet
var sheet = SpreadsheetApp.getActiveSheet();
// clear any existing contents
sheet.clear();
// append a header row
sheet.appendRow(["Folder","Name", "Last Updated", "Size MB", "URL"]);
// getFoldersByName = Gets a collection of all folders in the user's Drive that have the given name.
// folders is a "Folder Iterator" but there is only one unique folder name called, so it has only one value (next)
var folders = DriveApp.getFoldersByName(foldername);
var foldersnext = folders.next();
var lintotal = 2;
// Initiate recursive function
lintotal = SubCarpetas(foldersnext, foldername, lintotal);
}
function SubCarpetas(folder, path, cantlineas) {
cantlineas = ListarArchivos(folder, path, cantlineas);
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
var mysubfolders = subfolders.next();
var mysubfolderName = mysubfolders.getName();
var newpath = "";
newpath = path + "/" + mysubfolderName;
cantlineas = SubCarpetas(mysubfolders, newpath, cantlineas);
}
return(cantlineas)
}
// list files in this folder
// myfiles is a File Iterator
function ListarArchivos(mifoldersnext, mipath, milintotal) {
var datos = []; //temporary array that we are going to use to record on the sheet
var files = []; //array with all the files that we find in the folder that we are evaluating
var file = []; //array that we use to dump the data of each file before saving it
var total = 0;
var sheet = SpreadsheetApp.getActiveSheet();
var myfiles = mifoldersnext.getFiles();
// We create an array with the data of each file and save the total number of files
while (myfiles.hasNext()) {
files.push(myfiles.next());
total++;
}
// we sort the array by file names alphabetically // sorts the files array by file names alphabetically
files = files.sort(function(a, b){
var aName = a.getName().toUpperCase();
var bName = b.getName().toUpperCase();
return aName.localeCompare(bName);
});
////
var vuelta = 0;
var bulk = 500; // We define the number of lines to record each time, in the GoogleDoc spreadsheet
var linea = milintotal; // we define in which line we are going to save in the spreadsheet
for (var i = 0; i < files.length; i++) { // we go through the array of files and format the information we need for our spreadsheet
file = files[i];
var fname = file.getName(); //file name
var fdate = file.getLastUpdated(); // date and time last modified
var fsize = file.getSize()/1024/1024; // file size, we pass it from byte to Kbyte and then to Mb
fsize = +fsize.toFixed(2); // we format it to two decimal places
var furl = file.getUrl(); //File URL
datos[vuelta] = [mipath+" ("+total+")", fname, fdate, fsize, furl]; // we put everything inside a temporary array
vuelta++;
if (vuelta == bulk) {// when it reaches the defined quantity, save this array with 10 lines and empty it
linea = milintotal;
// Logger.log("linea = "+linea); //DEBUG
// Logger.log("vuelta = "+vuelta); //DEBUG
// Logger.log("total = "+total); //DEBUG
// Logger.log("lintotal = "+milintotal); //DEBUG
// Logger.log("registros en datos = "+datos.length); //DEBUG
// Logger.log("data = "+datos); //DEBUG
sheet.getRange(linea, 1, bulk,5).setValues(datos); // we save the data of the temporary array in the sheet
SpreadsheetApp.flush(); // we force the data to appear on the sheet - without this the data does not appear until finished (it generates a lot of impatience)
milintotal = milintotal + vuelta;
datos = []; // empty the temporary array
vuelta = 0;
}
}
if (datos.length>0) {// When exiting the loop we record what is left in the data array
linea = milintotal;
// Logger.log("linea = "+linea); //DEBUG
// Logger.log("vuelta = "+vuelta); //DEBUG
// Logger.log("total = "+total); //DEBUG
// Logger.log("lintotal = "+milintotal); //DEBUG
// Logger.log("records in data = "+ data.length); //DEBUG
// Logger.log("data = "+datos); //DEBUG
sheet.getRange(linea, 1, datos.length,5).setValues(datos);
SpreadsheetApp.flush(); //ansiolítico
milintotal = milintotal + datos.length;
datos = [];
vuelta = 0;
}
return (milintotal)
}
Thank you all
UPDATE!
So after looking at multiple forumes i found that the best thing atm i can do is make a break for this script by using the following script:
function runMe() {
var startTime= (new Date()).getTime();
//do some work here
var scriptProperties = PropertiesService.getScriptProperties();
var startRow= scriptProperties.getProperty('start_row');
for(var ii = startRow; ii <= size; ii++) {
var currTime = (new Date()).getTime();
if(currTime - startTime >= MAX_RUNNING_TIME) {
scriptProperties.setProperty("start_row", ii);
ScriptApp.newTrigger("runMe")
.timeBased()
.at(new Date(currTime+REASONABLE_TIME_TO_WAIT))
.create();
break;
} else {
doSomeWork();
}
}
//do some more work here
}
But after trying I do not understand where to divide this to make it work T-T any ideas?
I think the best would be to have a function that will check if it is already listed and if not updated to skip it to speed up the script but again I just do not know atm ware to start.
These links from the official documentation should help:
https://developers.google.com/apps-script/reference/drive/drive-app#searchFiles(String)
https://developers.google.com/apps-script/reference/drive/drive-app#searchFolders(String)
https://developers.google.com/drive/api/v2/search-files
https://developers.google.com/drive/api/v2/ref-search-terms
You can use the information in the documentation to create a script that only pulls the most recently added and/or updated files.
However, if you need to process a large volume of recently updated files you'll need to leverage some kind of batch processing solution that spans multiple sessions.
I have a function getFnF() that iterates through a Google Drive folder and all of it's subfolders. When getFnF() encounters a Google Sheets file, I have the script parse through that Google Sheets file and extract out any URL Links it finds using my function getLinksFromSheet(). The functions both work, but after about 10 minutes of iterating through the Drive folder and calling getLinksFromSheet() on the Google Sheets files encountered, I get a The JavaScript runtime exited unexpectedly. error. Does anybody have any ideas what would be causing this error? The Google Drive folder is quite large (~500 files total in the subfolders, ~75 of which are Google Sheets). Code below:
function getFnF(folder) {
var folder= folder || DriveApp.getFolderById("0AFZNRhJpE8LKUk9PVA"); //hard goded DEP-Gotham folder
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet1');
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
var firg=sh.getRange(sh.getLastRow() + 1,level + 1);
firg.setValue(Utilities.formatString('File: %s', file.getName()));
Logger.log(file.getName())
//if (file.getMimeType() == 'application/vnd.google-apps.document') {getAllLinks(file.getId(), false);};
//if (file.getMimeType() == 'application/vnd.google-apps.presentation') {getLinksFromSlides(file.getId());};
if (file.getMimeType() == 'application/vnd.google-apps.spreadsheet') {getLinksFromSheet(file.getId());};
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
var forg=sh.getRange(sh.getLastRow() + 1,level + 1);
forg.setValue(Utilities.formatString('Fldr: %s', subfolder.getName()));
level++;
getFnF(subfolder);
}
level--;
}
function getLinksFromSheet(sheetId){
var ss = SpreadsheetApp.openById(sheetId);
var sheets = ss.getSheets();
var parentDocName = ss.getName();
var destSs=SpreadsheetApp.getActive();
var destSh=destSs.getSheetByName('Extracted Links');
sheets.forEach(sheet => {
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(1,1, lastRow, lastColumn);
//var rangeValues = searchRange.getValues();
var rangeValues = searchRange.getRichTextValues();
for (var i = 0; i < lastRow; i++){
for (var j = 0; j < lastColumn; j++){
const runs = rangeValues[i][j].getRuns();
for (const v of runs) {
var nextLink = v.getLinkUrl();
if (nextLink != null) {
var row = destSh.getLastRow() + 1;
var r1=destSh.getRange(row, 1);
r1.setValue(parentDocName);
var r2=destSh.getRange(row, 2);
r2.setValue(nextLink);
};
}
}
}
});
Issue stems most likely from exceeding the limitation of runtime execution.
You can use getFilesByType to further whittle down the list and save time. Also did modify a bit in your code but should be able to do the same thing. They should have comments above them. Kindly check.
Usage:
function getFnF(folder) {
var folder = folder || DriveApp.getFolderById("0AFZNRhJpE8LKUk9PVA"); //hard goded DEP-Gotham folder
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Sheet1');
// limit files to only google sheets
var files = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
// assign getLastRow to lessen method calls
var lastRow = sh.getLastRow();
// initialize level value
var level = 1;
while (files.hasNext()) {
var file = files.next();
// I can use appendRow here, but I did't since column has a variable
// and you might change it. Feel free to update if necessary
var firg = sh.getRange(lastRow + 1, level + 1);
firg.setValue(Utilities.formatString('File: %s', file.getName()));
getLinksFromSheet(file.getId());
// iterate lastRow
lastRow++;
}
var subfolders = folder.getFolders()
while (subfolders.hasNext()) {
var subfolder = subfolders.next();
// I can use appendRow here, but I did't since column has a variable
// and you might change it. Feel free to update if necessary
var forg = sh.getRange(lastRow + 1, level + 1);
forg.setValue(Utilities.formatString('Fldr: %s', subfolder.getName()));
level++;
getFnF(subfolder);
// iterate lastRow
lastRow++;
}
// not sure what this does but you can freely remove this if not being used
level--;
}
function getLinksFromSheet(sheetId) {
var ss = SpreadsheetApp.openById(sheetId);
var sheets = ss.getSheets();
var parentDocName = ss.getName();
var destSs = SpreadsheetApp.getActive();
var destSh = destSs.getSheetByName('Extracted Links');
sheets.forEach(sheet => {
// getDataRange already gets all the data
var rangeData = sheet.getDataRange();
// Flatten 2d array
var rangeValues = rangeData.getRichTextValues().flat();
rangeValues.forEach(v => {
var link = v.getLinkUrl();
if(link)
// Use appendRow instead. Adjust array if needed to be in a different column.
destSh.appendRow([parentDocName, link]);
});
});
}
Run time difference:
The 6-second runs is the optimized one above while the 7-second runs is your code.
Test Conditions:
Two sheet files in parent folder, one sheet file in 1 sub-folder:
Each spreadsheet has 2 sheets, each sheet has 1 link.
Parent folder has one non-sheet file.
Note:
Given the significant runtime difference on a lesser number of files, certainly this will have greater impact on a huge number of files.
If you want to include other type of files, then you need to create a separate loop to process each filetype if you have different type of process for each.
You can also join 2 getFilesByType outputs into 1 array but getting links from different file types might vary so separate loop will be much safer.
To get around the time problems you are having, I'd suggest one script to write all the spreadsheet ids and then another script to go down and process them (run getLinksFromSheet()) a line at a time and then mark each line as done so you can rerun it until you can finish.
Getrichtextvalue > getlinkURL is just slowwwwwwwww and you can't get around that.
I think this could also be a memory size, or too much data in a single variable type of issue. I'm getting the same error after seconds of starting a debugging session, but no indication of what is causing it.
var folder = DriveApp.getFolderById('1_gA4D7dfybJ60IdfgsnqdfdsgVoo9D76fgsdgf9cqmAnJI7g7');
var contents = folder.getFiles();
var file;
var name;
var sheet = SpreadsheetApp.getActiveSheet();
var date;
var size;
sheet.clear();
sheet.appendRow(["Nome", "Data", "Dimensione"]);
while(contents.hasNext()) {
file = contents.next();
name = file.getName();
date = file.getDateCreated();
size = file.getSize();
id = file.getUrl();
data = [name, date, size,id]
sheet.appendRow(data);
}
};
Every time all the data is cleared, after that the data is added from the starting.
sheet.clear();sheet.appendRow(["Nome", "Data", "Dimensione"]);
Is there any way to check the data?
if the same data present Already then the function does not work on the row.
If a new record is added, it should also be added, but the function does not start again from one.
If I have 20 PDFs in my folder, and add one more PDF in folder, then add the function 21 pdf and do not run the function from the beginning.
Explanation:
The logic behind the following script is the following:
We get all the URLs of the files that are currently in column D of the sheet. These are the URLs of the files that have been recorder so far. We can safely assume that the URLs are always unique:
const aURLs = sheet.getRange('D2:D'+sheet.getLastRow()).getValues().flat();
The second step is to iterate through the files as the original script would do and check if the URL of a file is in aURLs. If the file URL is not in aURLs or in other words in column D, then add it to the newFiles array:
if(!uNames.includes(name)){
newFiles.push(data);
}
After we checked all the files, we can add, after the last row of sheet, only the new files:
sheet.getRange(sheet.getLastRow()+1,1,newFiles.length,newFiles[0].length).setValues(newFiles);
Solution:
Manually add the headers in the file for the first time only:
and then execute the script every next time:
function myFunction() {
const folder = DriveApp.getFolderById('1_gA4D7dfybJ60IdfgsnqdfdsgVoo9D76fgsdgf9cqmAnJI7g7');
const contents = folder.getFiles();
const sheet = SpreadsheetApp.getActiveSheet();
const aURLs = sheet.getRange('D2:D'+sheet.getLastRow()).getValues().flat();
const newFiles = [];
while(contents.hasNext()) {
let file = contents.next();
let name = file.getName();
let date = file.getDateCreated();
let size = file.getSize();
let id = file.getUrl();
let data = [name, date, size,id]
if(!aURLs.includes(id)){
newFiles.push(data);
}
}
sheet.getRange(sheet.getLastRow()+1,1,newFiles.length,newFiles[0].length).setValues(newFiles);
}
I'm running a SendEmail script with a 3 triggers to be sent out on Mondays, Wednesdays and Fridays.
I have 10 sheets on the spreadsheet (each one contains an SentEmail script and each needs to be sent out on those days but I have only 20 trigger limitation)
This is the code:
function sendEmail() {
var s = SpreadsheetApp.getActive().getSheetByName('BCX');
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getActiveSheet().getDataRange();
var range = s.getRange('B5:Q20');
var row = ss.getSheetByName('BCX').getRange("J1").getValue();
var to = "info#google.com";
var body = '';
var htmlTable = SheetConverter2.convertRange2html(range);
var body = "Hi Team!"
+ htmlTable
+ "<br/><br/><b><i>**This is an automated email**</i></b><br/><br/>Any question please let me know.<br/><br/>Regards,<br/><br/>";
var subject = "Google | Report " + row;
MailApp.sendEmail(to, subject, body, {htmlBody: body});
};
But if I use something like the following script it will create 3 triggers each week until it reaches 20 triggers (trigger limit).
function createTriggers() {
var days = [ScriptApp.WeekDay.MONDAY,
ScriptApp.WeekDay.WEDNESDAY,
ScriptApp.WeekDay.FRIDAY];
for (var i=0; i<days.length; i++) {
ScriptApp.newTrigger("sendEmail")
.timeBased().onWeekDay(days[i])
.atHour(7).create();
}
};
One solution to this question would be to combine the various scripts into a single script that can be triggered to run on Monday, Wednesday and Friday.
Within the script, the sequence of processing would be:
1) loop through the spreadsheets in a given folder/sub-folders of Google Drive. - this provides the unique spreadsheet ID.
2) for each spreadsheet, get the ID and use the openById(ID) to open the spreadsheet.
3) get the sheets for the spreadsheet
4) for each sheet, use the original code to build and send an email.
5) rinse and repeat for the next sheet, and next spreadsheet.
The following untested code combines the search for every spreadsheet within a specific folder and sub-folders, opening the spreadsheet and getting the sheets, and then looping through each sheet. The questioner need only add the name of the Google Drive Folder to initiated the search, and put their own code in the two places indicated.
function 53383834() {
/* Adapted from Code written by #hubgit https://gist.github.com/hubgit/3755293
Updated since DocsList is deprecated https://ctrlq.org/code/19854-list-files-in-google-drive-folder
*/
// List all files and sub-folders in a single folder on Google Drive
// declare the folder name
var foldername = 'XXXXXXXXXXXXXXXXXX'; // enter the folder name
// declare this sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActivesheet();
// getFoldersByName = Gets a collection of all folders in the user's Drive that have the given name.
// folders is a "Folder Iterator" but there is only one unique folder name called, so it has only one value (next)
var folders = DriveApp.getFoldersByName(foldername);
var foldersnext = folders.next();
// list files in this folder
var myfiles = foldersnext.getFiles();
// spreadsheets have a unique MIME-Type = application/vnd.google-apps.spreadsheet
var searchTerm = 'spreadsheet';
// loop through files in this folder
while (myfiles.hasNext()) {
var myfile = myfiles.next();
var fname = myfile.getName();
var fid = myfile.getId();
// get the MIME-Type and test whether the file is a spreadsheet
var ftype = myfile.getMimeType();
var indexOfFirst = ftype.indexOf(searchTerm);
if (indexOfFirst != -1) {
var ssid = fid;
// open the spreadsheet
var sso = SpreadsheetApp.openById(ssid);
// get the sheets
var sheets = sso.getSheets();
var sheetlen = sheets.length;
for (var i = 0; i < sheetlen; i++) {
// get the sheets, one by one
var thissheet = sso.getSheets()[i];
<<
insert questioners code here >>
}
}
}
// Now get the subfolder
// subfolders is a Folder Iterator
var subfolders = foldersnext.getFolders();
// now start a loop on the SubFolder list
while (subfolders.hasNext()) {
var subfolderdata = [];
var mysubfolders = subfolders.next();
var mysubfolder = mysubfolders.getName();
// Get the files
var mysubfiles = mysubfolders.getFiles();
// now start a loop on the files in the subfolder
while (mysubfiles.hasNext()) {
var smyfile = mysubfiles.next();
var sfname = smyfile.getName();
var sfid = smyfile.getId();
var sftype = smyfile.getMimeType();
var indexOffolder = sftype.indexOf(searchTerm);
if (indexOffolder != -1) {
var ssid = sfid;
// open the spreadsheet
var sso = SpreadsheetApp.openById(ssid);
// get the sheets
var sheets = sso.getSheets();
var sheetlen = sheets.length;
for (var i = 0; i < sheetlen; i++) {
// get the sheets, one by one
var thissheet = sso.getSheets()[i];
<<
insert questioners code here >>
}
}
}
}
}