You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

329 lines
8.6 KiB

/*global $, document, alert*/
(function () {
// Track multiple players on the page
var bbplayers = [];
// Stop all other bbplayers on page when starting another
function stopAllBBPlayers() {
var i = 0;
for (i = 0; i < bbplayers.length; i++) {
bbplayers[i].pause();
bbplayers[i].updateDisplay();
}
}
//Pad a number with leading zeros
function zeroPad(number, places) {
var zeros = places - number.toString().length + 1;
return new Array(+(zeros > 0 && zeros)).join("0") + number;
}
// Convert seconds to mm:ss format
function toTimeString(seconds) {
if (isNaN(seconds)) {
return "--:--";
}
var minutes = Math.floor(seconds / 60);
seconds = seconds - minutes * 60;
return zeroPad(minutes, 2) + ":" + zeroPad(seconds, 2);
}
// Parse out file name from path, unescape
function parseTitle(path) {
path = decodeURI(path);
return path.split('/').pop().split('.').shift();
}
// Object to represent bbplayer
var BBPlayer = function (bbplayer) {
this.bbplayer = bbplayer;
this.bbaudio = bbplayer.find("audio");
this.bbdebug = bbplayer.find(".bb-debug");
this.bbaudio.get(0).preload = "auto"; // seems not to preload on many mobile browsers.
this.state = "paused"; // TODO enum states
this.trackList = [];
this.init();
};
// Debug logger
BBPlayer.prototype.log = function (msg) {
if (this.bbdebug) {
this.bbdebug.append(msg + "<br>");
this.bbdebug.scrollTop(this.bbdebug.prop('scrollHeight') - this.bbdebug.height());
}
};
// say if audio element can play file type
BBPlayer.prototype.canPlay = function (extension) {
var audioElem = this.bbaudio.get(0);
if ((/mp3/i).test(extension) && audioElem.canPlayType('audio/mpeg')) {
return true;
}
if ((/ogg/i).test(extension) && audioElem.canPlayType('audio/ogg')) {
return true;
}
return false;
};
// Set up multiple sources as track list,
// Remove duplicate and unplayable sources
BBPlayer.prototype.loadSources = function () {
var self = this;
self.log('func: loadSources');
self.bbaudio.find("source").each(function (x) {
var fileName = $(this).attr('src').split('/').pop();
var extension = fileName.split('.').pop();
var trackName = fileName.split('.').shift();
var playable = self.canPlay(extension);
var audioElem = self.bbaudio.get(0);
if ($.inArray(trackName, self.trackList) === -1 && playable === true) {
self.trackList.push(trackName);
} else {
$(this).remove();
}
});
};
// Update display
BBPlayer.prototype.updateDisplay = function () {
var audioElem = this.bbaudio.get(0);
var duration = toTimeString(Math.ceil(audioElem.duration));
var elapsed = toTimeString(Math.ceil(audioElem.currentTime));
var title = parseTitle(audioElem.currentSrc);
this.bbplayer.find('.bb-trackLength').html(duration);
this.bbplayer.find('.bb-trackTime').html(elapsed);
this.bbplayer.find('.bb-trackTitle').html(title);
};
// Set current source for audio to given track number
BBPlayer.prototype.loadTrack = function (trackNumber) {
var source = this.bbaudio.find("source").eq(trackNumber).attr('src');
this.bbaudio.get(0).src = source;
this.currentTrack = trackNumber;
this.log('func: loadTrack: loaded ' + source);
};
// Load next track in playlist
BBPlayer.prototype.loadNext = function () {
this.log('func: loadNext');
var trackCount = this.bbaudio.find("source").length;
var newTrack = ((1 + this.currentTrack) % trackCount);
this.loadTrack(newTrack);
};
// Load previous track in playlist
BBPlayer.prototype.loadPrevious = function () {
this.log('func: loadPrevious');
var trackCount = this.bbaudio.find('source').length;
var newTrack = (this.currentTrack + (trackCount - 1)) % trackCount;
this.loadTrack(newTrack);
};
// Set up event handlers for audio element events
BBPlayer.prototype.setAudioEventHandlers = function () {
var self = this;
self.log('func: setAudioEventHandlers');
self.bbaudio.on('abort', function () {
self.log('event: audio abort');
});
// Update display and continue play when song has loaded
self.bbaudio.on('canplay', function () {
self.log('event: audio canplay');
if (self.state === 'playing' && $(this).get(0).paused) {
$(this).get(0).play();
}
self.updateDisplay();
});
self.bbaudio.on('canplaythrough', function () {
self.log('event: audio canplaythrough');
});
self.bbaudio.on('durationchange', function () {
self.log('event: audio durationchange');
});
self.bbaudio.on('emptied', function () {
self.log('event: audio emptied');
});
// Load next track when current one ends
self.bbaudio.on('ended', function () {
self.log('event: audio ended');
self.loadNext();
});
self.bbaudio.on('error', function () {
self.log('event: audio error');
});
self.bbaudio.on('loadeddata', function () {
self.log('event: audio loadeddata');
});
self.bbaudio.on('loadedmetadata', function () {
self.log('event: audio loadedmetadata');
});
self.bbaudio.on('loadstart', function () {
self.log('event: audio loadstart');
});
self.bbaudio.on('pause', function () {
self.log('event: audio pause');
});
self.bbaudio.on('play', function () {
self.log('event: audio play');
});
self.bbaudio.on('playing', function () {
self.log('event: audio playing');
});
self.bbaudio.on('progress', function () {
self.log('event: audio progress');
});
self.bbaudio.on('ratechange', function () {
self.log('event: audio ratechange');
});
self.bbaudio.on('seeked', function () {
self.log('event: audio seeked');
});
self.bbaudio.on('seeking', function () {
self.log('event: audio seeking');
});
self.bbaudio.on('stalled', function () {
self.log('event: audio stalled');
});
self.bbaudio.on('suspend', function () {
self.log('event: audio suspend');
});
self.bbaudio.on('timeupdate', function () {
// self.log('event: audio timeupdate');
self.updateDisplay();
});
self.bbaudio.on('volumechange', function () {
self.log('event: audio volumechange');
});
self.bbaudio.on('waiting', function () {
self.log('event: audio waiting');
});
};
// Change BBPlayer to play state
BBPlayer.prototype.play = function () {
stopAllBBPlayers();
var self = this;
self.log('func: play');
self.bbaudio.get(0).play();
self.state = "playing";
var playButton = self.bbplayer.find(".bb-play");
playButton.removeClass("bb-paused");
playButton.addClass("bb-playing");
};
// Change BBPlayer to pause state
BBPlayer.prototype.pause = function () {
this.log('func: pause');
this.bbaudio.get(0).pause();
this.state = "paused";
var playButton = this.bbplayer.find(".bb-play");
playButton.removeClass("bb-playing");
playButton.addClass("bb-paused");
};
// Set up button click handlers
BBPlayer.prototype.setClickHandlers = function () {
var self = this;
self.log('func: setClickHandlers');
var audioElem = self.bbaudio.get(0);
// Activate fast-forward
self.bbplayer.find('.bb-forward').click(function () {
self.log('event: click .bb-forward');
self.loadNext();
});
// Toggle play / pause
self.bbplayer.find('.bb-play').click(function () {
self.log('event: click .bb-play');
if (self.state === "paused") { //(audioElem.paused) {
self.play();
} else {
self.pause();
}
self.updateDisplay();
});
// Activate rewind
self.bbplayer.find('.bb-rewind').click(function () {
self.log('event: click .bb-rewind');
var time = audioElem.currentTime;
if (time > 1.5) {
audioElem.currentTime = 0;
} else {
self.loadPrevious();
}
});
// TODO make debug more "pluggy".
if (self.bbdebug) {
self.bbdebug.click(function () {
$(this).empty();
});
}
};
// BBPlayer initialisation
BBPlayer.prototype.init = function () {
var self = this;
self.setAudioEventHandlers();
self.loadSources();
// self.loadTrack (0);
self.currentTrack = 0;
self.setClickHandlers();
self.updateDisplay();
};
// Create BBPlayer Object for each element of .bbplayer class
$(document).ready(function () {
$(".bbplayer").each(function (x) {
bbplayers[x] = new BBPlayer($(this));
});
});
}());