How do get GIF from Google Docs using Apps Script? - google-apps-script

I want to get the gif image from google docs. Using Apps Script, gif images are got as
InlineImage. But it's only static without animating.
My code
var doc = DocumentApp.openByUrl('url');
Logger.log(doc.getBody().getImages()[0]);
var encoded = Utilities.base64Encode(doc.getBody().getImages()[0].getBlob().getBytes());
Logger.log(encoded);

You want to retrieve the original images from Google Document.
In your case, you want to retrieve an animation GIF from Google Document.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Unfortunately, it seems that the original images cannot be directly retrieved using getImages(). So in this answer, I use the method of documents.get in Google Docs API.
Flow:
The flow of this sample script is as follows.
Retrieve the object from Google Document using the method of documents.get in Google Docs API.
Retrieve the source information from the retrieved object.
The embeded original images can be retrieved from the property of inlineObjects.
Create the original images from the retrieved source information.
Sample script:
Before you use this script, please enable Google Docs API at Advanced Google services.
function myFunction() {
var documentId = "###"; // Please set Google Document ID.
// Retrieve the object from Google Document using the method of documents.get in Google Docs API.
var obj = Docs.Documents.get(documentId);
// Retrieve the source information from the retrieved object.
var inlineObjects = Object.keys(obj.inlineObjects).reduce(function(ar, e, i) {
var o = obj.inlineObjects[e].inlineObjectProperties.embeddedObject;
if (o.hasOwnProperty("imageProperties")) {
var res = UrlFetchApp.fetch(o.imageProperties.contentUri, {headers: {Authorization: "Baerer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true});
if (res.getResponseCode() == 200) ar.push(res.getBlob().setName("image" + (i + 1)));
}
return ar;
}, []);
// Create the original images from the retrieved source information.
inlineObjects.forEach(function(blob) {
var id = DriveApp.createFile(blob).getId();
Logger.log(id)
})
}
When you run the script, the image files are created to the root folder. And you can see the file IDs of them at the log. The filename is "image1", "image2",,, as the sample.
References:
Advanced Google services
Method: documents.get
InlineObject
If I misunderstood your question and this was not the direction you want, I apologize.

Related

Exception: Limit Exceeded: URLFetch URL Length on GOOGLE APPS SCRIPT [duplicate]

I am pulling data from an API which unfortunately has very big urls/end points.
Is there any way to shorten urls in order to bypass the Exception: Limit Exceeded: URLFetch URL Length error?
I found this: https://github.com/amitwilson/GoogleAppsScript/blob/master/LinkShortner but I don't know how to use it properly since most of the api calls i make are generated dynamically.
This is an example link (letters after "cursor=" is a cursor key which is different every time):
https://api.x.immutable.com/v1/orders?include_fees=false&status=filled&buy_token_address=0xacb3c6a43d15b907e8433077b6d38ae40936fe2c&order_by=updated_timestamp&direction=desc&user=0x72a2ffa8be361d4a5d575c55b7382d8c6317f77d&page_size=200&cursor=eyJvcmRlcl9pZCI6MTk0NTk2NzUyLCJzZXFfbnVtIjowLCJzdGF0dXMiOiJmaWxsZWQiLCJzdGFya19rZXkiOiIweDA3MWU2NjU0NTMzMGJiOGY5NDQ4ZWU1YTM3YTI5ODViZGYzYjQ1NzYwNDA5ODE4YmEwYTY0NmUxNjU4NTdhMWIiLCJ2YXVsdF9pZCI6MCwiZXRoZXJfa2V5IjoiMHg3MmEyZmZhOGJlMzYxZDRhNWQ1NzVjNTViNzM4MmQ4YzYzMTdmNzdkIiwic2VsbF90b2tlbl90eXBlIjoiRVRIIiwic2VsbF90b2tlbl9pZCI6IiIsInNlbGxfY2xpZW50X3Rva2VuX2lkIjoiIiwic2VsbF90b2tlbl9hZGRyZXNzIjoiIiwic2VsbF90b2tlbl9kZWNpbWFscyI6MTgsInNlbGxfcXVhbnRpdHkiOiIyODQzMDAwMDAwMDAwMDAwIiwic2VsbF9hc3NldF9uYW1lIjpudWxsLCJzZWxsX2Fzc2V0X2ltYWdlX3VybCI6bnVsbCwic2VsbF9jb2xsZWN0aW9uX25hbWUiOm51bGwsInNlbGxfY29sbGVjdGlvbl9pY29uX3VybCI6bnVsbCwiYnV5X3Rva2VuX3R5cGUiOiJFUkM3MjEiLCJidXlfY2xpZW50X3Rva2VuX2lkIjoiMjI0ODUzMTMiLCJidXlfdG9rZW5faWQiOiIweDU0ODRkZjA1NzM0OTkxNTg0NWNkNjM0YmVmNDAxNjY1YmE1YjAzZDEwNzE4YmU2ZTQxNmEyMTFhNmVhMGJkNzEiLCJidXlfdG9rZW5fYWRkcmVzcyI6IjB4YWNiM2M2YTQzZDE1YjkwN2U4NDMzMDc3YjZkMzhhZTQwOTM2ZmUyYyIsImJ1eV90b2tlbl9kZWNpbWFscyI6MCwiYnV5X3F1YW50aXR5IjoiMSIsImJ1eV9xdWFudGl0eV9pbmNsdXNpdmVfZmVlcyI6IjI4NDMwMDAwMDAwMDAxIiwiYnV5X2Fzc2V0X25hbWUiOiJFbGl4aXIgb2YgdGhlIFNuYWtlIiwiYnV5X2Fzc2V0X2ltYWdlX3VybCI6Imh0dHBzOi8vY2FyZC5nb2RzdW5jaGFpbmVkLmNvbS8_aWQ9ODU3XHUwMDI2cT00IiwiYnV5X2NvbGxlY3Rpb25fbmFtZSI6IkdvZHMgVW5jaGFpbmVkIiwiYnV5X2NvbGxlY3Rpb25faWNvbl91cmwiOiJodHRwczovL2ltYWdlcy5nb2RzdW5jaGFpbmVkLmNvbS9taXNjL2d1LXNpZ2VsLnBuZyIsImFtb3VudF9zb2xkIjoiMjg0MzAwMDAwMDAwMDAwMCIsImV4cGlyZWRfYXQiOiIyMTIxLTA1LTAzVDEwOjAwOjAwWiIsImNyZWF0ZWRfYXQiOiIyMDIyLTA1LTAzVDEwOjIwOjM0Ljc4ODkxN1oiLCJ1cGRhdGVkX2F0IjoiMjAyMi0wNS0wM1QxMDoyMDozNC43ODg5MTdaIiwiRmVlcyI6Ilczc2lZVzF2ZFc1MElqb2dJakk0TkRNd01EQXdNREF3TURBd0lpd2dJbVpsWlY5MGVYQmxJam9nSW0xaGEyVnlJaXdnSW05eVpHVnlYMmxrSWpvZ01UazBOVGsyTnpVeUxDQWljbVZqYVhCcFpXNTBYMlYwYUdWeVgydGxlU0k2SUNJd2VEVmpNell6WVRKaFlUZzJPV1F3WXpVeU1XTm1ZVE5sWWpCbE16YzBPVEpqTUdWaU5UbGxOVGdpTENBaWNtVmphWEJwWlc1MFgzTjBZWEpyWDJ0bGVTSTZJQ0l3ZURBMk1UY3haVEpoWlRRMU5qTXlNVE15TWpaak5XWm1aV1JpT1RSaE9UVXlOV0ppWm1Zell6bGtZMkpoWm1KaFpURTVabUk0TjJOa1ltSXpOMk5sTVdVaWZWMD0ifQ
In your situation, for example, how about the following sample script?
Sample script:
Before you use this script, please set apiKey and yourDynamicLinkDomain. Your yourDynamicLinkDomain might be like https://###.page.link.
const apiKey = "###"; // Please set your API key.
const yourDynamicLinkDomain = "###"; // Please set your dynamic link domain.
function getShortUrl_(longUrl) {
const url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=" + apiKey;
const options = {
payload: JSON.stringify({
dynamicLinkInfo: {
dynamicLinkDomain: yourDynamicLinkDomain,
link: longUrl,
},
}),
contentType: "application/json",
};
const res = UrlFetchApp.fetch(url, options);
const { shortLink } = JSON.parse(res.getContentText());
return shortLink;
}
// Please run this function.
function main() {
// do something for retrieving the long URL in your actual script.
const longUrl = "###"; // It supposes that your long URL is put to longUrl.
const shortUrl = getShortUrl_(longUrl); // Here, the long URL is shortned. You can use this.
// If "options" is required to be used, please use this.
const options = {
};
const res = UrlFetchApp.fetch(shortUrl, options);
}
In this sample script, it supposes that by your current script, longUrl is obtained. And, this sample script converts from the long URL to the short URL with the function getShortUrl_. And, you can use this short URL using UrlFetchApp.
Note:
This sample script supposes that you have already been able to use Firebase Dynamic Links API. Please be careful about this.
If you have never been able to be used Firebase Dynamic Links API, please check the official document. And, the following flow might be useful.
please check the following flow.
Please create a new Firebase project and link it to your Google Cloud Platform Project. Ref
At this time, please set dynamicLinkDomain at "Dynamic Links".
Please enable Firebase Dynamic Links API at the API console.
Please create your API key from your Google Cloud Platform Project.
Please use this API in the above script.
When I tested this script, I could confirm that the long URL is converted to the short URL and the short URL can be used with UrlFetchApp.
If I misunderstood about but I don't know how to use it properly since most of the api calls i make are generated dynamically., please tell me.
References:
Create Dynamic Links with the REST API
Class UrlFetchApp
Added:
From your following reply,
Hey I made a sample sheet so you can see how I get the longurl it is highlighted with yellow color in 202 row. docs.google.com/spreadsheets/d/… The API works like this: it can pull 200 rows, then on the last row of each call it shows this cursor ID which must be called again in next row in order to show the next 200 rows.
Check the sample sheet on my previous reply. Longurl is highlighted with YELLOW color.
When I saw your sample Spreadsheet, it seems that you are using the long URL as =importjson(CONCATENATE("https://api.x.immutable.com/v1/orders?include_fees=false&status=filled&buy_token_address=0xacb3c6a43d15b907e8433077b6d38ae40936fe2c&order_by=updated_timestamp&direction=desc&user=0x8604808B824C4444Fe4dF3f94850ACd584C5aD7d&page_size=200&cursor=",W202),"","noTruncate,noHeaders"). But unfortunately, from your question and your reply, I couldn't notice that you are using it like that.
In this case, it is required to use my sample script by modifying as follows.
Sample script:
Please copy and paste the following script to the script editor of your Spreadsheet and save the script.
function getShortUrl(longUrl) {
const apiKey = "###"; // Please set your API key.
const yourDynamicLinkDomain = "###"; // Please set your dynamic link domain.
const url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=" + apiKey;
const options = {
payload: JSON.stringify({
dynamicLinkInfo: {
dynamicLinkDomain: yourDynamicLinkDomain,
link: longUrl,
},
}),
contentType: "application/json",
};
const res = UrlFetchApp.fetch(url, options);
const { shortLink } = JSON.parse(res.getContentText());
return shortLink;
}
When this script is used for your sample Spreadsheet, please put the following formula to the cell "A203".
=importjson(getShortUrl(CONCATENATE("https://api.x.immutable.com/v1/orders?include_fees=false&status=filled&buy_token_address=0xacb3c6a43d15b907e8433077b6d38ae40936fe2c&order_by=updated_timestamp&direction=desc&user=0x8604808B824C4444Fe4dF3f94850ACd584C5aD7d&page_size=200&cursor=",W202)),"","noTruncate,noHeaders")
By this formula, the long URL retrieved with CONCATENATE("https://api.x.immutable.com/v1/orders?include_fees=false&status=filled&buy_token_address=0xacb3c6a43d15b907e8433077b6d38ae40936fe2c&order_by=updated_timestamp&direction=desc&user=0x8604808B824C4444Fe4dF3f94850ACd584C5aD7d&page_size=200&cursor=",W202) is shorten by shortenUrl(). And, use the shorten URL with importjson.
Note:
This sample script supposes that you have already been able to use Firebase Dynamic Links API. Please be careful about this.
When I tested the above script and formula to your sample Spreadsheet, I confirmed that the values are retrieved.

Getting image url in google script

Trying to get image url in google script.
couldn’t find any function that is able to get the url from images that are not in a specific cell, images are located above the grid.
any ideas?
Issue and workaround:
On October 30, 2018, in order to manage the images on the cells in Spreadsheet, a new Class of OverGridImage has been added. Ref By this, the images on the cells got to be able to be managed. This class has the method of getUrl. The official document of this method says as follows.
Gets the image's source URL; returns null if the URL is unavailable. If the image was inserted by URL using an API, this method returns the URL provided during image insertion.
Namely, for example, when the following script is run, the URL of the image can be retrieved.
function sample1() {
const sheet = SpreadsheetApp.getActiveSheet();
// Put image from URL.
sheet.insertImage("https://stackoverflow.design/assets/img/logos/so/logo-stackoverflow.png", 1, 1);
// Retrieve image URL.
const images = sheet.getImages();
const url = images[0].getUrl();
console.log(url)
}
In your actual situation, if your images are put on the cells using the above script, the URLs can be retrieved by the above simple script. But, here, there is an important point. After the image was put using this script, when you manually move the image, the URL cannot be retrieved. I think that this is a bug.
And also, if you had manually put the images from the URL and your drive, unfortunately, the URL of the images cannot be retrieved. About this, it has already been reported to the Google issue tracker. Ref
If you had manually put the images from the URL and your drive, and when you want to retrieve the URLs of the images, it is required to use a workaround. In this case, I would like to propose to use this method of this answer. In this answer, my created Google Apps Script library is used.
Usage:
1. Install Google Apps Script library.
You can see the method for installing this library at here.
2. Enable Drive API.
In this case, Drive API is used. So, please enable Drive API at Advanced Google services.
3. Sample script.
function sample2() {
const sheetName = "Sheet1"; // Please set the sheet name.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
const images = sheet.getImages();
const obj = images.reduce((o, e) => {
const u = e.getUrl();
if (u) o[e.getAnchorCell().getA1Notation()] = u;
return o;
}, {});
const res = DocsServiceApp.openBySpreadsheetId(ss.getId()).getSheetByName(sheetName).getImages();
if (res.length == 0) return;
const urls = res.map(({ image, range }, i) => {
if (obj[range.a1Notation]) return obj[range.a1Notation];
const o = Drive.Files.insert({ title: `sample${i + 1}` }, image.blob);
const url = o.thumbnailLink.replace(/\=s\d+/, "=s1000");
DriveApp.getFileById(o.id).setTrashed(true);
return url;
});
console.log(urls)
}
4. Testing.
When the above script is run, the images are retrieved from "Sheet1" and retrieve the URLs of the images. For example, when there are images put with the image URL using the script, the URL can be retrieved.
Note:
In this workaround, in order to retrieve the URL of the image, the thumbnail link is used. This link is not permanent. Please be careful about this. If you are required to retrieve the permanent link, please create the retrieved image file blob as the file, and please publicly share them, and then, please retrieve the WebContentLink. By this, you can retrieve the permanent link of the image.
References:
DocsServiceApp
Related thread
How to access new 'in-cell-image' from google apps script?

Can I use DocumentApp.openById() with read only permission?

I am creating a Google Apps Script add-on that is for a Google Spreadsheet, but it needs to be able to access the content of a separate Google Doc, which I am doing using DocumentApp.openById(). I have given the script these scopes:
"oauthScopes": [
"https://www.googleapis.com/auth/documents.readonly",
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
But apparently, that's not enough. The script is telling me it needs the https://www.googleapis.com/auth/documents permission to work properly. However, it seems excessive to give the add-on permission to edit ALL Google Docs files when it just needs to be able to view the content of one. Am I missing something? Is there a way to give it read-only access to a separate Google Docs file?
Here is the function I am using for testing, with most of the document ID censored out:
function getDoc() {
var id = '1NLH----------------------------------------'
var templateFile = DocumentApp.openById(id)
var templateText = templateFile.getBody().getText()
Logger.log(templateText)
}
Thanks!
I believe your goal as follows.
You want to retrieve the text data from Google Document using the following script.
function getDoc() {
var id = '1NLH----------------------------------------'
var templateFile = DocumentApp.openById(id)
var templateText = templateFile.getBody().getText()
Logger.log(templateText)
}
You want to achieve this using the scope of https://www.googleapis.com/auth/documents.readonly and Google Apps Script.
Issue and workaround:
In the current stage, DocumentApp.openById of Document service is used, it is required to use the scope of https://www.googleapis.com/auth/documents. It seems that this is the current specification. So, in this answer, as a workaround, I would like to propose to use Google Docs API instead of Document service. When Google Docs API is used, your script can be achieved using the scope of https://www.googleapis.com/auth/documents.readonly.
When your above script is modified using Google Docs API, it becomes as follows.
Sample script:
Before you use this script, please enable Google Docs API at Advanced Google services. This script can work with only the scope of https://www.googleapis.com/auth/documents.readonly.
function myFunction() {
const documentId = "###"; // Please set the Document ID.
const obj = Docs.Documents.get(documentId);
const text = obj.body.content.reduce((s, c) => {
if (c.paragraph && c.paragraph.elements) {
s += c.paragraph.elements.map(e => e.textRun.content).join("");
}
return s;
}, "");
console.log(text)
}
Reference:
Method: documents.get

When trying to convert ppt to Google Slide receive converting error

In my google script program, I am trying to iterate over a folder and make all of the ppt files into google slide files.
function makeSlides(url) {
slideUrls = [];
var id = getId(url);
var powerPoints = DriveApp.getFolderById(id).getFilesByType(MimeType.MICROSOFT_POWERPOINT);
// turn ppt into slides
while(powerPoints.hasNext()) {
var powerPoint = powerPoints.next()
try{
var sheet = powerPoint.getBlob().getAs(MimeType.GOOGLE_SLIDES);
DriveApp.getFolderById(url).createFile(sheet)
Logger.log("OK " + powerPoint.getName());
}catch(e) {
Logger.log("ERROR: " + e)
}
}
After checking the logs I get an error
Exception: Converting from application/vnd.openxmlformats-officedocument.presentationml.presentation to application/vnd.google-apps.presentation is not supported.
I know within the UI of Google Drive, you can open a ppt as a Google Slide. Is there any work around to this? Or am I doing it wrong?
I did find this but this is the opposite of what I am trying to accomplish.
It cannot convert from Powerpoint format to Google Slides using getAs(). You can achieve this using Drive API. In this modification, I used Drive API using Advanced Google Services.
When you use this script, please enable Drive API at Advanced Google Services and API console. You can see about this at here.
Modified script:
Please modify as follows.
From:
var sheet = powerPoint.getBlob().getAs(MimeType.GOOGLE_SLIDES);
DriveApp.getFolderById(url).createFile(sheet)
To:
Drive.Files.insert({title: powerPoint.getName(), mimeType: MimeType.GOOGLE_SLIDES}, powerPoint.getBlob());
Note:
In this modified script, the converted file is created to the root folder. If you want to create in the specific folder, please modify from {title: powerPoint.getName(), mimeType: MimeType.GOOGLE_SLIDES} to {title: powerPoint.getName(), mimeType: MimeType.GOOGLE_SLIDES, parents: [{id: folderId}]}.
If you want to retrieve the file ID from the converted file, please use var id = Drive.Files.insert({title: powerPoint.getName(), mimeType: MimeType.GOOGLE_SLIDES}, powerPoint.getBlob()).id.
References:
Advanced Google Services
Drive API
Drive.Files.insert
If I misunderstand your question, please tell me. I would like to modify it.

Google app scripts: email a spreadsheet as excel

How do you make an app script which attaches a spreadsheet as an excel file and emails it to a certain email address?
There are some older posts on Stackoverflow on how to do this however they seem to be outdated now and do not seem to work.
Thank you.
It looks like #Christiaan Westerbeek's answer is spot on but its been a year now since his post and I think there needs to be a bit of a modification in the script he has given above.
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
There is something wrong with this line of code, maybe that exportLinks has now depreciated. When I executed his code it gave an error to the following effect:
TypeError: Cannot read property "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" from undefined.
The workaround is as follows:
The URL in the above line of code is basically the "download as xlsx" URL that can be used to directly download the spreadsheet as an xlsx file that you get from File> Download as > Microsoft Excel (.xlsx)
This is the format:
https://docs.google.com/spreadsheets/d/<<<ID>>>/export?format=xlsx&id=<<<ID>>>
where <<>> should be replaced by the ID of your file.
Check here to easily understand how to extract the ID from the URL of your google sheet.
Here's an up-to-date and working version. One prerequisite for this Google Apps script to work is that the Drive API v2 Advanced Google Service must be enabled. Enable it in your Google Apps script via Resources -> Advanced Google Services... -> Drive API v2 -> on. Then, that window will tell you that you must also enabled this service in the Google Developers Console. Follow the link and enable the service there too! When you're done, just use this script.
/**
* Thanks to a few answers that helped me build this script
* Explaining the Advanced Drive Service must be enabled: http://stackoverflow.com/a/27281729/1385429
* Explaining how to convert to a blob: http://ctrlq.org/code/20009-convert-google-documents
* Explaining how to convert to zip and to send the email: http://ctrlq.org/code/19869-email-google-spreadsheets-pdf
* New way to set the url to download from by #tera
*/
function emailAsExcel(config) {
if (!config || !config.to || !config.subject || !config.body) {
throw new Error('Configure "to", "subject" and "body" in an object as the first parameter');
}
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = spreadsheet.getId()
var file = Drive.Files.get(spreadsheetId);
var url = 'https://docs.google.com/spreadsheets/d/'+spreadsheetId+'/export?format=xlsx';
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var fileName = (config.fileName || spreadsheet.getName()) + '.xlsx';
var blobs = [response.getBlob().setName(fileName)];
if (config.zip) {
blobs = [Utilities.zip(blobs).setName(fileName + '.zip')];
}
GmailApp.sendEmail(
config.to,
config.subject,
config.body,
{
attachments: blobs
}
);
}
Update: I updated the way to set the url to download from. Doing it through the file.exportLinks collection is not working anymore. Thanks to #tera for pointing that out in his answer.