I am trying to create a function in Google Apps Script that finds the file path of the folder.
Here is the error: TypeError: Cannot read property 'appendParagraph' of null (line 20, file "Code")
function getRoot() {
var doc = DocumentApp.getActiveDocument();
var header = DocumentApp.getActiveDocument().getHeader();
var name = doc.getName();
var id = doc.getId();
var txt = "Master Folder";
var parents = [];
var folders = DriveApp.getFileById(id).getParents();
while (folders.hasNext()){
var parent = folders.next();
var n = parent.getName();
parents.push(n);
}
var pLen = parents.length;
for (i = 0; i < pLen; i++){
txt = txt + "//" + parents[i];
}
var headerPar = header.appendParagraph(txt);
}
I believe your goal as follows.
You want to know the reason of the error message of TypeError: Cannot read property 'appendParagraph' of null.
You want to remove the error.
You want to retrieve the folder path of the active Google Document.
For this, how about this answer?
Modification points:
In your script, I think that the reason of your error message is the header is not existing in the Google Document. By this, header retrieved by getHeader() is null, and then, the error occurs. So in this case, please add the header using addHeader().
doc of var doc = DocumentApp.getActiveDocument(); can be used for getHeader().
If you want to retrieve the folder path from the root folder, I think that your script is required to be modified. In your current script, when the Google Document is put in the nested folders, only parent of the Document is retrieved.
When your script is modified using above points, it becomes as follows.
Modified script:
function getRoot() {
var doc = DocumentApp.getActiveDocument();
var header = doc.getHeader() || doc.addHeader(); // Modified
var name = doc.getName();
var id = doc.getId();
var txt = "Master Folder";
var parents = [];
var folders = DriveApp.getFileById(id).getParents();
// --- I modified below script
while (folders.hasNext()) {
var folder = folders.next();
parents.push(folder.getName());
folders = folder.getParents();
}
parents = parents.reverse();
// ---
var pLen = parents.length;
for (i = 0; i < pLen; i++){
txt = txt + "//" + parents[i];
}
var headerPar = header.appendParagraph(txt);
}
By this modification, when the header is existing, doc.getHeader() is used. When the header is not existing, doc.addHeader() is used. And, when the active Document is put to the folder path like root -> folder1 -> folder2, Master Folder//MyDrive//folder1//folder2 is put to the header.
References:
getHeader()
addHeader()
Related
I'm stuck into trouble trying to read an HTML file from a Google Drive. So
I tried :
to get a text with a help of UrlFetchApp.fetch("https://googledrive.com/host/{folderID}/{filename}.html"), but it fetches some google css file instead of mine.
to convert a file from blob to a text string with file.getAs(MimeType.PLAIN_TEXT), and it just outputs "Blob" without any file content. How can I extract a file text without any specific libraries?
var dApp = DriveApp;
var folderIter = dApp.getFoldersByName("Лаборатории ФББ");
var folder = folderIter.next();
var filesIter = dApp.getFilesByName("Labs.html");
var filelist = [];
var propfiledate = 0;
var propfilename;
while(filesIter.hasNext()){
var file = filesIter.next();
var filename = file.getName();
var fileurl = file.getUrl();
var filedate = file.getDateCreated();
if(filedate >= propfiledate){
var propfiledate = filedate;
var propfileurl = fileurl;
var propfilename = filename;
var propfile = file;
}
}
Logger.log(propfile);
// 1st try var myHtmlFile = UrlFetchApp.fetch(propfileurl);
// 2nd try var myHtmlFile = propfile.getAs(MimeType.PLAIN_TEXT);
// 3rd try var myHtmlFile = propfile.getBlob().text();
var ss = SpreadsheetApp.create("test");
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = ss.getActiveSheet();
sheet.appendRow(myHtmlFile.toString().split("\n"));
Logger.log(propfiledate);
Logger.log(propfilename);
Logger.log(propfileurl);
}
Using Apps Script on a dummy HTML file, you can get the HTML data that is inside of it.
Using DriveApp getFilesByName(name) method you retrieve the file by the name.
This will return a FileIterator since there can be many files with similar names.
Then you can get the file blob with getBlob() and the blob data as a string with getDataAsString()
I have managed to get the dummyHTML.html file data by using this previously mentioned methods:
function myFunction() {
var files = DriveApp.getFilesByName("dummyHTML.html");
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getBlob().getDataAsString());
}
}
I'm trying to upload multiple files into Google Drive Using Google Apps Script.
My code work fine when I want to upload one file
// UPLOAD IMG IN GOOGLE DRIVE
var url = 'http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png';
var response = UrlFetchApp.fetch(url); // get api endpoint
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob)
var img = file_img.getUrl();
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow([img]);
I'm trying to modify the above script in order to upload multiple files into google drive, but my code doesn't works.
This is my (not working) code:
// UPLOAD IMG IN GOOGLE DRIVE
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
for(var i=0; i<url.length; i++){
var response = UrlFetchApp.fetchAll(url);
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob[i])
var img = file_img.getUrl()[i];
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow(img[i]);
}
TypeError: response.getResponseCode is not a function
Any help?
Modification points:
In your script, for(var i=0; i<url.length; i++){}else{} is used. I thought that you might misunderstand the if statement and for loop.
When you want to compare the value at the if statement, please modify if(rc=200){ to if(rc==200){.
The response value from UrlFetchApp.fetchAll(url) is an array.
I think that the reason of the error message is this.
folder.createFile(fileBlob[i]) is folder.createFile(fileBlob).
file_img.getUrl()[i] is file_img.getUrl().
When file_img.setTrashed(true) is used, the downloaded files are moved to the trashbox. If you don't want to move them to the trashbox, please remove the line.
I think that when the values are put to the Spreadsheet by one request, the process cost will be low. In your script, I would like to propose to use setValues instead of appendRow.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please copy and paste the following modified script. And please set the variable of sheet, and the folder ID.
function myFunction() {
// var sheet = SpreadsheetApp.getActiveSheet();
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
var requests = url.map(u => ({url: u, muteHttpExceptions: true}));
var response = UrlFetchApp.fetchAll(requests);
var imgs = [];
for (var i = 0; i < response.length; i++) {
if (response[i].getResponseCode() == 200) {
var fileBlob = response[i].getBlob();
var folder = DriveApp.getFolderById("xxxxxx");
if (folder != null) {
var file_img = folder.createFile(fileBlob);
imgs.push([file_img.getUrl()]);
// file_img.setTrashed(true); // When this script is used, the downloaded files are moved to the trashbox.
}
}
}
if (imgs.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, imgs.length).setValues(imgs);
}
}
When muteHttpExceptions: true is used, the script can be run even when an error occurs.
References:
fetchAll(requests)
if...else
Loops and iteration
The next script what it does is to search all the spreadsheets with a certain name in the drive starting from a certain folder.
function searchSSH(folder, path) {
if (folder == null && path == null) {
return
searchSSH(DriveApp.getFolderById("ID"), "");
}
var files = [];
path = path + "/" + folder.getName();
var searchFile = "fullText contains 'Project <>' and mimeType='" + MimeType.GOOGLE_SHEETS + "'";
var fileIterate = folder.searchFiles(searchFile);
while ( fileIterate.hasNext() ) {
var file = fileIterate.next();
var fileId = file.getId();
var name = file.getName();
files.push(name);
for (var i=0; i<files.length; i++){
Logger.log(files[i]);
}
}
var folderIterate = folder.getFolders();
while(folderIterate.hasNext()) {
var searchFold = searchSSH(folderIterate.next(), path);
for (var i = 0; i < searchFold.length; i++) {
files.push(searchFold[i]);
}
}
return files;
}
What I am trying to do is to see how I can do it so that I can also look for a certain folder just like the searchFile does and I try to do it like this...
function searchSSH() {
var Folder = DriveApp.getFolderById("ID");
var folders = Folder.searchFolders('fullText contains "project"');
while (folders.hasNext()) {
var folder1 = folders.next();
Logger.log(folder1.getName());
for (var i = 0; i < folder1.length; i++) {
files.push(folder1[i]);
}
}
var files = [];
var searchFile = "fullText contains 'test <>' and mimeType='" + MimeType.GOOGLE_SHEETS + "'";
var fileIterate = Folder.searchFiles(searchFile);
while ( fileIterate.hasNext() ) {
var file = fileIterate.next();
var fileId = file.getId();
var name = file.getName();
files.push(name);
for (var i=0; i<files.length; i++){
Logger.log(files[i]);
}
}
return files;
}
But doesn´t works. What I'm trying to do is to iterate through all the folders until I find the folder with the name project and keep iterating in that folder until I find all the spreadsheets with the test name but only search in the first folder.
I try to iterate between folders until I find the folder with the name Project and inside that folder keep iterating until I find the file with the name Test and that it is type spreadsheet.
The first script if it finds the file but I want to specify I look inside the folders with the name Project to improve the performance of the script
The second script I'm trying is not iterating, so it does not work because when I run it, it only finds the first folder and dont searching inside the others folders, Thanks for trying to help me. I hope that now it has given me to understand
From your this reply, I could understand as follows.
You want to retrieve Spreadsheet with the filename of Test under the folder with the name of Project. You want to do this with low process cost.
If my understanding is correct, how about these sample scripts? Please choose from them for your situation. I think that there are several answers for your situation. So please think of this answer as one of them.
Pattern 1:
Flow:
Retrieve files from filename of Test using getFilesByName().
Retrieve parent folders of each file using getParents().
If the folder name is Project and the mimeType is Spreadsheet, it retrieves the file.
Sample script:
var fileName = "Test";
var folderName = "Project";
var files = DriveApp.getFilesByName(fileName);
while (files.hasNext()) {
var file = files.next();
var parents = file.getParents();
while (parents.hasNext()) {
var parent = parents.next();
if (file.getMimeType() == MimeType.GOOGLE_SHEETS && parent.getName() == folderName) {
// do something
}
}
}
Pattern 2:
Flow:
Retrieve folders from folder name of Project using getFoldersByName().
Retrieve files in each folders using getFilesByName().
If the filename is Test and the mimeType is Spreadsheet, it retrieves the file.
Sample script:
var fileName = "Test";
var folderName = "Project";
var folders = DriveApp.getFoldersByName(folderName);
while (folders.hasNext()) {
var folder = folders.next();
var files = folder.getFilesByName(fileName);
while (files.hasNext()) {
var file = files.next();
if (file.getMimeType() == MimeType.GOOGLE_SHEETS && file.getName() == fileName) {
// do something
}
}
}
Pattern 3:
Flow:
Retrieve folder IDs of folder name of Project using getFoldersByName().
Retrieve files with the parent folder of Project and the filename of Test and the mimeType of Spreadsheet using searchFiles().
Sample script:
var fileName = "Test";
var folderName = "Project";
var folders = DriveApp.getFoldersByName(folderName);
var folderIds = [];
while (folders.hasNext()) {
folderIds.push(folders.next().getId());
}
folderIds.forEach(function(id) {
var params = "'" + id + "' in parents and title='" + fileName + "' and mimeType='" + MimeType.GOOGLE_SHEETS + "'";
var files = DriveApp.searchFiles(params);
while (files.hasNext()) {
var file = files.next();
// do something
}
});
References:
getFilesByName()
getFoldersByName()
getParents()
searchFiles()
If these were not what you want, I'm sorry.
I'm trying to create a basic script on a 12-hour timer trigger that loops through each of my Google Calendars by their ICAL URL, and downloads the ICAL for a folder on my Google Drive (for backup purposes). It throws this error
"No item with the given ID could be found, or you do not have permission to access it. (line 23, file "Code")" (Line #23 is var folder... )
Running the script does download and save the ICAL file on the first run through the loop (and if I manually pass in each unique ICAL URL one at a time), but the error then terminates the loop. Seeing as how I've authorized access already and am the owner of everything here, I'm not sure what else I need.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL,folder) {
var fileName = "";
var fileSize = 0;
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DriveApp.getFolderById(folder); // << returns a permissions error thus terminating the for loop
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Updated: You are also re-initializing a variable that already exists from the parameters and as a global variable so we can remove the parameter if you want to keep the global variable.
We can also move the place where you get the Google Folder object. It stays the same every time so we don't need to retrieve it again.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL) {
var fileName = "";
var fileSize = 0;
var gfolder = DriveApp.getFolderById(folder);
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var file = gfolder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Let see where that gets us.
Your "folder" variable is outside the function, causing the data to be inaccessible to the "downloadFile" function.
Google apps coding seems to require variables to be in a function to be defined. I would recommend moving both "calendarsToSave" and "folder" to the inside of "downloadFile"
Here is an example that will return your error:
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
function myFunction() {
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}
And here is one that will return the file name:
function myFunction() {
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}
I have a Folder With more than 2000 Files.. And i Need to make a List of all these files on google spreadsheet.. I Found online some Scripts.. but they're not completely working.
When i hit "RUN" i just get a list of 250 Files.
Reading on Google Developers page i found some things about enabling Google Drive advanced services (and i did it)..
And i think i could solve this problem using something named "tokens"??
I don't know.. i'm not a programmer, and i barely know english..
i Tried editing this script making a fusion of what i found online.. But anything works.. i just get errors that i can't even understand..
So.. is there someone able to fix it?
function listFilesInFolder() {
var folder = DocsList.getFolder("Film");
var contents = folder.getFiles();
var file;
var data;
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(["Nome", "Data", "Dimensione"]);
for (var i = 0; i < contents.length; i++) {
file = contents[i];
if (file.getFileType() == "SPREADSHEET") {
continue;
}
data = [
file.getName(),
file.getDateCreated(),
file.getSize(),
];
sheet.appendRow(data);
}
};
This Script works for at least 2200 Files :)
function listFilesInFolder(id) {
var folder = DriveApp.getFolderById('MyFolderID');
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()
data = [name, date, size]
sheet.appendRow(data);
}
};
The answer above appends a row in every iteration wich is particularly slow and there is a chance you will exceed the maximum execution time (see best practices)) so here is a version that uses an array to collect data and writes the array using a single setValues() .
The other issue is that it gets all the files in your drive, not in the folder you chose...
so below is a version that gets all files that are not Google documents, ie it counts only files that take space (images, pdf...) with a maximum of 4000 files.
full code below :
function listFilesInFolder() {
var folder = DocsList.getFolderById('0B3qSFd3iikE3MS0yMzU4YjQ4NC04NjQxLTQyYmEtYTExNC1lMWVhNTZiMjlhMmI');
var file;
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
var data = [];
data.push(["Name", "Data", "Size", "url"]);
var filesresult = folder.getFilesByTypeForPaging(DocsList.FileType.OTHER, 4000);
var files = filesresult.getFiles();
Logger.log(files.length);
for (var i in files) {
file = files[i];
data.push([
file.getName(),
file.getDateCreated(),
file.getSize(),
file.getUrl()
]);
}
sheet.getRange(1,1,data.length,data[0].length).setValues(data);
}
Paging is what you're looking for. When you have a large number of results (like 2000 files), you generally divide the request into 'pages', either to show the user page by page or in this case, to stay within the API limits.
The 'token' isn't a big deal.. it's just how your script remembers the page number while it's dealing with the current page.
So there's information about this here: https://developers.google.com/apps-script/reference/docs-list/files-result
The script at the top of the page is quite apt to your situation. Your script becomes something like...
function listFilesInFolder() {
var folder = DocsList.getFolder("Film");
//var contents = folder.getFiles();
var file;
//var data;
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(["Nome", "Data", "Dimensione"]);
var pageSize = 200;
var files = null;
var token = null; // use a null token for the first lookup
do {
var result = DocsList.getAllFilesForPaging(pageSize, token);
files = result.getFiles();
token = result.getToken();
for (var i = 0; i < files.length; i++) {
//Logger.log(files[i].getName());
file = files[i];
if (file.getFileType() == "SPREADSHEET") {
continue;
}
data = [
file.getName(),
file.getDateCreated(),
file.getSize(),
];
sheet.appendRow(data);
}
} while (files.length >= pageSize);
};
I'm not promising this will work.. but I'm sure you can sort it out. Basically the "while loop" on that page replaces the "for loop" from your script. The loop on that page just calls Logger.log(), so you swap that with the sheet.appendRow(data)
I've taken the script suggested by Jonathan Livingston and made some edits.
Now it:
can take a name of a sheet with future report. It can make a new sheet if it doesn't exist,
gives more parameters, including list of editors (e-mails)
Here's the code:
function TESTlistFilesInFolder() {
listFilesInFolder("0B0pifCWzjn-ib0ZWT2x1ekNOWAY", "Files Report");
// ^^^^^^^^ folder ID ^^^^^^^^^ ^sheet Name^
}
// original script: http://stackoverflow.com/a/25730522/5372400
function listFilesInFolder(id, sheetName) {
sheetName = sheetName || id;
var sheet = createSheetIfNotExists(sheetName);
var folder = DriveApp.getFolderById(id);
var contents = folder.getFiles();
sheet.clear();
sheet.appendRow(["Name", "CreatedDate", "Last Updated", "Id", "Url", "Editors", "Viewers", "Owner", "Access", "Permission", "Size"]);
var data = [];
var file;
var info = [];
while(contents.hasNext()) {
data = [];
file = contents.next();
data.push(file.getName());
data.push(file.getDateCreated());
data.push(file.getLastUpdated());
data.push(file.getId());
data.push(file.getUrl());
// convert to string: http://www.w3schools.com/jsref/jsref_join.asp
data.push(getEmails(file.getEditors()).join());
data.push(getEmails(file.getViewers()).join());
data.push(getEmails(file.getOwner()).join());
data.push(file.getSharingAccess());
data.push(file.getSharingPermission());
data.push(file.getSize());
info.push(data);
}
var rows = info.length;
var cols = info[0].length;
var range = sheet.getRange(2,1,rows,cols);
range.setValues(info);
};
function createSheetIfNotExists(name) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
try {ss.setActiveSheet(ss.getSheetByName(name));}
catch (e) {ss.insertSheet(name);}
var sheet = ss.getSheetByName(name);
return sheet;
}
// users: https://developers.google.com/apps-script/reference/base/user
function getEmails(users) {
var emails = [];
var user;
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray(users)) { users = [users]; }
for (var i = 0; i < users.length; i++) {
user = users[i];
emails.push(user.getEmail());
}
return emails;
}