I'm trying to make a script work that uses theYoutube API, i put in a keyword, youtube api finds video -> script takes first result and returns VideoID. Now my problem is that the search function doesn't get triggerd when I press my submit button. Does anyone know what could be the cause of this? This is the code;
html
<script src="assets/js/search.js" type="text/javascript"></script>
<script src="https://apis.google.com/js/client.js?onload=onClientLoad" type="text/javascript"></script>
<body>
<center>
<h3 class="h3">KJKerstborrel - Muziekrequest</h3>
<div class="input">
<form name="muziek" action="succes/index" method="post">
<input type="text" class="input-xlarge" id="artiest" name="artiest" placeholder="Gewenste artiest" /><br>
<input type="text" class="input-xlarge" id="nummer" name="nummer" placeholder="Gewenst nummer" required/><br>
<button style="width: 200px;" class="btn btn-success" onClick="search()" type="button">Deze wil ik horen!</button><br>
</form>
</div>
</center>
</body>
JS
// Your use of the YouTube API must comply with the Terms of Service:
// https://developers.google.com/youtube/terms
var YT = 'undefined';
// Helper function to display JavaScript value on HTML page.
function showResponse(response) {
YT = response;
document.getElementById('VideoURL').value = YT.items[0].Id.VideoID;
}
// Called automatically when JavaScript client library is loaded.
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
search();
}
// Called automatically when YouTube API interface is loaded (see line 9).
function onYouTubeApiLoad() {
// This API key is intended for use only in this lesson.
// See http://goo.gl/PdPA1 to get a key for your own applications.
gapi.client.setApiKey('AIzaSyD49-XZ2JV7Rws3KDM2T7nA56Jbi-O7djY');
}
function search() {
// Use the JavaScript client library to create a search.list() API call.
var request = gapi.client.youtube.search.list({
part: 'id',
q: document.getElementById("artiest").value + " - " + document.getElementById("nummer").value,
});
// Send the request to the API server,
// and invoke onSearchRepsonse() with the response.
request.execute(onSearchResponse);
}
// Called automatically with the response of the YouTube API request.
function onSearchResponse(response) {
showResponse(response);
}
I made a few changes in the JS and i added a field in the html to display the video id.
The html file:
<script src="search.js" type="text/javascript"></script>
<script src="https://apis.google.com/js/client.js?onload=onClientLoad" type="text/javascript"></script>
<body>
<center>
<h3 class="h3">KJKerstborrel - Muziekrequest</h3>
<div class="input">
<form name="muziek" action="succes/index" method="post">
<input type="text" class="input-xlarge" id="artiest" name="artiest" placeholder="Gewenste artiest" /><br>
<input type="text" class="input-xlarge" id="nummer" name="nummer" placeholder="Gewenst nummer" required/><br>
<button style="width: 200px;" class="btn btn-success" onClick="search()" type="button">Deze wil ik horen!</button><br>
<input type="text" class="input-xlarge" id="VideoURL" name="VideoURL" placeholder="VideoURL"/><br>
</form>
</div>
</center>
</body>
The JS file:
// Your use of the YouTube API must comply with the Terms of Service:
// https://developers.google.com/youtube/terms
var YT = 'undefined';
// Helper function to display JavaScript value on HTML page.
function showResponse(response) {
YT = response;
// changed: namegiving
document.getElementById('VideoURL').value = YT.items[0].id.videoId;
}
// Called automatically when JavaScript client library is loaded.
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
//search(); // changed.
}
// Called automatically when YouTube API interface is loaded (see line 9).
function onYouTubeApiLoad() {
// This API key is intended for use only in this lesson.
// See http://goo.gl/PdPA1 to get a key for your own applications.
gapi.client.setApiKey('AIzaSyD49-XZ2JV7Rws3KDM2T7nA56Jbi-O7djY');
}
function search() {
// Use the JavaScript client library to create a search.list() API call.
var qVar = document.getElementById("artiest").value
+ " - "
+ document.getElementById("nummer").value;
// changed. added: type
var request = gapi.client.youtube.search.list({
type: 'video',
part: 'id',
q: qVar
});
// Send the request to the API server,
// and invoke onSearchRepsonse() with the response.
request.execute(onSearchResponse);
}
// Called automatically with the response of the YouTube API request.
function onSearchResponse(response) {
showResponse(response);
}
i followed your example and i got the same error but then followed this tutorial and i was able to make a successful call
https://developers.google.com/api-client-library/javascript/samples/samples
Related
I am creating an editor add-on for google sheets and I'm currently stumped on why my user property (MY_WEBHOOK) is being changed every time I try to save it with setProperty to this code:
function(){var L=h(fb(arguments));if(b&32)Vd(function(){a.apply(g||this,L)});else return m(a.apply(g||this,L))}
Here is the code I am using:
code.gs:
function saveSettings(url) {
PropertiesService.getUserProperties().setProperty('MY_WEBHOOK', url);
SpreadsheetApp.getUi().alert("Saved")
}
function getSettings() {
return PropertiesService.getUserProperties().getProperty('MY_WEBHOOK');
}
In my html file:
<body onload="get()">
<form>
<label>What is the URL?</label>
<input id="webhook-url" type="url" autofocus required placeholder="Webhook Here">
<br><br>
<input type="button" value="Save" onclick="save()">
<script>
function save() {
var url = document.getElementById('webhook-url').value
google.script.run.saveSettings(url)
alert(url)
alert(google.script.run.getSettings)
google.script.host.close()
}
function get() {
var settings = google.script.run.getSettings
document.getElementById('webhook-url').value = settings;
}
</script>
</form>
</body>
Modification points:
I think that there are 2 modification points in your script.
About google.script.run.getSettings, in this case, the function of getSettings is not run. Please add () like google.script.run.getSettings(). By this, the function is run.
I think that this is the reason of your issue.
About alert(google.script.run.getSettings) and var settings = google.script.run.getSettings, google.script.run returns no value. So in this case, withSuccessHandler is used.
google.script.run is run with the asynchronous process.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please modify your Javascript as follows.
function save() {
var url = document.getElementById('webhook-url').value
google.script.run.withSuccessHandler(() => {
google.script.run.withSuccessHandler(e => {
alert(e);
google.script.host.close();
}).getSettings();
}).saveSettings(url);
}
function get() {
google.script.run.withSuccessHandler(settings => {
document.getElementById('webhook-url').value = settings;
}).getSettings();
}
When above script is used, at first, the value is retrieved from getSettings by get(), and when the value is inputted and click button, the value is put by saveSettings() and the current value is retrieved by getSettings() and alert() is run, and then, google.script.host.close() is run.
Note:
This is a simple modification. So please modify it for your actual situation.
Reference:
Class google.script.run
My html code:
<h2>Please finalize your details</h2>
<form id="details" method="post" class="form">
Full name: <strong name="name_1">ABCDEF</strong><br><br>
ID No:<strong name="org_number_1">123</strong><br><br>
Mobile No:<strong name="ph_number_1"">1234567890</strong><br><br>
E-mail: <strong name="email_1">ABC#DEF.COM</strong><br><br>
ID Card: <img src="profile.png" alt="preview" name="image" style="width: 100px; height: 100px;"><br><br>
<button id="go">It's correct</button>
</form>
My javascript:
document.getElementById('go').addEventListener('click', submit);
function submit(){
var nme=document.getElementsByName("name_1")[0].innerHTML;
var id=document.getElementsByName("org_number_1")[0].innerHTML;
var phone=document.getElementsByName("ph_number_1")[0].innerHTML;
var email=document.getElementsByName("email_1")[0].innerHTML;
var img=document.getElementsByName("image")[0].src;
const xhr=new XMLHttpRequest();
xhr.onload=function(){
const serverResponse=document.getElementById("response");
serverResponse.innerHTML=this.responseText;
};
xhr.open("POST", "database_registration.php");
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("name="+nme+"&id="+id+"&phone="+phone+"&email="+email+"&img="+img); //this line throws the error "Failed to load resource: the server responded with a status of 405 (Method Not Allowed)"
}
I am executing my code in Visual Studio Code editor and my project location is in:
C:\Users\Abhishek\Desktop\Web-dev stuff\XAMPP\htdocs\Stack hack 20 20
This is the error:
Not only that, I've also tried working with Fetch API, but it throws the same error too. What do I do now? How can I make it work?
The error is not in the JS it's come from the server. What is in database_registration.php? If that doesn't have handling for POST then I'd expect the server to return 405.
404 would mean database_registration.php isn't there, but 405 means it is there, but doesn't allow POST specifically. Check the allow header on the response for the methods that are supported.
Try:
xhr.open("GET", "database_registration.php?" +
"name="+nme+"&id="+id+"&phone="+phone+"&email="+email+"&img="+img);
xhr.send();
To make a GET request instead.
Alternatively this could be an error parsing the posted content (misreported, as it should be 400 or maybe 406), try removing parts of the body to see if it works with a subset.
I have done the first checkbox (ID No) for you.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cafteria details</title>
<style>
#special{
height: 100px;
width: 100px;
border: 1px solid;
display: none;
}
</style>
</head>
<body>
<h2>Cafeteria registration</h2>
<form class="details">
Full name: <input type="text" placeholder="Please avoid any kind of prefixes" id="name" size=25><br><br>
Organization:<div id="org"><input onclick="myFunction()" type="checkbox" id="cb1">ID no: <input type="number" id="org_number"><br><br>
<input type="checkbox" id="cb2">Mobile No: <input type="tel" id="ph_number"></div><br><br>
E-mail: <input type="email" id="email" size=25><br><br>
Upload ID Card: <input type="file" name="id" accept=".pdf,.jpeg" id="img"><br><br>
</form>
<div id ="special">
</div>
<button id="button">Register</button>
</body>
<script>
function myFunction() {
var x = document.getElementById("cb1").checked;
if (x == true) {
document.getElementById("special").style.display="block";
}else{
document.getElementById("special").style.display="none";
}
}
// var x = document.getElementById("cb1").checked;
// if (x==true){
// document.getElementById("special").style.display="block";
// console.log(true)
// }
// if (document.getElementById("cb2").checked==true){
// document.getElementById("special").style.display="block";
// console.log(false)
// }
</script>
</html>
Your code looks fine. If you are using Live Server vscode extension to run your code, this is a known issue (and here) with the extension.
You could try to change the port number settings on the Live Server extension as suggested in the link above but your best bet would be to stop using Live Server to run this code.
Just start XAMPP and navigate to the right url in your browser (note you will have to eliminate spaces in your project folder name to something like stack-hack-20-20).
EDIT: It also seems to be the case with some other vscode extensions. You get a 405 status when you try to reach an endpoint. There is some restriction to using GET, HEAD or OPTIONS http methods so you either hit the endpoint using one of those methods or use a webserver like XAMPP for POST, DELETE etc.
I agree with #Keith that this error code usually indicates that the request method you used is not allowed by the server, but I've seen that not all developers use the correct error codes in every case.
I suspect you may have a parsing issue on the backend for the data you're submitting, since it isn't being URI encoded before it's sent.
Try this JavaScript instead and see if you get a different result:
document.getElementById('go').addEventListener('click', submit);
function submit() {
const formData = new FormData();
formData.append("name", document.getElementsByName("name_1")[0].innerHTML);
formData.append("id", document.getElementsByName("org_number_1")[0].innerHTML);
formData.append("phone", document.getElementsByName("ph_number_1")[0].innerHTML);
formData.append("email", document.getElementsByName("email_1")[0].innerHTML);
formData.append("img", document.getElementsByName("image")[0].src);
const xhr = new XMLHttpRequest();
xhr.onload = function() {
const serverResponse = document.getElementById("response");
serverResponse.innerHTML = this.responseText;
};
xhr.open("POST", "database_registration.php");
xhr.send(formData);
}
Try to create new url endpoint that support POST request on your backend PHP application. So your HTTP request which is sent from javascript can use POST request.
I'm new to security concepts. I have a program that is written in javascript and therefore can only be run in the browser. I was wondering is there any way to inject javascript code in this program?
My program looks like this:
index.html:
<form method="get" action="file.html">
Enter your name: <input name="name" type="text"> <input type="submit" value="enter">
</form>
file.html:
<head>
<script src="js/main.js"></script>
</head>
<body>
<div id="contents">
</div>
</body>
js/main.js:
function get_parameters() {
// 1. get the string of the get parameters after question mark
var parameters = window.location.search.substr(1);
// 2. make an array of parameters
parameters = parameters.split('&')
// 3. retrieve parameters
var res = {}
parameters.forEach(function (item) {
var tmp = item.split('=');
res[tmp[0]] = decodeURIComponent(tmp[1]);
})
// 4. return parameters
return res;
}
window.onload = function () {
var parameters = get_parameters();
if ('name' in parameters) {
document.getElementById('contents').innerHTML = '<div> Hello ' + parameters['name'] + '</div>';
}
};
Scripts can be inserted via the url. If you visit file.html?name=%3Cimg%20onerror%3Dalert(1)%20src%3D/%3E then you should see an alert.
The use of the innerHTML property is setting HTML containing user controlled content. If instead you use innerText then it wouldn't be possible. For example:
document.getElementById('contents').innerText = 'Hello ' + parameters['name'];
Hopefully I've included enough of the code w/o having to post it all...
I have a main function that calls displayDropdown()- which calls an HTMLService and displays a modal with a dropdown and a text box:
.
This is the (condensed) javascript code that stores the data:
<html>
<input type="submit" value="Submit" class="action" onclick="sendData()" />
</html>
<script>
function sendData() {
var values = {};
values.textJob = document.getElementById("input").value;
values.selectedJob = document.getElementById("dropJob").value;
google.script.run.withSuccessHandler(closeIt).grabData(values);
};
function closeIt(){
google.script.host.close()
};
</script>
Then the grabData() function in my .gs file:
function grabData(values) {
if(values.textJob=="")
//return values.selectedJob;
Logger.log(values.selectedJob);
else
//return values.textJob;
Logger.log(values.textJob);
}
If I keep the returns commented out and try to log the data, I get the expected data logged. But if I reverse that, and return it instead, go back up to the main function just after displayDropdown() was called, and set a variable to equal the grabData function:
displayDropdown();
var stuff = grabData();
Logger.log(stuff);
I get an error that says:
Why can't I access the data?
This is what I usually do to send data from HTML form to GS:
HTML
<form method="POST" action="#" id="formID">
<button class="btn" type="submit">Send</button>
</form>
JS
document.querySelector("#formID").addEventListener("submit", function(e) {
var test = google.script.run.withSuccessHandler('client side function').processForm(this);
});
I usually pass 'this' as an argument and I process the information on the GS.
EDIT:
GS
function processForm(values){
Logger.log(values);
Logger.log(typeof values);
}
Screenshoots:
1- Web app
2- Server logs (function processForm)
The javascript example for "search by keyword" that is given at the google developers page isn't working for me. https://developers.google.com/youtube/v3/code_samples/javascript
When I run the code, I get a disabled search box with "cats" inside. Also, the example doesn't explain how to write in the API key as opposed to the Client ID. It says it's possible, but gives no concrete example of how to do it. Can someone point out where this code is going wrong. The code for the two .js files and the html is as follows:
auth.js file:
// The client ID is obtained from the Google Developers Console
// at https://console.developers.google.com/.
// If you run this code from a server other than http://localhost,
// you need to register your own client ID.
var OAUTH2_CLIENT_ID = '__YOUR_CLIENT_ID__';
var OAUTH2_SCOPES = [
'https://www.googleapis.com/auth/youtube'
];
// Upon loading, the Google APIs JS client automatically invokes this callback.
googleApiClientReady = function() {
gapi.auth.init(function() {
window.setTimeout(checkAuth, 1);
});
}
// Attempt the immediate OAuth 2.0 client flow as soon as the page loads.
// If the currently logged-in Google Account has previously authorized
// the client specified as the OAUTH2_CLIENT_ID, then the authorization
// succeeds with no user intervention. Otherwise, it fails and the
// user interface that prompts for authorization needs to display.
function checkAuth() {
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
}
// Handle the result of a gapi.auth.authorize() call.
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
// Authorization was successful. Hide authorization prompts and show
// content that should be visible after authorization succeeds.
$('.pre-auth').hide();
$('.post-auth').show();
loadAPIClientInterfaces();
} else {
// Make the #login-link clickable. Attempt a non-immediate OAuth 2.0
// client flow. The current function is called when that flow completes.
$('#login-link').click(function() {
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: false
}, handleAuthResult);
});
}
}
// Load the client interfaces for the YouTube Analytics and Data APIs, which
// are required to use the Google APIs JS client. More info is available at
// http://code.google.com/p/google-api-javascript-client /wiki/GettingStarted#Loading_the_Client
function loadAPIClientInterfaces() {
gapi.client.load('youtube', 'v3', function() {
handleAPILoaded();
});
}
search.js file:
// After the API loads, call a function to enable the search box.
function handleAPILoaded() {
$('#search-button').attr('disabled', false);
}
// Search for a specified string.
function search() {
var q = $('#query').val();
var request = gapi.client.youtube.search.list({
q: q,
part: 'snippet'
});
request.execute(function(response) {
var str = JSON.stringify(response.result);
$('#search-container').html('<pre>' + str + '</pre>');
});
}
search.html
<!doctype html>
<html>
<head>
<title>Search</title>
</head>
<body>
<div id="buttons">
<label> <input id="query" value='cats' type="text"/><button id="search-button" disabled onclick="search()">Search</button></label>
</div>
<div id="search-container">
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="auth.js"></script>
<script src="search.js"></script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"> </script>
</body>
</html>
The documentation is misleading a bit (one might even say incorrect); the HTML for the "search by keyword" is loading the same "auth.js" that the other two examples on that page are, but it doesn't then have any HTML elements to actually trigger the login process (i.e. a "login button" if a user isn't already authorized) like the other two examples do. Bascially, if you're using that provided auth.js, you need to have, in your HTML, a section that looks like this:
<div id="login-container" class="pre-auth">
This application requires access to your YouTube account.
Please authorize to continue.
</div>
Then, you can also add the class of "post-auth" on a new div that wraps around your existing buttons and search container. The demo will then, when a user visits, only present the login link; when clicked on, and when a user allows the authorization, then the login link will be hidden and your search area will be shown (and the button enabled). That's just how the demo is set up.
Of course, search by keyword does NOT require oAuth2, and so (to answer your 2nd question) you might find it easier to A) remove the handleApiLoaded method (so your button is never disabled), and B) call gapi.client.load() manually (i.e. not triggered by an oAuth success). Then, call gapi.client.setApiKey({YOUR KEY}) so that all of your requests will include your key in their header.
Thanks so much jlmcdonald for your help. It took me a while to figure out the second part of your response, but I finally had success. The following html gets the example on the google developers webpage to work. Note though, at first I was getting a 401 error. To fix it, I had to go to the google developers console and select my project. Then, APIs&auth->consent screen and then fill in the email address and product name:
<!doctype html>
<html>
<head>
<title>Search</title>
</head>
<body>
<div id="login-container" class="pre-auth">
This application requires access to your YouTube account.
Please authorize to continue.
</div>
<div id="buttons" class="post-auth">
<label> <input id="query" value='cats' type="text"/><button id="search-button" disabled onclick="search()">Search</button></label>
</div>
<div id="search-container">
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="/files/theme/auth.js"></script>
<script src="/files/theme/search.js"></script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"> </script>
</body>
</html>
As you noted in your response, oAuth2 isn't necessary for a simple keyword search. The following is some html that just uses the API key. I didn't reference the two .js files like before, rather, I just included the script in the html. Your post at gapi.client.youtube is undefined? really helped me figure it out:
<!doctype html>
<html>
<head>
<title>Search</title>
</head>
<body>
<div id="buttons">
<label> <input id="query" value='cats' type="text"/><button id="search-button" onclick="keyWordsearch()">Search</button></label>
</div>
<div id="search-container">
</div>
<script>
function keyWordsearch(){
gapi.client.setApiKey('API key here');
gapi.client.load('youtube', 'v3', function() {
makeRequest();
});
}
function makeRequest() {
var q = $('#query').val();
var request = gapi.client.youtube.search.list({
q: q,
part: 'snippet'
});
request.execute(function(response) {
var str = JSON.stringify(response.result);
$('#search-container').html('<pre>' + str + '</pre>');
});
}
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"> </script>
</body>
</html>
Now that I got the search part, could you explain how I can display the thumbnails and titles of the results and then when I click them, the video opens in an embedded player on the same page? Thanks.
Thank you for your coding. Let me share my code:
function makeRequest(){
var q = $('#query').val();
var request = gapi.client.youtube.search.list({
q: q,
part: 'snippet'
});
request.execute(function(response){
var str = JSON.stringify(response.result,'',4);
$('#search-container').val( str);
makeControl(response);
});
}
function makeControl(resp){
var stList = '<table id="res1" border="1" cellspacing="1" width="100%"><tbody>';
for (var i=0; i<resp.items.length;i++){
var vid = resp.items[i].id.videoId;
var tit = resp.items[i].snippet.title;
if(typeof vid != 'undefined'){
stList += '<tr><td style="width:80px;vertical-align:top">'+
'<a class="show" href="#" title="'+ vid + '" onclick="playVid(this);'+
' return false">'+
'<img width="80" height="60" src="http://img.youtube.com/vi/'+
vid +'/default.jpg"></a></td>'+
'<td><b>'+i+'</b>-'+ tit +'</td></tr>';
}
}
document.getElementById('list1').innerHTML = stList + '</tbody></table>';
//HTML: <div id="list1"
//style="width:853px;height:400px;overflow:auto;background-color:#EEEEEE">
//</div>
}
function playVid(thi){
var st = 'https://www.youtube.com/embed/'+thi.title+'?autoplay=1';
document.getElementById('player').src = st;
//HTML: <iframe id="player" width="853" height="480" src="" frameborder="1" allowfullscreen>
//</iframe>
}