Fetching complete Google Photos album webpage from Apps Script - google-apps-script

I've been trying to scrape a publicly-shared photo album I have on Google Photos: sharing the album provides a link along the format of photos.app.goo.gl/{SOME_ID}. The goal is to be able to retrieve the individual photo URLs (the URLs that don't expire, following the format lh3.googleusercontent.com and which can then be embedded onto any other website within an tag).
I would like to do this in Google Apps Script and have tried the following:
var response = UrlFetchApp.fetch("https://photos.app.goo.gl/{SOME_ID}");
Logger.log(response.getContentText());
However, the response doesn't display any of the images as if the page would instead need to be loaded some more, even though I'm testing this on an album with just 2 photos. If I inspect the page manually, I can clearly see the images + image links along the lh3.googleusercontent.com format. What should I change to my fetch request?
I've seen other implementations (outside of Apps Script) using Axios that managed to get the URLs I want, but haven't found a way of importing the Axios library into Apps Script.

Answer:
You can use the Google Photos API in Apps Script to get the individual photo URLs of a shared album.
More Information:
UrlFetchApp.fetch() returns an HTTPResponse object within Apps Script which contains Headers, HTML Content and other information such as the HTTP response code, as if the page was being fetched and loaded via a browser. There is also a set of URL Fetch limits as detailed on the Quotas for Google Services page which result in you getting a truncated response for sufficiently large pages.
The Photos API however has methods which are specifically designed for the purpose you are describing, and this data can be retrieved from the mediaItems REST resource. Bear in mind however, that this returns all photos and not ones that are in a specific album; further processing would need to be done from there.
Example Code:
After creating a new project in the Developers Console, you need to enable the Photos API from the APIs & Services > Library menu item, and then link it to your Apps Script Project by going to the script UI and following Resources > Cloud Platform project. Add the project number of the project just created in the Developer's Console and press Set Project.
Here is a small code snippet which will return photos from your Google Photos account, and log the individual photo URLs in the Logger:
function logPhotoUrls() {
var url = 'https://photoslibrary.googleapis.com/v1/mediaItems';
var options = {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
},
method: 'get',
muteHttpExceptions: false
};
var response = UrlFetchApp.fetch(url, options);
for (var i = 0; i < 10; i++) {
Logger.log(JSON.parse(response.getContentText()).mediaItems[i].productUrl);
}
}
You will also need to edit your appscript.json, which you can see by following View > Show manifest file to include the following:
{
"oauthScopes": ["https://www.googleapis.com/auth/photoslibrary.readonly",
"https://www.googleapis.com/auth/script.external_request"]
}
References:
Google Apps Script - Quotas for Google Services
Google Photos Library API
Google Photos API - Get started with REST
Google Photos API - Method mediaItems:list
Google Developers Console
Google Apps Script - Class UrlFetchApp
Google Apps Script - Manifest structure

Related

How to call an API running locally from Apps Script

I am building a Container Bound Script using AppsScript wrt Google Sheets.
I am taking input by adding a menu on the google sheet as shown below,
And when clicked, prompted with a HTML form, in which we can upload a PDF, which is saved on Google Drive and the information regarding the file upload in saved on the google sheets, but I also want to send to a FastAPI running locally on my machine.
File Information stored on Google Sheets
Code for saving on Google Drive
function uploadFilesToGoogleDrive(data,name,type){
var datafile = Utilities.base64Decode(data)
//create a new blob with decode data, name, type
var blob2 = Utilities.newBlob(datafile, type, name);
var folder = DriveApp.getFolderById("<url>");
//Create new file (property of final user)
var newFile = folder.createFile(blob2);
var rowData = [
newFile.getName(),
newFile.getUrl(),
newFile.getDateCreated()
];
SpreadsheetApp.getActive().getSheetByName("sheet1").appendRow(rowData);
return newFile.getUrl()
}
For sending data to external API I came across Run app script function from website/localhost and Upload files from google drive to external api using google apps script
I am not getting a method through which I can send to API running locally without localtunnel.
It's not possible to run a Google Apps Scripts project locally, Google Apps Scripts projects run on Google Servers.
You can find more information here.
In your case, the only viable way I can think of for you to can call an API being served locally, would be to expose the appropriate endpoints from your API to the web. That way, the Google Servers responsible to run your script will have access to your API.
I understand that perhaps this solution is against the purpose of having an API server locally (since it won't be locally anymore), however Google Apps Script is designed to work on the Cloud.
In any case, you may find the Apps Script Class UrlFetchApp useful for making HTTP requests for your own API of any other.

Google API returns a response 200 empty JSON

I'm trying to make an HTTP GET request to the Google Street View Publish API, inside a Google Apps Script script, to fetch the photos list and save metadata about them to a Google spreadsheet.
The code I'm using on the script to contact the API:
var url = 'https://streetviewpublish.googleapis.com/v1/photos?fields=nextPageToken%2Cphotos&key=' + API_KEY;
var response = UrlFetchApp.fetch(url, {
muteHttpExceptions: true,
headers: {
//the accessToken is borrowed from the Apps Script Infrastructure `ScriptApp.getOAuthToken()`
//source: https://www.youtube.com/watch?v=aP6pxK3jexc
Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
}
});
console.log('API response:\n' + response);
And including the Street View Auth at the script's manifest oauthscopes.json file:
...
"oauthScopes": [
"https://www.googleapis.com/auth/streetviewpublish",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/spreadsheets"
]
...
Been using a time-based trigger to run the script every 15 min, and it has been working just fine for couple of hours and returning a JSON object with the photos on the account, until the API stopped to return a response, and it's now just returning an empty JSON object {}.
I don't think I consumed the quote for the API usage, my numbers from the GCP dashboard as follows:
Tried to create another API KEY and use it at the script, but still no luck.
Also, when tried to test the API from the Google APIs Explorer, authorize and execute, it gives me the response code 200 with an empty JSON object as well.
This has been working before, but, now it doesn't!
What might be the problem here?
Edit:
As suggested at the comments, I tried to:
Call the API endpoint with or without the API key and the other parameters, as follows:
https://streetviewpublish.googleapis.com/v1/photos?fields=nextPageToken%2Cphotos&key=' + API_KEY
https://streetviewpublish.googleapis.com/v1/photos?key=' + API_KEY
https://streetviewpublish.googleapis.com/v1/photos
Also, tried to revoke the access for both the Google APIs Explorer and the script on Google Apps Script, from the account security checkup. Which because of it when tried to run it again, it opened a popup window to ask for the authorization/permission again, which I granted as well.
Tried to log out of the Google account & clearing the browser's cache.
Yet, still, the same empty JSON object response!
Edit 2:
Also stopped the script's time-based triggers 2 days ago, still no luck!
The documentation says that pageSize defaults to 100. This is not the case. If you specify the pageSize parameter, it returns a response with photos.

Authorizing Google Charts to access private spreadsheets

I am trying to create a Web App using Google Apps Script to query data from my Google Sheet using Google Charts.
I have been able to successfully query the spreadsheet when the Google Sheet is publicly shared, however since the spreadsheet contains confidential info I would rather do it privately using authorizations.
The reason why I want to use Google Charts visualisation functions (as opposed to the server side Spreadsheet App) is because of the speed of querying large data sets.
I have tried following the steps in the above documentation. That is, creating a client id then using the gapi.auth library to authenticate myself but I continue to receive an error.
When i add the authorization library and first part of the code from the documentation (with console.log simply to see where it get's up to):
<script src="https://apis.google.com/js/auth.js?onload=init"></script>
<script>
var clientId = '1234.apps.googleusercontent.com';
var scopes = 'https://spreadsheets.google.com/feeds';
function init() {
console.log("here");
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true},handleAuthResult);
}
</script>
I receive the following error:
1289869776-mae_html_user_bin_i18n_mae_html_user.js:41 dropping
postMessage.. was from unexpected window
Any guidance is appreciated.
Since you are creating your web app using Google Apps Script, it's not necessary to "authorize Google Charts to access private charts" because you could use Google Apps Script services and methods to get the data from the spreadsheets and pass them to Google Charts.
On Converting from UiApp + Chart Service to Html Service + Google Visualization API it's shown how to convert the old dashboard example from from UiApp + Chart Service to HtmlService + Google Visualization API. This illustrates how to create a Google Apps Script web app that builds a chart from Google Spreadsheet data without "requiring authorization" as it's "implicitly" handled by Google Apps Script.
From the above link
Two functions cooperate to retrieve the dashboard’s data and display it. As soon as the visualization API is loaded, the sendQuery() function is invoked. Using the google.script.run facility, it sends its request to the server-side getSpreadsheetData() function. This is an asynchronous operation, so two callbacks are provided, a successHandler and a failureHandler. One or the other will receive the result of the server call, depending on the outcome.
H/T to jfllmartin, author of an answer to Converting my google dashboard app from the UI service to the HTML service where the above link was shared.
Related
How to create google dashboard including piechart and range select filter from a spreadsheet?
Display Spreadsheet data in Sites with Html Service
can I suggest you change from using Google sheets to using firebase with Google sheets or just Firebase, and then with Google appscript in the back end.
I often use a Google script to problematically update Firebase with data from the Google sheet. I then enjoy the speed and security of Firebase to deliver a super fast user experience.
There are two go to pages for using Firebase in appscript. The example page and the quick start.
Furthermore, I gave up using Google's own charting library and starting using high charts or chartJS, as they are more accessible.

Automating Google Slides production

I'm wondering if there may be a way to programmatically create presentations in Google Slides. So for example if underlying data changes I can just refresh the deck without lots of copy paste for all the charts etc.
Something similar to using like markdown and R slidify to produce data driven PDF presentations. My end product needs to be a nice pretty Google Slides presentation.
Is this the sort of thing I could use the Google Drive API for? I'm not sure if App Script can be used for Slides like you can for Sheets.
Am hoping it's a common enough problem that a solution exists.
One option is to just automatically produce a PDF and then manually import into Google Slides. Problem is that this approach is a bit limited due to errors on conversion and lack of other Slides functionality.
Any input much appreciated.
It's 2018, and great news (and answers!) to this older question:
The Google Slides REST API launched in Nov 2016... here is its launch
post and 1st developer video I made to get you started. A shorter code sample than the video's is the Quickstart in the docs (available in a variety of languages). If you're new to Google APIs, I recommend you watch this video, then this one, and finally this one first to get an idea of how to use them. The code samples are in Python, but if you're not a Python developer, just pretend it's pseudocode because many languages are supported by Google APIs Client Libraries. :-)
If you code in JS and want to have Google host+run your app, the Slides service in Google Apps Script launched in Sep 2017... here is its launch
post and 1st developer video I made to get you started. This is also the same technology behind Slides Add-ons. If you're new to Apps Script, I recommend you watch this video to get an idea of what it is and how to use it. Then check out its video library for more examples of using Apps Script. (Admittedly, it's easier to code w/Apps Script vs. the REST APIs, making it more "addictive" for developers... you were warned!) :-)
Additional videos on programmatically accessing Google Slides can be found via its developer video library. Videos on this and other G Suite developer technologies can be found in the G Suite Dev Show series which I produce.
There's no video for this, but there's an open source Markdown-to-Google Slides generator (written in Node.js) my colleague created that you may be interested in, representing one of the "reference apps" using the Slides API. You can find more about this app as well as others on the Samples page of the documentation.
No video for this either, but Node.js developers who want to get up-to-speed quickly learning how to use this API should try the Slides API codelab where you build an app that uses Google BigQuery to analyze open source licenses and generate a report presentation... letting you learn TWO Google Cloud technologies with one tutorial! :-)
The Google Slides API was launched on 11/9/2016. It provides the ability to read, create, and edit Google Slides presentations.
At the moment there still isn't an equivalent service in Apps Script, but you can use the Apps Script OAuth2 library and UrlFetchApp to make calls to the API within a script.
Requested feature, follow https://code.google.com/p/google-apps-script-issues/issues/detail?id=1573&q=presentation&colspec=Stars%20Opened%20ID%20Type%20Status%20Summary%20Component%20Owner for updates.
An example from Apps Script:
Enable the Slides API in the developer console:
Click on Resources > Developers Console Project > [Your_Project_Name].
Click on Enable API, search for Slides and enable the Slides API.
Use UrlFetchApp to send authenticated requests to the Slides API
As a simple example from within Apps Script, consider fetching the latest version of a Presentation (presentations.get).
// Add your presentation ID
var presentationId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// Force add the Drive scope (as this comment *will* get parsed
// and trigger a popup to authorize Drive access)
// DriveApp.createFile('')
// URL formed as per the Slides REST documentation
var url = 'https://slides.googleapis.com/v1/presentations/' + presentationId;
var options = {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
}
};
var response = UrlFetchApp.fetch(url, options);
// Turn this back into a JS Object so it can be used.
var presentation = JSON.parse(response.getContentText());
// Log the ID of the presentation
Logger.log(presentation.presentationId);
// Log the number of slides...
Logger.log(presentation.slides.length);
// Loop through the slides
var slides = presentation.slides;
slides.forEach(function(slide) {
// ... do something with each slide...
});
The structure of presentation is also documented in the REST reference. Armed with the REST reference, this example can be extended to be used with any Slides API request and response.

Using OAuth 2.0 with google apps scripts to access Instagram API

I am trying to set up a chron job to connect to the instagram API, grab 'my feed' and download the images. I cannot get past the OAuth 2.0 step. I have already looked at a number of resources including:
How to authorize with oauth 2.0 from appscript to Google APIs? - methods are deprecated and I cannot get the pop up to for the oauth to show up.
https://code.google.com/p/google-apps-script-issues/issues/detail?id=2580 and all the links that follow in the discussion. I cannot figure out how to apply this to work without an html page.
http://www.googleappsscript.org/home/downloading-instagram-photos-to-your-google-drive-using-google-apps-script works well for hash tags, but I would like to be able to get the feed from my user account.
Any help would be greatly appreciated, this is the best I have been able to figure out, if I could get the pop up to work I would be good to go, but I cannot.
function startInstagram () {
var redurl = getCallbackURL(getInstagram);
var consumerKey = '#######';
var consumerSecret = '#######';
var parameters = {
method : 'post',
payload:
'grant_type=authorization_code'+'&client_id='+consumerKey+'&client_secret='+consumerSecret+'&grant_type=authorization_code&redirect_uri='+redurl+'&response_type=token'
};
var token = UrlFetchApp.fetch('https://api.instagram.com/oauth/authorize/', parameters).getContentText();
Logger.log(['token', token]);
}
function getInstagram (vars) {
var res = {};
Logger.log(['get', vars]);
return;
}
function getCallbackURL(callbackFunction) {
var scriptUrl = 'https://script.google.com/d/<ID>';
var urlSuffix = '/usercallback?state=';
var stateToken = ScriptApp.newStateToken()
.withMethod(callbackFunction)
.withTimeout(60*10*5)
.createToken();
return scriptUrl + urlSuffix + stateToken;
}
There is a GitHub repository that describes a library for using OAuth2 in Apps Script. In its README file, it shows how to use the library with Drive API as an example. If you substitute the Instagram API for Drive in the example code, you should be close to what you need.
The Instagram API Authorization docs covers most of what you'll need to do to get an access token -- the steps parallel the instructions in the GitHub library.
You'll need to make sure your script is a registered application with Instagram so you can get the client ID and client secret and so you can set the redirect URI, which will be of the form
https://script.google.com/macros/d/{PROJECT KEY}/usercallback
for Apps Scripts.
If you are only interested in downloading your photos, the basic scope permissions (granted by default) should be sufficient.
Once you have a valid access token, you should be able to make requests from the Instagram API using UrlFetchApp.fetch().