Unzip File Only If New in Google Apps Scripts - google-apps-script

I have a folder (let's call it the source folder) on Google Drive that is updated from time to time with new zip files (underlying files are PDFs). I am trying to use Google Apps Script to unzip only the new zip files and place the underlying PDFs in another folder (let's call it the destination folder).
I am currently using the following code to unzip the files in the source folder, running on a time-based trigger. My current code does not differentiate between old and new zip files so I am getting a large number of duplicates accumulating in the destination folder. (I found this code on WeirdGeek: https://www.weirdgeek.com/2019/10/unzip-files-using-google-apps-script/)
function Unzip() {
//Add folder ID to select the folder where zipped files are placed
var SourceFolder = DriveApp.getFolderById("1KbyB2vTUfbwYdzBEyIwzTliXKjATbW8A")
//Add folder ID to save the where unzipped files to be placed
var DestinationFolder = DriveApp.getFolderById("1Z-iVlcROe5kVX8IkBlV9a98WKlvlfp3U")
//Select the Zip files from source folder using the Mimetype of ZIP
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP)
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
// Get the blob of all the zip files one by one
var fileBlob = ZIPFiles.next().getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);
}
}
I initially thought to add some sort of time-based restriction to the function, but because the source folder is being synced (using MultCloud) with an sFTP site, I don't want to go that direction.
I ALSO found the following code is used to put a "replace" restriction on saving new spreadsheets but couldn't figure out how to integrate this with my code. (Code is from user Tainake)
function saveAsSpreadsheet() {
var folderId = "0B8xnkPYxGFbUMktOWm14TVA3Yjg";
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFilesByName(getFilename());
if (files.hasNext()) {
files.next().setTrashed(true);
}
var sheet = SpreadsheetApp.getActiveSpreadsheet();
DriveApp.getFileById(sheet.getId()).makeCopy(getFilename(), folder);
}
Any ideas on how to solve this problem would be appreciated! I am a complete noob so I apologize in advance if this is a stupid question.
EDIT: I could not figure out how to unzip only "new" files in the source folder, and so my new code moves to trash all files in the destination folder, and then unzips all files in the source folder. Code is below:
function Unzip() {
//Add folder ID to select the folder where zipped files are placed
var SourceFolder = DriveApp.getFolderById("1KbyB2vTUfbwYdzBEyIwzTliXKjATbW8A")
//Add folder ID to save the where unzipped files to be placed
var DestinationFolder = DriveApp.getFolderById("1Z-iVlcROe5kVX8IkBlV9a98WKlvlfp3U")
//Delete files from the destination folder
//Get the files in the destination folder
var files = DestinationFolder.getFiles();
//Loop through the files in the destination folder
while(files.hasNext()){
//Get the individual file in the destination folder to process
var file = files.next();
//Trash that file
file.setTrashed(true);
}
//Select the Zip files from source folder using the Mimetype of ZIP
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP)
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
// Get the blob of all the zip files one by one
var fileBlob = ZIPFiles.next().getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);
}
}
I could see how this may not be the best solution to this issue, but this allows me to have a MultCloud sync the zip files into my Google Drive, and then allows me to have those files unzipped with a function that runs from time to time. Anyone have a better idea how to accomplish the same thing without deleteing and recreating all the files every time?
EDIT 2:
Thank you to Cameron, this question is answered. I am pasting the full code I am using below, for posterity / other newbies so that they don't have to piece it together:
function Unzip() {
//Add folder ID to select the folder where zipped files are placed
var SourceFolder = DriveApp.getFolderById("1KbyB2vTUfbwYdzBEyIwzTliXKjATbW8A")
//Add folder ID to save the where unzipped files to be placed
var DestinationFolder = DriveApp.getFolderById("1Z-iVlcROe5kVX8IkBlV9a98WKlvlfp3U")
//Select the Zip files from source folder using the Mimetype of ZIP
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP);
var now = new Date(); //get current time after you fetch the file list from Drive.
//Get script properties and check for stored "last_execution_time"
var properties = PropertiesService.getScriptProperties();
var cutoff_datetime = properties.getProperty('last_execution_time');
//if we have last execution date, stored as a string, convert it to a Date object.
if(cutoff_datetime)
cutoff_datetime = new Date(cutoff_datetime);
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
var file = ZIPFiles.next();
//if no stored last execution, or file is newer than last execution, process the file.
if(!cutoff_datetime || file.getDateCreated() > cutoff_datetime){
var fileBlob = file.getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);
}
}
//store "now" as last execution time as a string, to be referenced on next run.
properties.setProperty('last_execution_time',now.toString());
}

You can use the getDateCreated() function on a File object to determine when the file was created. By checking this value against a time limit, you should be able to determine if the file is new. If you are triggering your script with at least a few hours between executions, you could use a hardcoded cutoff time. So if you are triggering your script every six hours, you could ignore any files not created within the last 6 hours, for example.
However, a more robust approach would be to store the last successful execution time in a Script Property, so you could always process any files created since the last successful execution.
Note that this code will process all files currently in the folder the first time it runs, after that it will only process files created since the last run.
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP);
var now = new Date(); //get current time after you fetch the file list from Drive.
//Get script properties and check for stored "last_execution_time"
var properties = PropertiesService.getScriptProperties();
var cutoff_datetime = properties.getProperty('last_execution_time');
//if we have last execution date, stored as a string, convert it to a Date object.
if(cutoff_datetime)
cutoff_datetime = new Date(cutoff_datetime);
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
var file = ZIPFiles.next();
//if no stored last execution, or file is newer than last execution, process the file.
if(!cutoff_datetime || file.getDateCreated() > cutoff_datetime){
var fileBlob = file.getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);
}
}
//store "now" as last execution time as a string, to be referenced on next run.
properties.setProperty('last_execution_time',now.toString());

Related

Is it possible to save an excel attachment as a "proper" google sheet file? [duplicate]

I know it is possible to convert excel files to Google Sheets using script and drive API, but I'm looking for script to convert the excel sheet and move the converted file to a different folder.
So the required steps are as follows:
Convert excel (.xls/.xlsx) to Google Sheet from FolderA.
Move converted file from FoldarA to FolderB.
Delete original excel file from FolderA
Hopefully step 3 avoids this, but avoid duplicating already converted file.
The excel files are being pasted into a local folder that is being synced to google drive, and the files are no larger than 3mb. The current script is as follows. This is converting the files but placing them in the root folder, and will duplicate the conversion when the script runs again.
function importXLS(){
var files = DriveApp.getFolderById('1hjvNIPgKhp2ZKIC7K2kxvJjfIeEYw4BP').searchFiles('title != "nothing"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = { title : name+'_converted',
key : ID
}
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
}
}
}
You want to create the converted Google Spreadsheet files to "FolderB".
You want to delete the XLSX files in "FolderA" after the files were converted.
You want to achieve above using Google Apps Script.
If my understanding correct, how about this modification? In this modification, I modified your script.
Modification points:
You can directly create the file to the specific folder using the property of parents in the request body.
You can delete the file using Drive.Files.remove(fileId).
Modified script:
Before you use this script, please enable Drive API at Advanced Google services.
function importXLS(){
var folderBId = "###"; // Added // Please set the folder ID of "FolderB".
var files = DriveApp.getFolderById('1hjvNIPgKhp2ZKIC7K2kxvJjfIeEYw4BP').searchFiles('title != "nothing"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = {
title : name+'_converted',
parents: [{id: folderBId}] // Added
};
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
// Drive.Files.remove(ID); // Added // If this line is run, the original XLSX file is removed. So please be careful this.
}
}
}
Note:
If the number of XLSX files is large, the execution time might be over 6 minutes.
About // Drive.Files.remove(ID);, when you run this script, please be careful. Because the original XLSX files are completely deleted when the script is run. So I commented this. At first, please test the script using sample files.
References:
Files: insert
Files: delete

Save gmail attachment as google sheets in gdrive [duplicate]

I know it is possible to convert excel files to Google Sheets using script and drive API, but I'm looking for script to convert the excel sheet and move the converted file to a different folder.
So the required steps are as follows:
Convert excel (.xls/.xlsx) to Google Sheet from FolderA.
Move converted file from FoldarA to FolderB.
Delete original excel file from FolderA
Hopefully step 3 avoids this, but avoid duplicating already converted file.
The excel files are being pasted into a local folder that is being synced to google drive, and the files are no larger than 3mb. The current script is as follows. This is converting the files but placing them in the root folder, and will duplicate the conversion when the script runs again.
function importXLS(){
var files = DriveApp.getFolderById('1hjvNIPgKhp2ZKIC7K2kxvJjfIeEYw4BP').searchFiles('title != "nothing"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = { title : name+'_converted',
key : ID
}
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
}
}
}
You want to create the converted Google Spreadsheet files to "FolderB".
You want to delete the XLSX files in "FolderA" after the files were converted.
You want to achieve above using Google Apps Script.
If my understanding correct, how about this modification? In this modification, I modified your script.
Modification points:
You can directly create the file to the specific folder using the property of parents in the request body.
You can delete the file using Drive.Files.remove(fileId).
Modified script:
Before you use this script, please enable Drive API at Advanced Google services.
function importXLS(){
var folderBId = "###"; // Added // Please set the folder ID of "FolderB".
var files = DriveApp.getFolderById('1hjvNIPgKhp2ZKIC7K2kxvJjfIeEYw4BP').searchFiles('title != "nothing"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = {
title : name+'_converted',
parents: [{id: folderBId}] // Added
};
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
// Drive.Files.remove(ID); // Added // If this line is run, the original XLSX file is removed. So please be careful this.
}
}
}
Note:
If the number of XLSX files is large, the execution time might be over 6 minutes.
About // Drive.Files.remove(ID);, when you run this script, please be careful. Because the original XLSX files are completely deleted when the script is run. So I commented this. At first, please test the script using sample files.
References:
Files: insert
Files: delete

Google Apps Script Unzipping Files - Issues

I have a script that looks in a destination folder and unzips files to a new folder. All works perfect as long as the zip contains just one file; anymore and I only seem to unzip the first file.
Im pretty sure the line that's causing this is which is picking the first record in the array of files however I am not quite skilful enough to figure out how to get around this. Any help would be greatly appreciated
[var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);]
//Unzips all ZIP files in the folder
function Unzip() {
//Add folder ID to select the folder where zipped files are placed
var SourceFolder = DriveApp.getFolderById("14vRNV3FZJicplxeurycsfBHmETrUQBex")
//Add folder ID to save the where unzipped files to be placed
var DestinationFolder = DriveApp.getFolderById("1OJXkPrUqcqapsv366oCV_ZsvaECstKTn")
//Select the Zip files from source folder using the Mimetype of ZIP
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP)
//var ZIPFiles = SourceFolder.getFilesByName('MTTR.zip')
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
// Get the blob of all the zip files one by one
var fileBlob = ZIPFiles.next().getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]); //I think this line is where my issue is
}
Logger.log("Finished Unzipping files")
}
As what Rodrigo mentioned in the comments, you need to loop it on all the files. unZippedfile.length is the number of files in the zip file. Use a loop around the createFile method.
Code:
// loop to all zip files
while (ZIPFiles.hasNext()){
var fileBlob = ZIPFiles.next().getBlob();
var unZippedfile = Utilities.unzip(fileBlob);
// loop to all items inside the current zip file
for (i=0; i<unZippedfile.length; i++) {
var newDriveFile = DestinationFolder.createFile(unZippedfile[i]);
}
}
Output:
Note:
Sample output above show the unzipped files on the same directory as I instantiated both source and destination with the same directory ID.

Do not make copy of existing file in destination folder

I've been trying to copy contents from one folder to another folder in google drive using google app script. With some online help and documentation of google script, I was able to copy files from one folder to other but it copies all files from source folder to destination folder on time trigger, but I want only the new files to get copied in my destination folder and skip the present files that are already same in my source and destination folder.
I tried to check files by name before copying but couldn't find a way to compare files by name in two different folders of gdrive.
function CopyFiles() {
var SourceFolder = DriveApp.getFolderById('Sid');
var SourceFiles = DriveApp.getFolderById('Sid').getFiles();
var DestFolder = DriveApp.getFolderById('Did');
var DestFiles = DriveApp.getFolderById('Did').getFiles();
while (SourceFiles.hasNext())
{
var files = SourceFiles.next();
var dfiles = DestFiles.next();
if ( files == dfiles){
file.setTrashed(true);}
else{
var f = files.makeCopy(DestFolder);
}
}
}
What I want to achieve is that Script compares files by name in destination folder and if files by that name already exist than skip else, create a copy of that new file in the destination folder.
Copies files from source to destination if destination does have the same file names
In this version no files get trashed.
function CopyFiles() {
var srcFldr=DriveApp.getFolderById('srcId');
var srcFiles=srcFldr.getFiles();
var desFldr=DriveApp.getFolderById('desId');
var desFiles=desFldr.getFiles();
var dfnA=[];
while(desFiles.hasNext()) {
var df=desFiles.next();
dfnA.push(df.getName());
}
while(srcFiles.hasNext()) {
var sf=srcFiles.next();
if(dfnA.indexOf(sf.getName())==-1) {
sf.makeCopy(sf.getName(),desFldr);
}
}
}

Download Folder as Zip Google Drive API

I currently have a Google App Script in Google Sheet that gives me the URL of a folder, which I can then use to download. Though it is an extra step I would like to remove, and get the URL of the zipped content directly.
Here's my code (google app script):
function downloadSelectedScripts() {
// ...
var scriptFiles = getScriptFiles(scriptFileNames)
var tempFolder = copyFilesToTempFolder(scriptFiles)
Browser.msgBox(tempFolder.getUrl())
}
function copyFilesToTempFolder(files) {
var tempFolder = DriveApp.getFolderById(FOLDERS.TEMP)
var tempSubFolder = tempFolder.createFolder('download_' + Date.now())
for (var i in files) {
var file = files[i]
file.makeCopy(file.getName(), tempSubFolder)
}
return tempSubFolder
}
You want to compress all files in a folder as a zip file.
The folder has no subfolders.
All files are only text files.
The total size of all files is less than 50 MB.
You want to retrieve the URL for downloading the zip file.
If my understanding is correct, how about this sample script? The flow of this script is as follows.
Retrieve folder.
Retrieve blobs of all files in the folder.
Compress blobs and retrieve a blob of zip.
Create a zip blob as a file.
Retrieve URL for downloading.
Sample script:
When you use this script, please set the folder ID of folder that you want to compress.
function myFunction() {
var folderId = "###"; // Please set the folder ID here.
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFiles();
var blobs = [];
while (files.hasNext()) {
blobs.push(files.next().getBlob());
}
var zipBlob = Utilities.zip(blobs, folder.getName() + ".zip");
var fileId = DriveApp.createFile(zipBlob).getId();
var url = "https://drive.google.com/uc?export=download&id=" + fileId;
Logger.log(url);
}
Result:
The direct link of the zip file is returned as follows.
https://drive.google.com/uc?export=download&id=###
Note:
In the current stage, unfortunately, the folders cannot be included in the zip data with Google Apps Script.
In this sample script, the filename of zip file is the folder name. So please modify it for your situation.
If you want to download the zip file without login to Google, please share the file.
Reference:
zip(blobs, name)