Google App - check if file exists already? - google-apps-script

i use this code in upload form (google scripts):
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
however, i want to check if file exist with same name, then dont upload. How to do that?

Well that's simple enough. All you need to do is use the getFilesByName() and the use the hasNext() to see if any files were found:
var file = DriveApp.getFilesByName('name of file to upload')
var chk = file.hasNext()
if (chk === true) return 1
if a file with the name was found, then hasNext() will return true. That means that we need to stop the script. You can do throw instead of a return, but that is up to you. The whole thing can also be in one line
if DriveApp.getFilesByName('filename').hasNext() === true) return 1

Related

Google App Script Randomly Stopped Working - TypeError: Cannot read properties of undefined (reading 'streams') (line 6)

This Google Apps Script code to scrape press release news from Yahoo Finance randomly stopped working today.
It suddenly gives the following error -
TypeError: Cannot read properties of undefined (reading 'streams') (line 6)
function pressReleases(code) {
var url = 'https://finance.yahoo.com/quote/'+code+'/press-releases'
var html = UrlFetchApp.fetch(url).getContentText().match(/root.App.main = ([\s\S\w]+?);\n/);
if (!html || html.length == 1) return;
var obj = JSON.parse(html[1].trim());
var res = obj.context.dispatcher.stores.StreamStore.streams["YFINANCE:"+code+".mega"].data.stream_items[0].title;
return res || "No value";
}
Code in Cell (with the stock symbol in cell A6)
=pressReleases(A6)
I can still retrieve JSON using python and the format of the data in the JSON is the exact same so I'm guessing it's a problem with Google Apps Script but I'm having no luck in fixing it.
The JSON output is here: https://privatebin.net/?4064ef5520f5b445#FDiJS868e3xSsgzh3y8LsF72LsefyoZ635kqCx62ZtwH
Any help as to why it suddenly stopped working would be appreciated.
Your showing script is from this answer? When I saw the HTML, it seems that in the current stage, the data is converted with the salted base64. In this case, I would like to propose an answer by reflecting on the method of this answer.
Usage:
1. Get crypto-js.
Please access https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js. And, copy and paste the script to the script editor of Google Apps Script, and save the script.
2. Modify script.
function pressReleases(code) {
var url = 'https://finance.yahoo.com/quote/' + code + '/press-releases'
var html = UrlFetchApp.fetch(url).getContentText().match(/root.App.main = ([\s\S\w]+?);\n/);
if (!html || html.length == 1) return;
var obj = JSON.parse(html[1].trim());
// --- I modified the below script.
const { _cs, _cr } = obj;
if (!_cs || !_cr) return;
const key = CryptoJS.algo.PBKDF2.create({ keySize: 8 }).compute(_cs, JSON.parse(_cr)).toString();
const obj2 = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(obj.context.dispatcher.stores, key)));
var res = obj2.StreamStore.streams["YFINANCE:" + code + ".mega"].data.stream_items[0].title;
// ---
return res || "No value";
}
When this script is used and code is PGEN, the value of Precigen to Present at the 41st Annual J.P. Morgan Healthcare Conference is obtained.
Note:
If you want to directly load crypto-js, you can also use the following script. But, in this case, the process cost becomes higher than that of the above flow. Please be careful about this.
const cdnjs = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText());
I can confirm that this method can be used for the current situation (December, 21, 2022). But, when the specification in the data and HTML is changed in the future update on the server side, this script might not be able to be used. Please be careful about this.
Reference:
crypto-js
I believe match returns an array so perhaps you need
var html = UrlFetchApp.fetch(url).getContentText().match(/root.App.main = ([\s\S\w]+?);\n/)[index];
Oh I missed the fact that your using it in a conditional on the very next line and then in the next line you're using the index of one.
var obj = JSON.parse(html[1].trim());
so the problem must be either in a data variation or this line var res = obj.context.dispatcher.stores.StreamStore.streams["YFINANCE:"+code+".mega"].data.stream_items[0].title;

Google Apps Script opening a document by name?

I'm trying to make a program where if a document doesn't exist yet, create it, but if it does, edit it.
I tried to do it like this:
if(check == false){
var doc = DocumentApp.create('Announcements for '+ data[0][2]);
}
else{
var doc = DocumentApp.openById('Announcements for '+ data[0][2]);
}
Here, 'check' is true when the file exists, and false if it doesn't.
I'm assuming that the problem is that I'm using 'openById' incorrectly.
What is the document id, and how can my code know what it is?
Thanks in advance!
(First-time user here, sorry for any formatting errors)
edit: I'll be making multiple docs, and all I know about the doc I need to open is its name
The parameter of openById() is the file id of the document you are trying to access. File id is the value between the "/d/" and the "/edit" of your Google Document URL.
Example: https://docs.google.com/document/d/12345/edit where 12345 is the id.
DocumentApp does not have method for opening documents using file name. The only available methods are openById() and openByUrl().
An alternative is to use DriveApp to get the name, id, and mimetype of the files inside your Drive or Drive folder.
Example:
The code below will open a document if it matches the fileName 'Announcement 1' :
Code:
function openByName() {
//open specific folder and get the files
var files = DriveApp.getFolderById('insert folder id here').getFiles();
var fileName = 'Announcement 1';
//The code below will search for Announcement 1 file and open it if found.
while (files.hasNext()) {
var file = files.next();
var fileType = file.getMimeType();
//Check if the filename matches 'Announcement 1' and the file type should be google-apps.document
if(file.getName() == fileName && fileType == 'application/vnd.google-apps.document'){
//Open document
DocumentApp.openById(file.getId());
}
}
}
Test Folder:
References:
Class DocumentApp
Class DriveApp

Google Apps Script - get URL of File in Drive with File Name

I am attempting to create a form in Google Spreadsheets which will pull an image file from my Drive based on the name of the file and insert it into a cell. I've read that you can't currently do this directly through Google Scripts, so I'm using setFormula() adn the =IMAGE() function in the target cell to insert the image. However, I need the URL of the image in order to do this. I need to use the name of the file to get the URL, since the form concatenates a unique numerical ID into a string to use the standardized naming convention for these files. My issue is that, when I use getFilesByName, it returns a File Iteration, and I need a File in order to use getUrl(). Below is an snippet of my code which currently returns the error "Cannot find function getUrl in object FileIterator."
var poNumber = entryFormSheet.getRange(2, 2);
var proofHorizontal = drive.getFilesByName('PO ' + poNumber + ' Proof Horizontal.png').getUrl();
packingInstructionsSheet.getRange(7, 1).setFormula('IMAGE(' + proofHorizontal + ')');
If you know the file name exactly, You can use DriveApp to search the file and getUrl()
function getFile(name) {
var files = DriveApp.getFilesByName(name);
while (files.hasNext()) {
var file = files.next();
//Logs all the files with the given name
Logger.log('Name:'+file.getName()+'\nUrl'+ file.getUrl());
}
}
If you don't know the name exactly, You can use DriveApp.searchFiles() method.
You're close - once you have the FileIterator, you need to advance it to obtain a File, i.e. call FileIterator.next().
If multiple files can have the same name, the file you want may not be the first one. I recommend checking this in your script, just in case:
var searchName = "PO + .....";
var results = DriveApp.getFilesByName(searchName);
var result = "No matching files";
while (results.hasNext()) {
var file = results.next();
if (file.getMimeType() == MimeType. /* pick your image type here */ ) {
result = "=IMAGE( .... " + file.getUrl() + ")");
if (results.hasNext()) console.warn("Multiple files found for search '%s'", searchName);
break;
}
}
sheet.getRange( ... ).setFormula(result);
You can view the available MimeTypes in documentation

Google Apps Script, create a csv file and keep appending

I'd like to create a csv file by appending to the file, rather than create file in one go. Is that possible?
DriveApp.createFile uses one go creation. Can there be problems where I read a huge number of records and would rather grab so many records and append to file? Is there a limit to the size of array I create in google apps script ? I am thinking of going over half a million records in csv file. Thanks.
Google Apps Script does not have an "append" method using Drive API,
You can create a file and then update it's entire content like below:
function appendDataToCSV(content){
var fileId = '', // update this file with it's ID
csvFile = DriveApp.getFileById(fileId),
currentFileContent = "",
stringContent = "",
delimiter = ";";
//in case your content is a 2D array like:
// [[1,2,3,4],[5,6,7,8]]
if(content instanceof Array){
for(var i=0;i<content.length;i++){
stringContent += (content[i].join ? content[i] : content).join(delimiter);
}
}
stringContent = stringContent || content || "";
if(stringContent){
// get file's current text content
currentFileContent = csvFile.getBlob().getDataAsString();
// update the csv file with its previous content + the new one adding a new row between
csvFile.setContent(currentFileContent + "\n" + stringContent);
}
return "CSV File updated! New size: "+csvFile.getSize();
}
But, it has a 10MB max file size limitation;
Best regards!

Overwrite an Image File with Google Apps Script

Can I overwrite an image file with Google Apps Script? I've tried:
file.setContent(newBlobImage);
file.replace(newBlobImage);
Neither of those work. .setContent() will delete whatever data was in the file, and it looks like maybe it just writes the variable name as text, or something like that. I'm assuming that both .setContent() and .replace() are meant for text documents, and maybe that's why they don't work.
If it were a text file, or a spreadsheet, I might be able to clear it, then append new content.
I can trash the file, then create a new one, but I'd rather not if there is some other way.
If I write a file with the same name, it won't overwrite the existing file, it creates a another file with the same name.
The only way I've been able to trash the file is with DocsList and the only success I've had with creating an image file is with DriveApp. So I have to trash the file with DocsList, then create another file with DriveApp.
Well, I've figured out how to delete the file without sending it to the trash, so I won't need to clean out the trash later. The Google Drive SDK inside of Apps Script has a remove method that didn't send the file to trash, it's just gone.
var myFolder = DriveApp.getFolderById('3Bg2dKau456ySkhNBWB98W5sSTM');
thisFile = myFolder.getFilesByName(myFileName);
while (thisFile.hasNext()) {
var eachFile = thisFile.next();
var idToDLET = eachFile.getId();
Logger.log('idToDLET: ' + idToDLET);
var rtrnFromDLET = Drive.Files.remove(idToDLET);
};
So, I'm combining the DriveApp service and the DriveAPI to delete the file without sending it to the trash. The DriveAPI .remove needs the file ID, but I don't have the file ID, so the file gets looked up by name, then the file ID is retrieved, then the ID is used to delete the file. So, if I can't find a way to overwrite the file, I can at least delete the old file without it going to the trash.
I just noticed that the DriveAPI service has a Patch and an Update option.
.patch(resource, fileId, optionalArgs)
Google Documentation Patch Updates file metadata.
The resource arg is probably the metadata. The fileId is self explanatory. I'm guessing that the optionalArgs are parameters that follow the HTTP Request Patch semantics? I don't know.
It looks like both Patch and Update will update data. Update is a PUT request that will
clears previously set data if you don't supply optional parameters.
According to the documentation. So it's safer to use a Patch request because any parameters that are missing are simply ignored. I haven't tried it yet, but maybe this is the answer.
I'm getting an error with Patch, so I'll try Update:
.update(resource, fileId, mediaData)
That has a arg for mediaData in the form of a blob. And I think that is what I need. But I'm not sure what the resource parameter needs. So I'm stuck there.
An image file can be overwritten with Google Apps Script and the DriveAPI using the update() method:
.update(File resource, String fileId, Blob mediaData)
Where file resource is:
var myFileName = 'fileName' + '.jpg';
var file = {
title: myFileName,
mimeType: 'image/jpeg'
};
I'm getting the file ID with the DriveApp service, and the Blob is what was uploaded by the user.
In order to use DriveAPI, you need to add it through the Resources, Advanced Google Services menu. Set the Drive API to ON.
var allFilesByName,file,myFolder,myVar,theFileID,thisFile;
//Define var names without assigning a value
file = {
title: myFileName,
mimeType: 'image/jpeg'
};
myFolder = DriveApp.getFolderById('Folder ID');
allFilesByName = myFolder.getFilesByName(myFileName);
while (allFilesByName.hasNext()) {
thisFile = allFilesByName.next();
theFileID = thisFile.getId();
//Logger.log('theFileID: ' + theFileID);
myVar = Drive.Files.update(file, theFileID, uploadedBlob);
};
Thank you for this track !
This allowed me to find a solution to my problem : move a bound form after copying and moved his spreadsheet.
The Drive app advanced service must be activated in the "Resource Script Editor" to run this script.
function spreadsheetCopy() {
// Below is the file to be copied with a bound form.
var fileToCopy = DriveApp.getFileById("file_key"); // key is fileId
var saveFolder = DriveApp.getFolderById("folder_key"); // key is folderId
var currentFolder = "";
( fileToCopy.getParents().next() ) ? currentFolder = fileToCopy.getParents().next() : currentFolder = DriveApp.getRootFolder();
Logger.log(currentFolder)
var copyFile = fileToCopy.makeCopy(saveFolder),
copyName = copyFile.getName();
Utilities.sleep(30000);
moveFormCopy(currentFolder, saveFolder, copyName);
}
function moveFormCopy(currentFolder, saveFolder, copyName) {
var formsInFolder = currentFolder.getFilesByType(MimeType.GOOGLE_FORMS);
var form, copyForm, copyFormMimeType, copyFormName, copyFormId;
while ( formsInFolder.hasNext() ) {
form = formsInFolder.next();
if ( copyName === form.getName() ) {
copyForm = form;
copyFormMimeType = copyForm.getMimeType();
copyFormName = copyForm.getName();
copyFormId = copyForm.getId();
break;
}
};
var resource = {title: copyName, mimeType: copyFormMimeType};
Drive.Files.patch(resource, copyFormId, {addParents: saveFolder.getId(), removeParents: currentFolder.getId()})
}