[EDIT: Sorry to those who already answered -- in my sleep-deprived state, I forgot that this particular situation is a YouTube movie, not the JW FLV player. I can see that there is more extensive documentation on interacting with YouTube movies, so I will pursue that, but any more information is also welcome]
I am using embedded YouTube videos in a collection of divs that are being rotated by using the jQuery cycle plugin (http://malsup.com/jquery/cycle/).
I would like the cycle to stop when I click on one of the movies to start it playing, but I can't figure out how to attach a jQuery event handler to the player object.
Here's what my current code looks like (you can't directly select an object tag with jQuery, so I select the parent div and then get the object element as the first child):
$("div.feature-player").children(":first").click(function(event) {
$('#features').cycle('stop');
});
But that doesn't do the trick. I'm not a Flash author, so I'm not really familiar with ActionScript, and I've never set up an interaction between JavaScript and a Flash movie before.
The YouTube player API is pretty straight-forward. You just have to listen to the onStateChange event and control the cycle plugin depending on the state:
Here's a working demo: http://jsbin.com/izolo (Editable via http://jsbin.com/izolo/edit)
And the pertinent code:
function handlePlayerStateChange (state) {
switch (state) {
case 1:
case 3:
// Video has begun playing/buffering
videoContainer.cycle('pause');
break;
case 2:
case 0:
// Video has been paused/ended
videoContainer.cycle('resume');
break;
}
}
function onYouTubePlayerReady(id){
var player = $('#' + id)[0];
if (player.addEventListener) {
player.addEventListener('onStateChange', 'handlePlayerStateChange');
}
else {
player.attachEvent('onStateChange', 'handlePlayerStateChange');
}
}
Flash movies are pretty much black boxes as far as javascript is concerned. If the SWF you're using wasn't written to interact with javascript then you're probably out of luck.
You'll either need to figure out what javascript methods the movie you're using exposes (hopefully it has documentation), find another one that does provide javascript interaction, or write your own SWF to handle it.
What you're looking for is the flash ExternalInterface class, which is used for communication from flash to javascript and from javascript to flash.
If you're embedding the player using swfobject you're going to want to use swfobject.getObjectById to get a reference to the movie. Read the docs to see why you need to do this.
Also you'll need to set {wmode:"transparent"} for the player in order for it to bubble up click events to JavaScript.
Related
I am making a chrome extension that needs to know if a YouTube video is being played, paused, had a duration change, and if it is on an ad. I figured out how to do everything except knowing if it is on an advertisement. I found this post which was of some help, however, if I were to put this in my content script it would only run once and I want it to constantly check if there is an ad (since ads can happen in the middle of a video.
I am fairly new to Javascript, but I do understand the concepts of listeners and I would use a listener in this case, however, I do not know how to do that in this case because the div does not emit an event, it either exists or is null. Are there any other ways of doing that?
+1 to looking at YouTube video API events. Here's that page [0].
I haven't tried this myself, but I would start with the onStateChange event, because I suspect that an ad is a separate video from the desired video content itself. So there could be two "video cued" or "5" values fired. But, again, I haven't tried it myself. Good luck!
[0] https://developers.google.com/youtube/iframe_api_reference#Events
You can also use setInterval to detect ads continuously. This is a way without having to looking for API.
// According to the post you provided
function detectAds() {
return !!document.querySelector("div.ad-showing");
}
let timer;
function listen() {
timer = setInterval(function () {
if (detectAds()) { /* do something */ }
}, 1000); // runs every second
}
function unlisten() {
if (timer) clearInterval(timer);
}
I want to register an event handler to a video that is handled by the videojs but I can`t select the element in a reliable manner because the videojs removes the attributes from the video tag and add them to a container element that it adds.
videojs seems to append the same suffix: _html5_api to every video element ID, when it is wrapped inside the container div. Quoting from the source:
// Update tag id/class for use as HTML5 playback tech
// Might think we should do this after embedding in container so .vjs-tech class
// doesn't flash 100% width/height, but class only applies with .video-js parent
tag.id += '_html5_api';
So, one would argue that, a trivial fix would be something like this:
var vid = document.getElementById("ORIGINALVIDEOID_html5_api")
Of course, this hack lacks reliability since this suffix might change in future versions. However, one thing that is unlikely to be changed in the future, is the presence of the video element (albeit with a different ID) inside the wrapper div.
So, a more reliable way to obtain the video element per se is (assuming that the video tag ID is "cool"):
videojs("cool").ready(function(){
// Approach 1
var video1 = this.contentEl().querySelector("video");
console.log("video1");
console.log(video1);
// Approach 2
var video_id = this.contentEl().querySelector("video").getAttribute("id");
var video2 = document.getElementById(video_id);
console.log("video2");
console.log(video2);
// Not really needed, but here is a test that both approaches yield the same result
console.log("video1 === video2 ?")
console.log(video1===video2)
})
which yields in Firefox:
I included two approaches in the above script: one straightforward and one indirect (via the document and using the acquired ID). Of course you can use whichever of video1 and video2 you want.
A few things to note here:
This works only when inside a videojs().ready() function; this is a way to be 100% sure that the player is loaded
contentEl() returns the wrapper div and then, querySelector() is used on it to access the video element.
The other answers are trying to get a video element within the player but this is flawed as the player tech can be something other than a video element, e.g. the Flash tech. You should use the video.js API to listen to the events which will be surfaced from the tech.
var player = videojs("id");
player.on('play', function() {…});
I am trying to replay a .swf flash file using javascript.Currently I am aware of two methods of doing this:
1) hide the element and show it again
2) select the DOM element of the swfobject and call .Rewind() and .Play()
http://jsfiddle.net/me2loveit2/4qth8/
//method one
$('#objectID').hide();
setTimeout(function(){
$('#objectID').show();
},10)
//Method 2
document.getElementById('objectID').Rewind();
document.getElementById('objectID').Play();
The problem with hide and show is that it sometimes flashes on the screen and is visually unappealing.
And the problem with .Rewind() or .GotoFrame(0) and .Play() is that it only rewinds the main timeline.(notice only the second green block resets and animates)
I usually have no control or way to change anything within the flash, so I am trying to find a solution that does not involve editing the flash file.
Is there is a way to get the name of all the movie clips that are in the swf using Javascript?. Then I could rewind them individually using .TGotoFrame('movieclip',0)
Can I trigger the same events that hide and show do without actually hiding and showing the element? (How?)
Or is there a better way to replay?
You could also restart it without the 10ms delay by using swfobject to rewrite the swf tag:
$(document).on('click','#replay3',function(){
swfobject.embedSWF("http://philipp.werminghausen.us/testing/test.swf", 'replace', 275, 200, "9", null, {}, params, {}, function (res) {});
});
Example:
http://jsfiddle.net/5jqW4/
I found another way to do it as well by removing and reinserting one of the <param> tags.
This way I don't need to re-create the object:
http://jsfiddle.net/me2loveit2/5jqW4/10/
var param = $('#swf_movie').children().first().detach();
$('#swf_movie').append(param);
I've got a page with links to MP3s, when the link is clicked I use javascript to show a small Flash player (NiftyPlayer) under the link. When a different link is clicked, the old player is hidden and the new player is revealed.
The player auto-starts when the element is shown, and auto-stops when hidden - in Firefox.
In IE it will only auto-start and NOT auto-stop. This is what I would like to solve.
This is an example HTML with link and player
Misunderstood What You Said
<div id="player662431" class="playerhide"><embed src="http://www.example.com/shop/flash/player.swf?file=/mp3/Beat The Radar - Misunderstood What You Said.mp3&as=1" quality="high" bgcolor="#000000" width="161" height="13" name="niftyPlayer662431" align="" type="application/x-shockwave-flash" swLiveConnect="true" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>
Here is the javascript (I've got jQuery installed to let me hide all the open players on this page apart from the new one)
function toggle_visibility(id) {
$('.playerhide').hide();
var e = document.getElementById(id);
e.style.display = 'block';
}
I think what I need to do is start the player manually with javascript (rather than using the autostart as=1 function in the URL string)
There is some javascript that comes with NiftyPlayer to allow this EG
niftyplayer('niftyPlayer1').play()
there is also a stop method.
I need some help with javascript - how do I add this call to play into my toggle_visibility function (it has the same unique ID number added to the name of the player as the ID of the div that's being shown, but I don't know how to pull this ID number out of one thing and put it in another)
I also would like to be able to do
niftyplayer('niftyPlayer1').stop()
to stop the audio of the previously running player. Is it possible to store the current ID number somewhere and call it back when needed?
Thanks for the help, i'm a PHP programmer who needs some support with Javascript - I know what I want to achieve, just don't know the commands to do it!
Thanks
If you assigned each niftyplayer object a classname, f.x. ".players", then you could loop through each player, like this:
function toggle_visibility(id) {
$(".players").each(function(){
playerId = $(this).attr('id');
if(niftyplayer(playerId).getState() == 'playing') {
//Stop the currently playing player
niftyplayer(playerId).stop();
//Hide the div that was playing
$("#" + playerId).hide();
}
});
//Start the new player
niftyplayer(id).play();
$("#" + id).show();
}
So what this actually does, is it loops through all the players on the website. It checks if the status of each player is equal to "playing", if it is, then it stops it and hides the div tags. Then it starts the new player and shows that div tag.
I think this does it. Try it out.
I have a much better solution after I noticed a very nasty bug / 'feature' when using Internet Explorer in conjunction.
I had noticed that in IE the pages were taking a very long time to load when I had a lot of hidden Nifty Players, I looked closer using Fiddler and found that each instance of NiftyPlayer was preloading the MP3 in full, rather than loading on demand as with Firefox and Chrome etc.
This meant that a page with 100 items (each item having up to 4 MP3s) took several minutes to load at times with obvious data transfer implications.
My solution which is rather simpler (but maybe clunkier) than Indyber's is to just use
function toggle_visibility(id,mp3location) {
// hide all players
$(".playerarea").html('');
// show clicked player
$('#' + id).html('<embed src=\"http://www.xxx.com/shop/flash/player.swf?file=http://www.xxx.com/mp3/' + decodeURIComponent(mp3location) + '.mp3&as=1\" quality=high bgcolor=#000000 WMODE=transparent width=\"161\" height=\"13\" align=\"\" type=\"application/x-shockwave-flash\" swLiveConnect=\"true\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" class=\"playerNew\">');
}
which works fine with IE, and also solves the problem of not being able to stop the players from playing in IE
Is there a way to detect end of Flash movie (OOTB, without using some sort of flash callback).
Alternatively, is there a way to know the length of the movie?
Update:
IsPlaying() looked promising (periodically checking it), but as it turns out, nobody is creating straight forward swfs any more; now, the content is embedded in main layer and while the content plays, the main movie is stopped and IsPlaying is always false...
var movie = window.document.movie
if(movie.TCurrentFrame("/") == movie.TotalFrames())
alert("Movie Finished");
or you could have:
if (!movie.IsPlaying())
alert("Movie Stopped");
but thats not really what you're after.
import fl.video.VideoEvent.COMPLETE
video.addEventListener(VideoEvent.COMPLETE, alertHTML);
function alertHTML(e:VideoEvent):void{
ExternalInterface.call("alert(\"Video has stopped\");");
}
Give that a shot. You can replace the alert(\"Video has stopped\"); with your client-side javascript function.
You can chceck for movie length with ffmpeg -i movie.flv 2>&1, but i doesnt' tell you:
how long it takes to load the video and start playing
whether the user has hit the "pause" button.
Right now, the only way is to attach some javascript handlers to Flash events as other posts suggest.