I dynamically set image and audio sources when window/document is already loaded, e.g. I set them after user performs some manipulations on the page:
// image and audio set
jQuery("#image").css('background-image', 'url(../content/icons/1/18.png)').css('backgroundPosition', '0 -40px');
var myAudio = new Audio('http://domain/content/audio/1/full-18.mp3');
myAudio.pause();
// i want this part of code be executed only when images and audio is fully loaded
myAudio.play();
Solution number 1, isn't working
jQuery("#page").load(function() {});
Solution number 2, isn't working
jQuery(window).load(function() {});
Any other idea how to this can be solved? Thank you in advance
You need to specifically target the image element to check if it has loaded.
$('#image').load(function () {
console.log('image loaded');
});
To check if the audio element is ready to be played you need to use onloadeddata.
var myAudio = new Audio('http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood.mp3');
myAudio.onloadeddata = audioIsLoaded();
function audioIsLoaded() {
console.log('audio is loaded');
}
Run the below code snippet to see this in action.
$('#image').load(function() {
alert('image loaded');
});
var myAudio = new Audio('http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood.mp3');
myAudio.onloadeddata = audioReady();
function audioReady() {
alert('audio ready');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="image" src="http://armpit-wrestling.com/wp-content/uploads/2016/06/bret-hart.jpg">
Related
I have the following code which looks at a specific css class .vma_iFramePopup and from it, takes the link stored in the src. And then loads that in a modal popup.
$(document).ready(function () {
$(".vma_overlay").click(function (event) {
var $videoSrcOriginal = $(event.target).siblings('.vma_iFramePopup').attr("src");
// Check if the embedded youtube url has any attributes appended
// by looking for a '?' in the url.
// If one is found, append our autoplay attribute using '&',
// else append it with '?'.
if ($videoSrcOriginal.indexOf('?') > -1) {
var $videoSrc = $videoSrcOriginal
// when the modal is opened autoplay it
$('#vma_ModalBox').on('shown.bs.modal', function (e) {
// set the video src to autoplay
var $videoSrcAuto = $videoSrc + "&autoplay=1&mute=1";
$("#vma_video").attr('src', $videoSrcAuto);
$('body').addClass("modalyt");
})
} else {
var $videoSrc = $(".vma_iFramePopup").attr("src");
// when the modal is opened autoplay it
$('#vma_ModalBox').on('shown.bs.modal', function (e) {
// set the video src to autoplay
var $videoSrcAuto = $videoSrc + "?autoplay=1&mute=1";
$("#vma_video").attr('src', $videoSrcAuto);
$('body').addClass("modalyt");
})
}
// stop playing the youtube video when modal is closed
$('#vma_ModalBox').on('hide.bs.modal', function (e) {
$("#vma_video").attr('src', $videoSrc);
$('body').removeClass("modalyt");
})
});
});
I was informed that the videos are not playing in the modal. The modal when loaded is empty.
When I check the browser console, I am not seeing any relevant errors.
When I check the iframe inside my modal popup I see that it says
src(unknown)
in the src element:
<iframe class="embed-responsive-item" width="80%" height="80%" src(unknown) id="vma_video" allowfullscreen="" data-gtm-yt-inspected-9256558_25="true">></iframe>
I have not been able to identify why this is happening?
I 've tried fiddling on the live website with a very slight variation of your code and it seems to work:
$('.vma_overlay').on('click', function() {
var $videoSrcOriginal = $(this).siblings('.vma_iFramePopup').attr("src");
if ($videoSrcOriginal.indexOf('?') > -1) {
$('#vma_ModalBox').show();
var $videoSrcAuto = $videoSrcOriginal + "&autoplay=1&mute=1";
$('#vma_ModalBox #vma_video').attr('src', $videoSrcAuto);
$('body').addClass("modalyt");
}
});
It turns out the solution in this particular case was to replace:
$(document).ready(function () {
with:
window.onload = function () {
For some reason specific to our setup, the jquery way of getting document ready was not firing.
I have assumed (possibly incorrectly?), due to the asynchronous nature of HTML, that the timeline of page loading is as follows:
... etc loading html into DOM
encounter <audio> tag
preload is specified as "auto"; trigger buffering
continue loading html into DOM... etc
fire window.onload event callbacks
asynchronously some time later: audio resource is found, begin buffering, or server error is returned; fire readystatechange event callbacks
Whereas what I'm hoping for is that the preload attribute with a value of "auto" will delay the window.onload event from firing or delay tag-to-DOM processing until the audio resource is found and has had begun buffering, or a server error is returned and loading is canceled.
I can't imagine withholding window.onload for an audio resource, but then I have seen page processing come to a halt for flash resource loading or tracking script loading in the past.
TLDR: What is the exact timeline of window.onload with regard to resource loading--specifically the audio tag?
window.onload event appears to be called before the media src is fully loaded. Using approaches described at How do you check if a HTML5 audio element is loaded? ; and including .webkitAudioDecodedByteCount
<!DOCTYPE html>
<html>
<head>
<script>
window.addEventListener("load", function() {
var media = document.querySelector("audio");
console.log("window onload event"
, media.webkitAudioDecodedByteCount
, media.readyState)
})
function myOnCanPlayFunction() {
console.log("Can play", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
function myOnCanPlayThroughFunction() {
console.log("Can play through", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
function myOnLoadedData() {
console.log("Loaded data", event.target.webkitAudioDecodedByteCount
, event.target.seekable.start(0)
, event.target.seekable.end(0));
}
</script>
</head>
<body>
<audio oncanplay="myOnCanPlayFunction()"
oncanplaythrough="myOnCanPlayThroughFunction()"
onloadeddata="myOnLoadedData()"
src="/path/to/audio/file"
preload autoplay buffered controls></audio>
</body>
</html>
plnkr version 1 http://plnkr.co/edit/zIIDDLZeVU7NHdfAtFka?p=preview
An alternative approach using XMLHttpRequest , onended event of AudioContext; Promise; recursion to request, play array of files in sequence. See AudioContext.decodeAudioData()
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script>
var sources = ["/path/to/audio/src/1"
, "/path/to/audio/src/2"];
var src = sources.slice(0); // copy original array
function getAudio(url) {
return new Promise(function(resolve, reject) {
var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var source = audioCtx.createBufferSource();
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(audioData).then(function(decodedData) {
source.buffer = decodedData;
source.connect(audioCtx.destination);
console.log(source, decodedData);
// do stuff when current audio has ended
source.onended = function() {
console.log("onended:", url);
if (src.length)
resolve(src)
else resolve("complete")
}
source.start(0);
});
}
request.send();
})
}
var audio = (function tracks(s) {
return getAudio(s.shift())
.then(function(data) {
if (Array.isArray(data) && data.length) return tracks(data)
else return data
})
}(src));
// do stuff when all `src` have been requested, played, ended
audio.then(function(msg) {
console.log(msg)
})
</script>
</head>
<body>
</body>
</html>
plnkr version 2 http://plnkr.co/edit/zIIDDLZeVU7NHdfAtFka?p=preview
I am trying to repair a firefox addon that I created some time ago which has stopped functioning properly after a recent-ish Firefox update. The part which no longer functions was a mp3 player, which ran in the background.
The page-worker has a very small html page with an embedded media player and a script that controls the player. The script is passed in a filepath for an mp3 on my machine to use as the players src, and then told to start playing. This used to work, but now upon calling the embedded player's play function an error is thrown. The src is correctly set and the play event triggers, but the canplay event does not. The error code given is 4, which I believe is MEDIA_ERR_SRC_NOT_SUPPORTED.
If I open the HTML page and feed the player the filepath manually, it all works fine. What's going wrong here that wasn't before?
The HTML page is
<!DOCTYPE hmtl>
<html>
<head>
<title>Sound Stone: mp3 pageworker</title>
</head>
<body>
<video></video>
</body>
<html>
The content script is
var player = document.getElementsByTagName("video")[0];
var starttime;
var stoptime;
var checkTime;
self.port.on("start", function(url){
player.src=url;
player.pause();
stoptime = undefined;
self.port.emit("change", false);
});
self.port.on("stop", function(){
player.pause();
player.removeEventListener("canplay", goTo);
});
self.port.on("play", function(beg, end){
clearInterval(checkTime);
if(beg){
starttime = beg/1000;
}
if(end){
stoptime = end/1000;
}
player.play(); // this is where it goes wrong
if(beg){
player.addEventListener("canplay", goTo);
}
if(stoptime){
checkTime = setInterval(function (){
if(player.currentTime>=stoptime){
player.currentTime=99999;
clearInterval(checkTime);
}
}, 1000);
}
});
self.port.on("pause", function(){
player.pause();
});
player.onplay = function(){
self.port.emit("change", true);
}
player.onpause = function(){
self.port.emit("change", false);
}
player.onended = function(){
self.port.emit("done");
}
player.onerror = function(){
self.port.emit("out", player.error.code); // this outputs 4
self.port.emit("out", player.src); // this outputs as expected
}
function goTo(){
player.currentTime=starttime;
player.removeEventListener("canplay", goTo);
}
And a small excerpt of the main program is
var mp3 = worker.Page({
contentScriptFile: "./mp3.js",
contentURL: "./mp3.html",
});
mp3.port.on("out", function(msg){
console.log(msg);
});
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
I found a little code snippet within another question, playing an mp3 just with jquery play() and pause():
<a href="#" rel="http://www.uscis.gov/files/nativedocuments/Track%2093.mp3"
class="play">Play</a>
<div class="pause">Stop</div>
<script>
$(document).ready(function() {
var audioElement = document.createElement('audio');
var source = $('.play').attr('rel');
audioElement.setAttribute('src', source);
//audioElement.setAttribute('autoplay', 'autoplay');
audioElement.load()
$.get();
audioElement.addEventListener("load", function() {
audioElement.play();
}, true);
$('.play').click(function() {
audioElement.play();
});
$('.pause').click(function() {
audioElement.pause();
});
});
I get the audio source from the rel attribute of the "play"-link. Now I would like to add more audio links and make the source relative to their rel attributes.
I tried
var source = $(this).attr('rel');
and also .find() and .each(), but nothing worked so far. I've set up a jsfiddle with two audio links, where only the first audio file will be played. (The fiddle links to an external script, which the client uses on his site, where only jquery 1.4.3 is loaded, but I guess it's possible anyway. I just don't want to use an audio player plugin, I aim for a minimalistic solution.)
Any help would be highly appreciated!
You can update your script to create one audio tag per container:
$(document).ready(function () {
// For each container div
$(".container").each(function() {
// Create the HTML5 <audio> tag
var audioElement = document.createElement('audio');
// Find the play/pause buttons
var $play = $(this).find(".play");
var $pause = $(this).find(".pause");
// Load the source from the play button
var source = $play.attr('rel');
audioElement.setAttribute('src', source);
$.get();
// Play the sound when loaded
audioElement.addEventListener("load", function () {
audioElement.play();
}, true);
// When the user clicks on the play button, play the audio
$play.click(function () {
audioElement.play();
});
// When the user clicks on the pause button, pause it
$pause.click(function () {
audioElement.pause();
});
});
});
And updated Fiddle: http://jsfiddle.net/sY7UT/