Skip to content

Instantly share code, notes, and snippets.

@tanaikech
Last active December 27, 2023 04:13
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save tanaikech/c5b2811bce01cbcc26ffa357df496379 to your computer and use it in GitHub Desktop.
Save tanaikech/c5b2811bce01cbcc26ffa357df496379 to your computer and use it in GitHub Desktop.
Downloading Files From Google Drive Under No Authorization Using Browser

Downloading Files From Google Drive Under No Authorization Using Browser

This is a sample script for downloading files from Google Drive under no authorization using browser. By using this sample, you can make other users download files from your Google Drive. Even if the other users are not Google users, they can download the files.

Demo

This is a demonstration for downloading files from Google Drive under no authorization using browser. From the top document, You can see that an user who is not owner of Google Drive is downloading files.

Problems and Workaround

In order to download files from Google Drive under no authorization, there are some problems. When files are downloaded from Google Drive, it is necessary to use Download Link and Drive API.

  1. In the case of use the Download Link for each file, only owner of Google Drive can download the files, even if the permission of files are changed as the ANYONE.
  2. In the case of use the Drive API, users have to authorize at Google using OAuth2 process.

I have already known that files can download under no authorization using base64 and byte array. For these problems, I solved this using base64.

Sample Script

In order to use this sample script, it is necessary to deploy Web Apps. The how to deploy Web Apps is as follows.

  • On the Script Editor
    • File
    • -> Manage Versions
    • -> Save New Version
    • Publish
    • -> Deploy as Web App
    • -> At Execute the app as, select "your account"
    • -> At Who has access to the app, select "Anyone, even anonymous"
    • -> Click "Deploy"
    • -> Copy "Current web app URL"
    • -> Click "OK"

And then, please copy and paste following respective HTML and GAS to your script editor. You can use the sample for the script of both container-bound script and standalone script. Following image is the project pasted the sample script. You can see the 2 files in the project.

Script

HTML

Filename is index.html.

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>

<body>
    <div class="files">
        <form>
            <table class="table table-striped table-hover">
                <thead>
                    <tr>
                        <th>Download</th>
                        <th>FileName</th>
                        <th>Size[byte]</th>
                        <th>Parents</th>
                        <th>Updated</th>
                        <th>Created</th>
                    </tr>
                </thead>
                <tbody>
                    <? for (var i = 0; i < data.length; i++) { ?>
                        <tr>
                            <td>
                                <input type="checkbox" id="checkbox" name="fileId" value="<?= data[i].file_id  ?>" />
                            </td>
                            <td>
                                <?= data[i].file_name ?>
                            </td>
                            <td>
                                <?= data[i].file_size ?>
                            </td>
                            <td>
                                <?= data[i].folder_tree ?>
                            </td>
                            <td>
                                <?= data[i].file_updated ?>
                            </td>
                            <td>
                                <?= data[i].file_created ?>
                            </td>
                        </tr>
                        <? } ?>
                </tbody>
            </table>
            <div class="allchk">
                <input type="checkbox" id="allCheck01">
                <label for="allCheck01">Check All</label>
            </div>
            <input type="button" class="create" value="Download" onclick="google.script.run.withSuccessHandler(executeDownload).getparams(this.parentNode)">
        </form>
    </div>
    <a id="dl" target="_blank" href="#"></a>
</body>

<script>
$(function() {
    $('.table tr').click(function(event) {
        if (event.target.type !== 'checkbox') {
            $(':checkbox', this).trigger('click');
        }
    });

    $('.allchk input').click(function() {
        var files = $('.files').find('input');
        if ($(this).is(':checked')) {
            $(files).prop('checked', true);
        } else {
            $(files).prop('checked', false);
        }
    });
});

function executeDownload(base64dat) {
    $("#dl").prop("href", window.URL.createObjectURL(toBlob(base64dat))).prop("download", "dl_" + getfmtDate() + ".zip")[0].click();
}

function toBlob(base64) {
    var bin = atob(base64.replace(/^.*,/, ''));
    var buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
        buffer[i] = bin.charCodeAt(i);
    }
    try {
        var blob = new Blob([buffer.buffer], {
            type: 'application/zip'
        });
    } catch (e) {
        return false;
    }
    return blob;
}

function getfmtDate() {
    var dt = new Date();
    return dt.getFullYear().toString() +
        cd((dt.getMonth() + 1).toString()) +
        cd(dt.getDate().toString()) +
        "_" +
        cd(dt.getHours().toString()) +
        cd(dt.getMinutes().toString()) +
        cd(dt.getSeconds().toString());
};

function cd(dat) {
    return dat.length == 1 ? "0" + dat : dat;
};
</script>

</html>

Google Apps Script

Filename is code.gs.

var folderId = "### Folder ID ###"; // <--- Your shared folder ID

function doGet() {
    var t = HtmlService.createTemplateFromFile('index');
    t.data = getFileList();
    return t.evaluate();
}

function getparams(e) {
    return zipping(typeof(e.fileId) == "string" ? [e.fileId] : e.fileId);
}

function getFileList() {
    var folderlist = (function(folder, folderSt, results) {
        var ar = [];
        var folders = folder.getFolders();
        while (folders.hasNext()) ar.push(folders.next());
        folderSt += folder.getId() + "#_aabbccddee_#";
        var array_folderSt = folderSt.split("#_aabbccddee_#");
        array_folderSt.pop()
        results.push(array_folderSt);
        ar.length == 0 && (folderSt = "");
        for (var i in ar) arguments.callee(ar[i], folderSt, results);
        return results;
    })(DriveApp.getFolderById(folderId), "", []);
    var localTimeZone = Session.getScriptTimeZone();
    var filelist = [];
    var temp = {};
    for (var i in folderlist) {
        var folderid = folderlist[i][folderlist[i].length - 1];
        var folder = DriveApp.getFolderById(folderid);
        var files = folder.getFiles();
        while (files.hasNext()) {
            var file = files.next();
            temp = {
                folder_tree: function(folderlist, i) {
                    if (i > 0) {
                        return "/" + [DriveApp.getFolderById(folderlist[i][j]).getName() for (j in folderlist[i])
                            if (j > 0)].join("/") + "/";
                    } else {
                        return "/";
                    }
                }(folderlist, i),
                file_id: file.getId(),
                file_name: file.getName(),
                file_size: file.getBlob().getBytes().length,
                file_created: Utilities.formatDate(file.getDateCreated(), localTimeZone, "yyyy/MM/dd HH:mm:ss"),
                file_updated: Utilities.formatDate(file.getLastUpdated(), localTimeZone, "yyyy/MM/dd HH:mm:ss"),
            };
            filelist.push(temp);
            temp = {}
        }
    }
    var sortedlist = filelist.sort(function(e1, e2) {
        return (e1.folder_tree > e2.folder_tree ? 1 : -1) });
    return sortedlist;
}

function zipping(fileId) {
    var blobs = [];
    var mimeInf = [];
    fileId.forEach(function(e) {
        try {
            var file = DriveApp.getFileById(e);
            var mime = file.getMimeType();
            var name = file.getName();
        } catch (e) {
            return e
        }
        Logger.log(mime)
        var blob;
        if (mime.indexOf('google-apps') > 0) {
            mimeInf =
                mime == "application/vnd.google-apps.spreadsheet" ? ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", name + ".xlsx"] : mime == "application/vnd.google-apps.document" ? ["application/vnd.openxmlformats-officedocument.wordprocessingml.document", name + ".docx"] : mime == "application/vnd.google-apps.presentation" ? ["application/vnd.openxmlformats-officedocument.presentationml.presentation", name + ".pptx"] : ["application/pdf", name + ".pdf"];
            blob = UrlFetchApp.fetch("https://www.googleapis.com/drive/v3/files/" + e + "/export?mimeType=" + mimeInf[0], {
                method: "GET",
                headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
                muteHttpExceptions: true
            }).getBlob().setName(mimeInf[1]);
        } else {
            blob = UrlFetchApp.fetch("https://www.googleapis.com/drive/v3/files/" + e + "?alt=media", {
                method: "GET",
                headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
                muteHttpExceptions: true
            }).getBlob().setName(name);
        }
        blobs.push(blob);
    });
    var zip = Utilities.zip(blobs, Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyyMMdd_HHmmss") + '.zip');
    var bytedat = DriveApp.createFile(zip).getBlob().getBytes();
    return Utilities.base64Encode(bytedat);
}

Flow of sample script

  1. All files in a folder that owner of Google Drive decided display as a list using Web Apps.
  2. Users access to the site which was used by Web Apps using own browser.
  3. When users clicked the files from the list and pushed DOWNLOAD button, the files are converted to base64 using Google Apps Script.
  4. The converted-base64 data are transfered to the site and are converted to blob using Javascript in HTML.
  5. The blob data are compressed by ZIP, and then they are downloaded.
  6. Google Spreadsheet, Google Document and Google Slide are converted to Microsoft Excel, Word and Powerpoint, respectively. Images and PDF are not converted to other format.

Sample Folder Structure

The folder structure as a sample is as follows. sharedFolder is the top directory that owner was set. All of files and directories in the directory that owner defined is displayed as a list. At the demonstration, you can see it.

References

TOP

@ut4utc
Copy link

ut4utc commented Sep 6, 2018

Hi tanaikech, Can you help me with code? How I can get all filenames in current directory in Apps Script? I know how I can get all files from ROOT, but in API say that parentFolder - need be parent, not root. I'm confuse. I want get all filenames with directory where I run my Docs file with script - then parsing all names and find Max number and then automatically create new filename with max-number+1.
For example structure:

/
  1001.10002 DIR
     file1001.001.doc
     file1001.002.doc
     file1001.003.doc 
  1002.10001 DIR

If I'm create new file in DIR 1001.10002 my script need automatically rename new file to file1001.004.doc

This code working well, but it started only in ROOT DIR, can't current :(

// get all files in Root dir
  var files = parentFolder;
  while (files.hasNext()) {
    var file = files.next();  
   //  Logger.log(file.getName());
   DocumentApp.getUi().alert(file.getName());
  }

But my code not working, and I'm novice in Apps Script & 2 days can't find solution:

function myFunction() {
  var ui = DocumentApp.getUi();
  thisFileId = DocumentApp.getActiveDocument().getId();
  var thisFile = DriveApp.getFolderById(thisFileId);
  var parentFolder = thisFile.getParents();
  
  var currentFolderName = parentFolder.next();
  ui.alert(currentFolderName); // I'm find current folder - it work!
  
  
  var list = [];
  list.push(['Name','ID','Size']);
  var files = currentFolderName.getFiles();
  while (files.hasNext()){
    file = files.next();
    var row = []
    row.push(file.getName(),file.getId(),file.getSize())
    list.push(row);
    Logger.log(list);
   ui.alert(list); // <--  it not workin :(
  }
}

Can you help me with it?

@Bayurzx
Copy link

Bayurzx commented Mar 23, 2020

Thank you tanaikech. Could you help me with a code that allow me share a single pdf this will allow a gmail user read only access from my drive for this file

@blackjack4494
Copy link

You have to deactivate new V8 Runtime to use this script without modifications.

I tried this using my gsuite but I can only set access for me or anyone within my organization.

@mintuchoysn
Copy link

mintuchoysn commented Sep 7, 2022

Code not save in script.google.com . Code is missing here--------) for (j in folderlist[i])
if (j > 0)].join("/") + "/";
} else {
return "/";

Please help

@rserdar
Copy link

rserdar commented Dec 15, 2022

Code not save in script.google.com . Code is missing here--------) for (j in folderlist[i]) if (j > 0)].join("/") + "/"; } else { return "/";

Please help

Yes please help

@adickdid69
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment