I am using SWFObject to embed YouTube videos into our website. There are many links to videos in one page and each link clears a wrapper div, then loads a new embed into it, with this code:
$('a.video-link').each(function () {
$(this).on('click', function(e) {
e.preventDefault();
if ($('#video-wrap').has('object').length == 0) {
var params = { allowScriptAccess: 'always', allowFullScreen: 'true' };
var atts = { id: 'ytapiplayer' };
swfobject.embedSWF($(this).attr('href'), 'ytapiplayer', '1000', '562', '8', null, null, params, atts);
$('#video-wrap').show();
} else {
$('#video-wrap').find('object').remove();
$(this).trigger('click');
}
});
});
These are the Youtube links I am using for each embed:
http://www.youtube.com/v/{Youtube ID}?hl=en_US&rel=0&hd=1&border=0&version=3&fs=1&autoplay=1&autohide=1&enablejsapi=1&playerapiid=ytapiplayer
Then, here is the onYouTubePlayerReady() event handler:
function onYouTubePlayerReady(id) {
console.log('youtube player is ready.');
var ytplayer = document.getElementById('ytapiplayer');
ytplayer.addEventListener('onStateChange', 'onYouTubePlayerStateChange');
ytplayer.addEventListener('onError', 'onYouTubePlayerError');
}
All videos load fine, however the onYouTubePlayerReady is never hit!
I have tried solutions from here and here but nothing worked :(
Please help me solve this problem. The ultimate goal is to get the Youtube API to work.
Thanks.
EDIT: I tried to play with the code, make sure all names are correct, separate into different script tags and/or .js file, load it on the beginning, inside document.ready(), still, onYouTubePlayerReady is not firing. What do you think?
Here is the working code:
Executing SWFObject on each video link:
$('a.video-link').on('click', function(e) {
e.preventDefault();
// SWFObjects loads a video object into div with ID ytapiplayer.
// If the wrapper div already contains a video we need to remove it first:
if ($('#video-wrap').has('object').length == 0) {
var params = { allowScriptAccess: 'always', allowFullScreen: 'true' };
var atts = { id: 'ytapiplayer' };
swfobject.embedSWF($(this).attr('href'), 'ytapiplayer', '1000', '562', '8', null, null, params, atts);
$('#video-wrap').show();
} else {
$('#video-wrap').find('object').remove();
$(this).trigger('click');
}
});
The YouTube link with API values:
http://www.youtube.com/v/' + data.YoutubeLink + '?hl=en_US&rel=0&hd=1&border=0&version=3&fs=1&autoplay=1&autohide=1&enablejsapi=1&playerapiid=ytapiplayer
And the SWFObject event handlers I put this code in a separate .js file, loaded before the code executing SWFObject. I don't know if it's necessary, but it's working anyway:
function onYouTubePlayerReady(id) {
// We need the actual DOM element for this, if we want to use more advanced API.
// This is because addEventListener activates the API.
var ytplayer = $('#ytapiplayer').get(0);
ytplayer.addEventListener('onStateChange', 'onYouTubePlayerStateChange'); // onYouTubePlayerStateChange(newState)
ytplayer.addEventListener('onError', 'onYouTubePlayerError'); // onYouTubePlayerError(errorCode)
}
Related
I am currently developing a chrome extension that can get cookies from a website, using chrome.getCookies.
However, the url parameter in
chrome.getCookies
must be a static url in order to work, like this:
chrome.cookies.get({url: 'https://example.org/#/', name:
'token'}, function(cookie) {
document.getElementById("token").innerHTML = cookie.value
});
But I want to make that url changed dynamically based on which tab I am using that extension. So I tried this:
var tabUrl;
chrome.tabs.getSelected(null, function(tab) {
tabUrl = tab.url
});
chrome.cookies.get({url: tabUrl, name:
'token'}, function(cookie) {
document.getElementById("token").innerHTML = cookie.value
});
And it didn't work. What should I to to achieve my goal?
Edit: If anyone ever reach this page, here the solution, you have to put subsequent code inside the callback, here's the correct one:
chrome.tabs.getSelected(null, function(tab) {
chrome.cookies.get({url: tab.url, name: 'expa_token'}, function(cookie) {
document.getElementById("token").innerHTML = cookie.value
});
});
I’ve seen different web apps like Playmoss, Whyd, and Songdrop etc. that, I believe, HAVE to utilize the Soundcloud Embedded Widget in order to produce the functionality of playing multiple tracks, in sucession, not apart of a set/(playlist). Currently I am having issues reproducing this functionality with the following library, so I decided to attempt to write my own:
https://github.com/eric-robinson/SCLPlayer
I am very new to writing javascript, but my below code, will load a first track, and play it once hitting the “ready” bind. Once hitting the “finish” bind, It will then jump to the loadNextTrack() function and load the next tracks URL, into the src of the widget’s iFrame. After that, it doesn’t ever hit the original “ready” bind, which would then begin playback.
So to clear things up, playback doesn’t begin for the second track.
<script type = "text/javascript">
var SCLPlayer = {
isPlayerLoaded : false,
isPlayerFullLoaded : false,
needsFirstTrackSkip : true,
isPaused: true,
scPlayer : function() {
widgetContainer = document.getElementById('sc');
widget = SC.Widget(widgetContainer);
return widget;
},
loadNextTrack : function() {
var ifr = document.getElementById('sc');
ifr.src = 'http://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/231758952';
console.log ('Loading Next Track');
SCLPlayer.scPlayer().bind(SC.Widget.Events.READY, function() {
console.log ('Player is Ready, next Track');
SCLPlayer.scPlayer().play();
});
}
};
$( '#sc' ).ready(function() {
SCLPlayer.scPlayer().bind(SC.Widget.Events.READY, function() {
SCLPlayer.isPlayerLoaded = true;
//window.location = 'sclplayer://didLoad';
console.log ('Player is Ready');
SCLPlayer.scPlayer().play();
});
SCLPlayer.scPlayer().bind(SC.Widget.Events.PLAY, function() {
SCLPlayer.isPaused = false;
//window.location = 'sclplayer://didPlay';
console.log ('Player did Play');
});
SCLPlayer.scPlayer().bind(SC.Widget.Events.PAUSE, function() {
SCLPlayer.isPaused = true;
//window.location = 'sclplayer://didPause';
console.log ('Player did Pause');
});
SCLPlayer.scPlayer().bind(SC.Widget.Events.FINISH, function() {
SCLPlayer.isPaused = true;
//window.location = 'sclplayer://didFinish';
console.log ('Player did Finish');
SCLPlayer.loadNextTrack();
});
});
</script>
</head>
<body>
<iframe id = "sc" width="100%" height="100%" scrolling="no" frameborder="no" src="http://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/226183306"></iframe>
</body>
The whole point of me writing this Javascript is so that I can then use a Swift to Javascript bridge in my iOS app to then control the loading of tracks into the embedded players. For some reason over a slower connection, the next track doesn't always load into the player, using the "bridge". I hope to provide the nextTrackURL to the javascript side of things before the currentTrack finishes, so that the bridge conveys nothing and the Javascript handles new track loading, solely on its own.
I think you want to use the load function to specify the url for the new track
From the soundcloud Widget API docs:
load(url, options) — reloads the iframe element with a new widget specified by the url. All previously added event listeners will continue working. options is an object which allows you to define all possible widget parameters as well as a callback function which will be executed as soon as new widget is ready. See below for detailed list of widget parameters.
var url = "https://api.soundcloud.com/";
var options = [];
// if a track
url += "tracks/";
// if a playlist
url += "playlists/"
// append the id of the track / playlist to the url
url += id;
// set any options you want for the player
options.show_artwork = false;
options.liking = false;
options.auto_play = true;
widget.load(url, options, OPTIONAL_CALLBACK_FUNCTION);
Edited to show binding...
The bind code is called once, after the widget is initially loaded.
The ready event is only called once, when the widget is initially loaded, it is not called for each subsequent call using load().
try {
widget.bind(SC.Widget.Events.FINISH,
function finishedPlaying() {
// your code / function call
}
);
widget.bind(SC.Widget.Events.PAUSE,
function paused() {
// your code / function call
}
);
widget.bind(SC.Widget.Events.PLAY,
function playing() {
// your code / function call
widget.getCurrentSound(function scCurrentSound(sound) {
// this also binds getCurrent sound which is called
// each time a new sound is loaded
});
}
);
widget.bind(SC.Widget.Events.PLAY_PROGRESS,
function position(pos) {
// your code / function call
}
);
widget.bind(SC.Widget.Events.SEEK,
function seek(pos) {
// your code / function call
}
);
widget.bind(SC.Widget.Events.READY,
function ready() {
// your code / function call
}
);
} catch(e) {
// exception handler code
}
I am developing a chrome extension in which one can select a color scheme from list given in popup and apply it to the open (highlighted) tab. From one of code snippet I comes to know that using code : "document.body.style.backgroundColor='red'" in chrome.tabs.executeScript change the background color. but there is only one line in code.
What my steps are
select the color scheme from popup
get the class name of the selected li
apply that class to the DOM document
Please see the code below
popup.js
document.addEventListener('DOMContentLoaded', function () {
var li = document.querySelectorAll('li');
for (var i = 0; i < li.length; i++) {
li[i].addEventListener('click', click);
}
});
function click(e) {
// console.log(e.target.className); // gives correct value
chrome.tabs.executeScript(null, {
code : "var scriptOptions = { param1: e.target.className} ;"}, function(e){
console.log('clicked class');
console.info(param1); // gives nothing
document.body.setAttribute('class', e.target.className);
});
window.close();
}
How to get e.target.className inside function(e) ?
again If I use jquery. it changed the that popup background color only, see the code
$(function(){
console.log('jQuery added');
$(document).on ('click', 'li', function(){
var cl = this.className;
$('body').removeClass().addClass(cl);
});
});
Please tell me
What is the proper way to accomplish this in both javascript and jQuery
How to get e.target.className inside function(e) ?
Let's look at the following sample code:
var a = 1;
function f(a) {
alert(a);
}
f(2);
This is a simplified version of your problem. There is a variable a in the global scope, but by naming your function parameter a you're essentially making a local variable of the same name.
In your code:
function click(e) {
// e is now from click(e)
chrome.tabs.executeScript(null, {
code : "var scriptOptions = { param1: e.target.className} ;"}, function(e){
// e is now from function(e)
});
}
The solution is simple: you're not using the parameter of the callback of executeScript, so just use function() { /* ... */ } as a callback.
If I use jQuery, it changes the popup background color only
Your code operates in the context of your popup; $('body') refers to popup's body. Same with document.body - the callback of executeScript executes in the popup.
To change the active tab, this needs to be done from the content script in that tab.
What is the proper way to accomplish this
While you could just inject code, it's better to make a content script that waits for a command.
// content.js
if(!injected) { // Make sure it's only executed once
injected = true;
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.action == "bodyClass") {
document.body.setAttribute('class', message.class);
}
});
}
Then from the popup, you inject this script then message it:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
// requires only activeTab permission
chrome.tabs.executeScript(tabs[0].id, {file: "content.js"}, function() {
// This code executes in the popup after the content script code executes
// so it is ready for the message
chrome.tabs.sendMessage(tabs[0].id, {action: "bodyClass", class: "example"});
});
});
If you need jQuery, you need to inject it first:
chrome.tabs.executeScript(tabs[0].id, {file: "jquery.js"}, function() {
chrome.tabs.executeScript(tabs[0].id, {file: "content.js"}, function() {
/* content script ready */
}
}
Alternatively, you can define the script in the manifest and not inject it every time, but this potentially drains memory as it is injected in tabs where it is not needed.
There is bug in chromium and in chrome I need to use JSON.stringify(e.target.className) the before sending via code
code : "var scriptOptions = { selectedClass: " + JSON.stringify(cl) + " }"
from chorme.sendMessage documentation
Sending a request from the extension to a content script looks very
similar, except that you need to specify which tab to send it to.
function click(e) {
var cl = e.target.className; // both gives the same result that is OK.
chrome.tabs.query({ active: true, highlighted: true, currentWindow: true }, function(htab) {
// console.log(JSON.stringify(htab, ['active', 'id', 'index', 'windowId', 'title', 'url'], 4));
chrome.tabs.executeScript(htab[0].id, {
code : "var scriptOptions = { selectedClass:" + JSON.stringify(cl) + " }" }, function() {
chrome.tabs.executeScript(htab[0].id, { file: "js/script.js" }, function(){
console.log('Inside script file');
chrome.tabs.sendMessage(htab[0].id, { action: "bodyColor" }, function(resp) {
console.log('response aaya');
});
});
});
});
}
Is it possible to do a javascript action after play button is pushed? I know I will need to use onStateChange function form Youtube's API. But I really don't know where to start? Any help? Thank you.
--
I have also found something here: http://apiblog.youtube.com/2011/01/introducing-javascript-player-api-for.html
Here's a solution that you should be able to extend easily: http://jsbin.com/evagof
Hey here is the answer .
http://jsfiddle.net/masiha/4mEDR/
Enjoy ...let me know if you have more qtns
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load("swfobject", "2.1");
</script>
<script type="text/javascript">
// Update a particular HTML element with a new value
function updateHTML(elmId, value) {
document.getElementById(elmId).innerHTML = value;
}
// This function is called when the player changes state
function onPlayerStateChange(newState) {
updateHTML("playerState", newState);
if(newState === 1){
//if the player is now playing
//add your code here
}
}
// This function is automatically called by the player once it loads
function onYouTubePlayerReady(playerId) {
ytplayer = document.getElementById("ytPlayer");
// This causes the updatePlayerInfo function to be called every 250ms to
// get fresh data from the player
setInterval(updatePlayerInfo, 250);
updatePlayerInfo();
ytplayer.addEventListener("onPlayerStateChange");
}
// The "main method" of this sample. Called when someone clicks "Run".
function loadPlayer() {
// The video to load
var videoID = "ylLzyHk54Z0"
// Lets Flash from another domain call JavaScript
var params = { allowScriptAccess: "always" };
// The element id of the Flash embed
var atts = { id: "ytPlayer" };
// All of the magic handled by SWFObject (http://code.google.com/p/swfobject/)
swfobject.embedSWF("http://www.youtube.com/v/" + videoID +
"?version=3&enablejsapi=1&playerapiid=player1",
"videoDiv", "480", "295", "9", null, null, params, atts);
}
function _run() {
loadPlayer();
}
google.setOnLoadCallback(_run);
</script>
<div id="videoDiv">Loading...</div>
<p>Player state: <span id="playerState">--</span></p>
http://code.google.com/apis/ajax/playground/?exp=youtube#polling_the_player
Maybe Youtube made some changes since this question was posted, but most of the answers didn't work. I found that the easiest way was to use the iframe_api (https://developers.google.com/youtube/iframe_api_reference)
Here is an example
https://thimble.webmaker.org/en-US/project/39354/edit
My javascript:
function onYouTubePlayerReady()
{
playerObj = document.getElementById("player_embed");
playerObj.addEventListener("onStateChange", test);
// Make sure the document is loaded before any DOM-manipulation
$(document).ready(function() {
// Update player information every 500ms
setInterval(updatePlayerInfo, 500);
});
}
function test(newState)
{
alert(newState);
}
My videos are loaded correctly and I can control fine them through my javascript. However the onStateChange event never seems to trigger. It never comes up with an alert when I'm playing/stopping/pausing videos etc. Anyone with a solution/similar problem?
You must pass the function name as a string to addEventListener.
playerObj.addEventListener("onStateChange", "test");
This format is for JQuery but the logic is same, create a function inside onYouTubePlayerReady to pass the playerId
$(document).ready(function() {
onYouTubePlayerReady = function(playerId) {
eventHandler=function(state){onStateChangeID(state,playerId);}
playerObj = document.getElementById("player_embed");
playerObj.addEventListener('onStateChange','eventHandler',false);
}
onStateChangeID=function(newState,playerId) {
console.log("onStateChange: ("+playerId+") " + newState);
}
});