Save ip camera video to google drive using apps script UrlFetchApp - google-apps-script

My idea was to setup a script with GAS to record videos of my ip camera to google drive. Currently it can access the camera videostream, take data and save it do drive. It's not working because instead of getting a limited amount of data due to the http request header range parameter it takes the maximum size the http request could receive. Furthermore the asf video seems to get corrupted, and can't be played on VLC.
Any idea for making the script download a defined video size and in the correct format?
function myFunction() {
var URL = 'http://201.17.122.01:82/videostream.asf?user=xxxx&pwd=xxxxxx&resolution=32&rate=1'; // file to backup
var chunkSize = 1048576; // read the file in pieces of 1MB
var chunkStart = 0, chunkEnd = chunkStart + chunkSize;
var chunkHTTP = UrlFetchApp.fetch(URL, {
method: "get",
contentType: "video/x-ms-asf",
headers: {
"Range": "bytes=" + chunkStart + "-" + chunkEnd
}
})
var chunk = chunkHTTP.getContentText();
// write to Drive
try {
var folder = DocsList.getFolder('bakfolder');
} catch(err) {
var folder = DocsList.createFolder('bakfolder');
}
fileOnDrive = folder.createFile('ipcamera.asf', chunk);
Logger.log(" %s bytes written to drive", chunk.length);
}

I do not have an ip camera, so can't test and help you with the chunking of received data. But I suspect that you are using wrong methods for extracting received video data and saving it to Drive:
a) .getContentText() method gets the content of an HTTP response encoded as a string - probably wrong for working with video stream data. Try using .getBlob() or .getContent() instead;
b) folder.createFile(name, content) method creates a text file in the current folder. Use .createFile(blob) method instead.
You will most likely have t experiment with the stream bytes to get it as a blob Apps Script can work with. If I find an ip camera or another video stream I can access, I will test it out and update this.

Related

Are there any batch methods to speed up file creation on Google Drive?

I need to create a lot of individual files on Google Drive in one folder. Currently the only way I see it can be done is using folderName.createFile(). Creating files one by one with this command is tediously slow.
Is there a faster way to do it like a batch creation tool from an array of files?
Yes, the latest Google Drive API (v3) supports any 100 actions in a single http call. The default endpoint is /batch/api_name/api_version. Most of the Drive client libraries have functions built-in to work with it.
This page gives the details, and here is an example in Java. Notice how all of the queries, after being constructed, are queue()-ed into the batch call, which is executed as a single HTTP connection.
Update from comments: Google Drive API does not currently support batch file upload or download queries. Consider looking into Google Cloud Platform's Storage Buckets (or similar services) for more large-scale file options.
Ok pleased to confirm it can be done with UrlFetchApp.fetchAll().
Here is how I did it. I am not a professional programmer so please forgive my transgressions in the code :) Special thanks to #TheMaster and #Tanaike who put me on the right track.
On the web app you need to apply the following code:
//doPost (note I updated the code on stackoverflow after posting my answer as there was an error)
const doPost = e => {
try{
var diskPath = getFolder(e.parameter.diskPath)[0];
const file = diskPath.createFile(e.parameter.fileName,Utilities.newBlob(Utilities.base64DecodeWebSafe(e.parameter.file),e.parameter.contentType));
}
catch(e){
return ContentService.createTextOutput(e)
}
return ContentService.createTextOutput( 'Saved:' + 'e.parameter.fileName: '+e.parameter.fileName + 'e.parameter.contentType '+e.parameter.contentType);
}
The code must be published as a web app. within the script editor click "Publish" and then "Deploy as a web app" and select "Project version" as "New". "Who has access to the app:" should be set to "Anyone, even anonymous" and then save. You will be given a public URL and you enter that in the script below:
//save files function
function saveFiles(fileArr){ //note file blobs must have setName and have contentType set so we save them in the fetch array: arr = [[file1/Blob2,'image/jpeg',name1],[file2/Blob2,'text/html',name2],............];
var url = 'INSERT YOUR WEB APP PUBLIC URL HERE'
var fetchArr = [];
for (var i in fileArr){
var file = fileArr[i][0];
var bytes
try{ //if file is already blob prevent error getting Blob
bytes = file.getBlob().getBytes()
}
catch(e){
bytes = file.getBytes();
}
var fileName = fileArr[i][2];
var contentType = fileArr[i][1];
var payload = {
fileName: fileName,
contentType : contentType,
file: Utilities.base64EncodeWebSafe(bytes)
};
var options = {
url: url,
method: "POST",
payload: payload,
muteHttpExceptions : true,
};
fetchArr.push(options)
}
UrlFetchApp.fetchAll(fetchArr);
}
The above code creates a fetch array of URLs with files attached, and then posts them to the web app. The web app then saves them asynchronously saving you a heap of time if you have a lot of files you want to save to disk at once.
In order to run the code you need to call saveFiles(fileArr) from another script which builds the array. The array should have the following format:
[[file or blob, content type, name for the new file as a string],[file or blob, content type, name for the new file as a string],.....]
The content type is a MIME type and can be derived from the old file (if you are not making a new Blob) like so: fileName.getContentType(). If you are making a new Blob you should set the contentType according to the MIME type for the file type you are creating.
Edited: Just a note about rate limiting. I hit a rate limit when I tried to save over 13 files in one go, but I was able to send batches of 10 files every few seconds without any problems.

How to upload an existing file in Drive to Drive using Apps Script

Introduction
Let me first introduce the goal of what I am trying to do.
I had a file split into two parts earlier
Size of both of these files together may exceed 50 MB (as a long term goal). Since UrlFetchApp.fetch() has restriction regarding the size of the request, I want to upload them separately, where each file will be less than 50 MB and consequently merge them. For now (to try the Drive API), I am using small files.
First file is of 640000 bytes (a multiple of 256) 524288 bytes. I realise I did a mistake earlier i.e I was using the size of the file as a multiple of 256 but it should be a multiple of 256*1024
Second file is of 47626 bytes 163339 bytes.
I had split the files using curl and uploaded them to my drive (normal web upload).
My intention is to upload the partial files one by one using Resumable Upload to Google Drive using the Google Drive API from Google Apps Script so that they maybe merged into one file.
What I have tried so far?
Yesterday, I had asked a question here. I was trying to perform a resumable upload using Drive.Files.insert and a user pointed out it is not possible using Drive.Files.insert which is quoted below.
Unfortunately, in the current stage, the resumable upload cannot be achieved using Drive.Files.insert. It seems that this is the current specification at Google side
What I am trying now is using Google Drive API. Enclosed below is the code.
function myFunction() {
var token = ScriptApp.getOAuthToken();
var f1_id = '1HkBDHV1oXXXXXXXXXXXXXXXXXXXXXXXX';
var f2_id = '1twuaKTCFTXXXXXXXXXXXXXXXXXXXX';
var putUrl = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
var fileData = {
name : 'Merged-file-from-GAS',
file : DriveApp.getFileById(f1_id).getBlob()
}
var options = {
method : 'put',
contentType:"application/json",
headers : {
Authorization: 'Bearer ' + token,
'X-Upload-Content-Type' : 'application/octet-stream',
'Content-Type' : 'application/json; charset=UTF-8'
},
muteHttpExceptions: true,
payload : fileData
};
var response = UrlFetchApp.fetch(putUrl, options);
Logger.log(response.getResponseCode());
Logger.log(response.getAllHeaders());
}
I also tried changing the method to patch
I added Content-Length : 640000 inside headers and in that case I receive an error as provide below.
Exception: Attribute provided with invalid value: Header:Content-Length
I tried to create a file using Drive.Files.insert(resource) using blank resource. Then I tried to update it using UrlFetchApp(patchUrl,options) while having the variable
var patchUrl = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=resumable';
Result
It does not create any file.
Logger logs for the result of the attached code (initial code) are provided below:
[20-05-12 21:05:37:726 IST] 404.0
[20-05-12 21:05:37:736 IST] {X-Frame-Options=SAMEORIGIN, Content-Security-Policy=frame-ancestors 'self', Transfer-Encoding=chunked, alt-svc=h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43", X-Content-Type-Options=nosniff, Date=Tue, 12 May 2020 15:35:37 GMT, Expires=Mon, 01 Jan 1990 00:00:00 GMT, X-XSS-Protection=1; mode=block, Content-Encoding=gzip, Pragma=no-cache, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Vary=[Origin, X-Origin], Server=GSE, Content-Type=text/html; charset=UTF-8}
Question
What is the proper way of initiating a upload of a file in Drive to Drive using Drive API from Apps Script while keeping the upload type as resumable?
What should subsequent requests be like? So that files above 50 MB can be subsequently uploaded to the merged file?
Edit 1
Tried it again using corrected file chunks sizes. Same problem persists.
Edit 2
To understand the code in the answer, I used the code in // 2 of Tanaike's code alone to understand how Location is retrieved.
function understanding() {
var token = ScriptApp.getOAuthToken();
const filename = 'understanding.pdf';
const mimeType = MimeType.PDF;
const url = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
const location = res1.getHeaders().Location;
Logger.log(location);
}
This creates a file understanding.pdf of size 0 bytes. However, Logger.log(location) logs null.
Why is it so?
The mistake was in the end point. Setting it to
https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable works. It retrieves the location.
From your question and replying, I could understand your situation and goal like below.
In your sample files, "file A" and "file B" are 524,288 bytes and 163,339 bytes, respectively.
Your tested script is the script showing in your question.
You want to merge the files using the resumable upload.
The mimeType of the merged file is PDF.
For this, how about this answer?
Modification points:
Unfortunately, your script is incomplete for achieving the resumable upload. The flow of the resumable upload at Google Drive API is as follows. Ref
Request for retrieving the location which is used as the endpoint for uploading data.
In your case, the new file is created. So it is required to use the POST method.
Request to the retrieved location by including the data (in your case, it's each file.).
In this case, it is required to upload the data using a loop. And the PUT method is used.
Here, each file size is most important. If the file size except for the last file is not the multiples of 262,144 bytes, the resumable upload cannot be run by an error. Please be careful this.
For above flow, when the sample script is prepared, it becomes as follows.
Usage:
1. Enable Drive API.
In this case, Drive API is used. So please enable Drive API at Advanced Google Services. By this, the Drive API is automatically enabled at API console.
The flow of the sample script is as follows.
Create an object for using at the resumable upload.
Retrieve "location" for starting the resumable upload.
Upload each file and merge them.
2. Sample script.
Please copy and paste the following script. And please set the file IDs. In this case, please set them in order for merging. Please be careful this.
function myFunction() {
const fileIds = ["###", "###"]; // Please set the file IDs of the file "A" and "B" in order.
const filename = "sample.pdf";
const mimeType = MimeType.PDF;
// 1. Create an object for using at the resumable upload.
const unitSize = 262144;
const fileObj = fileIds.reduce((o, id, i, a) => {
const file = DriveApp.getFileById(id);
const size = file.getSize();
if (i != a.length - 1 && (size % unitSize != 0 || size > 52428800)) {
throw new Error("Size of each file is required to be the multiples of 262,144 bytes and less than 52,428,800 bytes.");
}
o.files.push({data: file.getBlob().getBytes(), range: `bytes ${o.size}-${o.size + size - 1}\/`, size: size.toString()});
o.size += size;
return o;
}, {size: 0, files: []});
// 2. Retrieve "location" for starting the resumable upload.
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
const location = res1.getHeaders().Location;
// 3. Upload each file and merge them.
fileObj.files.forEach((e, i) => {
const params = {
method: "put",
headers: {"Content-Range": e.range + fileObj.size},
payload: e.data,
muteHttpExceptions: true,
};
const res = UrlFetchApp.fetch(location, params);
const status = res.getResponseCode();
if (status != 308 && status != 200) {
throw new Error(res.getContentText());
}
if (status == 200) {
console.log(res.getContentText())
}
});
// DriveApp.createFile() // This comment line is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive" by the script editor. So please don't remove this line.
}
Result:
When the resumable upload is finished, the following result can be seen at the log. And you can see the merged file at the root folder.
{
"kind": "drive#file",
"id": "###",
"name": "sample.pdf",
"mimeType": "application/pdf"
}
Note:
This is a simple sample script. So please modify this for your actual situation.
I tested above script for your sample situation that "file A" and "file B" are 524,288 bytes and 163,339 bytes. So when several files with about 50 MB in size are merged using this script, an error occurs.
If the memory error occurs when the large files are used, in the current stage, it seems that this is the specification of Google side. So please be careful this.
Reference:
Perform a resumable upload
Tanaike's answer is more than perfect. It's elegant and has even helped me to learn about array.reduce function. Before I asked this question, I had minimal knowledge about JavaScript and almost zero knowledge in using Google Drive API.
My intention was to learn the whole process of resumable upload step by step using Google Apps Script as the language. Using Tanaike's code as reference I wrote a script which instead of being productive, manageable, and elegant would provide myself (at least) an idea of how resumable upload works step by step. I have used no loops, no objects, and even no arrays.
Step 1 ( Declare the necessary variables )
var fileId1 = "XXXXXXXXXXX"; //id of the first file
var fileId2 = "YYYYYYYYYYY"; //id of the second file
var filename = "merged.pdf"; //name of the final merged file
var mimeType = MimeType.PDF; //Mime type of the merged file
Step 2 ( Initiate the resumable upload )
//declare the end point
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
//Send the request
//Method to be used is Post during initiation
//No file is to be sent during initiation
//The file name and the mime type are sent
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
Step 3 ( Save the resumable session URI )
const location = res1.getHeaders().Location;
Step 4 (a) ( Upload file 1 )
Note : Step 4 (a) and (b) can be performed using a loop. In my case, I used it two times without loop
var file = DriveApp.getFileById(fileId1); //get the first file
var data = file.getBlob().getBytes(); //get its contents in bytes array
//Method used is PUT not POST
//Content-Range will contain the range from starting byte to ending byte, then a slash
//and then file size
//bytes array of file's blob is put in data
var params = {
method : "put",
headers : {
'Content-Range' : `bytes 0-524287/687627`
},
payload : data,
muteHttpExceptions: true
};
//Request using Resumable session URI, and above params as parameter
var result = UrlFetchApp.fetch(location,params);
Step 4 (b) ( Upload the second file )
//Almost same as Step 4 (a)
//The thing that changes is Content Range
file = DriveApp.getFileById(fileId2);
data = file.getBlob().getBytes();
params = {
method : "put",
headers : {
'Content-Range' : `bytes 524288-687626/687627`
},
payload : data,
muteHttpExceptions : true
};
result = UrlFetchApp.fetch(location, params);
Now instead of doing step 4 n number of times, it's better to use a loop.
Also, this code doesn't checks for possible error that might have occurred during the process.
Hope this code helps someone, even though it was more of a self-teaching experiment. :)

UrlFetchApp Service Time Out

the urlfetch has a limited data allowed so in order to load a large CSV or TSV file (50K) I've created a proxy server (REST)
which makes the request under the hood, map it to list and cache it for 6 hours.
then, I added an endpoint to fetch data based on a range (see signature below)
signature:
var PROXY = 'http://lagoja-services.rcb.co.il/api/adwordsProxy/feed/{base64URL}/{seperator}/{from}/{to}'
when someone reaches the range endpoint, I create a CSV on-the-fly.
the first loading of this large file on the server takes between 60-80 seconds, other followed requests take the content from the cache so it takes only 2 seconds.
the problem I have is that I'm getting a timeout after 60 seconds using the urlfetch built-in class so it Alternately works (sometimes it works and sometimes getting timeout exception)
there is no way of reducing the first load!
it seems that I can't control the client timeout (from some unknown reason)
any other solution for me?
thanks, Roby (-:
hi, I've created a dedicated "test" endpoint for you to reproduce the issue. this endpoint tries to load the massive file every time (no cache)
function main() {
var response = UrlFetchApp.fetch('http://lagoja-services.rcb.co.il/api/adwordsProxy/test');
var status_code = response.getResponseCode();
Logger.log('status code %s', status_code);
}
endpoint:
http://lagoja-services.rcb.co.il/api/adwordsProxy/test
exception:
Timeout: http://lagoja-services.rcb.co.il/api/adwordsProxy/test
hi all,
i found a solution (which i don't like of course)
but i didn't have any better suggestion.
the idea is to ping the server to fetch the file, wait till it loaded into the cache and then request the loaded content... a shitty solution but at least it works lol
api:
[HttpGet]
[Route("api/fire")]
public HttpResponseMessage FireGetCSVFeed(...) {
HostingEnvironment.QueueBackgroundWorkItem(async ct => {
// make a request to the original CSV file - takes 60-80 seconds
});
return Request.CreateResponse(HttpStatusCode.OK, "Working...");
}
adwords script:
function sleep(milliseconds) {
var start = new Date().getTime();
while (new Date().getTime() < start + milliseconds);
}
function main() {
var response = UrlFetchApp.fetch(baseURL + 'fire');
sleep(1000 * 120); // yes i know, i'm blocking everything )-:
response = UrlFetchApp.fetch(baseURL + 'getCSV');
status_code = response.getResponseCode();
Logger.log('status code %s', status_code);
}

How to get the absolute file path of a Google drive file as a url?

Is there any way to get the file path of a file in Google drive? Generally, google drive file url can be a sharing url. But what if we wanted to access the absolute file path? Something like:
drive.google.com/file/myvideo.mp4
And then I wanted to show the video file in a webpage using a video tag.
Google drive is taking too long to process a video file that I uploaded, so I cannot embed it on my website, so I thought maybe accessing the file path will do the trick :)
So how to get something like above url?
Thanks for helping.
Edit:
Found it! Now I can get the absolute file path of any file in my drive. Follow the steps:
1- Open:
https://drive.google.com/us?id=yourfileid
Where yourfileid is file id
2- load and copy the URL at the page
3- that's it, it's the absolute file path URL
to get the absolute path of a video on the google drive just send a request to the link
https://drive.google.com/u/1/get_video_info?docid="+IdVideo
the return will be a byte-by-byte file that contains all the information in the video including the absolute link it is worth remembering that the data is encoded in url right away to access it just decode another important point and that the link you obtained is only valid for the device that made the request why the link it is linked to the ip and also to the agent that sent the request for example if you sent the request with postman and try to open the link in chrome there will be an access denied error and vice versa.
Below is an example of the response provided by the request:
status=ok&hl=pt_BR&allow_embed=0&ps=docs&partnerid=30&autoplay=0&docid=1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8&abd=0&public=true&el=embed&title=Jogos+Vorazes+Em+Chamas+-+ToTTi9.mp4&BASE_URL=https%3A%2F%2Fdrive.google.com%2Fu%2F0%2F&iurl=https%3A%2F%2Fdrive.google.com%2Fu%2F0%2Fvt%3Fauthuser%3D0%26id%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%26s%3DAMedNnoAAAAAYHNJTEUxV9Q3qpFIyzfWQ9jSgXyoRJ7h&cc3_module=https%3A%2F%2Fs.ytimg.com%2Fyt%2Fswfbin%2Fsubtitles3_module.swf&ttsurl=https%3A%2F%2Fdrive.google.com%2Fu%2F0%2Ftimedtext%3Fauthuser%3D0%26id%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%26vid%3D78edbfcf1fc76400&reportabuseurl=https%3A%2F%2Fdrive.google.com%2Fu%2F0%2Fabuse%3Fauthuser%3D0%26id%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8&token=1&plid=V0QWdNzM2hSOAQ&fmt_stream_map=18%7Chttps%3A%2F%2Fr2---sn-bg0eznlz.c.drive.google.com%2Fvideoplayback%3Fexpire%3D1618175340%26ei%3DLC1zYNjFDcOM8gStnI64Bg%26ip%3D45.184.131.85%26cp%3DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%26id%3D78edbfcf1fc76400%26itag%3D18%26source%3Dwebdrive%26requiressl%3Dyes%26mh%3DXL%26mm%3D32%26mn%3Dsn-bg0eznlz%26ms%3Dsu%26mv%3Du%26mvi%3D2%26pl%3D24%26ttl%3Dtransient%26susc%3Ddr%26driveid%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%26app%3Dexplorer%26mime%3Dvideo%2Fmp4%26vprv%3D1%26prv%3D1%26dur%3D8775.029%26lmt%3D1612203534601168%26mt%3D1618160459%26sparams%3Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%26sig%3DAOq0QJ8wRQIhAPjdubHafwixI9u_3cHc4Qt0sF8092zP3ZNSxPvqHY7nAiApe4jGKLmb4jVA4vqAGa5M-Sv2vPiwCCMFDIjzPvpq-Q%3D%3D%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%26lsig%3DAG3C_xAwRgIhAL9KrFxY09TeS3LW7B6wVmuM6pJTlVNC7B3uqVYHYXiuAiEAv43kEsHHcDK805VYorcU_CSm9_END9gpT_KX7QSZ9PA%3D%2C22%7Chttps%3A%2F%2Fr2---sn-bg0eznlz.c.drive.google.com%2Fvideoplayback%3Fexpire%3D1618175340%26ei%3DLC1zYNjFDcOM8gStnI64Bg%26ip%3D45.184.131.85%26cp%3DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%26id%3D78edbfcf1fc76400%26itag%3D22%26source%3Dwebdrive%26requiressl%3Dyes%26mh%3DXL%26mm%3D32%26mn%3Dsn-bg0eznlz%26ms%3Dsu%26mv%3Du%26mvi%3D2%26pl%3D24%26ttl%3Dtransient%26susc%3Ddr%26driveid%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%26app%3Dexplorer%26mime%3Dvideo%2Fmp4%26vprv%3D1%26prv%3D1%26dur%3D8775.029%26lmt%3D1612196404551931%26mt%3D1618160459%26sparams%3Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%26sig%3DAOq0QJ8wRAIgJFTtuzFA6Y8D-esOQBFfwIc0N2Sncbo32ERciZ9TaecCIGCvb44U8ejqtdUzc84GmFKT_17DpYj2iWXBROl3n5E2%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%26lsig%3DAG3C_xAwRQIgVeWACgdswVRbGA7KGlPCE1rbEkmbG-J7Qu_frbBTd3ECIQCvqYFUuOZ9quV33O5FsS5duvgynpNG_5IEZDm48i7Uhw%3D%3D%2C37%7Chttps%3A%2F%2Fr2---sn-bg0eznlz.c.drive.google.com%2Fvideoplayback%3Fexpire%3D1618175340%26ei%3DLC1zYNjFDcOM8gStnI64Bg%26ip%3D45.184.131.85%26cp%3DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%26id%3D78edbfcf1fc76400%26itag%3D37%26source%3Dwebdrive%26requiressl%3Dyes%26mh%3DXL%26mm%3D32%26mn%3Dsn-bg0eznlz%26ms%3Dsu%26mv%3Du%26mvi%3D2%26pl%3D24%26ttl%3Dtransient%26susc%3Ddr%26driveid%3D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%26app%3Dexplorer%26mime%3Dvideo%2Fmp4%26vprv%3D1%26prv%3D1%26dur%3D8775.029%26lmt%3D1612265735773933%26mt%3D1618160459%26sparams%3Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%26sig%3DAOq0QJ8wRAIgVK9gEt4VVCfclg29yeicdxkjSLBH5GLBaGc2zZ3rFs8CIEAZ-8QHSI3r2a2JI27km7J_6lf1yAF_knmUCfboxC5G%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%26lsig%3DAG3C_xAwRQIhAIMFtRVlbf2oImOUp7CqF_MlH5073S-RvuJ2s3rHqwHPAiBIjnF5UtBKJ73vipMsiqERIQ0kIVFeAq_jFP93gEhnVA%3D%3D&url_encoded_fmt_stream_map=itag%3D18%26url%3Dhttps%253A%252F%252Fr2---sn-bg0eznlz.c.drive.google.com%252Fvideoplayback%253Fexpire%253D1618175340%2526ei%253DLC1zYNjFDcOM8gStnI64Bg%2526ip%253D45.184.131.85%2526cp%253DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%2526id%253D78edbfcf1fc76400%2526itag%253D18%2526source%253Dwebdrive%2526requiressl%253Dyes%2526mh%253DXL%2526mm%253D32%2526mn%253Dsn-bg0eznlz%2526ms%253Dsu%2526mv%253Du%2526mvi%253D2%2526pl%253D24%2526ttl%253Dtransient%2526susc%253Ddr%2526driveid%253D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%2526app%253Dexplorer%2526mime%253Dvideo%252Fmp4%2526vprv%253D1%2526prv%253D1%2526dur%253D8775.029%2526lmt%253D1612203534601168%2526mt%253D1618160459%2526sparams%253Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%2526sig%253DAOq0QJ8wRQIhAPjdubHafwixI9u_3cHc4Qt0sF8092zP3ZNSxPvqHY7nAiApe4jGKLmb4jVA4vqAGa5M-Sv2vPiwCCMFDIjzPvpq-Q%253D%253D%2526lsparams%253Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%2526lsig%253DAG3C_xAwRgIhAL9KrFxY09TeS3LW7B6wVmuM6pJTlVNC7B3uqVYHYXiuAiEAv43kEsHHcDK805VYorcU_CSm9_END9gpT_KX7QSZ9PA%253D%26type%3Dvideo%252Fmp4%253B%2Bcodecs%253D%2522avc1.42001E%252C%2Bmp4a.40.2%2522%26quality%3Dmedium%2Citag%3D22%26url%3Dhttps%253A%252F%252Fr2---sn-bg0eznlz.c.drive.google.com%252Fvideoplayback%253Fexpire%253D1618175340%2526ei%253DLC1zYNjFDcOM8gStnI64Bg%2526ip%253D45.184.131.85%2526cp%253DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%2526id%253D78edbfcf1fc76400%2526itag%253D22%2526source%253Dwebdrive%2526requiressl%253Dyes%2526mh%253DXL%2526mm%253D32%2526mn%253Dsn-bg0eznlz%2526ms%253Dsu%2526mv%253Du%2526mvi%253D2%2526pl%253D24%2526ttl%253Dtransient%2526susc%253Ddr%2526driveid%253D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%2526app%253Dexplorer%2526mime%253Dvideo%252Fmp4%2526vprv%253D1%2526prv%253D1%2526dur%253D8775.029%2526lmt%253D1612196404551931%2526mt%253D1618160459%2526sparams%253Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%2526sig%253DAOq0QJ8wRAIgJFTtuzFA6Y8D-esOQBFfwIc0N2Sncbo32ERciZ9TaecCIGCvb44U8ejqtdUzc84GmFKT_17DpYj2iWXBROl3n5E2%2526lsparams%253Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%2526lsig%253DAG3C_xAwRQIgVeWACgdswVRbGA7KGlPCE1rbEkmbG-J7Qu_frbBTd3ECIQCvqYFUuOZ9quV33O5FsS5duvgynpNG_5IEZDm48i7Uhw%253D%253D%26type%3Dvideo%252Fmp4%253B%2Bcodecs%253D%2522avc1.42001E%252C%2Bmp4a.40.2%2522%26quality%3Dhd720%2Citag%3D37%26url%3Dhttps%253A%252F%252Fr2---sn-bg0eznlz.c.drive.google.com%252Fvideoplayback%253Fexpire%253D1618175340%2526ei%253DLC1zYNjFDcOM8gStnI64Bg%2526ip%253D45.184.131.85%2526cp%253DQVRGWkJfVFNSQVhPOlp3SExoWl9oYTNKYk56Sm1iU3dGd25LakR1Y1BUM01JNmVUYW5SRDNWZjM%2526id%253D78edbfcf1fc76400%2526itag%253D37%2526source%253Dwebdrive%2526requiressl%253Dyes%2526mh%253DXL%2526mm%253D32%2526mn%253Dsn-bg0eznlz%2526ms%253Dsu%2526mv%253Du%2526mvi%253D2%2526pl%253D24%2526ttl%253Dtransient%2526susc%253Ddr%2526driveid%253D1HCK3eleZSNQfpuZaI_oyIBQ9I_DroTq8%2526app%253Dexplorer%2526mime%253Dvideo%252Fmp4%2526vprv%253D1%2526prv%253D1%2526dur%253D8775.029%2526lmt%253D1612265735773933%2526mt%253D1618160459%2526sparams%253Dexpire%252Cei%252Cip%252Ccp%252Cid%252Citag%252Csource%252Crequiressl%252Cttl%252Csusc%252Cdriveid%252Capp%252Cmime%252Cvprv%252Cprv%252Cdur%252Clmt%2526sig%253DAOq0QJ8wRAIgVK9gEt4VVCfclg29yeicdxkjSLBH5GLBaGc2zZ3rFs8CIEAZ-8QHSI3r2a2JI27km7J_6lf1yAF_knmUCfboxC5G%2526lsparams%253Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%2526lsig%253DAG3C_xAwRQIhAIMFtRVlbf2oImOUp7CqF_MlH5073S-RvuJ2s3rHqwHPAiBIjnF5UtBKJ73vipMsiqERIQ0kIVFeAq_jFP93gEhnVA%253D%253D%26type%3Dvideo%252Fmp4%253B%2Bcodecs%253D%2522avc1.42001E%252C%2Bmp4a.40.2%2522%26quality%3Dhd1080&timestamp=1618160940245&length_seconds=8774&fmt_list=37%2F1920x1080%2F9%2F0%2F115%2C22%2F1280x720%2F9%2F0%2F115%2C18%2F640x360%2F9%2F0%2F115
if you are using java script below this is a code snippet get the video link with 720 quality if available or whatever is available:
async function obter_link_video(IdVideo){
var All_Sizes_Video = {};
var Returned = await fetch('https://drive.google.com/u/1/get_video_info?docid='+IdVideo);
Returned = await Returned.text();
Returned = await Returned.split("&");
Returned.map((Value) => {
var Result = Value.split("=");
All_Sizes_Video[Result[0]] = Result[1];
});
if(All_Sizes_Video.status == "ok"){
var size_array = [];
var fmt_list = await decodeURIComponent(All_Sizes_Video.fmt_list);
var fmt_list = fmt_list.split(",");
var lenght_fmt_list = fmt_list.length-1;
fmt_list.map((value, index) => {
var result = value.split("/")[0];
size_array.push(result);
size_array.sort((a, b) => a - b);
var length_size_array = size_array.lenght-1;
if(index == lenght_fmt_list){
size_array = lenght_fmt_list == 0 ? size_array[0] : size_array[1];
}
});
var map_all_links = await decodeURIComponent(All_Sizes_Video.fmt_stream_map);
map_all_links = map_all_links.split(",");
map_all_links.map((value) => {
var select_size_video_by_link = value.split("|")[0] == size_array ? setlink_do_video(value.split("|")[1]) : "wrong";
setesta_usando_link_absoluto(true);
console.log(value.split('|')[1]);
});
}
}
and finally the last addendum is that each ip can make a maximum of 2000 requests per day to get information about the video if this value is exceeded you will get an error.

Can I overwrite the contents of an Excel file (exported from Google Sheets) saved on Google Drive with apps script

I use Google Apps script to export a Google Sheet as an Excel file to Google Drive. The Excel file then syncs with 6 others users to their local machines via the Google Drive Desktop app. Each time the Google Sheet is exported it creates a new file rather than replacing the old one albeit with the same filename and deletes the original version. This would be fine except that when it then syncs, with Google Drive Desktop, Windows deletes the original version and sends it to the recycle bin.
The file is created every 15 minutes and is 3mb in size so after a few weeks the recycle bins are full of Gigabytes of data.
Is it possible to update the contents of a file rather than create a new file?
Here's what I use at the moment:
var blob = exportAsExcel(spreadsheetId)
var file = DriveApp.createFile(blob).setName(excelFileName);
fileId = file.getId();
file.makeCopy(destinationFolder);
Drive.Files.remove(fileId);
}
function exportAsExcel(spreadsheetId) {
var file = Drive.Files.get(spreadsheetId);
var url = file.exportLinks['application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet'];
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
return response.getBlob();
}
You can overwrite a file using Drive API. The detail information is https://developers.google.com/drive/v3/reference/files/update.
I prepared a method to overwrite a spreadsheet to existing excel file. This method uses your method exportAsExcel(). At first, please confirm whether Drive API is enabled at Google API console and Advanced Google services.
src_sheetId and dst_fileId are spreadsheet ID and existing excel file that you want to overwrite, respectively. By running overWrite(), the existing excel file is overwritten. So the file name and file ID of excel file are not changed.
Script :
function overWrite(src_sheetId, dst_fileId) {
UrlFetchApp.fetch(
"https://www.googleapis.com/upload/drive/v3/files/" + dst_fileId + "?uploadType=multipart",
{
method: "PATCH",
headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()},
contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
payload: exportAsExcel(src_sheetId).getBytes()
}
);
}
By the way, does exportAsExcel() of your script work fine? When I use it, an error occurs. I removed the error by modification below.
From :
var url = file.exportLinks['application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet'];
To :
var url = file.exportLinks['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
If I misunderstand your question, I'm sorry.