check if infinite stream
This commit is contained in:
112
static/player.js
112
static/player.js
@@ -22,6 +22,8 @@ elms.forEach(function(elm) {
|
|||||||
var Player = function(playlist) {
|
var Player = function(playlist) {
|
||||||
this.playlist = playlist;
|
this.playlist = playlist;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
this.isStream = false; // Track if current audio is a stream
|
||||||
|
this.durationCheckInterval = null; // For periodic duration validation
|
||||||
|
|
||||||
// Display the title of the first track.
|
// Display the title of the first track.
|
||||||
track.innerHTML = '1. ' + playlist[0].title;
|
track.innerHTML = '1. ' + playlist[0].title;
|
||||||
@@ -54,16 +56,24 @@ Player.prototype = {
|
|||||||
if (data.howl) {
|
if (data.howl) {
|
||||||
sound = data.howl;
|
sound = data.howl;
|
||||||
} else {
|
} else {
|
||||||
|
// Detect if this is a streaming URL
|
||||||
|
self.isStream = (data.file === 'stream' || data.file.indexOf('stream') !== -1);
|
||||||
|
|
||||||
sound = data.howl = new Howl({
|
sound = data.howl = new Howl({
|
||||||
src: [ './' + data.file ],
|
src: [ './' + data.file ],
|
||||||
html5: true, // Force to HTML5 so that the audio can stream in (best for large files).
|
html5: true, // Force to HTML5 so that the audio can stream in (best for large files).
|
||||||
onplay: function() {
|
onplay: function() {
|
||||||
// Display the duration.
|
// Display the duration using our validation logic
|
||||||
duration.innerHTML = self.formatTime(Math.round(sound.duration()));
|
duration.innerHTML = self.formatDuration(sound.duration());
|
||||||
|
|
||||||
// Start updating the progress of the track.
|
// Start updating the progress of the track.
|
||||||
requestAnimationFrame(self.step.bind(self));
|
requestAnimationFrame(self.step.bind(self));
|
||||||
|
|
||||||
|
// Start periodic duration checking for streams
|
||||||
|
if (self.isStream) {
|
||||||
|
self.startDurationCheck();
|
||||||
|
}
|
||||||
|
|
||||||
// Start the wave animation if we have already loaded
|
// Start the wave animation if we have already loaded
|
||||||
wave.container.style.display = 'block';
|
wave.container.style.display = 'block';
|
||||||
bar.style.display = 'none';
|
bar.style.display = 'none';
|
||||||
@@ -76,17 +86,26 @@ Player.prototype = {
|
|||||||
loading.style.display = 'none';
|
loading.style.display = 'none';
|
||||||
},
|
},
|
||||||
onend: function() {
|
onend: function() {
|
||||||
|
// Stop duration checking
|
||||||
|
self.stopDurationCheck();
|
||||||
|
|
||||||
// Stop the wave animation.
|
// Stop the wave animation.
|
||||||
wave.container.style.display = 'none';
|
wave.container.style.display = 'none';
|
||||||
bar.style.display = 'block';
|
bar.style.display = 'block';
|
||||||
self.skip('next');
|
self.skip('next');
|
||||||
},
|
},
|
||||||
onpause: function() {
|
onpause: function() {
|
||||||
|
// Stop duration checking when paused
|
||||||
|
self.stopDurationCheck();
|
||||||
|
|
||||||
// Stop the wave animation.
|
// Stop the wave animation.
|
||||||
wave.container.style.display = 'none';
|
wave.container.style.display = 'none';
|
||||||
bar.style.display = 'block';
|
bar.style.display = 'block';
|
||||||
},
|
},
|
||||||
onstop: function() {
|
onstop: function() {
|
||||||
|
// Stop duration checking
|
||||||
|
self.stopDurationCheck();
|
||||||
|
|
||||||
// Stop the wave animation.
|
// Stop the wave animation.
|
||||||
wave.container.style.display = 'none';
|
wave.container.style.display = 'none';
|
||||||
bar.style.display = 'block';
|
bar.style.display = 'block';
|
||||||
@@ -222,7 +241,17 @@ Player.prototype = {
|
|||||||
// Determine our current seek position.
|
// Determine our current seek position.
|
||||||
var seek = sound.seek() || 0;
|
var seek = sound.seek() || 0;
|
||||||
timer.innerHTML = self.formatTime(Math.round(seek));
|
timer.innerHTML = self.formatTime(Math.round(seek));
|
||||||
progress.style.width = (((seek / sound.duration()) * 100) || 0) + '%';
|
|
||||||
|
// Calculate progress, handling infinite duration
|
||||||
|
var currentDuration = sound.duration();
|
||||||
|
var correctedDuration = self.validateDuration(currentDuration);
|
||||||
|
|
||||||
|
if (correctedDuration === Infinity || !isFinite(correctedDuration)) {
|
||||||
|
// For streams, don't show progress bar
|
||||||
|
progress.style.width = '0%';
|
||||||
|
} else {
|
||||||
|
progress.style.width = (((seek / correctedDuration) * 100) || 0) + '%';
|
||||||
|
}
|
||||||
|
|
||||||
// If the sound is still playing, continue stepping.
|
// If the sound is still playing, continue stepping.
|
||||||
if (sound.playing()) {
|
if (sound.playing()) {
|
||||||
@@ -266,6 +295,83 @@ Player.prototype = {
|
|||||||
var seconds = (secs - minutes * 60) || 0;
|
var seconds = (secs - minutes * 60) || 0;
|
||||||
|
|
||||||
return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and correct duration for streaming audio
|
||||||
|
* @param {Number} duration Raw duration from Howler
|
||||||
|
* @return {Number} Corrected duration
|
||||||
|
*/
|
||||||
|
validateDuration: function(duration) {
|
||||||
|
// If duration is Infinity, keep it as is
|
||||||
|
if (duration === Infinity || !isFinite(duration)) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If duration is suspiciously large (> 24 hours), treat as stream
|
||||||
|
if (duration > 86400) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For streaming URLs, always return Infinity
|
||||||
|
if (this.isStream) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format duration for display, handling streaming audio
|
||||||
|
* @param {Number} duration Duration in seconds
|
||||||
|
* @return {String} Formatted duration string
|
||||||
|
*/
|
||||||
|
formatDuration: function(duration) {
|
||||||
|
var correctedDuration = this.validateDuration(duration);
|
||||||
|
|
||||||
|
if (correctedDuration === Infinity || !isFinite(correctedDuration)) {
|
||||||
|
// Add live class for styling
|
||||||
|
duration.classList.add('live');
|
||||||
|
return 'LIVE';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove live class for non-streaming content
|
||||||
|
duration.classList.remove('live');
|
||||||
|
return this.formatTime(Math.round(correctedDuration));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start periodic duration checking for streams
|
||||||
|
*/
|
||||||
|
startDurationCheck: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.durationCheckInterval) {
|
||||||
|
clearInterval(self.durationCheckInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.durationCheckInterval = setInterval(function() {
|
||||||
|
var sound = self.playlist[self.index].howl;
|
||||||
|
if (sound && sound.playing()) {
|
||||||
|
var currentDuration = sound.duration();
|
||||||
|
var correctedDuration = self.validateDuration(currentDuration);
|
||||||
|
|
||||||
|
// If duration changed from finite to infinite or vice versa, update display
|
||||||
|
if ((correctedDuration === Infinity) !== (duration.innerHTML === 'LIVE')) {
|
||||||
|
duration.innerHTML = self.formatDuration(currentDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 5000); // Check every 5 seconds
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop periodic duration checking
|
||||||
|
*/
|
||||||
|
stopDurationCheck: function() {
|
||||||
|
if (this.durationCheckInterval) {
|
||||||
|
clearInterval(this.durationCheckInterval);
|
||||||
|
this.durationCheckInterval = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -62,6 +62,22 @@ body {
|
|||||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.33);
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stream indicator styling for LIVE duration */
|
||||||
|
#duration.live {
|
||||||
|
background: rgba(255, 0, 0, 0.8);
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
opacity: 0.9;
|
||||||
|
animation: livePulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes livePulse {
|
||||||
|
0% { opacity: 0.9; }
|
||||||
|
50% { opacity: 0.6; }
|
||||||
|
100% { opacity: 0.9; }
|
||||||
|
}
|
||||||
|
|
||||||
/* Controls */
|
/* Controls */
|
||||||
.controlsOuter {
|
.controlsOuter {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
Reference in New Issue
Block a user