4
votes

I'm trying to write a Google Apps Script to download all files in a particular Drive folder (likely .csv files). I have found the getDownloadUrl() method but I haven't been able to figure out what to do with it. I'm currently trying the following code, where files is the list of the files in the folder:

while(files.hasNext()) {
  var response = UrlFetchApp.fetch(files.next().getDownloadUrl());
  Logger.log(response.getContentText());
}

When I try to run the code, however, I get a 401 error which I guess means I lack the proper authorization? But I was under the impression that I wouldn't need to go through all of the OAuth2 steps if everything was taking place within my one Google account. The Google guide to connecting to external APIs makes it look like I should be able to just fetch the url. I've already gotten access to my Drive files, because the download URL does exist when I run that method. What am I missing here? I'm really new to all of this so maybe it's something basic.

Thanks!

EDIT: I managed to fix the 401 error by modifying the code as follows:

while(files.hasNext()) {
  var response = UrlFetchApp.fetch(files.next().getDownloadUrl(),{headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
  Logger.log(response.getContentText());
}

But the issue remains that this only returns the contents to me, rather than downloading the file. How can I initiate a download from the results of this fetch call?

5

5 Answers

1
votes

Besides listing all download links, I guess original poster also wants to download files to user's computer (according to earlier discussion).

To do this, encode blob with base 64 in server side (e.g. Google App Script) and download with data URI in client's browser. Below are code for this, with help of this answer.

Google App Script

...

function getBlobInBase64(fileId){
  // omit authorization code if any

  var file = DriveApp.getFileById(fileId);
  var blob = file .getBlob();
  
  return {
    file_name: file.getName(),
    mime: file.getMimeType(),
    b64: Utilities.base64Encode(blob.getBytes());
}

...

Javascript that serve with index.html

...

function getFile(fileId){
  google.script.run.withSuccessHandler((data) => {

    var uri = 'data:' + data.mime + ';charset=ISO-8859-1;base64,' + encodeURIComponent(data.b64);
    downloadURI(uri, data.file_name);

  }).withFailureHandler((err) => {
    console.log(err);
  }).getBlobInBase64();
}

...

NOTE: I haven't run this code but the method should work as used in my other project.

0
votes

This will log the file names & URLS for any files available for downloading (first 100 in root drive):

function myFunction() {
  var files = DriveApp.getFiles();
  var c = 0;
  while (files.hasNext() && c<100) {
    var file = files.next();
    Logger.log("File Name: " + file.getName());
    Logger.log("  Download URL: " + file.getDownloadUrl());
    c++;
  }
}
0
votes

My answer might be a bit off but I think you have a better chance downloading files from Google Drive using the webContentLink as it is the method I commonly use. I obtain webContentLink by using Files.list and ask for webContentLink in the fields parameter. I run that link through the browser and it downloads the file.

0
votes

If you are trying to download Google Drive files to local computer using Google Apps Script, Then please understand that Google Apps Script is a server side scripting language. It can't download and save files to your local drive.

0
votes

Here is a webapp that may be helpful for you. It does not do exactly what you are looking for but you may be able to edit it and get a result. Hope it helps!

CODE:

function doGet(e) { // main function
  var template = HtmlService.createTemplateFromFile('index.html'); // filename always!
  return template.evaluate().setTitle('Search Drive').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

// Process the form
function processForm(searchTerm) {
  var resultToReturn;
  Logger.log('processForm was called! ' + searchTerm);
  resultToReturn  = SearchFiles(searchTerm); // Call to the search files function to search files on google drive
  Logger.log('resultToReturn: ' + resultToReturn);
  return resultToReturn; // return the results
}

function SearchFiles(searchTerm) {
  var searchFor ="title contains '" + searchTerm + "'"; //single quotes are needed around searchterm
  var owneris ="and '[email protected]' in Owners"; //email address to search for 
  var names = [];
  Logger.log(searchFor + " " + owneris);
  var files = DriveApp.searchFiles(searchFor + " " + owneris); 
  while (files.hasNext()) {
    var file = files.next();
    var fileId = file.getId();// To get FileId of the file
    var lm = file.getLastUpdated();
    var name = file.getName()+"|~|"+fileId+"|~|"+lm; // Im concatenating the filename with file id separated by |~|
    names.push(name); // adding to the array
  }
  return names; // return results
}

INDEX.html

<html>
  <head>
    <base target="_top">
    <script>
      function displayMessage() {
        var searchTerm;
        searchTerm = document.getElementById('idSrchTerm').value;
        console.log('searchTerm: ' + searchTerm );
        // Below call means: call to processForm passing the searchTerm value (previously escaped) and after finish call the handleResults function
         google.script.run.withSuccessHandler(handleResults).processForm(searchTerm.replace("'","\'")); 
       }
         
        
      function handleResults(results){
         console.log('Handle Results was called! ');
         document.writeln('<a href="http://LINKBACKTOYOURSCRIPT">BACK</a><br/><br/>');
         var length=results.length; // total elements of results
         for(var i=0;i<length;i++)
         {
         var item=results[i];
         item=item.split("|~|"); // split the line |~|, position 0 has the filename and 1 the file id
         
         document.writeln("<b><a href='https://docs.google.com/document/d/"+item[1]+"' target='_blank'>"+item[0]+"</b></a> (Last modified: "+item[2]+")<br/><br/>"); // write result
        
        }
        document.writeln("End of results...");
       }


    </script>
  </head>
  <body><center><br/>
    Search: <input type="text" id="idSrchTerm" name="search">
    <input type="button" value="search files on Google Drive" name="submitButton" onclick="displayMessage()"/>
</center>
  </body>
</html>