I have a music blog that contains various embedded soundcloud and youtube players.
What I want to do is prevent any audio from playing simultaneously. In other words while I am playing a youtube video, if I click to play the soundcloud embed I want the youtube player to pause and vice versa.
I have developed code that pauses the streaming youtube player if I click to play another youtube player (soundcloud already does this inherently). I just need to make it cross compatible. Really would appreciate some help, thanks.
var playerCurrentlyPlaying = null;
var players = {}
YT_ready(function() {
$(".youtube_embed").each(function() {
var identifier = this.id;
var frameID = getFrameID(identifier);
if (frameID) {
players[frameID] = new YT.Player(frameID, {
events: {
"onStateChange": function(event){
if (event.data == YT.PlayerState.PLAYING)
{
if(playerCurrentlyPlaying != null &&
playerCurrentlyPlaying != frameID)
callPlayer( playerCurrentlyPlaying , 'pauseVideo' );
playerCurrentlyPlaying = frameID;
}
}
}
});
}
});
});
I have used functions from these sources:
Listening for Youtube Event in JavaScript or jQuery
YouTube iframe API: how do I control a iframe player that's already in the HTML?
YouTube API Target (multiple) existing iframe(s)
Rendered HTML using UniqueID():
<span class="soundcloud_embed" id="soundcloud_post_312">
<iframe id="ui-id-1" width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F103518792&show_artwork=true&secret_token=s-LnOTK"></iframe>
</span>
<span class="youtube_embed" id="youtube_post_309">
<iframe id="ui-id-2" width="528" height="190" src="//www.youtube.com/embed/Y3CYKXBEtf0" frameborder="0" allowfullscreen></iframe>
</span>
First of all, things will be greatly simplified if you are able to get an ID onto the iframes themselves, like this:
<span class="soundcloud_embed">
<iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F4997623" id="sound1"></iframe>
</span>
<span class="soundcloud_embed">
<iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F105153133" id="sound2"></iframe>
</span>
<span class="youtube_embed">
<iframe width="400" height="225" src="//www.youtube.com/embed/tv8WgLEIPBg" id="vid1" frameborder="0" allowfullscreen></iframe>
</span>
<span class="youtube_embed">
<iframe width="400" height="225" src="//www.youtube.com/embed/FmICU1gMAAw" id="vid2" frameborder="0" allowfullscreen></iframe>
</span>
If you'd prefer not to hack the auto_html gem that you mention in order to get IDs, you can either use jquery's .uniqueId() function to generate them on all iframes or use the getFrameID() helper method from the post you referred to (and seem to already be using).
To make it as easy as possible to get the two APIs (Youtube and Soundcloud) to be able to respond to each other's events, you can use a couple of control objects that keep track of which players are on your page and which of them is currently playing (this strategy is similar to that employed by the links you referred to, but are expanded to be able to keep track of which player belongs to which API). With it, define a generic pause function that serves as a simplistic wrapper for both APIs:
var playerCurrentlyPlaying = {"api":null,"frameID":null};
var players = {"yt":{},"sc":{}};
pauseCurrentPlayer=function() {
var api=playerCurrentlyPlaying["api"],
frameid=playerCurrentlyPlaying["frameID"];
switch(api) {
case "yt":
players[api][frameid].pauseVideo();
break;
case "sc":
players[api][frameid]["widget"].pause();
break;
}
};
Next, you'll want to define two separate functions; the first will be called whenever a YouTube play event is captured, and the second whenever a Soundcloud play event is captured. Currently the Soundcloud HTML5 Widget has a few bugs that force the necessity to include some pretty ugly hacks--namely, the Play event sometimes isn't fired when you play a Soundcloud sound for the first time. Luckily, the Play_Progress event is, so we can leverage that, but must also include a workaround so it doesn't create a race condition when pausing a sound and starting a video:
onYTPlay =function(frameid) {
if (playerCurrentlyPlaying["frameID"]!=frameid && playerCurrentlyPlaying["frameID"]!=null) {
pauseCurrentPlayer();
}
playerCurrentlyPlaying["api"]="yt";
playerCurrentlyPlaying["frameID"]=frameid;
};
onSCPlay=function(frameid,event) {
if (event==SC.Widget.Events.PLAY||players["sc"][frameid]["firstplay"]==true) {
if (playerCurrentlyPlaying["api"]=="yt") { // because any soundcloud player will be automatically paused by another soundcloud event, we only have to worry if the currently active player is Youtube
pauseCurrentPlayer();
}
playerCurrentlyPlaying["api"]="sc";
playerCurrentlyPlaying["frameID"]=frameid;
players["sc"][frameid]["firstplay"]=false;
}
};
Finally, you can then add your hooks to the Youtube embeds and the Soundcloud embeds, remembering the hack we have to put in for the Soundcloud Play event. Don't forget to embed the Soundcloud Widget API (<script src="w.soundcloud.com/player/api.js"; type="text/javascript"></script>), and then use this code to do your bindings:
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
$(".youtube_embed iframe").each(function() {
players["yt"][$(this).attr('id')] = new YT.Player($(this).attr('id'), {
events: { 'onStateChange': onYTPlayerStateChange }
});
});
}
onYTPlayerStateChange = function(event) {
if (event.data==YT.PlayerState.PLAYING) {
onYTPlay(event.target.a.id);
}
};
(function(){
$(".soundcloud_embed iframe").each(function() {
var frameid=$(this).attr('id');
players["sc"][frameid]={};
players["sc"][frameid]={"widget":SC.Widget(document.getElementById(frameid)),"firstplay":true};
players["sc"][frameid]["widget"].bind(SC.Widget.Events.READY, function() {
players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY, function() {
onSCPlay(frameid,SC.Widget.Events.PLAY);
});
players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY_PROGRESS, function() {
onSCPlay(frameid,SC.Widget.Events.PLAY_PROGRESS);
});
});
});
}());
This approach is set up to handle multiple players of both APIs, and should be decently extensible if you want to support other embeddable media widgets (provided they expose an event when they start to play and they have the ability to programmatically pause players).
it's possible. check widget api playground. you can watch all state events from soundcloud iframe widget. this can be done on flash embed too.
https://w.soundcloud.com/player/api_playground.html
watch for SC.Widget.Events.PLAY {"loadedProgress":0,"currentPosition":0,"relativePosition":0} event on start playing
Related
I'm using a Vimeo video-embed (iFrame embed code from their website) on my website, and I need the video to automatically stop at a specific timestamp (I'll use 6 seconds here) whenever users of my site play the video. The content after the timestamp is unnecessary.
But unlike YouTube, Vimeo doesn't seem to have an easy way to set end times for any video you embed from them. Unfortunately, I do not own the video so I can't edit the footage directly, so I believe a JavaScript solution is the best option.
Here's the aforementioned iFrame embed HTML from Vimeo that I use on my site:
<iframe id="vidz" src="https://player.vimeo.com/video/401649410?h=11d74aa27c&portrait=0" width="450" height="253" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen=""></iframe>
Upon trying to select elements within the iFrame (like the video itself), my JS selectors don't seem to be working at all, perhaps because the video is from a separate source not hosted on my site?
Here's code I've been working with, but it doesn't appear to be interacting with the iFrame, as I believe I would need to add this eventListener to a video, directly. But I can't select the embeded video via JS either, it seems. So I'm not quite sure how to handle this:
var vid = document.querySelector("#vidz");
vid.addEventListener("timeupdate", function(){
if(t >= 6000)
{
vid.pause();
}
});
I can also provide the HTML to any elements within the iFrame, but again, I'm not sure how I'd be able to interact with those elements.
Any ideas? Any and all help would be deeply appreciated. Cheers.
use Vimeo js file and below is a script you want video will pause after 6 minutes (specific time) (360 means 6 minutes)
<script src="https://player.vimeo.com/api/player.js"></script>
var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
function foo() {
player.getCurrentTime().then(function(time) {
console.log('time:', time);
if(time >= 360){
player.pause()
}
});
setTimeout(foo, 1000);
}
player.on('play', function() {
foo();
});
</script>
I have some embed code like:
<iframe id="video1" class="video" src=""//www.dailymotion.com/embed/video/VIDEO_ID?autoPlay=1&wmode=transparent&loop=1&controls=0&showinfo=0&api=1&endscreen-enable=0&mute=1" allowfullscreen="true" frameborder="0" width="560" height="349"></iframe>
I am trying to access this video using Javascript but the Video ID is not known in advance (it must be able to be set within our CMS and be changed by any editor). Also it is possible to have more than one video on the page. Hard-coding the video ID(s) in my .js file is not possible.
Using the Javascript API, I need to write a custom play/pause function (passing in the button object they clicked) and also to detect when the video has ended and re-start it (to imitate looping, which Dailymotion apparently does not support for some reason). But it seems a call to:
DM.Player(document.getElementById(iframeID), { video: VIDEO_ID})
requires the video's ID to be known (I do know the iFrame ID where the video is but apparently that isn't enough to access the player like it is for other video platforms).
I then need to be able to create a function to call play or pause based on whether the user has clicked the play/pause toggle on a specific video. My Javascript knowledge isn't great, but I have been able to do this with other platforms by knowing the iframe ID. The play/pause does work if I hard-code a video ID but only if there is one video on the page and only if I do not try to "loop" the video.
This is a private video, if that matters - we want it to only be viewed on our website and not on Dailymotion.
Pseudo-code greatly appreciated as I find their API documentation a bit incomplete for a newcomer (such as not specifying if parameters are required or optional, and not listing available options like for params and events during DM.Player initialization)
EDIT: Here is how I access the video API with other video hosting services (YouTube, Vimeo, Brightcove, etc)
I build an array of all HTML elements with a certain class name (recall there can be more than one video). Say the class name is ".video" so I build an array of all ".video" on the page and their corresponding HTML id. I then use document.getElementById to populate the array with the players.
Then in the play/pause click function, I can access the video like so:
var player = players[index];
var state = player.getPlayerState();
if (state == 1) {
player.pauseVideo();
}
else {
player.playVideo();
}
This does not work for Dailymotion because the actual DM Video ID (and not the HTML element's ID) must be known in advance. I was wondering if there is a way to access the video via the Javascript API without knowing the video ID?
I don't use DailyMotion API but I knocked up this experiment which might be useful to you.
See if the comments in my example code below help you to understand how to use your own buttons with JS functions and how to handle video "end" event etc.
<!DOCTYPE html>
<html>
<body>
<!-- 1. Load DailyMotion API (Javascript) -->
<script src='https://api.dmcdn.net/all.js'> </script>
<!-- 2. Create container for DM Player instance -->
<div id='player'></div>
<!-- 3. Javascript stuff goes here -->
<script>
//Set VIDEO_ID (retrieve or update from your CMS)
//**example** var VIDEO_ID = get_video_id.php **where PHP returns/echo the text of ID**
var VIDEO_ID = "xwr14q"; //update this via your CMS technique
//Create DM Player instance//
var player = DM.player(document.getElementById('player'), {
video: VIDEO_ID,
width: "100%", height: "100%",
params: { autoplay: false, mute: true }
});
//Handle video ending (seek back to zero time)//
player.addEventListener('end', function (evt) { evt.target.currentTime = 0; evt.target.play() } );
//Control functions for DM Player instance//
function func_Play()
{ player.play(); }
function func_Pause()
{ player.pause(); }
</script>
<p>
<!-- Buttons for play pause -->
<button onclick="func_Play()"> PLAY </button>
<button onclick="func_Pause()"> PAUSE </button>
</p>
</body>
</html>
Also regarding
"...It is possible to have more than one video on the page"
Do some "experience quality" tests. Just be sure your users don't mind multiple looping videos running at once (eg: may slow your page / their browser, or drain their data allowance if on mobile, etc).
To handle multiple videos, I would just put each video player in it's own HTML page (like above shown code) and then in main page just load multiple iframes pointing to each player's HTML.
I have a YouTube player that sits in a slide of a Bootstrap carousel that sits in a template (the below doesn't include the html for the carousel):
<script type="text/html> <div class="video-container" id="introVideoTmpl">
<iframe width="640" height="480" src="//www.youtube.com/embed/Kn-7OlEVdNM?rel=0&enablejsapi=1" id="videoOne" frameborder="0" allowfullscreen></iframe>
</script>
I render this by making a JavaScript call:
renderPageOne = function(){
var introVideoTmpl= $("#introVideoTmpl").html();
$("#container").empty();
$("#container").append(_.template(introVideoTmpl, ""));
getPlayerOne();
getPlayerOne() generates an instance of the player:
function getPlayerOne() {
playerOne = new YT.Player('videoOne', {});
}
This playerOne has a pauseVideo() method which I call when needed.
It works fine most of the times but sometimes, with low bandwith the API seems not to load properly and the pauseVideo() does not work.
How can I check that the API is loaded properly so that the video can be paused when necessary?
Manage to solve the problem.
Problem I think was that the youtube api didn't load properly on low bandwith so avoided it all together and used the function callPlayer instead.
YouTube iframe API: how do I control a iframe player that's already in the HTML?
I have a webpage, and I made a video for it. With HTML5 formats (webm,ogg,mp4) works only the Chrome correctly. When the video is finishing, I can hide the video with JavaScript. I thought I can make with youtube player, (autoplay, hide controls etc) but i can't hide it, when it is finished. I found the "onStateChange function but I can't use it. Any ideas?
<iframe width="840" height="630" src="URLrel=0&showinfo=0;&autoplay=1;controls=0" frameborder="0" allowfullscreen></iframe>
You need to use the YouTube Iframe Player API to check (1) that the video has ended (YT.PlayerState.ENDED) when onPlayerStateChange is invoked, and (2) remove/hide the DOM element that contains the video, i.e. the iframe.
function onPlayerStateChange(event) {
// check if video ended and remove player
if (event.data == YT.PlayerState.ENDED) {
console.log($('#player').remove());
done = true;
}
}
You have a fully working solution in here: http://jsfiddle.net/jibietr/ua57A/1/
A quick and dirty solution would be to use innerHTML to overwrite the iframe when the user closes the video with an onclick event. If the iframe is wrapped inside a with id = "iframeDiv", you can call the following function onclick of the close video button:
function hideIframe() {
document.getElementById("iframeDiv").innerHTML = '';
}
The iframe would reappear when the user opens the video:
function showIframe() {
document.getElementById("iframeDiv").innerHTML = '<iframe width="840" height="630" src="URLrel=0&showinfo=0;&autoplay=1;controls=0" frameborder="0" allowfullscreen></iframe>';
}
I have a HTML5 YouTube Player on my Website:
<iframe id="video1"
width="600"
height="283"
src="youtubeurl"
frameborder="0"
allowfullscreen></iframe>
That renders OK. Now I want to change the video being played based on a JavaScript function call:
function doSomething() { ... }
Here is what I've tried.
$("#video1").attr('src', 'otherURL' + '?' + "wmode=transparen");
$('#video1').hide();
setTimeout(function () {
$('#video1').show(); }, 100);
But nothing happens! How can I do that?
Have you tried embedding a YouTube player into your page? If you do this it will make your life easier trying to operate on the player functionality.
Some of the embedded player functions include:
loadVideoByUrl()
playVideo()
nextVideo()
You can find everything you need here in the YouTube JavaScript API
You can embed your player into an iframe using the examples detailed here.
To control YouTube player you'd better use YouTube API. It is pretty easy. check out this exaple http://jsfiddle.net/uLygZ/1/ I tried to make free of jQuery calls, but note that my scripts are executed inside document-ready handler.
For more information see https://developers.google.com/youtube/