youtube api v3 search by keyword javascript - javascript

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>
}

Related

Silence net::ERR_CONNECTION_REFUSED

Connecting to a non-existent web socket server results in loud errors being logged to the console, usually to the tune of ... net::ERR_CONNECTION_REFUSED.
Anyone have an idea for a hackaround to silence this output? XMLHttpRequest won't work since it yields the same verbose error output if the server is not reachable.
The goal here is to test if the server is available, if it is then connect to it, otherwise use a fallback, and to do this without spamming the console with error output.
Chrome itself is emitting these messages, and there is no way to block them. This is a function of how chrome was built; whenever a ResourceFetcher object attempts to fetch a resource, its response is passed back to its context, and if there's an error, the browser prints it to the console - see here.
Similar question can be found here.
If you'd like, you can use a chrome console filter as this question discusses to block these errors in your console, but there is no way to programmatically block the messages.
I don't know why do you want to prevent this error output. I guess you just want to get rid of them when debugging. So I provide a work around here may be just useful for debugging.
Live demo: http://blackmiaool.com/soa/43012334/boot.html
How to use it?
Open the demo page, click the "boot" button, it will open a new tab. Click the "test" button in the new tab and check the result below. If you want to get a positive result, change the url to wss://echo.websocket.org.
Why?
By using post message, we can make browser tabs communicate with each other. So we can move those error output to a tab that we don't concern.
P.S. You can refresh the target page freely without loosing the connection between it and boot page.
P.P.S You can also use storage event to achieve this.
boot.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>boot page</title>
</head>
<body>
<button onclick="boot()">boot</button>
<p>BTW, you can boot the page without the button if you are willing to allow the "pop-up"</p>
<script>
var targetWindow;
function init() {
targetWindow
}
function boot() {
targetWindow = window.open("target.html");
}
boot();
window.addEventListener('message', function(e) {
var msg = e.data;
var {
action,
url,
origin,
} = msg;
if (action === "testUrl") {
let ws = new WebSocket(url);
ws.addEventListener("error", function() {
targetWindow.postMessage({
action: "urlResult",
url,
data: false,
}, origin);
ws.close();
});
ws.addEventListener("open", function() {
targetWindow.postMessage({
action: "urlResult",
url,
data: true,
}, origin);
ws.close();
});
}
});
</script>
</body>
</html>
target.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>target page</title>
</head>
<body>
<h4>input the url you want to test:</h4>
<textarea type="text" id="input" style="width:300px;height:100px;">
</textarea>
<br>
<div>try <span style="color:red">wss://echo.websocket.org</span> for success result(may be slow)</div>
<button onclick="test()">test</button>
<div id="output"></div>
<script>
var origin = location.origin;
var testUrl = origin.replace(/^https?/, "ws") + "/abcdef"; //not available of course
document.querySelector("#input").value = testUrl;
function output(val) {
document.querySelector("#output").textContent = val;
}
function test() {
if (window.opener) {
window.opener.postMessage({
action: "testUrl",
url: document.querySelector("#input").value,
origin,
}, origin);
} else {
alert("opener is not available");
}
}
window.addEventListener('message', function(e) {
var msg = e.data;
if (msg.action === "urlResult") {
output(`test ${msg.url} result: ${msg.data}`);
}
});
</script>
</body>
</html>

Evaluate JavaScript code using PhantomJS

I'm trying to use PhantomJS to run some JavaScript from an ad server and parse out the response object for information about the ad that was served. This is readily available from Firefox/Chrome Dev Tools, but I need to access that same information from a server. I can get Phantom to run, but as soon as I try to include external JS page.includeJs("http://www.someadserver.com/config.js?nwid=1909"and access variables that are set via that external JS someadserver.setup({ domain: 'http://www.someadserver.com'}); it fails miserably. Any help would be greatly appreciated.
"use strict";
var page = require('webpage').create();
page.content = `
<html>
<head>
<script>
someadserver.setup({ domain: 'http://www.someadserver.com'});
</script>
<title>The title of the web page.</title>
</head>
<body>
<div class="ads_leaderboard">
<!-- position: leaderboard -->
<script>
someadserver.call( "std" , {
siteId: 100806,
pageId: 656377,
target: ""
});
</script>
</div>
<div id="foo">this is foo</div>
</body>
</html>`;
var title = page.evaluate(function (s) {
page.includeJs(
"http://www.someadserver.com/config.js?nwid=1909",
function() {
return document.querySelector(s).innerText;
}, 'title');
});
console.log(title);
phantom.exit(1);
EDIT 1:
I've simplified my script (below) and I'm clearly missing something. When I run the script below using bin/phantomjs /srv/phantom_test.js the only output I get is end page. Why aren't the rest of the console.log statements executing?
"use strict";
var page = require('webpage').create();
page.content = "<html>" +
"<head>" +
" <title>The title of the web page.</title>" +
"</head>" +
"<body>" +
"<div id=\"foo\">this is foo</div>" +
"</body>" +
"</html>";
page.includeJs("http://www.someadserver.com/config.js?nwid=1909", function() {
console.log('start function');
var title = page.evaluate(function(s){
return document.querySelector(s).innerText;
}, 'title');
console.log(title);
console.log('end function');
});
console.log('end page');
phantom.exit();
The stuff inside page.evaluate is executed in the context of a target page as if that code was inside of that page.
page.includeJS(...) will not be a valid code on a someadserver.com.
The correct way is vice versa:
page.includeJs("http://www.someadserver.com/config.js?nwid=1909", function() {
var title = page.evaluate(function(s){
return document.querySelector(s).innerText;
}, 'title');
});
Your first snippet doesn't work, because assigning a value to page.content immediately executes it. So, someadserver.setup(...) is executed immediately as if the page is actually loaded, but at this time the page.includeJs(...) call hasn't happened yet.
You should be able to actually include script that you want to run inside of the page source:
var content = `
<html>
<head>
<script src="http://www.someadserver.com/config.js?nwid=1909"></script>
<script>
someadserver.setup({ domain: 'http://www.someadserver.com'});
</script>
<title>The title of the web page.</title>
</head>
<body>
<div class="ads_leaderboard">
<!-- position: leaderboard -->
<script>
someadserver.call( "std" , {
siteId: 100806,
pageId: 656377,
target: ""
});
</script>
</div>
<div id="foo">this is foo</div>
</body>
</html>`;
page.setContent(content, "http://www.someadserver.com/");
var title = page.evaluate(function (s) {
return document.querySelector(s).innerText;
}, 'title');
console.log(title);
phantom.exit();
I've also used page.setContent in order to set the domain, so that further script loading is not broken. When a page source is assigned to page.content, the default URL is actually about:blank and you don't want that.
Further problems with your first snippet:
The beginnings and ends of page.evaluate and page.includeJs don't match up!
There is no page inside of page.evaluate, because the page context is sandboxed!
Your second snippet doesn't work, because page.includeJs(...) is a asynchronous function (it has a callback!), so you're exiting the script too early.

Getting song from Soundcloud using widget embedded in own website

I am developing an application that uses SoundCloud API.
I am using frames for having the soundcloud widget on my page.
I made a search bar where user can put an input (such as singer name) and based on that input I am trying to format a URL that will go and retrieve track or playlist from SoundCloud (anything that works)
Right now - it is unable to get the url due to invalid formatting - kindly suggest the best open ended url format so that users can search any singer/song to get back a the correct url (which then gets added to the player).
Code:
EJS file:
<html>
<head>
<title>MIX Mashup Page</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.11.0.min.js'></script>
<script type='text/javascript' src='./javascripts/form.js'></script>
<link rel='stylesheet' href='stylesheets/style2.css' />
<script type='text/javascript' src='http://connect.soundcloud.com/sdk.js'> </script>
<script type='text/javascript' src='https://w.soundcloud.com/player/api.js'></script>
<script src="https://w.soundcloud.com/player/api.js" type="text/javascript"></script>
</head>
<body>
<button id ='mixes'> MIXES </button>
<h1> MIX </h1>
Search Track to Play <input id = "searchbar" type="text" name="Search"/> <button id ='search'>Search</button>
<iframe id="sc-widget" src="https://w.soundcloud.com/player/?url=http://soundcloud.com/christineandthequeens/tilted&single_active=false" width="33%" height="365" scrolling="no" frameborder="yes"></iframe>
</body>
</html>
Javascript File:
$(document).ready(function() {
SC.initialize({
client_id:'3dcb8913f19ee91a5f6c203c56333d75'
});
$("#stream").click(function(){
SC.stream("/tracks/293", {autoPlay: true});
});
var iframeElement = document.querySelector('iframe');
var widget1 = SC.Widget(iframeElement);
(function(){
var widgetIframe = document.getElementById('sc-widget'),
widget = SC.Widget(widgetIframe);
widget.bind(SC.Widget.Events.READY, function(){
widget.bind(SC.Widget.Events.PLAY, function(){
// get information about currently playing sound
widget.getCurrentSound(function(currentSound){
console.log('sound ' + currentSound.get('') + 'began to play');
});
});
// get current level of volume
widget.getVolume(function(volume){
console.log('current volume value is ' + volume);
});
// set new volume level
widget.setVolume(50);
// get the value of the current position
});
}());
})
$(function() {
$("#search").click(function(){
//storing values from the url
var searchrequest = $("#searchbar").val();
result = "https://w.soundcloud.com/player/? url=http://soundcloud.com/"+searchrequest;
console.log(searchrequest);
//$('iframe src').html(result);
console.log(result);
$("#sc-widget").attr("src", result);
});
});
Your current code works as long as the user adds the exact artist username and a slash in the query. fiddle
I would suggest using the soundcloud tracks api to query and display a list of matching results which the user can choose from.
BTW: The widget api has a load(url, options) method for reloading the widget with a different resource.

Initiating the Google+ Sign-In flow with JavaScript not working

I'm following the current tutorial and for some reason when ever I click on the Sign in with Google button nothing seems to happen and I'm not entirely sure why. Here is the code:
<html>
<head>
<title></title>
<script src="https://apis.google.com/js/client:platform.js" async defer></script>
</head>
<body>
<meta name="google-signin-clientid" content="782332402251-os0n348u3v5vaq5kff87f5pc65ib6i19.apps.googleusercontent.com" />
<meta name="google-signin-scope" content="https://www.googleapis.com/auth/plus.login" />
<meta name="google-signin-requestvisibleactions" content="http://schema.org/AddAction" />
<meta name="google-signin-cookiepolicy" content="single_host_origin" />
<script src="https://apis.google.com/js/client:platform.js?onload=render" async defer>
/* Executed when the APIs finish loading */
function render()
{
// Additional params including the callback, the rest of the params will
// come from the page-level configuration.
var additionalParams = {
'callback': signinCallback
};
// Attach a click listener to a button to trigger the flow.
var signinButton = document.getElementById('signinButton');
signinButton.addEventListener('click', function() {
gapi.auth.signIn(additionalParams); // Will use page level configuration
});
}
function signinCallback(authResult)
{
if (authResult['status']['signed_in']) {
// Update the app to reflect a signed in user
// Hide the sign-in button now that the user is authorized, for example:
document.getElementById('signinButton').setAttribute('style', 'display: none');
} else {
// Update the app to reflect a signed out user
// Possible error values:
// "user_signed_out" - User is signed-out
// "access_denied" - User denied access to your app
// "immediate_failed" - Could not automatically log in the user
console.log('Sign-in state: ' + authResult['error']);
}
}
</script>
<button id="signinButton">Sign in with Google</button>
</body>
</html>
Any idea where I'm going wrong?
Looks like a mistake in the tutorial. Emedding Javascript within a script tag with a src attribute is not valid in HTML5. You need to move your code into a separate script tag.
<script type="text/javascript">
// your code here
</script>
See here - http://jsfiddle.net/7umb41z2/

Cannot read property "search" of undefined

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

Categories