How to get video duration of google drive file via API? - google-apps-script

On my website, I am hosting a few videos via Google Drive. On my sidebar, there is a thumbnail of the videos and I'd like to show the duration of the video in the corner. I have looked at two similar questions (here and here) to solve this problem. This is what I produced from looking at these two problems:
function sample1() {
console.log("running script");
var fileId = "theFileID"; // Please set the file ID of the video file.
var fields = "mimeType,name,videoMediaMetadata"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files/" + fileId + "?fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
var obj = JSON.parse(res);
console.log("filename: %s, duration: %s seconds", obj.name, obj.videoMediaMetadata.durationMillis / 1000);
}
sample1();
However, when I check the console after running this script, nothing is printed after "running script". Is there a different approach I should be taking in my program when attempting to solve this problem via Google APIs?

Using the Drive API method Files: get with Apps Script I have been able to get the durationMillis from the video.
You have to add the Drive API Advanced Services on the Apps Script project:
function getVideoLength() {
var fileId = "FILE ID";
var returnedFile = Drive.Files.get(fileId);
Logger.log(returnedFile.videoMediaMetadata.durationMillis)
}

Related

Google Slides to PNG with Apps Script [duplicate]

Good Morning All. I have written a short script which batch-creates [single page] Google Slides based on rows from a spreadsheet. While in the loop for each creation, I would like to create a PNG of the Slide in Google Drive (or download on the user's desktop). These pictures should be the same specs as if a user clicked File>Download>PNG - the heavy small text requires full projector HD - so I don't believe I can use the "Thumbnail" function which appears limited to 1600 pixels.
My code below generates the error "Converting from text/html to image/png is not supported" - so I'm not sure if this is a limitation of the API or a problem with my coding. Thank you in advance.
var options =
{
"contentType" : "image/PNG"
};
var url = 'https://docs.google.com/presentation/d/' + presentationCopyId + '/export/PNG';
var response = UrlFetchApp.fetch(url, options);
var image = response.getAs(MimeType.PNG);
image.setName(SlideName);
DriveApp.createFile(image);
Yes, It is possible.
You can use Google slide API and make a PNG file of every page of Google slide.
Here is the code,
BUT first you have to enable API as following
open script editor
click on resources-> Advanced Google Services
Enable Google slide API and Drive API .
click on ok
now copy and paste this code,
and write your slide ID in presentationID.
function generateScreenshots() {
var presentationId = "***ADD YOUR Google Slide ID Only***";
var presentation = SlidesApp.openById(presentationId);
var baseUrl =
"https://slides.googleapis.com/v1/presentations/{presentationId}/pages/{pageObjectId}/thumbnail";
var parameters = {
method: "GET",
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
contentType: "application/json",
muteHttpExceptions: true
};
// Log URL of the main thumbnail of the deck
Logger.log(Drive.Files.get(presentationId).thumbnailLink);
// For storing the screenshot image URLs
var screenshots = [];
var slides = presentation.getSlides().forEach(function(slide, index) {
var url = baseUrl
.replace("{presentationId}", presentationId)
.replace("{pageObjectId}", slide.getObjectId());
var response = JSON.parse(UrlFetchApp.fetch(url, parameters));
// Upload Googel Slide image to Google Drive
var blob = UrlFetchApp.fetch(response.contentUrl).getBlob();
DriveApp.createFile(blob).setName("Image " + (index + 1) + ".png");
screenshots.push(response.contentUrl);
});
return screenshots;
}
This answer is outdated, leaving up for documentation purposes but please see other answer.
Answer:
Unfortunately it is not possible to export a Slides as a PNG file using the the Slides nor Drive APIs.
More Information:
According to the documentation, there are only four available MimeTypes for exporting Presentations files:
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.oasis.opendocument.presentation
application/pdf
text/plain
Attempting to export to the image/png MIME Type results in the following error:
Converting from text/html to image/png is not supported
For testing purposes, I tried using the /export/pdf endpoint and making a second conversion to PNG from there like so:
function slidesAsPngAttempt() {
var presentationCopyId = "1Loa...pQs";
var options =
{
"contentType" : "application/pdf"
};
// for exporting to pdf the /export/pdf needs to be all lower case to avoid 404
var url = 'https://docs.google.com/presentation/d/' + presentationCopyId + '/export/pdf';
var response = UrlFetchApp.fetch(url, options);
var pdfAsblob = response.getBlob();
var image = pdfAsblob.getAs('image/png');
image.setName(DriveApp.getFileById(presentationCopyId).getName());
DriveApp.createFile(image);
}
Unfortunately, a similar error occurs when running var image = pdfAsblob.getAs('image/png'):
Converting from application/pdf to image/png is not supported.
From the same export MIME types reference documentation, the only export types available for PDF files are:
text/csv
text/tab-separated-values
application/zip
References:
G Suite documents and corresponding export MIME types
Google Apps Script - method Blob.getAs(contentType)

Google Drive API files by created Date

My goal is to delete files from a specific folder older than 60 days.
I have a script as follows (based on code from another post I can't find anymore):
function getOldFileIDs() {
var fileIDs = [];
// Old date is 60 days
var oldDate = new Date().getTime() - 3600*1000*24*60;
var cutOffDate = Utilities.formatDate(new Date(oldDate), "GMT", "yyyy-MM-dd");
// Get folderID using the URL on google drive
var folder = DriveApp.getFolderById('XXXXX');
var files = folder.searchFiles('modifiedDate < "' + cutOffDate + '"');
while (files.hasNext()) {
var file = files.next();
fileIDs.push(file.getId());
Logger.log('ID: ' + file.getId() + ', Name: ' + file.getName());
}
return fileIDs;
};
function deleteFiles() {
var fileIDs = getOldFileIDs();
fileIDs.forEach(function(fileID) {
DriveApp.getFileById(fileID).setTrashed(true);
});
};
This code works but it uses "modifiedDate" When I look in the folder, I see there are many very old files with a "modified" date of today for some reason, but the "Created" date seems correct.
Therefore, I tried changing the code to "createdDate" but that doesn't work.
I decided to actually look at the documentation:
https://developers.google.com/apps-script/reference/drive/drive-app#searchFiles(String)
https://developers.google.com/drive/api/guides/ref-search-terms
It seems like "modifiedDate" isn't even listed yet it seems to work.
Delete old files:
function delOldFiles() {
const dt = new Date();
const dtv = new Date(dt.getFullYear(),dt.getMonth(),dt.getDate() - 60).valueOf();
var folder = DriveApp.getFolderById('XXXXX');
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
if(new Date(file.getDateCreated()).valueOf() < dtv) {
Drive.Files.remove(file.getId());
}
}
}
Issue and workaround:
The parameter of "searchFiles" method uses the search query for Drive API v2. When I tested createdDate > '####-##-##' for "searchFiles" and "Files: list" of Drive API v2, I confirmed errors like Invalid argument: q and Invalid query occurred, respectively. This has already been mentioned in Lorena Gomez's answer
Fortunately, when Drive API v3 is used, createdTime can be used. createdTime of Drive API v3 is the same with createdDate of Drive API v2. In this answer, as a workaround, I would like to propose using Drive API v3 instead of Drive API v2 ("searchFiles" of DriveApp). I have already posted this workaround at this post. But, this has not been posted in Stackoverflow. When this is posted here, I thought that it might be useful for other users.
When Drive API v3 is reflected in your script, how about the following modification?
Modified script:
This script uses Drive API. So, please enable Drive API at Advanced Google services.
function getOldFileIDs() {
var folderId = "###"; // Please set your folder ID.
var fileIDs = [];
// Old date is 60 days
var oldDate = new Date().getTime() - 3600 * 1000 * 24 * 60;
var cutOffDate = Utilities.formatDate(new Date(oldDate), "GMT", "yyyy-MM-dd");
var query = `'${folderId}' in parents and createdTime < '${cutOffDate}' and trashed=false`;
var pageToken = "";
do {
var url = encodeURI(`https://www.googleapis.com/drive/v3/files?q=${query}&pageSize=1000&pageToken=${pageToken}&fields=files(id,name,createdTime),nextPageToken&orderBy=createdTime`);
var res = UrlFetchApp.fetch(url, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } });
var obj = JSON.parse(res.getContentText());
if (obj.files.length > 0) {
fileIDs = [...fileIDs, ...obj.files.map(({ id }) => id)];
obj.files.forEach(({ id, name, createdTime }) => Logger.log(JSON.stringify({ id, name, createdTime })));
}
pageToken = obj.nextPageToken;
} while (pageToken);
return fileIDs;
}
When this script is run, the file list including file IDs is retrieved with the search query of '${folderId}' in parents and createdTime < '${cutOffDate}' and trashed=false.
When you are not required to check the process, please remove obj.files.forEach(({ id, name, createdTime }) => Logger.log(JSON.stringify({ id, name, createdTime })));.
Note:
As additional information, in order to remove the files, when the number of files is large when setTrashed is run in a loop, the process cost becomes high. In this case, how about using batch requests? When batch requests are used, the process cost can be reduced. Ref
When batch requests are used with Google Apps Script, a script is a bit complicated. So, I created a Google Apps Script library. Ref When your script of deleteFiles() is modified for removing the files with the batch requests, how about the following modification?
1. Install Google Apps Script library.
Please install the Google Apps Script library. You can see how to install it here.
2. Sample script.
In this sample, the result is the same with setTrashed. The files of fileIDs are moved to the trash box.
function deleteFiles() {
var fileIDs = getOldFileIDs();
var requests = fileIDs.map(id => ({
method: "PATCH",
endpoint: `https://www.googleapis.com/drive/v3/files/${id}`,
requestBody: { trashed: true },
}));
var result = BatchRequest.EDo({ batchPath: "batch/drive/v3", requests });
console.log(result);
}
If you want to completely delete the files of fileIDs, please use the following script. But, this script completely deletes the files. So, please be careful about this. So, I would like to recommend using the above script. After you check the files in the trash box, you can empty the trash box.
function deleteFiles() {
var fileIDs = getOldFileIDs();
var requests = fileIDs.map(id => ({
method: "DELETE",
endpoint: `https://www.googleapis.com/drive/v3/files/${id}`,
}));
var result = BatchRequest.EDo({ batchPath: "batch/drive/v3", requests });
console.log(result);
}
References:
Files: list of Drive API v3
BatchRequest of Google Apps Script library
Regarding your question:
Therefore, I tried changing the code to "createdDate" but that doesn't work.
This seems to be an issue which has already been reported in this issue tracker, you can keep track of this to see any updates in the future, this is another thread related to the issue. #Cooper's answer is a good workaround to achieve what you're looking for.

Send Image From Google Sheets (Google Disk) to Telegram bot

I'm trying sent images chart from Google Sheets to Telegram.
I'm saving image chart to Google Disk and then send it to Telegram chat (helping this my telegram bot).
If I send Google Drive link to telegram in that way:
first try:
file_id_0 = "https://drive.google.com/file/d/1kvitP05ofdyT4YtHgNBdjP-sxIFQlpo7/view?usp=drivesdk";
This is first try result: First Try - It's bad: I want to see only image on telegram chat - without links.
On this site I found resolve this problem (sorry I'm loss the link): use Google Docs with file_id from Google Drive. File ID on link up between "/d/file_id/view".
To confirm this decision, I took the id of some other file on Google Drive and concatenate it:
file_id_2 = "1bSSzt5S9SgafeAK7D6dfRiFGECxhSuXo";
sendImage(chatId, "https://docs.google.com/uc?id=" + file_id_2);
Second try result: Second Try - It's perfect - what I need!
Now I'm trying to extract file_id from Google Drive file
file.getId()
and concatenate this Id to google docs link.
Third try result:third try - unsuccessful.
If I grab the link in debug programm and open this at browser - this opened correctly (as in second try). In my opinion link on second and third link without differences. At least they open correctly in the browser.
How should I insert this link to my function so that there are no problems?
P.S: I'm so sorry for my English. I am ready to give any explanations and I hope that the pictures helped understanding my problem.
Full Code:
function downloadChart2() {
let chatId = "-xxx";
var sheet = SpreadsheetApp.getActiveSheet();
// Get chart and save it into your Drive
var chart = sheet.getCharts()[0];
var file = DriveApp.createFile(chart.getBlob());
// Set url in one cell and resize the column
sheet.getRange(23, 1).setValue(file.getUrl())
sheet.autoResizeColumn(1);
file.setName("1234");
// first try - successful, but bad view on Telegram
var file_id_0 = file.getUrl();
sendText(chatId, file_id_0);
// second try - successful, but i grab this id on adress panel in my brouser
var file_id_1 = "1cAdAMWFdzZFRgXiM9kbxkzrwVAGpoOIy";
sendImage(chatId, "https://docs.google.com/uc?id=" + file_id_1);
// third try - unsuccessful
var file_id_2 = file.getId();
var file_id_3 = "https://docs.google.com/uc?id=" + file_id_2; // this link correctly
sendImage(chatId, file_id_3); // but this don't work
}
}
function sendImage(chatId, text, keyBoard) {
let data = {
method: 'post',
payload: {
method: 'sendMessage',
chat_id: String(chatId),
text: text,
parse_mode: 'HTML',
reply_markup: JSON.stringify(keyBoard)
}
}
var caption = "Second";
UrlFetchApp.fetch("https://api.telegram.org/bot" + token + "/sendPhoto?caption=" + encodeURIComponent(caption) + "&photo=" + encodeURIComponent(text) + "&chat_id="
+ chatId + "&parse_mode=HTML");
}
When I saw your script, I thought that the created image file might not be publicly shared. I thought that this might be the reason for your issue. So how about the following modification?
From:
var file = DriveApp.createFile(chart.getBlob());
To:
var file = DriveApp.createFile(chart.getBlob());
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
Reference:
setSharing(accessType, permissionType)
Link
var file_id_3 = "https://docs.google.com/uc?id=" + file_id_2;
is not direct link to image. It's redirection link.
I do this:
var file = DriveApp.getFileById(file_id);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var file_uri = file.getUrl();
sendImage(chatId,file_uri);
It's work.

Google Suite - Apps Script - Download Slides as PNG files via API

Good Morning All. I have written a short script which batch-creates [single page] Google Slides based on rows from a spreadsheet. While in the loop for each creation, I would like to create a PNG of the Slide in Google Drive (or download on the user's desktop). These pictures should be the same specs as if a user clicked File>Download>PNG - the heavy small text requires full projector HD - so I don't believe I can use the "Thumbnail" function which appears limited to 1600 pixels.
My code below generates the error "Converting from text/html to image/png is not supported" - so I'm not sure if this is a limitation of the API or a problem with my coding. Thank you in advance.
var options =
{
"contentType" : "image/PNG"
};
var url = 'https://docs.google.com/presentation/d/' + presentationCopyId + '/export/PNG';
var response = UrlFetchApp.fetch(url, options);
var image = response.getAs(MimeType.PNG);
image.setName(SlideName);
DriveApp.createFile(image);
Yes, It is possible.
You can use Google slide API and make a PNG file of every page of Google slide.
Here is the code,
BUT first you have to enable API as following
open script editor
click on resources-> Advanced Google Services
Enable Google slide API and Drive API .
click on ok
now copy and paste this code,
and write your slide ID in presentationID.
function generateScreenshots() {
var presentationId = "***ADD YOUR Google Slide ID Only***";
var presentation = SlidesApp.openById(presentationId);
var baseUrl =
"https://slides.googleapis.com/v1/presentations/{presentationId}/pages/{pageObjectId}/thumbnail";
var parameters = {
method: "GET",
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
contentType: "application/json",
muteHttpExceptions: true
};
// Log URL of the main thumbnail of the deck
Logger.log(Drive.Files.get(presentationId).thumbnailLink);
// For storing the screenshot image URLs
var screenshots = [];
var slides = presentation.getSlides().forEach(function(slide, index) {
var url = baseUrl
.replace("{presentationId}", presentationId)
.replace("{pageObjectId}", slide.getObjectId());
var response = JSON.parse(UrlFetchApp.fetch(url, parameters));
// Upload Googel Slide image to Google Drive
var blob = UrlFetchApp.fetch(response.contentUrl).getBlob();
DriveApp.createFile(blob).setName("Image " + (index + 1) + ".png");
screenshots.push(response.contentUrl);
});
return screenshots;
}
This answer is outdated, leaving up for documentation purposes but please see other answer.
Answer:
Unfortunately it is not possible to export a Slides as a PNG file using the the Slides nor Drive APIs.
More Information:
According to the documentation, there are only four available MimeTypes for exporting Presentations files:
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.oasis.opendocument.presentation
application/pdf
text/plain
Attempting to export to the image/png MIME Type results in the following error:
Converting from text/html to image/png is not supported
For testing purposes, I tried using the /export/pdf endpoint and making a second conversion to PNG from there like so:
function slidesAsPngAttempt() {
var presentationCopyId = "1Loa...pQs";
var options =
{
"contentType" : "application/pdf"
};
// for exporting to pdf the /export/pdf needs to be all lower case to avoid 404
var url = 'https://docs.google.com/presentation/d/' + presentationCopyId + '/export/pdf';
var response = UrlFetchApp.fetch(url, options);
var pdfAsblob = response.getBlob();
var image = pdfAsblob.getAs('image/png');
image.setName(DriveApp.getFileById(presentationCopyId).getName());
DriveApp.createFile(image);
}
Unfortunately, a similar error occurs when running var image = pdfAsblob.getAs('image/png'):
Converting from application/pdf to image/png is not supported.
From the same export MIME types reference documentation, the only export types available for PDF files are:
text/csv
text/tab-separated-values
application/zip
References:
G Suite documents and corresponding export MIME types
Google Apps Script - method Blob.getAs(contentType)

How to get file (video) duration of google drive file programmatically?

Either using rest API, Google Scripts, Node SDK, whatever works.
I'm seeing this in the docs but that doesn't seem to tell me the duration:
function watchFile(fileId, channelId, channelType, channelAddress) {
var resource = {
'id': channelId,
'type': channelType,
'address': channelAddress
};
var request = gapi.client.drive.files.watch({
'fileId': fileId,
'resource': resource
});
request.execute(function(channel){console.log(channel);});
}
I found this link but it doesn't seem to help https://apis-nodejs.firebaseapp.com/drive/classes/Resource$Files.html#watch
You want to retrieve the duration of the video on your Google Drive.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this sample script? In this modification, I used files.get and files.list methods of Drive API. From your question, I thought that the script that the endpoint is directly requests might be useful for your situation. So I proposed the following script.
1. Using files.get method
In this sample script, the duration is retrieved from a video file.
Sample script:
function sample1() {
var fileId = "###"; // Please set the file ID of the video file.
var fields = "mimeType,name,videoMediaMetadata"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files/" + fileId + "?fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res);
Logger.log("filename: %s, duration: %s seconds", obj.name, obj.videoMediaMetadata.durationMillis / 1000);
// DriveApp.getFiles() // This line is put for automatically detecting the scope (https://www.googleapis.com/auth/drive.readonly) for this script.
}
2. Using files.list method
In this sample script, the durations are retrieved from a folder including the video files.
Sample script:
function sample2() {
var folderId = "###"; // Please set the folder ID including the video files.
var q = "'" + folderId + "' in parents and trashed=false";
var fields = "files(mimeType,name,videoMediaMetadata)"; // duration is included in "videoMediaMetadata"
var url = "https://www.googleapis.com/drive/v3/files?q=" + encodeURIComponent(q) + "&fields=" + encodeURIComponent(fields) + "&access_token=" + ScriptApp.getOAuthToken();
var res = UrlFetchApp.fetch(url);
var obj = JSON.parse(res);
for (var i = 0; i < obj.files.length; i++) {
Logger.log("filename: %s, duration: %s seconds", obj.files[i].name, obj.files[i].videoMediaMetadata.durationMillis / 1000);
}
// DriveApp.getFiles() // This line is put for automatically detecting the scope (https://www.googleapis.com/auth/drive.readonly) for this script.
}
Note:
These are simple sample scripts. So please modify them for your situation.
I'm not sure about the format of your video files. So if above script cannot be used for your situation, I apologize.
References:
Files of Drive API
Class UrlFetchApp
If I misunderstood your question and this was not the result you want, I apologize.
Updated: March 19, 2020
From January, 2020, the access token cannot be used with the query parameter like access_token=###. Ref So please use the access token to the request header instead of the query parameter. It's as follows.
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});