Youtube video not loading with playlists - javascript

I'm having problems enqueuing a playlist using the YouTube IFrame API.
(https://developers.google.com/youtube/iframe_api_reference#Queueing_Functions)
I'm using flash to show the youtube videos. Using HTML5 shows another issue where the videoplayback call is called multiple times before the video loads.
On loading the playlist, the video itself doesn't load. It shows up in the network tab
as a call to videoplayback that is 'pending' until it times out after 7.5 minutes at which point it tries again and everything works. The playlist, incidentally, has loaded successfully - mousing over the youtube iframe shows a loaded playlist.
The code to replicate this is below, and the issue is found following these steps:
1. Click a channel
2. If channel loads, goto 1, else check network tab.
I know the method of replication is contrived, however I'm seeing this 'sometimes'
on first load.
The playing channel isn't at fault - this has been seen with many different channels.
Is it my code? Is there a work around? Is there a fix?
Tested on Windows 7 32bit using Chrome 28, Firefox 22.0 and IE 10
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<title>
Youtube Test
</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type='text/javascript'>
var collection = [];
var player = null;
var playlistEnqueued = false;
function clear() {
// Removes the iframe.
if (player !== null) {
player.destroy();
}
collection = [];
playlistEnqueued = false;
player = null;
}
function createYT(videoId) {
// Clear anything that's up currently
clear();
// Yes, this could be $.ajax, however this way reduces the dependency on jQuery
// further for the purposes of this test.
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
parseJSONResponse(JSON.parse(xmlhttp.responseText));
}
}
xmlhttp.open("GET", "https://gdata.youtube.com/feeds/users/" + videoId + "/uploads?alt=json", true);
xmlhttp.send();
}
function parseJSONResponse(data) {
var feed = data.feed;
$.each(feed.entry, function(index, entry, list) {
collection.push(entry.id.$t.match('[^/]*$')[0]);
});
playVideo();
}
function playVideo(videoId) {
try {
if (videoId === undefined || videoId === null) {
videoId = collection[0];
}
if (typeof(YT) == 'undefined' || typeof(YT.Player) == 'undefined') {
window.onYouTubeIframeAPIReady = function() {
playVideo(videoId);
};
$.getScript('//www.youtube.com/iframe_api');
} else {
if (playlistEnqueued === true) {
player.playVideoAt(0);
} else {
player = new YT.Player('video', {
events: {
'onReady':function(event) {
try {
player.cuePlaylist(collection);
} catch (e) {
console.error(e);
}
},
'onError':function(error) {
console.error(error);
}
},
videoId: videoId,
width: 425,
height: 356,
playerVars: {
autoplay: 1,
}
});
// Attaching event listener after object creation due to
// http://stackoverflow.com/questions/17078094/youtube-iframe-player-api-onstatechange-not-firing
player.addEventListener('onStateChange', function(state) {
try {
stateChanged(state);
} catch (e) {
console.error(e);
}
});
}
}
} catch (e) {
console.error(e);
}
}
function stateChanged(state) {
// This state will be called on enqueueing a playlist
if (state.data == 5) {
playlistEnqueued = true;
playVideo();
}
}
$(document).on('ready', function() {
var player = $(document).find("#player");
$("a").on('click', function() {
var channel = $(this).attr('data-channel');
createYT(channel);
return false;
});
});
</script>
</head>
<body>
<div class='test'>
<div id='video'>
</div>
<a href='#' data-channel='mit'>MIT</a>
<a href='#' data-channel='tedtalksdirector'>TED</a>
<a href='#' data-channel='minutephysics'>Minute Physics</a>
</div>
</body>
</html>
When using flash, and on waiting for the video connection to timeout and try again the following is seen in the network tab. As you can see it's 'pending', failed, and then tried again after 7.5 minutes.
Chrome network tab once the video starts playing:
Chrome network tab on video playback
More images when I get past 10 reputation...

I've got this up and running on jsFiddle (http://jsfiddle.net/3Bm2V/5/) and it seems to be working ok. I did have to change the
$(document).on('ready', function () {
to
$(function() {
to get it to work in jsFiddle, so try the link above and see if it works for you now?

Related

canplay event does not occur on Google Chrome mobile until Audio.play() is called

I made a simple audio player. Pardon the track, but I needed online MP3 track that is not protected by CORS:
try {
var a = new Audio("https://storytime.voxsnap.com/1/audio/2017/03/26/GoTime-New_Years_Tips.mp3");
a.addEventListener("timeupdate", function(e) {
document.getElementById("progress").max = this.duration;
document.getElementById("progress").value = this.currentTime;
})
a.addEventListener("canplay", function() {
console.log("Can play.");
const button = document.getElementById("playstop");
button.removeAttribute("disabled");
button.innerHTML = "";
button.appendChild(new Text("Play"));
});
a.addEventListener("error", function() {
console.log("Audio error.");
document.body.appendChild(new Text("ERROR: "+a.error));
});
a.addEventListener("loadstart", function() {
console.log("Loading started.");
});
a.addEventListener("loadedmetadata", function() {
console.log("Metadata loaded. Duration: "+this.duration);
});
document.getElementById("playstop").addEventListener("click", function() {
this.innerHTML = "";
if(a.paused) {
this.appendChild(new Text("Pause"));
a.play();
}
else {
this.appendChild(new Text("Play"));
a.pause();
}
})
}
catch(e) {
document.body.appendChild(new Text("ERROR: "+e.message+"\n\n"+e.stack));
}
progress {
width: 100%;
}
<progress id="progress" value="0" max="100"></progress>
<button id="playstop" disabled="disabled">
loading...
</button>
Now this works nicely, doesn't it? But not on Android's google chrome. The issue is that the canplay event doesn't occur - Google chrome won't start downloading the full file until .play() is called. But I cannot call .play() until I know audio can be played, so I'm kinda stuck.
What is the correct approach here?

Getting an embedded YouTube video to play after it's been closed & re-opened on iOS7 Safari

Relatively new to JS here. I've created a button that embeds a YouTube video on the page when you click it, and the user has the ability to close it. On desktop and Android OS, it can be closed and re-opened as many times as the user wants. However, on iOS, the video only plays the first time.
I believe this issue is caused by the fact that Apple doesn't want the video to play without the user's permission, so when you click the "play" button it brings up the video - but the default YouTube play button itself is not there when the video is closed and re-opened.
This should be most of the relevant code.
VideoPlayer = new VideoPlayer('Header', 'xi2-7FCuDdg');
$("#HomePlayButton").on('click', function () {
disable_scroll();
VideoPlayer.play();
$("#Header").append($('<img src="/images/close.png" />'));
$("#VideoCloseButton").on('click', function () {
VideoPlayer.stop();
VideoPlayer.hide();
enable_scroll();
$("#VideoCloseButton").unbind('click');
$("#VideoCloseButton").remove();
return false;
});
});
this.play = function () {
if (!Initialized) {
// This autoplays the video
Init();
Initialized = true;
} else {
if ($("#" + YouTubeElementId).css('display') == "none") {
$("#" + YouTubeElementId).css('display', 'block');
}
YouTubePlayer.playVideo();
}
}
this.stop = function () {
YouTubePlayer.stopVideo();
}
this.isPlaying = function () {
return (Initialized) ? YouTubePlayer.getPlayerState() == 1 : false;
}
this.hide = function () {
$("#" + YouTubeElementId).css('display', 'none');
}
this.show = function () {
$("#" + YouTubeElementId).css('display', 'block');
}
I'm assuming the easiest way to solve this would be to entirely destroy the iframe and make a new one every time the video is closed, but I was unable to successfully implement that.
Glad to post more code if it's necessary.

Can I start playing another video after the original video finished? (Vimeo)

Hy,
I need to develeop a site, that will embed videos from Vimeo.
If I use VimeoAPI, can Ilisten when the video is finished? And if it finished, can I start another video from Vimeo?
Thanks, Dave.
Assuming that you have used the code provided in the Vimeo Api page you should be using the following to show an initial video:
<!doctype html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="custom.js" ></script>
</head>
<body>
<iframe id="vimeoplayer"
src="//player.vimeo.com/video/76979871?api=1&player_id=vimeoplayer"
width="100%" height="100%" webkitallowfullscreen mozallowfullscreen
allowfullscreen ></iframe>
<div>
<button>Play</button>
<button>Stop</button>
<p>Status: <span class="status">…</span></p>
</div>
</body>
</html>
Make sure that the iframe ID is the same with the "player_id".
Then in your custom.js file use the code from the Vimeo API page:
$(function() {
var player = $('#vimeoplayer');
var url = window.location.protocol + player.attr('src').split('?')[0];
var status = $('.status');
// Listen for messages from the player
if (window.addEventListener){
window.addEventListener('message', onMessageReceived, false);
}
else {
window.attachEvent('onmessage', onMessageReceived, false);
}
// Handle messages received from the player
function onMessageReceived(e) {
var data = JSON.parse(e.data);
switch (data.event) {
case 'ready':
onReady();
break;
case 'playProgress':
onPlayProgress(data.data);
break;
case 'pause':
onPause();
break;
case 'finish':
onFinish();
break;
}
}
// Call the API when a button is pressed
$('button').on('click', function() {
post($(this).text().toLowerCase());
});
// Helper function for sending a message to the player
function post(action, value) {
var data = {
method: action
};
if (value) {
data.value = value;
}
var message = JSON.stringify(data);
player[0].contentWindow.postMessage(data, url);
}
function onReady() {
status.text('ready');
post('addEventListener', 'pause');
post('addEventListener', 'finish');
post('addEventListener', 'playProgress');
}
function onPause() {
status.text('paused');
}
// when the video is finished
function onFinish() {
status.text('finished');
// load the next video
document.getElementById('vimeoplayer').src = "//player.vimeo.com/video/104990881?api=1&player_id=vimeovideo";
}
function onPlayProgress(data) {
status.text(data.seconds + 's played');
}
});
The code that changes the video, once the first one is finished, is inside the onFinish() function. The code inside this function changes the iframe source (src) to the one of the next video that you want to play.
You could use alternative methods of displaying another video and the above method is a very basic one just to display the requested functionality.
I wrote a jQuery Vimeo plugin a few months ago. Using this plugin, the code would be something like:
$("#somevideo").on("finish", function(){
$("#anothervideo").vimeo("play");
});
Yes, check out the player API for information on how to be notified when a video is complete, and how to start new videos https://developer.vimeo.com/player/js-api

HTML5 Audio does not play more than once

this does not work for me! anyone having the same issue? my code seems straightforward but it only plays once I need to be able to play over and over. see as follows:
My Html:
<audio id="siren" src="sounds/400.ogg" preload="auto">
and my JS:
function play_siren() {
log("play sound");
if(document.getElementById('siren').paused == true){
document.getElementById('siren').play();
}
}
function pause_siren() {
try{
if(document.getElementById('siren').paused == false){
document.getElementById('siren').pause();
}
log("paused siren");
}catch(err){
log(err.message);
}
try{
if(document.getElementById('siren').currentTime > 0.0){
document.getElementById('siren').currentTime = 0.0;
}
log("reset siren");
}catch(err){
log(err.message);
}
}
it is started programmatically in the JS code as follows:
if(Obj[3].siren == true && isPlayingSiren == false){
play_siren();
isPlayingSiren = true;
}else if(Obj[3].siren == false && isPlayingSiren == true){
pause_siren();
isPlayingSiren = false;
}
I found this gentleman's code and his DOES seem to work: http://html5.komplett.cc/code/chap_video/js_audioPlayer_en.html
But setting "currentTime = 0" is not doing anything for me.
I can't figure it out. I tested with Chrome, Firefox and Safari. Firefox does not work at all so far Chrome seems to be the best for HTML5 but still I can only play once.
I even tried mp3 and ogg same behavior.
Please shed some light. Thank you!
here is full HTML:
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" media="all" href="js_audioPlayer.css">
<title>HTMLMediaElement example - Audio Player</title>
<script src="../js/audioPlayer.js"></script>
</head>
<body>
<fieldset>
<audio src="sounds/400.ogg" preload="auto"></audio>
<legend>Audio Player (400)</legend>
</fieldset>
<script>
function loadXMLDoc(){
_pause();
updateProgress(0);
playPause();
}
var loadXmlTimer = setInterval(loadXMLDoc, 2000);
</script>
</body>
</html>
and here is full javascript:
// global callback functions
var playPause, updateProgress, _play, _pause;
/* initialize audio player */
window.onload = function() {
// keep track of playback status
var AudioStatus = {
isPlaying : false
};
// define references to audio, pulldown menu, play-button, slider and time display
var audio = document.querySelector("AUDIO");
/* load track by menu-index */
var loadTrack = function(idx) {
audio.src = '../sounds/400.ogg';
audio.load();
};
/* callback to play or pause */
_play = function() {
audio.play();
log("play");
AudioStatus.isPlaying = true;
};
_pause = function() {
audio.pause();
log("pause");
AudioStatus.isPlaying = false;
};
playPause = function() {
if (audio.paused) {
_play();
}
else {
_pause();
}
};
/* callback to set or update playback position */
updateProgress = function(value) {
audio.currentTime = value;
log("updateProgress");
};
};
the timer plays the sounds programmatically on the expiration. this works as long it is private. I did not understand why it has to be private.
Does it pass thru the if statement?
You could use ontimeupdate for placing the value of document.getElementById('siren').currentTime in a variable.
If set to more than 0, then you could update it in an if conditionnal.
All of the previous solutions are unacceptable because they download the same sound file for each time the sound is played! Do this instead, for the sake of simplicity and efficiency:
var sound = document.getElementById("mySound")
if(window.chrome){
sound = sound.cloneNode()
}
sound.play()
This is how I fixed the problem with chrome specifically.

Steam Browser with html5 audio tag

I'm currently making a small app, which main use will be from the steam browser. However im having some issues getting audio tags to play. Though the site http://html5test.com/ suggests that it does support the audio tags.
Has anyone else had success with such things in the steam browser?
I've tried with several file formats, .wav, .mp3, .ogg
Heres the code, it works fine in IE10, FF and Chrome.
JS
<script type="text/javascript">
var lastPlayer = null;
var loopAudio = false;
function play_sound(file)
{
if (is_playing()) { return }
lastPlayer = file;
lastPlayer.addEventListener('ended', function() {
if (loopAudio == true) {
lastPlayer.play();
}
}, false);
lastPlayer.play();
};
function stop_sound()
{
lastPlayer.pause();
lastPlayer.currentTime = 0;
};
function loop_sound()
{
if (loopAudio === false) { loopAudio = true }
else { loopAudio = false }
};
function is_playing()
{
if (lastPlayer === null) { return false; }
else { return !lastPlayer.ended && 0 < lastPlayer.currentTime; }
};
</script>
HTML
<audio id="Calm_waves" src="http://localhost/Calm_waves.mp3" preload="none"></audio>
<button class="span2 btn btn-large btn-primary" onclick="javascript:play_sound(Calm_waves);">Calm Waves</button>
Further tinkering i managed to get this working using the ogg format, though i tried this format before, i tried again using one of the recommended converters from the WebM projects site. http://www.mirovideoconverter.com/

Categories