You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
First and foremost, thank you so very much for your work and open sourcing it for our community. I am personally very grateful for you!
I've successfully deployed a GAS that uploads 10 files concurrently using your ResumeableUploadForGoogleDrive (the first version which stores each file in RAM). I've had some users report that their uploads stop at a certain percentage (every person's percentage was different). These users are usually uploading >1,000 files that are 30-80Mb each. I assume that they're hit some out-of-memory error on their machine.
I was hoping that replacing ResumeableUploadForGoogleDrive could be swapped with ResumeableUploadForGoogleDrive2, but I didn't have success with that. I received the console error There are no required parameters. accessToken, fileName, fileSize, fileType and fileBuffer are required. But, upon code review, it appears to me that these are being provided in the resource. I see it listed in my code as:
Could you please help shed some light on this? Note: In the code below, I copied your unminified v2 code directly into script blocks and removed the 2 at the end of each ResumableUploadForGoogleDrive to maintain compatibility with the exist HTML code.
<!DOCTYPE html><html><head><basetarget="_blank"><metaname="viewport" content="width=device-width, initial-scale=1.0" />
<title>Drive Multi Large File Upload</title><linkhref="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><linkrel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css"><style>
.disclaimer{width: 480px; color:#646464;margin:20px auto;padding:0 16px;text-align:center;font:400 12px Roboto,Helvetica,Arial,sans-serif}.disclaimer a{color:#009688}#credit{display:none}
</style></head><body><formclass="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;"><divid="forminner"><divclass="row"><divclass="col s12"><h5class="center-align teal-text">Vendor Upload Form</h5></div></div><divclass="row"><? if (!event_Date) { ?><spanstyle="color: red;">Warning: You are viewing the generic version of this page. A unique, event-specific URL should have been provided for uploading your files. Please contact our vendor team if you need assistance obtaining the correct link.
<br><br>
If your event does not require a customized URL, you may proceed with the form below.</span><br><br><? } ?><divclass="input-field col s12"><labelfor="eventDate" style="top: -20px;">Event Date</label><inputid="eventDate" type="date" name="Event Date" class="validate" required="required" aria-required="true"
<? if (event_Date_Formatted) { ?>
value="<?= event_Date_Formatted ?>"
disabled
<? } ?>></div><divclass="input-field col s12"><inputid="eventName" type="text" name="Event Name" class="validate" required="required" aria-required="true"
<? if (event_Name) { ?>
value="<?= event_Name ?>"
disabled
<? } ?> oninput="this.value = this.value.replace(/\s+/g, '')"><labelfor="eventName">Event Name</label></div></div><divclass="row"><divclass="input-field col s12"><selectid="brand" name="Brand" class="browser-default" required="required" aria-required="true"><labelfor="name">Brand</label></div><script>constbrandEnum={"Brand 1": "B1","Brand 2": "B2",};</script><? if (event_Brand) { ?><script>document.addEventListener('DOMContentLoaded',function(){consteventBrand="<?= event_Brand ?>";// Assuming eventBrand is available in the global scopeif(eventBrand){constbrandValue=brandEnum[eventBrand];constoption=document.createElement('option');option.value=brandValue;option.selected=true;option.textContent=eventBrand;document.getElementById('brand').appendChild(option);}});</script><? } else { ?><optionvalue="" disabledselected>Choose a brand</option><optionvalue="B1">Brand 1</option><optionvalue="B2">Brand 2</option><? } ?></select></div></div><divclass="row"><divclass="input-field col s12"><selectid="type" name="Event Type" class="browser-default" required="required" aria-required="true"><labelfor="type">Brand</label><optionvalue="" disabledselected>Choose an event type</option><optionvalue="Wedding">Wedding</option><optionvalue="Pre-Wedding">Pre-Wedding Event / Getting Ready</option><optionvalue="Post-Wedding">Post-Wedding Event / Gather After</option><optionvalue="Business_Event">Business Event</option><optionvalue="Engagement">Engagement</option><optionvalue="Family">Family</option><optionvalue="Maternity">Maternity</option><optionvalue="Newborn">Newborn</option><optionvalue="Senior">Senior</option><optionvalue="Portrait">Portrait</option><optionvalue="Editorial">Editorial</option><optionvalue="Other">Other</option></select></div></div><divclass="row" id="folderPathRow" style="display: none;"><pstyle="white-space: nowrap;">The folder path for this upload is:</br><strong>Products & Services/<spanid="folderPathDisplay"></span>/<spanid="folderNameDisplay"></span>/Unedited/<spanid="typeNameDisplay"></span>/</strong></p><script>document.addEventListener('DOMContentLoaded',function(){varbrandField=document.getElementById("brand");vardateField=document.getElementById("eventDate");varnameField=document.getElementById("eventName");functionupdateEventName(){vardateValue=dateField.value.replace(/-/g,'');if(dateValue){nameField.value=dateValue+'_'+nameField.value.replace(/^\d{8}_/,'');}}nameField.addEventListener('input',updateEventName);dateField.addEventListener('input',updateEventName);vartypeField=document.getElementById("type");varfolderPathRow=document.getElementById("folderPathRow");functionupdateFolderPath(){if(brandField.value&&nameField.value&&typeField.value&&dateField.value){varfolderHtmlPath=brandField.value+"/"+"Client Content"+"/"+dateField.value.substring(0,4)+"/"+dateField.value.substring(5,7);folderPathRow.style.display="block";document.getElementById("folderNameDisplay").textContent=nameField.value;document.getElementById("typeNameDisplay").textContent=typeField.value;document.getElementById("folderPathDisplay").textContent=folderHtmlPath;}else{folderPathRow.style.display="none";}}updateFolderPath();nameField.addEventListener('input',updateFolderPath);brandField.addEventListener('change',updateFolderPath);typeField.addEventListener('change',updateFolderPath);dateField.addEventListener('change',updateFolderPath);// Update eventName field with dateValue when the form loadsupdateEventName();});</script></div><divclass="row"><divclass="file-field input-field col s12"><divid="input-btn" class="btn"><span>File(s)</span><inputid="file" type="file" multiple></div><divclass="file-path-wrapper"><inputclass="file-path validate" type="text" placeholder="Select one or more files"></div></div></div><divclass="row"><divclass="input-field col s6"><buttonid="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Upload</button></div></div><divclass="row"><divclass="input-field col s12 hide" id="update"><hr><p>
Please wait as your file is being uploaded. Do not close or refresh the window while uploading.
</p></div></div><divclass="row"><divclass="input-field col s12" id="total"></div></div><divclass="row"><divclass="input-field col s12" id="progress"></div></div></div><divid="success" style="display:none"><h5class="left-align teal-text">File(s) Uploaded!</h5><p>Everything has been uploaded</p></div></form><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script><scriptsrc="https://gumroad.com/js/gumroad.js"></script><script>/** * ResumableUploadToGoogleDrive for Javascript library * GitHub https://github.com/tanaikech/ResumableUploadForGoogleDrive2_js<br> * In this Class ResumableUploadToGoogleDrive2, the selected file is uploaded by splitting data on the disk. By this, the large file can be uploaded.<br> */(function(r){letResumableUploadToGoogleDrive;ResumableUploadToGoogleDrive=(function(){functionResumableUploadToGoogleDrive(){this.obj={};this.chunkSize=52428800;this.endpoint="https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&supportsAllDrives=true";}/** * Run resumable upload a file. * @param {Object} resource the object for resumable uploading a file. */ResumableUploadToGoogleDrive.prototype.Do=asyncfunction(resource,callback){callback({status: "initialize"},null);try{this.obj=awaitinit.call(this,resource);}catch(err){callback(null,err);return;}try{consthead=awaitgetLocation.call(this);this.location=head.get("location");callback({status: "getLocation"},null);callback({status: "start"},null);constfileSize=resource.file.size;constlen=Math.ceil(fileSize/this.chunkSize);for(leti=0;i<len;i++){letstart=i*this.chunkSize;letend=fileSize<start+this.chunkSize
? fileSize
: start+this.chunkSize;letdata=resource.file.slice(start,end);end-=1;callback({status: "Uploading",progressNumber: {current: i,end: len},progressByte: {current: start,end: end,total: fileSize,},},null);try{constres=awaitgetFile.call(this,{
fileSize,
len,
start,
end,
data,
i,});if(res.status=="Next"||(res.status=="Done"&&i==len-1)){callback(res,null);}else{callback(null,"Internal error.");return;}}catch(err){callback(null,err);return;}}}catch(err){callback(null,err);return;}};constinit=function(resource){returnnewPromise((resolve,reject)=>{if(!("accessToken"inresource)||!("file"inresource)){reject({Error:
"There are no required parameters. accessToken, fileName, fileSize, fileType and fileBuffer are required.",});return;}letobject={};object.resource=resource;if("chunkSize"inresource&&resource.chunkSize>=262144&&resource.chunkSize%262144==0){this.chunkSize=resource.chunkSize;}if("fields"inresource&&resource.fields!=""){this.endpoint+="&fields="+encodeURIComponent(resource.fields);}if("convertToGoogleDocs"inresource&&resource.convertToGoogleDocs){fetch("https://www.googleapis.com/drive/v3/about?fields=importFormats",{method: "GET",headers: {Authorization: "Bearer "+resource.accessToken},}).then((res)=>{if(res.status!=200){res.json().then((e)=>reject(e));return;}res.json().then((res)=>{if(resource.file.typeinres.importFormats){object.resource.fileType=res.importFormats[resource.fileType][0];}resolve(object);});}).catch((err)=>{reject(err);});}else{resolve(object);}});};constgetLocation=function(){returnnewPromise((resolve,reject)=>{constresource=this.obj.resource;constaccessToken=resource.accessToken;letmetadata={mimeType: resource.file.type,name: resource.file.name,};if("folderId"inresource&&resource.folderId!=""){metadata.parents=[resource.folderId];}fetch(this.endpoint,{method: "POST",body: JSON.stringify(metadata),headers: {Authorization: "Bearer "+accessToken,"Content-Type": "application/json",},}).then((res)=>{if(res.status!=200){res.json().then((e)=>reject(e));return;}resolve(res.headers);}).catch((err)=>{reject(err);});});};constgetFile=function({ fileSize, len, start, end, data, i }){constlocation=this.location;returnnewPromise(function(resolve,reject){constfr=newFileReader();fr.onload=asyncfunction(){constbuf=fr.result;constobj={data: newUint8Array(buf),length: end-start+1,range: "bytes "+start+"-"+end+"/"+fileSize,startByte: start,endByte: end,total: fileSize,cnt: i,totalChunkNumber: len,};awaitdoUpload(obj,location).then((res)=>resolve(res)).catch((err)=>reject(err));};fr.readAsArrayBuffer(data);});};constdoUpload=function(e,url){returnnewPromise(function(resolve,reject){fetch(url,{method: "PUT",body: e.data,headers: {"Content-Range": e.range},}).then((res)=>{conststatus=res.status;if(status==308){resolve({status: "Next",result: r});}elseif(status==200){res.json().then((r)=>resolve({status: "Done",result: r}));}else{res.json().then((err)=>{err.additionalInformation="When the file size is large, there is the case that the file cannot be converted to Google Docs. Please be careful this.";reject(err);return;});return;}}).catch((err)=>{reject(err);return;});});};returnResumableUploadToGoogleDrive;})();return(r.ResumableUploadToGoogleDrive=ResumableUploadToGoogleDrive);})(this);</script><script>//const chunkSize = 52428800;constuploadParentFolderId="0AJYnVPHJrxDBUk9PVA";// creates a folder inside of this folderfunctionsubmitForm(){if($('#submit-btn.disabled')[0])return;// short circuitvardate=$('#eventDate').val();varname=$('#eventName').val();varbrand=$('#brand').val();varfiles=[...$('#file')[0].files];// convert from FileList to array// Error validationif(!date||!name||!brand||files.length===0){showError("Please fill in all required fields and select a file.");return;}disableForm();// prevent re submissionvarfolderPath=document.getElementById("brand").value+"/"+"Client Content"+"/"+document.getElementById("eventDate").value.substring(0,4)+"/"+document.getElementById("eventDate").value.substring(5,7);varfolderName=document.getElementById("eventName").value;vartypeName=document.getElementById("type").value;console.log("The folderPath is: "+folderPath)constnewFolderObj=createOrGetFolder(folderPath,folderName,typeName,uploadParentFolderId).then(newFolderId=>{console.log("Found or created guest folder with id: "+newFolderId);google.script.run.withSuccessHandler(accessToken=>ResumableUploadForGoogleDrive(accessToken,newFolderId)).getOAuthToken();});}functionupload({ accessToken, file, idx, newFolderId }){returnnewPromise((resolve,reject)=>{letfr=newFileReader();fr.fileName=file.name;fr.fileSize=file.size;fr.fileType=file.type;fr.readAsArrayBuffer(file);fr.onload=e=>{varid=`p_${idx}`;vardiv=document.createElement("div");div.id=id;document.getElementById("progress").appendChild(div);document.getElementById(id).innerHTML="Initializing.";constf=e.target;constresource={fileName: f.fileName,fileSize: f.fileSize,fileType: f.fileType,fileBuffer: f.result,accessToken: accessToken,folderId: newFolderId,};constru=newResumableUploadToGoogleDrive();ru.Do(resource,function(res,err){if(err){reject(err);return;}console.log(res);letmsg="";if(res.status=="Uploading"){msg=Math.round((res.progressNumber.current/res.progressNumber.end)*100)+`% (${f.fileName})`;}else{msg=`${res.status} (${f.fileName})`;}if(res.status=="Done"){resolve(res.result);}document.getElementById(id).innerText=msg;});};});}asyncfunctionResumableUploadForGoogleDrive(accessToken,newFolderId){constn=10;// You can adjust the chunk size.constf=document.getElementById("file");constfiles=[...f.files].sort((a,b)=>a.name.localeCompare(b.name));vartotalFiles=files.length.toString();constsplitFiles=[...Array(Math.ceil(files.length/n))].map((_)=>files.splice(0,n));console.log("The splitFiles are: "+splitFiles)console.log("The total number of files is: "+totalFiles);document.getElementById("total").innerHTML=`Total Files: ${totalFiles}`;for(leti=0;i<splitFiles.length;i++){constpercentCompletion=Math.floor((i/splitFiles.length)*100);document.getElementById("progress").innerHTML=`Upload Progress: ${percentCompletion}% (Refreshs after upload group of ${n})`;constres=awaitPromise.all(splitFiles[i].map(async(file,j)=>awaitupload({ accessToken, file,idx: `${i}_${j}`, newFolderId })));console.log(res);}document.getElementById("progress").innerHTML=`Upload Progress: 100%`;}functiondisableForm(){$('#submit-btn').addClass('disabled');$('#input-btn').addClass('disabled');$('#update').removeClass('hide');}functioncreateOrGetFolder(folderPath,folderName,typeName,uploadParentFolderId){returnnewPromise((resolve,reject)=>{google.script.run.withSuccessHandler(response=>{console.log("createOrGetFolder response: ",response);if(response&&response.length){resolve(response);}reject(response);}).createOrGetFolder(folderPath,folderName,typeName,uploadParentFolderId);});}functionshowSuccess(){$('#forminner').hide();$('#success').show();}functionshowError(e){$('#progress').addClass('red-text').html(e);}functionshowMessage(e){$('#update').html(e);}functionshowProgressMessage(e){$('#progress').removeClass('red-text').html(e);}</script></body></html>
The text was updated successfully, but these errors were encountered:
Hi there,
First and foremost, thank you so very much for your work and open sourcing it for our community. I am personally very grateful for you!
I've successfully deployed a GAS that uploads 10 files concurrently using your ResumeableUploadForGoogleDrive (the first version which stores each file in RAM). I've had some users report that their uploads stop at a certain percentage (every person's percentage was different). These users are usually uploading >1,000 files that are 30-80Mb each. I assume that they're hit some out-of-memory error on their machine.
I was hoping that replacing
ResumeableUploadForGoogleDrive
could be swapped withResumeableUploadForGoogleDrive2
, but I didn't have success with that. I received the console errorThere are no required parameters. accessToken, fileName, fileSize, fileType and fileBuffer are required.
But, upon code review, it appears to me that these are being provided in theresource
. I see it listed in my code as:Could you please help shed some light on this? Note: In the code below, I copied your unminified v2 code directly into script blocks and removed the
2
at the end of eachResumableUploadForGoogleDrive
to maintain compatibility with the exist HTML code.The text was updated successfully, but these errors were encountered: