dynamically loading data from JSON in Google App Script on Sites - json

I have a google app script where I am trying to get data from a JSON call:
var ajaxError = function(){
$loadingItem.text('Could not load examples :(');
};
// dynamically load sites using Masonry from Zootool
$.getJSON('http://zootool.com/api/users/items/?username=desandro' +
'&apikey=8b604e5d4841c2cd976241dd90d319d7' +
'&tag=bestofmasonry&callback=?')
.error( ajaxError() )
.success(function( data ){...
Basically I am trying to implement this JQuery plugin example http://masonry.desandro.com/
in a Google Apps script returning Html from a file.
This Jason call ends up in error... but why? where can I see what is going wrong? Javascript console is not displaying any error. The URL works: http://zootool.com/api/users/items/?username=desandro&apikey=8b604e5d4841c2cd976241dd90d319d7&tag=bestofmasonry&callback=?

Related

Embedding Google Apps Script in an iFrame Error

I'm trying to load a web app into an iframe in an external html file. I've built and tested the app and it works fine, stand alone. But when I load it into an iframe i get the following error..
"Exception: No HTML file named WebAppBoot was found. (line 2, file "Code")"
I modified the Code.gs to set the XFrameOptionsMode to allow all, like so...
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('WebAppBoot');
output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
I still get the same error
I used this tutorial as the starting point for my web app.. Bootstrap Google Web Application Form Take a look at it to see the file structure in the google "Project", its exactly the same as my web app
Remove the ; of line 2, and output from line 3
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('WebAppBoot')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
then publish again your web app creating a new version (on the version dropdown, select New)
Every time that you made a change to your code that want to see on the /exec web app URL you have to publish again your web creating a new version.
try this:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('WebAppBoot');
output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

Google Script returning ‘Exception: Empty Response’ when running BigQuery query via API [duplicate]

I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js

Cannot upload from Drive via YouTube Data API in Google Apps Script: empty response

I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js

AngularJS, JSON, and js restrictions. How read a JSON file from outside with $http.get and "file:///" URI?

Is there any known and consolidated alternative for defining a new Angular scope reading data from outside?
I am working on a demo that should make available a standalone html page which reads the data from the same html file position, and on client machines without any webserver.
This because the HTML is generated on the fly from a pdf.
Do you have any idea?
In my working code below I should change $http.get('data.json'.. to avoid the Google restriction (on Firefox my sample is working fine).
<script>
var isisApp = angular.module('isisApp', []);
isisApp.controller('ISISListCtrl', function($scope, $http) {
$http.get('data.json').success(function(data) {
$scope.IsisDocument = data;
etc.....
and this is the error I get from Chrome:
XMLHttpRequest cannot load file:///C:/temp/data.json. Cross origin requests are only supported for HTTP. angular.js:8081
Error: A network error occurred.
Thanks in advance
Fabio
If you want to test your code, while developing, you have two options:
Use a local web server. You could use Node.js platform, using expressjs.
Start Chrome from the terminal with the –allow-file-access-from-files option

Google Maps differences between async loading and general script tag

In an attempt to load google maps asynchronously I took a look at google's async page
Essentially I am looking for an alternative to document.write in the API and according to some users on this google group post Using the async version will handle this scenario.
My question is why would this script:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=SET_TO_TRUE_OR_FALSE"
type="text/javascript"></script>
Be any different than:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=TRUE_OR_FALSE&callback=initialize";
document.body.appendChild(script);
when the first and second both call the same js file which obviously has the document.write within it? Also why would an updated API want to consider using document.write over append if write generally goes against content security policy?
As a little background info I'm experimenting with Google's packaged apps and their csp doesn't allow for document.write.
One of the main advantage of loading scripts (or other resources) asynchronously/dynamically is that it can dramatically speed up your page load times.
From Google's Developer best practices:
https://developers.google.com/speed/docs/best-practices/rtt#PreferAsyncResources
When a browser parses a traditional script tag, it must wait for the
script to download, parse, and execute before rendering any HTML that
comes after it. With an asynchronous script, however, the browser can
continue parsing and rendering HTML that comes after the async script,
without waiting for that script to complete. When a script is loaded
asynchronously, it is fetched as soon as possible, but its execution
is deferred until the browser's UI thread is not busy doing something
else, such as rendering the web page.
Another trick I use to decide on whether or not to load a script (such as the Google Maps API) asynchronously is, I ask myself, "Is there a chance that the user will not see, benefit or interact with the results of the loaded script?". If the answer is yes, then I'll usually tie the loading of the script to some DOM event (such as button click etc).
In other words, if a user has to click a button on my web page to view my Google Map; why bother loading all that extra script if there's a chance the user will never even see it? Instead, load the script asynchronously when a button is clicked, and then load my map.
Actually the javascript file at maps.googleapis.com/maps/api/js is a dynamic one. The server responds with a different js file for different parameters. To know the difference, just load the following files from a browser address bar.
https://maps.googleapis.com/maps/api/js?v=3.exp
and
https://maps.googleapis.com/maps/api/js?v=3.exp&callback=initialize
You will notice that there is a "document.write" in the first js file as quoted below
function getScript(src) {
document.write('<' + 'script src="' + src + '"' +
' type="text/javascript"><' + '/script>');
}
whereas there is a document.createElement in the second case as follows
function getScript(src) {
var s = document.createElement('script');
s.src = src;
document.body.appendChild(s);
}
The difference is that, when a script is loaded synchronously, the browser waits for it to load completely and when the script calls document.write, the text is appended to the document being loaded. But asynchronous call is made once a document is fully loaded. As a result document.write would replace the existing document, and hence the browser ignores such a call from an asynchronously loaded script. When you load the js with "callback=initialize", the self executing function already contains the call back to initialize, and a modified function which can load further scripts asynchronously.
All you have to do is set a callback to be executed after the map script loads:
Then in your app's main .js file, define the callback:
window.myCallbackFuction = function() {
return console.log("Loaded Google Maps!");
// the rest of the maps initialization goes here, per the docs
};
The tricky part is refactoring your code so that any map-related code isn't executed until you're certain that the myCallbacFuction() was executed.
There is an example on how to load Google maps asynchronously. Basic idea is to create a script tag like you did and let this function be executed onload.