Onended switch to Next track - javascript

I'm trying to build an MP3 player. Here I want to perform a switch to the next song once the current tack ends.
Here is a part of my code:
function clicki(ID, norrnd) {
if (norrnd == 'nor') {
$('.liActive').removeClass('liActive');
$('#' + ID).next().addClass('liActive');
// Set track Data
$('audio').attr('id', 'audioNor');
$('audio').attr('src', $('.liActive').attr('rel'));
// Play
var player = $('.tbd').get(0);
player.play();
$('#pause').removeClass('hi');
$(player).bind('ended', clicki(ID++, 'nor')); //as well as .onfinish result in TOO MUCH RECURSION error.
}
}
<audio controls id="" class="tbd" type="audio/mpeg" src="Ella Fitzgerald - It Don't Mean a Thing.mp3"></audio>
So when I just initiate clicki() first time the page instantly freezes:
Too Much Recursion.
How do I make the track be automatically switched with no Recursion flood?

You're calling the function immediately -- you need to create a function around it:
function clicki(ID, norrnd) {
if (norrnd === 'nor') {
$('.liActive').removeClass('liActive');
$('#' + ID).next().addClass('liActive');
// Set track Data
$('audio').attr('id', 'audioNor');
$('audio').attr('src', $('.liActive').attr('rel'));
// Play
var $player = $('.tbd');;
$player.get(0).play();
$('#pause').removeClass('hi');
// if you call it now, it's going to keep calling itself
$player.bind('ended', function () {
clicki(ID++, 'nor');
});
}
}

Related

Can't make nativescript-videoplayer and nativescript-audioplayer work alongside each other?

So i'm currently building an app using the multiplatform framework of nativescript. I've got the two plugins in question to work by themselves, but when both of them runs at the same time, and i wish to pause both tracks (video and audio with separate track files), only one of them stops, while the other continues. Why is that?
To start off, my nativescript audioplayer code is:
var videoViewModel = new Observable();
videoViewModel.audioPlayer = new TNSPlayer();
let audioParams = {
audioFile: selectedVideoEntity.audioPath_,
loop: true,
completeCallback: function(){},
errorCallback: function(error){console.log("failed with: ", error)}};
let audioPlayerCreatedCallback = () => {
videoViewModel.audioPlayer.getAudioTrackDuration().then((duration) => {
// iOS: duration is in seconds
// Android: duration is in milliseconds
console.log(`song duration:`, duration);
});
}
//todo: change to something more meaningfull (new RegExp('^' + "https\:\/\/|http\:\/\/", 'i')).test(selectedVideoEntity.audioPath)
if(selectedVideoEntity.audioPath.startsWith("http")){
console.log("getting from url");
videoViewModel.audioPlayer.playFromUrl(audioParams).then(audioPlayerCreatedCallback);
}
else{
videoViewModel.audioPlayer.playFromFile(audioParams).then(audioPlayerCreatedCallback);
}
When this is setup, I move on to making the videoplayer. This is implemented in xml.
<Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:VideoPlayer="nativescript-videoplayer"
loaded="loaded" class="page" navigatingFrom="onNavigatingFrom" actionBarHidden="true">
<StackLayout id="layout">
<VideoPlayer:Video id="videoPlayer" controls="true" loop="false"
finished="{{ videoFinished }} "
src="{{ videoPlayerViewModel.videoPath }}" observeCurrentTime="true" muted="true" />
<VideoPlayer:Video id="rewardVideoPlayer" controls="true" loop="false"
finished="{{ rewardVideoFinished }} "/>
</StackLayout>
</Page>
And then I grab the object from the associated page file
let videoPlayer = page.getViewById("videoPlayer");
Expect the video to have it's source and all set at this point.
Now is where the issues begin. The thing i want is to pause the video and the audio at the same time, so my approach is to pause the audio, whenever i call the cycleVideoPlayers pause function and afterwords, like this:
videoViewModel.audioPlayer.pause();
videoViewModel.videoPlayer.pause();
At this point only one of them stops (mostly the audio) and the video continues on. Any ideas why?
Links to the plugins:
https://github.com/bradmartin/nativescript-audio
https://github.com/bradmartin/nativescript-videoplayer
TO CLARIFY THE SITUATION
This only pauses one of the tracks and resumes the paused track, without having any effect
videoViewModel.audioPlayer.pause();
videoViewModel.videoPlayer.pause();
// Wait a few seconds
videoViewModel.audioPlayer.resume();
videoViewModel.videoPlayer.play();
This pauses the video and resumes flawlessly
videoViewModel.videoPlayer.pause();
// Wait a few seconds
videoViewModel.videoPlayer.play();
Same goes for audio
videoViewModel.audioPlayer.pause();
// Wait a few seconds
videoViewModel.audioPlayer.resume();
The explicit code that tries to pause and resume is given here. This code is in an exports.loaded function, in one of my nativescript page .js files.
cycleVideoPlayer.on(gestures.GestureTypes.swipe, function(eventdata) {
console.log("Swipe detected, with direction: " + eventdata.direction);
if (!paused) {
(function() {
vm.audioPlayer.pause();
vm.cycleVideoPlayerViewModel.pause(); //This doesnt work alongside audiopause.. why?
paused = true;
console.log("Paused");
});
} else {
(function() {
vm.audioPlayer.resume();
vm.cycleVideoPlayerViewModel.play();
paused = false;
console.log("Resumed");
});
}
});
If anybody have an idea or need clarification on the matter, please comment :)

Alternating multiple video lists in html5 stored as javascript arrays

I have designed an i-phone-like screen on a web browser where I am testing this application I am in the process of building. It works great up until the point where I want to call out another set of videos.
What works
The application is structured so that when the user sees the screen she is directed to a channel that has a vertical video.
The buttons on the top left and top right advance to the next and the previous video.
<div id="topVid" class="videoContainer">
<div class="topHorizontalButtonRow">
</div>
<video class="topVid" loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/ParisisBurning_660x370_I_went_to_a_ball.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
There is a "channel" button that shows the user a smaller window if pressed, where the user can view other channels by clicking on a second set of buttons next and previous buttons.
<div id="bottomVid" class="videoContainerTwo hiddenElement">
<div class="topHorizontalButtonRow">
<div class="buttonLeftTriangleBlue"></div>
<div class="buttonRightTriangleBlue"></div>
</div>
<video loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/Politics_Refugee_Sign.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
jquery show/hide smaller window:
$(".buttonTeardropChannelBlue").click( function (){
if( $("#bottomVid").is(':visible') ) {
$("#bottomVid").hide();
} else {
$("#bottomVid").show();
}
});
If the user wants to watch this specific channel, she can click on the smaller window, which hides the current window and advances to the other channel. The video can be clicked on, and once that happens, the user will be directed to the next channel.
Below is the code that works perfectly to advance the video of the current selection, and it contains the videos in arranged in an array.
var Vids = (function() {
var _currentId = -1;
var _urls =
["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
What does not work
The issue: showing and hiding multiple video lists
However, the problem starts when I want to select a different class of videos, which has the exact same code except for different videos. I have changed the name of the function to say, VidsTwo but the problem remains.
var VidsTwo = (function() {
var _currentId = -1;
var _urls = ["videos/Politics_Atl_We_are_the_people.mp4","videos/Politics_Atlanta_Whose_Streets.mp4", "videos/Politics_Womens_March_Washington_CBS_VERT.mp4",
"videos/Politics_No_bans_no_walls_America_is_home_to_all_VERT.mp4",
"videos/Politics_Let_them_in_VERT.mp4",
"videos/Politics_Tear it Down_JFK_VERT.mp4",
"videos/Politics_This_is_What_America_Looks_Like_embrace.mp4",
"videos/Politics_This_land_was_made_VERT.mp4", "videos/Politics_We_need_an_independent_investigation_town_hall.mp4",
"videos/Politics_Just say no_town_hall_VERT.mp4", ]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
The issue remains: the buttons will continue to play the videos of the current channel in addition to the ones of the new channel, and it will not hide the current video. I understand it happens because in the javascript code, it uses the select element by tag which is "video". and all the array lists have "video" so it is playing all of them.
What is the best solution to this problem, given that I want to be able to separate the videos into categories "channels" that will have similar thematic content, and that this categories will be called by users as they look at a second smaller window of videos?
Core questions
Is there a way to have it NOT play a selection of arrays? What can I change in the Javascript code that will indicate that these separate video arrays do not belong to the same class? How can I make it clear in the code that these videos, although they are all videos, belong to different categories and therefore can only be played if their specific category is called?
Brainstorming solutions:
I am thinking I would probably need a second div that will have a
second row of buttons that call out the second function, since the
prev and next indicate a separate variable that was declared for each
class of videos...but this is getting a bit complicated for my newbie
skills:)
Or perhaps each video on a parent class should be saved on the
html itself as a hidden div and should be called by using "show
next child of parent div", as opposed to being saved as an array on
the javascript code?
The next step is adding marquee text to each video so maybe having
separate hidden divs on the html itself is a better solution than
having the videos stored as javascript arrays?
This is basically a prototype/beta for something that will become an
app so there is no database yet, (which will make it easier to
store this info eventually once I begin more in-depth user tests).
This complication is for testing only:)
UPDATE: I am still curious as to what the best solution would be, however I have decided, in this case, to add divs directly to the html and use jquery's next sibling selectors. Because I will have some text specific to some videos, they won't be properly connected to the javascript arrays anyway. I find the javascript array solution "cooler" but it is perhaps not the best in the end.
make Vids like this:
var Vids = function(vidArray=[]) {
var _currentId = -1;
var _urls = vidArray;
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
};
then prepare your url array and call Vids:
var urls =["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"];
Vids(urlf).play(3); //Replace 3 with any id

Javascript - Automatic video playlist

I'd like to know how could I achieve a video playlist without any buttons or control that would simply play an array of videos and would start again when the last is over.
I found this piece of code about a clickable playlist : http://jsfiddle.net/e8CbF/
but I really don't know how to make it automatic. Also, the array is coming from a PHP variable, how I can I use it inside this code ?
function loadVids(vidsArray){
for(var a=0,b,f=document.createDocumentFragment();b=vidsArray[a];++a){
var c=document.createElement('div');
c.textContent=b;
f.appendChild(c);
}
d.appendChild(f);
}
var video=document.createElement('video'),vids=['http://screen.alifts.com/screenfiles/video1.mp4','http://screen.alifts.com/screenfiles/video2.mp4'], /* Is it there that I should put the php array ? */
d=document.createElement('div');
d.onclick=function(e){if(e.target.parentNode==this){
video.src=e.target.textContent;
video.play();
}}
document.body.appendChild(video);
document.body.appendChild(d);
loadVids(vids);
Your code is a total mess. So i completely rewrite it.
<video src="" id="player"/>
<script>
var video=counter=0;
videos=['<?php echo join("';'",$array);?>'];
window.onload=()=>{
//get the video frame
video=document.getElementById("player");
//if the video ended, play next.
video.addEventListener("ended",play,false);
//start
play();
}
var play=()=>{
//add the video src
video.src=videos[counter];
//play next video next time
counter++;
if(counter==videos.length){
counter=0;
}
};
</script>

Dynamic sounds not playing after two plays

I have a little html5 application where you can play a sound by clicking a button.
I have a function that adds an <audio> tag to a <div> with an id "playing." The sound removes itself when it is done.
function sound(track){
$("#playing").append("<audio src=\"" + track + "\" autoplay onended=\"$(this).remove()\"></audio>");
}
For the button I have:
<button onclick="sound('sounds/tada.mp3')">Tada</button>
When I click the button, an <audio> briefly appears in the element inspector and disappears when it is finished, just the way I want it, but after triggering it two times, it just stops working in Chrome, at least. There are no errors in the console either.
What is going on?
Get rid of the onclick/onend in your HTML and reference the button in your js:
HTML
<button id='tada' sound_url='sounds/tada.mp3'>Tada</button>
And the JS
var sound = function(track){
$("#playing").append("<audio id='played_audio' src='\" + track + \"' autoplay='true'></audio>");
}
$('#tada').on('click', function () {
var sound_url = $(this).attr('sound_url');
sound(sound_url);
});
$('#playing').on('end', 'played_audio', function() {
$(this).remove();
});
Okay, lets see..
var audioURL = "http://soundbible.com/mp3/Canadian Geese-SoundBible.com-56609871.mp3";
var audioEl = null;
function removeAudio() {
if (audioEl && audioEl.parentNode)
audioEl.parentNode.removeChild(audioEl);
}
function sound() {
removeAudio();
audioEl = document.createElement("audio");
audioEl.src = audioURL;
audioEl.controls = true;
audioEl.addEventListener("ended", removeAudio); // <-- Note it's ended, not end!
document.getElementById("playing").appendChild(audioEl);
audioEl.play();
}
document.getElementById("tada").addEventListener("click", sound);
<div id="playing">
</div>
<button id="tada">Tada</button>
I'm not seeing any problems with this script.
Decide audioURL, set audioEl to null as it will be used later
When the element with ID "tada" is clicked, run our sound function.
Remove the audio.
Create the audio element.
When the audio is finished, remove the audio.
Append the audio to the element with ID "playing".
Play the audio.
One thing to note is that I use the ended event, not the end event.
(This answer is here because Andrew really wants us to answer it.)

Starting and Stopping Audio in Javascript

I have a function tied to an onClick event. It's supposed to play a song. If there's a song already playing it's supposed to stop the current song and start playing the new one. The only problem is that as far as I know there is only a pause method and it means that the previous song will resume from the paused position and not the beginning. Is there any way around this (like a .stop() method)?
Here's my code:
var currSong="";
function playSong(newSong){
alert(newSong);
if (newSong != ""){
if(currSong != "" ) {
document.getElementById(currSong).pause();
}
document.getElementById(newSong).play();
currSong = newSong;
}
}
From looking at the MDC documentation for the audio element, it appears that the correct way to do this is by setting the currentTime property:
function playSong(newSong){
alert(newSong);
if (newSong != ""){
if(currSong != "" ) {
document.getElementById(currSong).pause();
}
var newSongEl = document.getElementById(newSong);
newSongEl.currentTime = 0;
newSongEl.play();
currSong = newSong;
}
}
Also, it would be better to store the relevant element in currSong, rather than its ID, unless you are using the ID for something else.

Categories