Infinite loop with random playlist - javascript

I have numerous MP3 files in a folder.
When I enter a page, I want a song from that playlist to play. After this song is over, I want a new one to play (not the same one) and so on.
<script type="text/javascript">
var song = ["../audio/1.mp3" , "../audio/2.mp3", "../audio/3.mp3", "../audio/4.mp3", "../audio/5.mp3" ];
var soundFile = song[Math.floor(Math.random()*song.length)];
document.write("<embed id='sound' src='" + soundFile + "' loop='true' type='audio/mpeg' controller='false' height='0' width='0'>");
</script>
What's wrong, because it always plays the same song.

Use an already defined embedded element and set the src attribute.
<embed id='sound' loop='true' type='audio/mpeg' controller='false' height='0' width='0'>
<script type="text/javascript">
var songs = ["../audio/1.mp3" , "../audio/2.mp3", "../audio/3.mp3", "../audio/4.mp3", "../audio/5.mp3" ];
var remainingSongs = songs;
var el = document.getElementById("sound");
var pickSong = function(){
// No songs left?
if(!remainingSongs.length) {
remainingSongs = songs;
}
// Pick song
var index = Math.floor(Math.random() * (remainingSongs.length - 1));
var soundFile = remainingSongs[index];
// Remove song from array
remainingSongs.splice(index, 1);
el.setAttribute("src", soundFile);
}
pickSong();
el.addEventListener("ended", pickSong, false);
</script>

You have an off-by-one error. I think it should be:
var soundFile = song[(Math.floor((Math.random())*(song.length-1)))];
But otherwise this should work. Could be a combination of the erroneous code and weird browser caching?
Also, check the web server you are using to serve the files and clear its cache.
Plus make sure your audio files are actually different.
Also, random chance may be tricking you. Give it a few goes.
This works for me in Chrome Canary on OSX:
<!DOCTYPE html>
<html>
<head>
<script>
var song = ['./foo.m4a', 'bar.m4a', 'bam.m4a'];
var soundFile = song[(Math.floor((Math.random())*(song.length-1)))];
document.write('<embed id="sound" src="' + soundFile + '" loop="true" type="audio/mpeg" controller="false" height="0" width="0">');
</script>
</head>
<body></body>
</html>

The problem is the loop attribute for the embed element doesn't know about your array of audio sources. It's just going to loop over the same source file.
Luckily, there is a pretty easy solution. The following will create an Audio element, with the Audio constructor, and continue to set a "random" audio source from the song array when the previous is done playing. We can do this by listening for the ended event.
<script type="text/javascript">
var song = ["../audio/1.mp3" , "../audio/2.mp3", "../audio/3.mp3", "../audio/4.mp3", "../audio/5.mp3" ];
var audio = new Audio();
var setSound = function() {
var soundFile = escape(song[Math.floor(Math.random()*song.length)]);
audio.setAttribute('src', soundFile);
audio.play();
};
// set initial source
setSound();
// set a new source, when current sound is done playing
audio.addEventListener('ended', setSound, false);
</script>

Related

How play group of audio files in HTML and JavaScript?

<html>
<body>
<audio autoplay id ="audio_1" src = "./Dusty.wav"></audio>
<audio loop id = "audio_2" src = "./Dusty3.wav"></audio>
<audio loop id = "audio_3" src = "./Dusty2.wav"></audio>
<!-- <input type = "button" value = "play" onClick="audiofun();" -->
</body>
<script>
// audiofun()
// {
var audio = document.getElementById("audio_1");
var audio2 = document.getElementById("audio_2");
var audio3 = document.getElementById("audio_3");
// audio2.pause();
// audio3.pause();
audio.addEventListener("ended", function () {audio2.play();})
audio2.addEventListener("ended", function () {audio3.play();})
// }
</script>
</html>
When I run this code audio2.play() is continuously playing and audio3.play is not at all playing. can anyone put light on my error... thanks in advance
i feel like your problem comes from the property "loop" in your audio tag. Maybe you should try:
<audio id = "audio_2" src = "./Dusty3.wav"></audio>
<audio id = "audio_3" src = "./Dusty2.wav"></audio>
And add a event listener on your first, then second audio.
var audio = document.getElementById("audio_1");
var audio2 = document.getElementById("audio_2");
var audio3 = document.getElementById("audio_3");
document.getElementById('audio_1').addEventListener('ended',audio_1Handler,false);
function audio_1Handler(e) {
audio2.play();
}
document.getElementById('audio_2').addEventListener('ended',audio_2Handler,false);
function audio_2Handler(e) {
audio3.play();
}
the snippet above is highly inspired of : this post
Hopefully this helps you.
Feel free to ask any further questions !

Web: How to play audio files one after the other without a delay ?

I have urls of several audio files like this:
example.net/{num}.mp3
And I would like to play them one after the other without a delay between them.
I tried having two audio elements with preload=true and switching between them, but I still have a delay.
Any ideas ?
I'd like to see the actual code of what you have so far, because I'm not 100% sure what "switching between them" means, but I wrote the following example which starts the next file playing before the first one finishes. You specify a set amount of "overlap", and it starts playing the next file JSFiddle: http://jsfiddle.net/76xqhupw/4/
const OVERLAP_TIME = 1.0; //seconds
const song1 = document.getElementById('audio1');
const song2 = document.getElementById('audio2');
song1.addEventListener("timeupdate", function() {
if (song1.duration - song1.currentTime <= OVERLAP_TIME) {
song2.play();
}
});
song1.play();
This is just relevant to playing the next audio element instantly, since you said you already had two audio elements, but if I'm missing something let me know.
<html>
<head>
<title>Subway Maps</title>
<link rel="stylesheet" type="text/css" href="main.css" />
</head>
<body onload="onload();">
<video id="idle_video" width="1280" height="720" onended="onVideoEnded();"></video>
<script>
var video_list = ["Skydiving Video - Hotel Room Reservation while in FreeFall - Hotels.com.mp4",
"Experience Conrad Hotels & Resorts.mp4",
"Mount Airy Casino Resort- Summer TV Ad 2.mp4"
];
var video_index = 0;
var video_player = null;
function onload(){
console.log("body loaded");
video_player = document.getElementById("idle_video");
video_player.setAttribute("src", video_list[video_index]);
video_player.play();
}
function onVideoEnded(){
console.log("video ended");
if(video_index < video_list.length - 1){
video_index++;
}
else{
video_index = 0;
}
video_player.setAttribute("src", video_list[video_index]);
video_player.play();
}
</script>
</body>
for refrence how to display multiple videos one by one dynamically in loop using HTML5 and javascript
You can use ended event, Array.prototype.shift() to set src of element to next item within array, if array .length is greater than 0, call .load(), .play()
var url = "example.net/"
var type = ".mp3";
var n = [0,1,2,3,4,5];
var audio = document.querySelector("audio");
audio.onended = function() {
if (n.length) {
this.src = url + n.shift() + type;
this.load();
this.play();
}
}
audio.src = url + n[0] + type;
audio.load();
audio.play();

How to change html5 video source on click?

What I'm trying to do is create a sort of playlist, using just html5 and vanilla javascript (no jquery). The same short video keeps looping until you click one of the arrows, then the next (or previous) video in line gets loaded in the same video element.
Here's what I have:
HTML
<video autoplay="true" loop="true" id="video">
<source src="img-vid/video1.mp4" type="video/mp4" id="vid-src">
</video>
<img src="img-vid/Arrow_left.png" class="arrow arrow-left" id="left">
<img src="img-vid/Arrow_right.png" class="arrow arrow-right" id="right">
Javascript
var button_next = document.getElementById("right");
var button_previous = document.getElementById("left");
var playlist = document.getElementById("video");
var source = document.getElementById("vid-src");
button_next.onclick = play_next;
button_previous.onclick = play_prev;
function play_next() {
var filename = '';
if (source.src == "img-vid/video1.mp4"){
filename = "video2";
}
else if (source.src == "img-vid/video2.mp4"){
filename = "video3";
}
else if (source.src == "img-vid/video3.mp4"){
filename = "video4";
}
else {
filename = "video1";
}
source.src = "img-vid/" + filename + ".mp4";
playlist.load();
playlist.play();
}
//same for function play_prev(), but order of videos is reversed
However, with this code, clicking either arrow doesn't seem to do anything. I'm not sure what I'm doing wrong though. My first thought was that the if-tests were failing, so it just re-loaded the same video, but even after removing the tests and setting filename to be "video2", it didn't do anything.
Edit 1: Changed scope on var filename, like Dev-One suggested. Video source still doesn't change though.
Edit 2: changing the following:
button_next.onclick = play_next;
button_previous.onclick = play_prev;
to
button_next.addEventListener("click", play_next);
button_previous.addEventListener("click", play_prev);
seems to help. When clicking on the arrows now, the video changes, but not to the correct one. Pressing the arrow-right always brings up video1, while pressing arrow-left always shows video3. These are the videos in the last else-statement for each method, so there still seems to be an issue with my if-tests.
Edit 3: Everything is now working as planned! I also had to change
source.src == ...
to
source.getAttribute("src") == ...
in my if-tests. source.src always returned the full url (http://..../img-vid/video1.mp4), not the relative one (img-vid/video1.mp4), so every if-test failed.
As mentioned in the edits I made, I managed to solve my problem by changing button.onclick to button.addEventListener() and changing source.src to source.getAttribute("src").
From observing the code, one mistake i can find is var filename is used out of scope.
Change it to:
function play_next() {
var filename = '';
if (source.src == "img-vid/video1.mp4"){
filename = "video2";
}
else if (source.src == "img-vid/video2.mp4"){
filename = "video3";
}
else if (source.src == "img-vid/video3.mp4"){
filename = "video4";
}
else {
filename = "video1";
}
source.src = "img-vid/" + filename + ".mp4";
playlist.load();
playlist.play();
}

Passing Variables via URL to change source tag

I have 15 videos I need to show. Instead of creating 15 pages with each html5 video embed targeting a different video, I rather have just one page and via the URL tell the player what to load. This way I can just have 15 custom links but just one player and one html page. Need this to be supported by all browsers, iOS and Android.
Example:
www.mysite.com/videoplayer.html?v=mymovie
www.mysite.com/videoplayer.html?v=mymovie&t=13.6 - this should jump to the player playhead to a point in time.
videoplayer.html
<script>
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
alert('Query Variable ' + variable + ' not found');
}
var videoFile = getQueryVariable("v");
var videoElement = document.getElementById("mp4source");
videoElement.setAttribute("source", videoFile + ".mp4");
</script>
<video id="mp4" controls="controls">
<source id="mp4source" src="../videos/jude.mp4" type="video/mp4" />
</video>
Main.html
<div id="menubar1">
Play Movie
Chapter 2
</div>
I'm a beginner to javascript, please be specific in your answers.
Thanks.
IMHO DOM Manipulation on the main page would be a better solution, but here it is, at least for modern browsers, from your example code.
I changed your getQueryVariable in order to be able to use it as a
boolean.
To change the current playback time, you will have to wait for the
video's metadata to be loaded, then you can set the currentTime
property (in seconds).
In order to comply the "all browsers" support you will have
to transcode your videos to ogg vorbis format, then add a source pointing to
this video file. This will do for major modern browsers.
For older browsers, you will have to add a fallback (e.g. flash player or java applet).
For the "jumping playhead" in ios, you have some tricks to do : look at this question , personally I used this code which seems to work on my ipad ios 8. Note that it will lack of autoplay if you decide to add it in the video tag.
Now, you can't get video for all browsers (e.g text-based browsers).
Live Example
Play Movie Chapter 2
Commented videoplayer.html
<video id="video" controls="controls">
<source id="mp4source" src="" type="video/mp4" />
<source id="oggSource" src="" type="video/ogg" />
</video>
<script>
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
//returning false will help knowing if that variable exists
return false;
}
function loadVideo() {
var videoFile = getQueryVariable("v");
//if v is not set
if (!videoFile) {
alert('please choose a video file, \n maybe you came here by accident?');
//no need to go further
return;
}
//Select the sources for the mp4 and the ogg version
var mp4source = document.getElementById("mp4source");
mp4source.setAttribute("src", videoFile + ".mp4");
var oggSource = document.getElementById("oggSource");
oggSource.setAttribute("src", videoFile + ".ogv");
//if t is set
if (getQueryVariable("t")) {
//userAgent can be overridden but it may be the best way to detect ios devices
var iOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/) !== null;
if (iOS) {
iOSLoadSeek();
} else {
//wait for the video meta data to be loaded
document.getElementById('video').addEventListener('loadedmetadata', function() {
//then change the time position
this.currentTime = getQueryVariable("t");
})
}
}
}
//ios load seek workaround, edited from https://gist.github.com/millermedeiros/891886
function iOSLoadSeek() {
var vid = document.getElementById('video');
if (vid.readyState !== 4) { //HAVE_ENOUGH_DATA
vid.addEventListener('canplaythrough', iosCanPlay, false);
vid.addEventListener('load', iosCanPlay, false); //add load event as well to avoid errors, sometimes 'canplaythrough' won't dispatch.
vid.addEventListener('play', iosCanPlay, false); //Actually play event seems to be faster
vid.play();
setTimeout(function() {
vid.pause(); //block play so it buffers before playing
}, 10); //it needs to be after a delay otherwise it doesn't work properly.
}
}
//called when one of the three events fires
function iosCanPlay() {
//remove all the event listeners
this.removeEventListener('canplaythrough', iosCanPlay, false);
this.removeEventListener('load', iosCanPlay, false);
this.removeEventListener('play', iosCanPlay, false);
//finally seek the desired position
this.currentTime = getQueryVariable("t");
this.play();
}
//When the page is loaded, execute
window.onload = loadVideo();
</script>

Replacing HTML5 video src strings in javascript does not replace video

I'm a javascript novice building a simple page to practice using HTML5 video. It's basically a full-page looping video and a javascript timer that tracks and updates time on page. (Inspired, of course, by Infinite Drunk Ron Swanson). Here is a live version of the page. Be careful: both links play sound.
I'd like the script to select one of seven videos to play on page load. The code should choose a random integer between 1 and 7, generate strings to the appropriate files in a "media/" directory, and replace the video <source> tag's src attribute with the new string.
This all seems to be working correctly: there are no errors in the console, locally or as uploaded to github-pages, and when I inspect the <video> element in the Chrome developer toolbar, I can see that the code is replacing the src strings correctly. But the page doesn't seem to load different videos! This is extra-aggravating, as it was working correctly a few commits ago. I've gone back through the history to see what's changed, but I can't find anything.
I come from Python, and I suspect there's something I just don't get yet, but I don't know enough to figure out what!
UPDATE: I have solved this problem with the help of this question, by using createElement and appendChild to insert the source tags instead of changing the attributes of each element in the NodeList returned by querySelectorAll. Here is the relevant new code:
function add_source(element, src, type) {
var source = document.createElement("source");
source.src = src;
source.type = type;
element.appendChild(source);
}
function main() {
var video_no = random_int(1,7);
var video_string_mpeg = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".mp4";
var video_string_webm = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".webm";
var videoplayer = document.querySelector(".videoplayer");
add_source(videoplayer, video_string_mpeg, "video/mp4");
add_source(videoplayer, video_string_mpeg, "video/webm");
get_seconds();
}
This is great, but I don't completely understand why it worked. Explanations are still welcome!
Here's the javascript:
start = new Date();
start_time = start.getTime();
function get_seconds() {
var now = new Date();
var time_now = now.getTime();
var time_diff = time_now - start_time;
var seconds = time_diff/1000;
var timer_string = Math.round(seconds);
document.getElementById("timer").innerHTML = timer_string;
window.setTimeout("get_seconds();", 1000);
}
function random_int(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; }
function main() {
var video_no = random_int(1,7);
var video_string_mpeg = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".mp4";
var video_string_webm = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".webm";
var sources = document.querySelectorAll(".videoplayer source");
sources.item(0).src = video_string_mpeg;
sources.item(1).src = video_string_webm;
get_seconds();
}
And the HTML:
<html>
<link rel="stylesheet" href="charleston.css">
<script src="charleston.js" type="text/javascript">
</script>
<body onload="main();">
<video class="videoplayer" loop autoplay>
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy1.mp4" type="video/mp4" />
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy1.webm" type="video/webm" />
Christ on a cracker, Trudy! Update your web browser!
<audio loop autoplay>
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/charleston.mp3" type="audio/mpeg" />
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/charleston.ogg" type="audio/ogg" />
</audio>
</video>
<div class="timer_box">
<p>Hell's bells, Trudy! You've been dancing for <a id="timer">0</a> seconds.
Tweet
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></p>
</div>
</body>
</html>
I don't think the CSS or media files are the problem, but you can see them in the project repository if you'd like. A live version is available here. (NB: It plays sound). As you can see, it does everything right except selecting different videos.
I believe you can also call .load() on your video object to reload the <source>'s defined in the corresponding video object.
"When your listener function is triggered, it should change the media’s src property, then call the load method to load the new media and the play method to play it, as shown in Listing 3-4." - Apple

Categories

Resources