I need to load the YouTube API locally (Google Extension not allowing external scripts). So I downloaded the files into my directory:
https://www.youtube.com/player_api
https://s.ytimg.com/yts/jsbin/www-widgetapi-vfl4qCmf3.js
However, when I try to programmatically inject this via a content script, it gives the following error:
Uncaught ReferenceError: YTConfig is not defined
To the OP: You were almost there! I'd like to acknowledge Jonathan Waldman, MSDN author, for mentioning this technique during one of his training sessions...
To review, YTConfig is defined at:
http://www.youtube.com/iframe_api
And here:
http://www.youtube.com/player_api
The iframe_api is the preferred link to use.
To recap, the links you provide above each link to JS code:
https://www.youtube.com/player_api
https://s.ytimg.com/yts/jsbin/www-widgetapi-vfl4qCmf3.js
You also need a Div tag with an id of "player" and another Script tag that lets you specify which video you want to see. So there are four Script tags total:
For content in iframe_api
For content at https://s.ytimg.com/yts/jsbin/www-widgetapi-vfl4qCmf3.js
For the player Div tag:
<div id="player"></div>
For JavaScript that configures the video
This translates loosely to:
<script>...place the player Div here</script>
<script>...place code from www-widgetapi-vfl4qCmf3.js here...</script>
<script>...place code from iframe_api here...</script>
<script>...place the code below here</script>
Here is the code for the final Script tag (note that you will likely want to change the videoId property so that it points to the ID of the desired video on the YouTube site):
<script>
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
When I did the above, the page worked and I had all of the YouTube code local to my development machine.
Related
I currently have a node bot embedded on my web app via direct line but I am struggling to attach:
Spotify Audio
I am trying to do so by using the URL attachment or an adaptive card, but the spotify embed doesn't play
Below is the code I use:
var send = {
text: "stuff",
attachments: [
contentType: "audio/ogg",
contentUrl: "spotifyEmbedUrl"
]
}
await stepContext.context.sendActivity(send);
I am unsure on how I can get spotify audio to play.
Is there a way I can return HTML code (and so get around it by adding an iframe into the chat etc?)
OR maybe I could create a modal popup that I could create the embed iframe?
Any help would be appreciated!
Unfortunately, you can't just send a file to a web page and it automatically start playing. Additionally, while Spotify provides embed URLs, which are not a direct link to an audio file, you can't simply tell the browser to play the file.
However, Spotify provides the embed code for displaying a play button that can be used in a page to play a song. Assuming you are using Web Chat in a web site (and even if you're not, this will give you an idea) and that, from the code you supplied, you are wanting to send the song in an activity, you can achieve this by sending the embed code in the activity, instead, via Web Chat's store. When the activity is received, the embed code is passed to a function to update the page and, thus, display the play button.
Be aware, the play button is essentially a UI widget, not a media player. There is no functionality available for telling the play button to auto play, stop, or anything else. The most you can do is display the button after which the user will be required to interact with it.
Also, this is a someone bare bones, simplified implementation. There are many things that aren't accounted for - please don't consider this a complete solution. There are aspects you will need to consider (e.g. multiple cards that utilize a postBack action).
In your bot: You want to send the embed code in an activity. Whether that is an event, message, or something else, is up to you. As you can see below, I have chosen to send a hero card that initiates a postBack when the button is pressed (a postBack sends data behind the scenes without displaying the action to the user).
const card = CardFactory.heroCard(
"Rome Wasn't Built in a Day",
null,
CardFactory.actions([
{
type: 'postBack',
title: 'Read more',
value: `<iframe src="https://open.spotify.com/embed/track/6lzd7dxYNuVSvh7sJDHIa3" width="300" height="380" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>`
}
]),
{
subtitle: 'Artist: Morcheeba',
text: 'Album: Parts of the Process - released 2003'
}
);
await stepContext.context.sendActivity({ attachments: [card]});
Web Chat: First, use Web Chat's store to filter on incoming activities that include attachments where the button type (action) is postBack. When the condition is met, get the last card rendered and assign an event listener. When the card's button is clicked, get the 'spotify' container element and update the innerHTML with the embed code that was sent in the activity, thus displaying the play button.*
Please note, the setTimeout() used below is necessary for enabling the click action. Without the time out, the event listener being appended to the button would occur before the store finished processing the incoming activity.
<div id="webchat" role="main"></div>
<div class='spotify'></div>
[...]
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => action => {
if ( action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' ) {
const activity = action.payload?.activity;
if (activity.attachments && activity.attachments[0].content.buttons[0]?.type === 'postBack') {
setTimeout(() => {
const spotifyIframe = activity.attachments[0].content.buttons[0].value
let cards = document.querySelectorAll( '.ac-adaptiveCard' )
let cardLength = cards.length;
let card = cards[ cardLength - 1 ];
card.querySelectorAll( 'button' ).forEach( button => {
button.addEventListener( 'click', ( e ) => {
e.preventDefault();
const spotifyContainer = document.querySelector( '.spotify' );
spotifyContainer.innerHTML = spotifyIframe
} )
} );
}, 300);
}
next( action );
} );
Hope of help!
I've been able to do video searches and read info using just one link that starts with googleapis.com but for the playlistitemsinsert to put videos into a playlist, I'm having trouble with the syntax. I'm trying to randomize the order of videos in a YouTube playlist. I understand you can shuffle play but its easier for me to remove the videos if they're played in chronological order, also its easier to go back to a video you recently watched.
I have all of the video ids in a column in excel I'm just not sure how to use vba to do a POST HTTP request to insert the videos into a playlist. Can you help me with the syntax on this?
Although not using excel as database This works using youtube api. and users youtube created play list . shuffles the play list into new order every time page is refreshes
Load YT-player API.
Load YT-playlist user playlist id "**.youtube.com/playlist?list=PLo16_*******"
To Shuffle playlist use > player.setShuffle(true);
To Start YT-player at video 1 in shuffled playlist use > player.playVideoAt(0)
working demo Responsive shuffled YouTube Playlist on Google sites
code jsfiddle.net
<!DOCTYPE html>
<html>
<!-- Responsive YouTube shuffled playlist player -->
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag.
style = replaces size in the player script makes it responsive -->
<div style=" top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
id='player'>
</div>
</body>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
playerVars: {
autoplay: 0,
loop: 1,
controls: 1,
showinfo: 1,
frameborder: 1,
'listType': 'playlist',
'list': "PLo16_DLriHp4A8BvkJFZfO_4KDVv7yGgy", // your YouTube playlist id here
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
// first shuffle play list
player.setShuffle(true);
// Onload and on refresh shuffles the users YT playlist but always starts playing
// the first video in the original list at its new index position
//ie. video (1) = video( new shuffled pos ?)
// to get over this we can start the player at the new shuffled playlist
//video 1(index=0) this changes every time it's refreshed
player.playVideoAt(0)
}
// 5. The API calls this function when the player's state changes.
// option to to add bits
function onPlayerStateChange(event) {
const player = event.target;
}
</script>
</html>
Here is some link which provides subtitle list of youtube video in xml format.
'https://www.youtube.com/api/timedtext?lang=en&v=6dlr-1Qk8Uc'
'http://video.google.com/timedtext?type=track&v=zenMEj0cAC4&id=0&lang=en'
But it is not applied for all videos.
Some videos have subtitle(cc) icon at bottom of video and on click this subtitle appears, but this links cannot return the subtitle data.
Then I have checked the respose data on click the cc icon , it return data of all videos which have subtitle.
But I cannot get how to call this api using node js.
Instead of use the YouTube Data API - caption1 for retrieve the captions of a video, you can also use an AJAX callback for get the captions.
1If you want use the YouTube Data API for query the captions, I advise you read the documentation carefully.
In this example, an AJAX callback is used for retrieve the captions from a given YouTube video.
Using the XML parser, the response of the previous AJAX callback is iterated in a for-loop for get the captions:
// Ajax callback to the YouTube channel:
$.ajax({
type: "GET",
url: "http://video.google.com/timedtext?type=track&v=zenMEj0cAC4&id=0&lang=en",
crossDomain: true,
}).done(function(data) {
getCaption(data);
});
// Variables.
var parser, xmlDoc;
var HTML_captions = "";
// Parse the AJAX response and get the captions.
function getCaption(data) {
try {
// Loop the results of the ajax:
for (var i = 0; i < data.getElementsByTagName("transcript")[0].childNodes.length; i++) {
HTML_captions += data.getElementsByTagName("transcript")[0].childNodes[i].innerHTML + "<br/>";
}
// Preparing captions...
fillData();
} catch (err) {
console.log(err);
alert('Error at getCaption function - see console form more details.');
}
}
// Fill the data "captions" in a HTML "div" control.
function fillData() {
try {
document.getElementById("demo").innerHTML = HTML_captions;
} catch (err) {
console.log(err);
alert('Error at fillData function - see console form more details.');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<div class="infoVideo">
<span>These are the captions of the following YouTube video:</span>
<br/>
<span>Title: How Turbochargers Work</span>
<br/>
<span>URL: https://www.youtube.com/watch?v=zenMEj0cAC4</span>
</div>
<br/>
<div id="demo"><i>Loading captions...</i></div>
google.com/webstore i have add my extension
i Have check "This item uses inline install."
Websites: chose Verify site
google.com/webmasters i have add site and Verifyed.
when i put this code on me site:
<link rel="chrome-webstore-item"href="https://chrome.google.com/webstore/detail/itemID">
<button onclick="chrome.webstore.install()" id="install-button">Add to Chrome</button>
<script>
if (document.getElementById('extension-is-installed')) {
document.getElementById('install-button').style.display = 'none';
}
</script>
i click on button "Add to Chrome" install app extension, but when i refresh site button "Add to Chrome" is display. why? i cant Understanding
You're obviously following the guide at https://developer.chrome.com/webstore/inline_installation
In that case, you missed a step.. Let's look at the code.
if (document.getElementById('extension-is-installed')) {
document.getElementById('install-button').style.display = 'none';
}
The condition here is whether an element with ID extension-is-installed is present on the page. But what adds it?
A step back:
For example, you could have a content script that targets the installation page:
var isInstalledNode = document.createElement('div');
isInstalledNode.id = 'extension-is-installed';
document.body.appendChild(isInstalledNode);
So, you need to add a Content Script that adds that element to the page.
However, I doubt that guide will work. By default, content scripts execute after DOM is loaded (and therefore, that hiding script has executed). You can make them run at document_start, but then body does not exist yet.
Let me make an alternative hiding script, based on communicating with the extension using "externally_connectable". Suppose your website is example.com, and your extension's ID is itemID
Add example.com to sites you want to be messaged from:
"externally_connectable" : {
"matches" : [
"*://*.example.com/*"
]
},
In your background page, prepare for the message from the webpage:
chrome.runtime.onMessageExternal.addListener(
function(message, sender, sendResponse) {
if(message.areYouThere) sendResponse(true);
}
);
In your page at example.com, add a button (hidden by default) and code to show it when appropriate:
<button onclick="chrome.webstore.install()"
id="install-button" style="display:none;">
Add to Chrome
</button>
<script>
if (chrome) {
// The browser is Chrome, so we may need to show the button
if(chrome.runtime && chrome.runtime.sendMessage) {
// Some extension is ready to receive messages from us
// Test it:
chrome.runtime.sendMessage(
"itemID",
{areYouThere: true},
function(response) {
if(response) {
// Extension is already installed, keep hidden
} else {
// No positive answer - it wasn't our extension
document.getElementById('install-button').style.display = 'block';
}
}
);
} else {
// Extension is not installed, show button
document.getElementById('install-button').style.display = 'block';
}
}
</script>
Was requested to add page reload after install. chrome.webstore.install has a callback parameter specifically for this.
Instead of using onclick attribute, assign a function:
document.getElementById('install-button').addEventListener("click", function(e) {
chrome.webstore.install(function() {
// Installation successful
location.reload();
});
});
I'm trying to display a div inside tab playlists if the href contains a spotifyURI. This will be used to display a playlist under a tab.
Step by step this is my problem:
Click playlist tab and then click the "My playlist1".
The href is displayed in the playlist container under the tab playlists. (perfect so far)
Click the start tab and then click the playlists tab.
Instead of displaying the list of playlists the playlist container is show again. So the last used url is cached?
Then if the playlists tab is clicked again the url will be "reseted" and the list of playlists will be shown and playlist container hidden.
I'd like 4. to show the playlist list right away instead.
Is there a way to reset or what am I missing?
<script>
$(document).ready(function() {
sp = getSpotifyApi(1);
var m = sp.require("sp://import/scripts/api/models");
updateTabs();
m.application.observe(m.EVENT.ARGUMENTSCHANGED, updateTabs);
function updateTabs()
{
console.log(m.application.arguments);
var args = m.application.arguments;
$('.section').hide();
if (args[1] == "spotify") $("#playlist").html("args:"+args).show();
else $("#"+args[0]).show();
}
});
</script>
<div id="playlist" class="section">Container for playlist content</div>
<div id="start" class="section">Welcome</div>
<div id="playlists" class="section">
My playlist1
My playlist2
</div>
Thanks alot for all replys!
Here is how I will proceed using JQuery.
First of all you need to use the Localstorage :
var stor = sp.require("sp://import/scripts/storage");
Then if for exemple you get a list of playlist you can build the list like this
for (var i=0; i<d.playlists.length; i++) {
$('#playlists').append('My <a id="p' + i + '"href="'+ d.playlists[i] +'">playlist1</a>');
$('#playlists #p'+i).live('click', function(e) {
e.preventdefault();
stor.set('choosenplaylist', d.playlists[i]);
});
}
This was for the storage now for when changing tad :
if (!stor.get('choosenplaylist')=='') {
location.href=stor.get('choosenplaylist');
}
Okay this is a suggestion and it need to be tested regarding to your app.
Im trying this out now, and i can reproduce your bug (im guessing it's a bug, the tab should replace the url in my opinion)
But, until it's fixed, my best guess is to capture the playlist links in an event handler and cancelling the original event, after cancelling you replace the content with the appropriate playlist view.
Tab test code (on gist.github.com)
I've abstracted the actual view binding from the event handler, and added a click event hook that calls the abstract view binder instead of the "real" one, this also supports deep linking into the an app