I've been using this custom audio player I put together with a few tutorials and solves around the Internet and have been using it for the past 2 months.
It worked 100% in Chrome, but after an update the seek bar happened to stop working.
Is this an issue on my end? or does it work for anyone else?
HTML:
<div id="musicplayer">
<table>
<tr>
<audio id="audio" src="../audio/oby/weightless/Got To Be Free.mp3"></audio>
<td>
<button id="play" type="button" onclick="playPause()" ></button>
</td>
<td>
<div id="boxed" >
Select a song from the playlist
<p class="right" id="timeInfo">00:00</p>
<input type="range" step="any" id="seekbar"></input>
</div>
</td>
</tr>
</table>
</div>
JavaScript:
<script>
var audio = document.getElementsByTagName('audio')[0],
div = document.getElementById('timeInfo');
function formatTime(s, m) {
s = Math.floor( s );
m = Math.floor( s / 60 );
m = m >= 10 ? m : '0' + m;
s = Math.floor( s % 60 );
s = s >= 10 ? s : '0' + s;
return m + ':' + s;
}
setInterval(function()
{
div.textContent = formatTime(audio.currentTime);
}, 100);
seekbar.value = 0;
var audio = document.getElementById("audio");
var seekbar = document.getElementById('seekbar');
function setupSeekbar() {
seekbar.min = audio.startTime;
seekbar.max = audio.startTime + audio.duration;
}
audio.ondurationchange = setupSeekbar;
function seekAudio() {
audio.currentTime = seekbar.value;
}
function updateUI() {
var lastBuffered = audio.buffered.end(audio.buffered.length-1);
seekbar.min = audio.startTime;
seekbar.max = lastBuffered;
seekbar.value = audio.currentTime;
}
seekbar.onchange = seekAudio;
audio.ontimeupdate = updateUI;
audio.addEventListener('durationchange', setupSeekbar);
audio.addEventListener('timeupdate', updateUI);
</script>
Duplicate code:
audio.ondurationchange = setupSeekbar;
and
audio.addEventListener('durationchange', setupSeekbar);
try removing any of these lines.
and if setting seekbar value in javascript will triger onchange... you will have to remove seekbar.onchange = seekAudio;
Is your seekbar doesn't seek when user click any time? Or is there a problem on updating time. (time is updating but seekbar doesn't)?
You do not need these codes, might also cause problem one... (the seekbar update problem)
var lastBuffered = audio.buffered.end(audio.buffered.length-1);
seekbar.min = audio.startTime;
seekbar.max = lastBuffered;
EDIT (offtopic): For better performance remove the code
setInterval(function()
{
div.textContent = formatTime(audio.currentTime);
}, 100);
and append this to updateUI
div.textContent = formatTime(audio.currentTime);
Related
I got this code here on stack overflow which is a custom audio player. But then modified the code to fetch audio from my database. The problem am having is only the first song gotten from my database is been played.
This is my code that displays the audio with the controls
<?php
require '../db.php';
$sql = "select * from songs order by song_id asc";
$sql_query = mysqli_query($con,$sql);
$i=0;
while ($row = mysqli_fetch_array($sql_query)) {
$image = $row['song_image'];
$song_name = $row['song_name'];
$audio = $row['song_audio'];
?>
<audio controls="controls" class='podcast-audio hide' id="player">
<source src="../Admin/Song/songAudio/<?php if(isset($audio)){ echo $audio;}?>" type="audio/mpeg"
/>
</audio>
<div id="audio-player">
<div id="controls">
<i id="play" class="fa fa-play cursor-pointer"></i>
<span id="time" class="time">00:00</span>
<div id="progressbar" class='cursor-pointer ui-progressbar'></div>
<span id="end-time" class="time">00:00</span>
<i id="mute" class="fa fa-volume-up cursor-pointer"></i>
<div id="volume" class='cursor-pointer ui-progressbar'></div>
</div>
</div>
<?php
$i++;
}
?>
This is my javascript code responsible for playing the audio
$(document).ready(function() {
var audio_player = $("#audio-player");
var play_button = $('#play');
var progress_bar = $("#progressbar");
var time = $("#time");
var mute_button = $('#mute');
var volume_bar = $('#volume');
var more_info = $('#more-info-box');
var player = $('#player')[0];
var duration = 0;
var volume = 0.5;
var end_time = $('#end-time');
player.onloadedmetadata = function () {
duration = player.duration;
var minutes = parseInt(duration / 60, 10);
var seconds = parseInt(duration % 60);
// finding and appending full duration of audio
end_time.text(minutes + ':' + seconds);
console.log('ddd', progress_bar)
progress_bar.progressbar("option", { 'max': duration });
};
player.load();
player.volume = 0.5;
player.addEventListener("timeupdate", function () {
progress_bar.progressbar('value', player.currentTime);
time.text(getTime(player.currentTime));
}, false);
volume_bar.progressbar({
value: player.volume * 100,
});
volume_bar.click(function (e) {
var info = getProgressBarClickInfo($(this), e);
volume_bar.progressbar('value', info.value);
player.volume = info.value / info.max;
});
progress_bar.progressbar({
value: player.currentTime,
});
progress_bar.click(function (e) {
var info = getProgressBarClickInfo($(this), e);
player.currentTime = player.duration / info.max * info.value;
});
play_button.click(function () {
player[player.paused ? 'play' : 'pause']();
$(this).toggleClass("fa-play", player.paused);
$(this).toggleClass("fa-pause", !player.paused);
});
mute_button.click(function () {
if (player.volume == 0) {
player.volume = volume;
} else {
volume = player.volume;
player.volume = 0;
}
volume_bar.progressbar('value', player.volume * 100);
$(this).toggleClass("fa-volume-up", player.volume != 0);
$(this).toggleClass("fa-volume-off", player.volume == 0);
});
more_info.click(function () {
audio_player.animate({
height: (audio_player.height() == 50) ? 100 : 50
}, 1000);
});
});
function getTime(t) {
var m = ~~(t / 60), s = ~~(t % 60);
return (m < 10 ? "0" + m : m) + ':' + (s < 10 ? "0" + s : s);
}
function getProgressBarClickInfo(progress_bar, e) {
var offset = progress_bar.offset();
var x = e.pageX - offset.left; // or e.offsetX (less support, though)
var y = e.pageY - offset.top; // or e.offsetY
var max = progress_bar.progressbar("option", "max");
var value = (x * max) / progress_bar.width();
return { x: x, y: y, max: max, value: value };
}
It looks like you're using the same javascript/HTML ID on each of the play, pause buttons.
Eg. if you're returning 3 songs, then the id within Javascript will be appearing 3 times...
<audio ... id="player">
<audio ... id="player">
<audio ... id="player">
So, as an ID on a page can only be created once, when your javascript function goes to find the song, it finds the first ID, gets it's the source and plays it.
I'd suggest that you either:
I can see you're using a counter. Change the ID of each player id to be player1, player2, etc and refer to that, OR
Get your player code to search by class instead of by id. Eg.
var player = $('.podcast-audio')[0][0];
I have two tracks that get loaded on a single <audio> when you hit play on either of these tracks. That seems to work perfectly fine. Each of these tracks has a separate <progress> field but no matter what track you play you only see the progress bar moving on the first <progress> field.
Is there a way to fix this?
There's also an error when you pause a song and resume it. The total and current time text fields display a "Na" message for a split second before showing the correct total/current time back again.
How can I stop that from happening?
HTML
<audio id="globalAudio"></audio>
<div class="mp3Player" data-src="https://www.freesound.org/data/previews/338/338825_1648170-lq.mp3" data-pos="0">
<button class="btnPlayPause button">Play</button>
<span class="infoLabel">
<span id="seekObjContainer">
<progress id="seekbar" value="0" max="1"></progress>
</span>
<span class="start-time"></span>
<span class="end-time"></span>
</span>
</div>
<div class="mp3Player" data-src="http://www.lukeduncan.me/oslo.mp3" data-pos="0">
<button class="btnPlayPause button">Play</button>
<span class="infoLabel">
<span id="seekObjContainer">
<progress class="seekbar1" value="0" max="1"></progress>
</span>
<span class="start-time"></span>
<span class="end-time"></span>
</span>
</div>
JS
var globalAudio = document.getElementById("globalAudio");
var current = null;
var playingString = "<span>Pause</span>";
var pausedString = "<span>Play</span>";
$(document.body).on('click', '.btnPlayPause', function(e) {
var target = this;
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.substr(0, 2),
time = minutes + ':' + seconds;
return time;
}
function calculateCurrentValue(currentTime) {
var current_hour = parseInt(currentTime / 3600) % 24,
current_minute = parseInt(currentTime / 60) % 60,
current_seconds_long = currentTime % 60,
current_seconds = current_seconds_long.toFixed(),
current_time = (current_minute < 10 ? "0" + current_minute : current_minute) + ":" + (current_seconds < 10 ? "0" + current_seconds : current_seconds);
return current_time;
}
function initProgressBar() {
var length = globalAudio.duration;
var current_time = globalAudio.currentTime;
var totalLength = calculateTotalValue(length);
jQuery(".end-time").html(totalLength);
var currentTime = calculateCurrentValue(current_time);
jQuery(".start-time").html(currentTime);
var progressbar = document.getElementById('seekbar');
progressbar.value = globalAudio.currentTime / globalAudio.duration;
console.log(target);
}
if (current == target) {
target.innerHTML = pausedString;
target.parentNode.setAttribute('data-pos', globalAudio.currentTime); //start from paused
globalAudio.pause();
current = null;
} else {
if (current != null) {
current.innerHTML = pausedString;
current.parentNode.setAttribute('data-pos', '0'); //reset position
target.parentNode.setAttribute('data-pos', globalAudio.currentTime); //start from paused
}
current = target;
target.innerHTML = playingString;
globalAudio.src = target.parentNode.getAttribute('data-src');
globalAudio.play();
globalAudio.onloadeddata = function() {
globalAudio.currentTime = parseFloat(target.parentNode.getAttribute('data-pos'));
globalAudio.addEventListener("timeupdate",function(){ initProgressBar(); });
};
}
});
Here's is a working example in this fiddle
Thank you
That's because only the first <progress> tag have an id:
<progress id="seekbar" value="0" max="1"></progress>
<progress class="seekbar1" value="0" max="1"></progress>
Then:
var progressbar = document.getElementById('seekbar'); // <-- always getting the first progress tag
progressbar.value = globalAudio.currentTime / globalAudio.duration;
For the NaN issue appearing for a split second, that's because when loading a source in an <audio> tag the duration is unknown until the browser has retrieved the file's metadata. While this duration is unknown its value is NaN (Not A Number).
You may add a check:
if (Number.isNaN(element.duration)) {
// display 00:00 or whatever you want
}
I am working on a project that generates a 6 digit string key all the while being timed. So my stopwatch has 3 buttons. Start, stop, and reset. I want to create a program in which, when i click on start it will generate a key and the stopwatch will run. So i want to know how i can have the button execute two actions at once. Same with stop, and reset will generate a new key. Also how can i put these two codes together into one?
My code for key generator:
function Keygenerate() {
var text ="";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for(var i=0; i < 5; i++ ){
text += possible.charAt(Math.floor(Math.random() * possible.length()));
}
return text;
}
My code for the Stopwatch:
<div class="class">
<p>CSC 131 Attendance Tracker</p>
</div>
<div class="stopwatch">
<div class="title">
<h2>KEY:</h2>
</div>
<div class="key">
<input type="text" name="output">
</div>
<div class="time">
<h2>TIME:</h2>
</div>
<div class="display">
<span class="minutes">00:</span><span class="seconds">00:</span><span class="centiseconds">00</span>
</div>
<div class="controls">
<button class="start">Start</button>
<button class="stop">Stop</button>
<button class="reset">Reset</button>
</div>
</div>
<script>
var ss = document.getElementsByClassName('stopwatch');
[].forEach.call(ss, function (s) {
var currentTimer = 0,
interval = 0,
lastUpdateTime = new Date().getTime(),
start = s.querySelector('button.start'),
stop = s.querySelector('button.stop'),
reset = s.querySelector('button.reset'),
mins = s.querySelector('span.minutes'),
secs = s.querySelector('span.seconds'),
cents = s.querySelector('span.centiseconds');
start.addEventListener('click', startTimer);
stop.addEventListener('click', stopTimer);
reset.addEventListener('click', resetTimer);
function pad (n) {
return ('00' + n).substr(-2);
}
function update () {
var now = new Date().getTime(),
dt = now - lastUpdateTime;
currentTimer += dt;
var time = new Date(currentTimer);
mins.innerHTML = pad(time.getMinutes()) + ":";
secs.innerHTML = pad(time.getSeconds()) + ":";
cents.innerHTML = pad(Math.floor(time.getMilliseconds() / 10));
lastUpdateTime = now;
if(now == time.getMinutes()){
clearInterval(interval);
}
}
function startTimer () {
if (!interval) {
lastUpdateTime = new Date().getTime();
interval = setInterval(update, 1);
}
}
function stopTimer () {
clearInterval(interval);
interval = 0;
}
function resetTimer () {
stopTimer();
currentTimer = 0;
mins.innerHTML = secs.innerHTML = cents.innerHTML = pad(0);
}
});
</script>
</body>
Well, at its basic you would do it by attaching two functions to an event:
<button onclick = "generate_key(); stopwatch_run();">
You can also attach functions to a click event:
object.addEventListener("click", function(){ ... });
It seems like what you're asking is very basic, so I am not sure if I'm being helpful.
I have been working on this HTML5 audio player that tracks the playtime of an audio file. I have gotten it to work on the page, but I cannot seem to make it work when it is called from a popover. I am seeing no errors.
<audio id="player" ontimeupdate='updateTrackTime(this);'>
<source src="http://sifidesign.com/audio/explosion.mp3" type="audio/mp3" />
<script>
document.getElementsByClassName("speaker").onclick = function() {updateTrackTime()};
function updateTrackTime(track){
var currTimeDiv = document.getElementById('currentTime');
var durationDiv = document.getElementById('duration');
var currTime = Math.floor(track.currentTime).toString();
var duration = Math.floor(track.duration).toString();
currTimeDiv.innerHTML = formatSecondsAsTime(currTime);
if (isNaN(duration)){
durationDiv.innerHTML = '00:00';
}
else{
durationDiv.innerHTML = formatSecondsAsTime(duration);
}
}
</script>
</audio>
<div class="speaker"></div>
<span id="currentTime">00:00</span> / <span id="duration">00:00</span>
What else could I try?
Thank you!
—T
Since the popover is created dynamically, you will have to use event delegation.
document.body.addEventListener("click",function(e){
if(e.target.className == "speaker"){
updateTrackTime();
}
});
EDIT
Full working code:
document.body.addEventListener("timeupdate",function(e){
if(e.target.tagName == "AUDIO"){
updateTrackTime(e.target);
}
},true)
function updateTrackTime(track){
var currTimeDiv = document.getElementById('currentTime');
var durationDiv = document.getElementById('duration');
var currTime = Math.floor(track.currentTime).toString();
var duration = Math.floor(track.duration).toString();
currTimeDiv.innerHTML = formatSecondsAsTime(currTime);
if (isNaN(duration)){
durationDiv.innerHTML = '00:00';
}
else{
durationDiv.innerHTML = formatSecondsAsTime(duration);
}
}
function formatSecondsAsTime(secs, format) {
var hr = Math.floor(secs / 3600);
var min = Math.floor((secs - (hr * 3600))/60);
var sec = Math.floor(secs - (hr * 3600) - (min * 60));
if (min < 10){
min = "0" + min;
}
if (sec < 10){
sec = "0" + sec;
}
return min + ':' + sec;
}
#currentTime,#duration{
background:yellow;
}
<audio id="player" autoplay>
<source src="https://megafood.com/wp-content/uploads/2015/07/Erin-Audio-Road-Less-Traveled.mp3" type="audio/mp3" />
</audio>
<div class="speaker"></div>
<span id="currentTime">00:00</span> / <span id="duration">00:00</span>
EDIT
The script is working on your page because it's updating the time in the DOM:
The problem is that since you declared the HTML for the popover, it conflicts with the content that is dynamically-created by the popover because they have the same id. Since the popover content is at the bottom of the page, the script won't change it because there can only be one ID per page and it selects the first one.
I think the easy fix would be to change the IDs to classes for #player, #currTime, #duration
I'm using the stopwatch code I found here:
http://www.kellishaver.com/projects/stopwatch/
(function($) {
$.fn.stopwatch = function() {
var clock = this;
var timer = 0;
clock.addClass('stopwatch');
//console.log(clock);
// This is bit messy, but IE is a crybaby and must be coddled.
clock.html('<div class="display"><span class="hr">00</span>:<span class="min">00</span>:<span class="sec">00</span></div>');
clock.append('<input type="button" class="start" value="Start" />');
clock.append('<input type="button" class="stop" value="Stop" />');
clock.append('<input type="button" class="reset" value="Reset" />');
//console.log(clock.html());
// We have to do some searching, so we'll do it here, so we only have to do it once.
var h = clock.find('.hr');
var m = clock.find('.min');
var s = clock.find('.sec');
var start = clock.find('.start');
var stop = clock.find('.stop');
var reset = clock.find('.reset');
stop.hide();
start.bind('click', function() {
timer = setInterval(do_time, 1000);
stop.show();
start.hide();
});
stop.bind('click', function() {
clearInterval(timer);
timer = 0;
start.show();
stop.hide();
});
reset.bind('click', function() {
clearInterval(timer);
timer = 0;
h.html("00");
m.html("00");
s.html("00");
stop.hide();
start.show();
});
function do_time() {
// parseInt() doesn't work here...
hour = parseFloat(h.text());
minute = parseFloat(m.text());
second = parseFloat(s.text());
second++;
if(second > 59) {
second = 0;
minute = minute + 1;
}
if(minute > 59) {
minute = 0;
hour = hour + 1;
}
h.html("0".substring(hour >= 10) + hour);
m.html("0".substring(minute >= 10) + minute);
s.html("0".substring(second >= 10) + second);
}
};
})(jQuery);
And I use it like this:
<script type="text/javascript">
$('#clock1').stopwatch();
</script>
It works fine and I can stop it using the stop button. However I would like to be able to stop it programatically using javascript. Something like this:
<script type="text/javascript">
$('#clock1').stop();
</script>
I created the stop function but I cannot access the timer var defined in stopwatch(). How can I do it?
How about:
$('#clock1').find('.stop').trigger('click');
You can add a small API to the code and attach it using $.data:
var api = {
stop: function() {
stop.click(); // this should probably be improved, but you get the idea
}
};
$(clock).data('stopwatch', api);
Then use:
$('#clock1').data('stopwatch').stop();
You can also add the reset and start functions to the API using the same logic. A good thing here is that you can improve the execution code on a coffee break later without changing the way external programs uses the API.