On VideoJS website you state that support was moved to StackOverflow, so let's try it here. I've got the following code:
var player = _V_('the_id', {}, function(){
jQuery('.remove').on('click.destroyvideojs', function(){
player.destroy();
jQuery(this).unbind('click.destroyvideojs');
});
});
It initializes video at first and it destroys it.
But when I want to initialize it again using the same exact piece of code, it doesn't work. It doesn't initialize the script on the same element ID (when it was removed from DOM and added again with correct initialization call after it's been added). I'm wondering why this might be happening?
Another try today:
var the_id = 'my_id';
var player = _V_(the_id, {}, function(){
player.destroy();
_V_(the_id, {}, function(){
alert('reinit');
});
});
So, re-initialization of VideoJS simply doesn't work. Furthermore, it removed controls from the video now.
In case this helps anyone, it looks like it's dispose in Version 4:
var player = videojs('my-video');
player.dispose();
Having looked at the source for Video.js 5.0.0. #l:17236 You can just do the following:
if(videojs.getPlayers()[id]) {
delete videojs.getPlayers()[id];
}
It seems that player hasn't been defined when the callback executes.
Take a look at this js fiddle http://jsfiddle.net/gaboesquivel/BA8Pm/
destroy(); works for me. this how the function looks like
destroy: function () {
this.stopTrackingProgress();
this.stopTrackingCurrentTime();
_V_.players[this.id] = null;
delete _V_.players[this.id];
this.tech.destroy();
this.el.parentNode.removeChild(this.el)
}
check this solution too
http://help.videojs.com/discussions/problems/861-how-to-destroy-a-video-js-object#comment_13544514
I pulled some of My hare from My head, very hard to find response fore such questions...
So here is My solution, with JQuery... the solution was born from the question how to destroy uninitialised player objects, you guys save my day in the end, cos We can destroy only players that are shown, and even if I clean the HTML and reinitialise dynamically playerJs the flash fall back will not work for unshowed undestroyed media-player.
so here is the solution:
$.each(_V_.players, function (key, player) {
if (player.isReady) { player.destroy(); }
else { delete _V_.players[player.id]; }
});
a little messy but will do just fine.
cheers!
The api reference your looking for is .dispose(); however it does not remove settings from the dom. If you have third party plugins other items may litter your DOM after the dispose is run. To run dispose and clean up your dom use a code like this
dispose = function() {
if (settings.debug) {
console.info('place.videojs_element.dispose()');
} /*Target the Player Element*/
var player = videojs(settings.element.id + '_player'); /*Pause Video*/
player.pause(); /*Wait for third party scripts to stop listening!!! <-- Important*/
setTimeout(function() { /*Dispose of the player*/
player.dispose();
/*I have a new video element waiting to be placed ( this code is proprietary )*/
var epi = new EPI();
epi.place.videojs_element(settings, data); /*Wait time 600ms*/
}, 600); /*Destroy the old video element <--- Important */
$('#' + settings.element.id).empty();
}
See a working example in action: http://codepen.io/JaminQuimby/pen/yNaOwz/
The above will give you a clean DOM and completely remove the video player.
Related
I'm building an online 'TV' which will use YouTube live-streams for multiple channels.
The channels are contained within tabs. The videos need to be stopped when changing tabs otherwise you can hear the audio in the background.
Here's a link to the JSFiddle: https://jsfiddle.net/matlow/08k4csuh/
I've managed to turn the 'Channel 1' off when changing to another channel with:
var iframe = document.getElementsByClassName("tvscreen")[0].contentWindow;
and
iframe.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
In the tab javascript for loop which also handles the tabcontent[i].style.display = "none";
I think I need to use the for loop to call each instance of the iframe... but I'm quite new to javascript so I'm not quite sure how to achieve this.
It will also help to use iframe.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); so the video plays automatically again when clicking on the relevant tab... but again I'm not quite sure how to implement this.
I've been working on this for a few days so if anyone had any tips or pointers I would really appreciate it!
Thanks for reading! :)
You are not using YouTube's API properly. See https://developers.google.com/youtube/iframe_api_reference
In your fiddle, programmatic play is not possible, because you can't know when the YouTube player is ready, as you are not the one initialising it. Your attempts to play the video might take place too early.
Programmatic pause (you managed to pause the first video) is possible thanks to enablejsapi=1 in the iframe src and the fact that the player is ready at that point.
Here's a fork of your fiddle - https://jsfiddle.net/raven0us/ancr2fgz
I added a couple of comments. Check those out.
// load YouTube iframe API as soon as possible, taken from their docs
var tag = document.createElement('script');
tag.id = 'iframe-demo';
tag.src = 'https://www.youtube.com/iframe_api';
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// initialised players are kept here so we don't have to destroy and reinit
var ytPlayers = {};
function mountChannel(channel) {
var player;
var iframeContainer = document.querySelectorAll('#' + channel + ' iframe');
// if the channel & iframe we want to "mount" exist, check for playing iframes before doing anything else
if (iframeContainer.length > 0) {
// Object.keys() is ECMA 5+, sorry about this, but no easy to check if an object is empty
// alternatively, you could have an array, but in that case, you won't be able to fetch a specific player as fast
// if you don't need that functionality, array is as good cause you will just loop through active players and destroy them
var activePlayersKeys = Object.keys(ytPlayers);
if (activePlayersKeys.length > 0) { // if players exist in the pool, destroy them
for (var i = 0; i < activePlayersKeys.length; i++) {
var activeChannel = activePlayersKeys[i];
var activePlayer = ytPlayers[activeChannel];
activePlayer.getIframe().classList.remove('playing'); // mark pause accordingly, by removing class, not necessary
activePlayer.pauseVideo();
}
}
// check if player already initialised and if player exists, check if it has resumeVideo as a function
if (ytPlayers.hasOwnProperty(channel)) {
ytPlayers[channel].playVideo();
} else {
var iframe = iframeContainer[0];
player = new YT.Player(iframe, {
events: {
'onReady': function (event) {
// event.target is the YT player
// get the actual DOM node iframe nad mark it as playing via a class, styling purposes, not necessary
event.target.getIframe().classList.add('playing');
// play the video
event.target.playVideo();
// video may not autoplay all the time in Chrome, despite its state being cued and this event getting triggered, this happens due to a lot of factors
},
// you should also implement `onStateChange` in order to track video state (as a result of user actions directly via YouTube controls) - https://developers.google.com/youtube/iframe_api_reference#Events
}
});
// append to the list
ytPlayers[channel] = player;
}
}
}
// Get the element with id="defaultOpen" and click on it
function onYouTubeIframeAPIReady() {
// YouTube API will call this when it's ready, only then attempt to "mount" the initial channel
document.getElementById("defaultOpen").click();
}
This is the first time I worked with YouTube's iframe API, but it seems reasonable.
I have a problem with embedded video. I use "Embed.ly API" and "player.js":
https://docs.embed.ly/docs/oembed
https://docs.embed.ly/docs/playerjs
I'm trying to embed a video from "youku.com" on my site. The "youku.com" is a content provider, as stated here: https://embed.ly/providers
Video is added but player's methods (play, pause and others) does not work for video. But if I changing video service from "youku.com" to "youtube.com" and use video from "youtube.com", then methods works well.
I also tried to connect the "platform.js" instead of the player. The result is the same.
Maybe the "player.js" worked before, I guess that the "youku.com" has changed its API, but the "player.js" did not track changes.
Does the player.js really work with "youku.com" now? Perhaps something should be added to my code for solve the problem? I am not in China, can it have any effect due to the fact that "youku.com" is a Chinese service?
Thanks.
My code js: (And another question: are there any errors in the code?)
var obj_json = $.getJSON('https://api.embedly.com/1/oembed?' + $.param({
url: :url, // for example: https://v.youku.com/v_show/id_XMzg2MjgwNzA0OA==.html
key: :key // my_API_key
})).done(function () {
$('.embeded').html(obj_json.responseJSON.html).find('iframe.embedly-embed').each(function () {
// initialize the player.
var player = new playerjs.Player(this);
player.on('ready', function () {
player.setLoop(true); // it is not work
player.play(); // it is not work
//..................................
// There are also special buttons on the page, clicking on which the video should start or stop:
$('.button_play').click(function () {
player.play(); // pressing occurs, but player it is not work
});
$('.button_pause').click(function () {
player.pause(); // pressing occurs, but player it is not work
});
//.........................................
});
});
});
As an exercise I have to do a little online bike reservation app. This app begins with a header which explains how to use the service. I wanted this tutorial be optional so I wrote a welcome message in HTML and if the user doesn't have a var in his cookies saying he doesn't want to see the tutorial again, the welcome message is replaced by a slider that displays the information.
To achieve that is fetch a JSON file with all the elements I need to build the slider (three divs : the left one with an arrow image inside, the central one where the explanations occur and the right one with another arrow). Furthermore I want to put "click" events on the arrows to display next or previous slide. However, when I do so, only the right arrow event works. I thought of a closure problem since it is the last element to be added to the DOM that keeps its event but tried many things without success. I also tried to add another event to the div that works ("keypress") but only the click seems to work. Can you look at my code give me an hint on what is going on?
Here is the init function of my controller:
init: function() {
var load = this.getCookie();
if(load[0] === ""){
viewHeader.clearCode();
var diapoData = ServiceModule.loadDiapoData("http://localhost/javascript-web-srv/data/diaporama.json");
diapoData.then(
(data) => {
// JSON conversion
modelDiapo.init(data);
// translation into html
controller.initElementHeader(modelDiapo.diapoElt[0]);
controller.hideTuto();
}, (error) => {
console.log('Promise rejected.');
console.log(error);
});
} else {
viewHeader.hideButton();
controller.relaunchTuto();
}
}
There is a closer look at my function translating the JSON elements into HTML and adding events if needed :
initElementHeader: function(data){
data.forEach(element => {
// Creation of the new html element
let newElement = new modelHeader(element);
// render the DOM
viewHeader.init(newElement);
});
}
NewElement is a class creating all I need to insert the HTML, viewHeader.init() updates the DOM with those elements and add events to them if needed.
init: function(objetElt){
// call the render
this.render(objetElt.parentElt, objetElt.element);
// add events
this.addEvent(objetElt);
},
Finally the addEvent function:
addEvent: function(objet){
if(objet.id === "image_fleche_gauche"){
let domEventElt = document.getElementById(objet.id);
domEventElt.addEventListener("click", function(){
// do things
});
}
else if(objet.id === "image_fleche_droite"){
let domEventElt = document.getElementById(objet.id);
domEventElt.addEventListener("click", function(){
// do stuff
});
};
},
I hope being clear enough about my problem. Thank You.
Ok, I found the problem, even if the element was actually created, it somehow stayed in the virtual DOM for some time, when the "getElementById" in "addEvent" was looking for it in the real DOM it didn't find the target and couldn't add the event. This problem didn't occur for the last element since there was nothing else buffering in the virtual DOM.
On conclusion I took out the function adding events out of the forEach loop and created another one after the DOM is updated to add my events.
I'm trying to make a custom "nickname-highlighter" just for me, on a distant and javascript based webchat. Clearly, I want that each time my nickname appears in the chat, a sound is played.
In this chat there is a #TheChatDiv in which a new .NewChatText is added each time a user write something new.
So far I've tried this :
$('#TheChatDiv').bind("DOMSubtreeModified",function(){
// Do things, like play the song of your people.
});
Which actually works well, except that i'm unable to extract the text of the chat posted. The thing is that I also need to read the text posted, to detect my nickname in it and make my code behave like it needs to.
Any idea how I could do that ?
You should generally create an event or fire a function whenever a message is inserted into the chat element and then search the added message for whatever you're looking for, however if that's not an option you'd generally be better of using mutation observers instead of the deprecated DOMSubtreeModified event, something like this
var observer = new MutationObserver(function(mutations) {
$.each(mutations, function(_, mutation) {
$.each(mutation.addedNodes, function(_, node) {
if ( $(node).text().indexOf('Cyc') != -1) {
// Play sound for Cyc
}
});
});
});
observer.observe(
$('#TheChatDiv').get(0),
{ attributes: true, childList: true, characterData: true }
);
FIDDLE
As for me the better way is to inject highlighting logic directly in your receiveMessage function where NewChatText is being created and appended to the TheChatDiv.
I assume you have something like:
function receiveMessage(message) {
var chat = $('#TheChatDiv');
$('<div>')
.text(message)
.addClass('NewChatText')
.appendTo(chat);
if (message.indexOf('YourNickName') {
// Play sound, highlight etc.
}
}
Try this:
var nickname = $('.NewChatText .nickname').text();
if (nickname == 'YOURNAME') {
// Insert your code here, the autor of .NewChatText is 'YOURNAME'
}
If this isn't the response you are searching for, you should describe your problem more in detail.
I'm stuck with a little problem with MediaElement.js player.
To get the instance of the player, I do this (works with html5 compatible browser):
// Get player
this.playerId = $('div#shotlist-player video').attr('id');
this.player = window[this.playerId];
But it's not working as soon as it fallback in flash. In fact, it's not working because I'm not calling an instance of MediaElement itself. But I don't see how I can call it.
The player is created with
$('video').mediaelementplayer({....});
How can I get the mediaelement object?
------------EDIT----------------
Ok I finally found how to make it works:
// Get player
mePlayer = $('div#shotlist-player video.video-js')[0];
this.player = new MediaElementPlayer(mePlayer);
Now I can user mediaElement instance correctly.
This post is a lot of speculation, but may be correct. Docs are lacking (;
The answer by sidonaldson is perfectly acceptable if you wish to create a new MediaElement instance and get a handle on it. If there's one already present, it seems to try to reinitialize another instance on that element and freaks out.
I am pretty sure mediaelement.js augments the builtin HTML5 controls by providing a JavaScript API to manipulate Flash/Silverlight players via those elements. I may be wrong, but other advice I've seen on this issue in multiple places is to do something like:
$playButton.click(function() {
$('video, audio').each(function() {
$(this)[0].player.play();
});
});
To create a play button as an external DOM element which will fire off all players on the page. This indicates to me that the implementation is something like I've described.
Try:
var player = $('video').mediaelementplayer({
success: function (me) {
me.play();
}
});
// then you can use player.id to return the id
// or player.play();