Skip to content

Instantly share code, notes, and snippets.

@robrocker7
Created March 11, 2013 14:35
Show Gist options
  • Save robrocker7/5134669 to your computer and use it in GitHub Desktop.
Save robrocker7/5134669 to your computer and use it in GitHub Desktop.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
/******************************/
/* Application */
/******************************/
function PlayerApp() {
var VERSION = '1.0.0';
var me = this;
var template = null;
var element = null;
/******************************/
/* Models */
/******************************/
// TODO : Write better model functionality
var Song = {
imageUrl: null,
title: null,
artist: null,
album: null,
mediaUrl: null,
mediaResource: null,
mediaId: null,
searchKey: null,
liked: false
};
var MediaObj = {
mediaId: null,
mediaName: null,
image: null,
type: null,
url: null,
stationId: null
};
me.init = function() {
// init funciton
me.streamController = new StreamController();
me.previewController = new PreviewController();
// initial handlebars template
var source = $("#player-template").html();
me.element = $('#player .player-controller');
me.template = Handlebars.compile(source);
// load initial song data for default images
var song = $(me.Song).clone();
song.imageUrl = '/static/core/img/blank_58x58.jpg';
var media = $(me.MediaObj).clone();
media.image = '/static/core/img/blank_58x58.jpg';
me.streamController.set('currentSong', song);
me.streamController.set('currentMedia', media);
me._renderHtml();
};
me._renderHtml = function() {
me.element.html(me.template(me.streamController));
}
me._getTime = function(nMSec) {
var nSec = Math.floor(nMSec/1000),
min = Math.floor(nSec/60),
sec = nSec-(min*60);
return min+':'+(sec<10?'0'+sec:sec);
};
me._getDurationEstimate = function(oSound) {
if (oSound.instanceOptions.isMovieStar) {
return (oSound.duration);
} else {
return (!oSound._data.metadata || !oSound._data.metadata.data.givenDuration ? (oSound.durationEstimate||0) : oSound._data.metadata.data.givenDuration);
}
};
};
/******************************/
/* Controllers */
/******************************/
var PlayerController = Class.extend({
trackSound: null,
volume: 75,
songsPlayed: 0,
state: 'stopped',
currentSong: null,
progress_element: null,
init: function(){
this._self = this;
var _self = this._self;
$(document).on('click', '#pause-btn', function(e){
e.preventDefault();
_self.pause();
});
$(document).on('click', '#play-btn', function(e){
e.preventDefault();
_self.play();
});
},
stop: function() {
if (!this._self.trackSound) {
return false;
}
this._self.trackSound.stop();
this._self.trackSound.destruct();
this._self.trackSound = null;
this._self.set('state', 'stopped');
},
play: function() {
if (!this._self.trackSound) {
return false;
}
this._self.trackSound.play();
this._self.trackSound.unmute();
this._self.set('state', 'playing');
},
pause: function() {
if (!this._self.trackSound) {
return false;
}
this._self.trackSound.pause()
this._self.set('state', 'paused');
},
updateProgress: function(position, duration) {
$(this._self.progress_element).find(".prog-position").text(PlayerApp._getTime(position, true));
$(this._self.progress_element).find(".prog-duration").text(PlayerApp._getTime(duration, true));
$(this._self.progress_element).find(".prog-bar").css('width', ((position/PlayerApp._getDurationEstimate(this._self.trackSound))*100)+'%');
},
});
var PreviewController = PlayerController.extend({
init: function(){
this._super();
var _self = this._self;
$(document).on('click', '#preview-play-action', function(e){
e.preventDefault();
_self.stop();
});
$(document).on('click', '.headphone-icon', function(e){
e.preventDefault();
var parent = $(this).parent();
media = {
type: 'sample',
id: parent.attr('data-id'),
source: 'msr'
};
_self.getSong(media);
});
this._self.progress_element = $('#preview-progress');
},
set: function(key, value) {
this._self[key] = value;
this._self.observer();
},
getSong: function(media) {
// had to init this var because we need ot call self in the resolveMedia
var _self = this._self;
_self.set('state', 'loading');
if (_self.trackSound) {
_self.stop();
}
//$('#player-loading').fadeIn('slow');
PlayerApp.mediaController.resolveSampleMedia(media, function(song) {
if(song) {
_self.trackSound = soundManager.createSound({
id: 'S-' + song.mediaId,
serverURL: song.mediaUrl,
url: song.mediaResource,
bufferTime: 6,
autoLoad: true,
onconnect: function (bSuccess) {
if(bSuccess) {
_self.play();
_self.updateProgress(this.position, this.duration);
} else {
// TODO: log and report issue
}
},
onfinish: function () {
_self.stop();
// TODO start playing streamer
},
volume: (_self.volume >= 0 ? _self.volume : 75),
whileloading: function () {
},
whileplaying: function () {
_self.updateProgress(this.position, this.duration);
}
});
_self.set('currentSong', song);
} else {
// TODO Properly handle no song return
}
});
},
observer: function() {
switch(this._self.state) {
case 'stopped':
console.log('stopped');
if(PlayerApp.streamController.state == 'paused') {
PlayerApp.streamController.play();
}
if($('#preview-player').is(":visible")) {
$('#preview-player').hide();
}
break;
case 'playing':
console.log('playing');
break;
case 'paused':
console.log('paused');
break;
case 'loading':
console.log('loading');
if($('#preview-player').is(":hidden")) {
$('#preview-player').show();
}
// if the streamer is playing pause it
if(PlayerApp.streamController.state == 'playing') {
PlayerApp.streamController.pause();
}
break;
}
}
});
var StreamController = PlayerController.extend({
currentMedia: null,
init: function(){
this._super();
var _self = this._self;
$(document).on('click', '#skip-btn', function(e){
e.preventDefault();
_self.skip();
});
$(document).on("click", '.play-me', function(e) {
_self.prepareSong(e);
});
$(document).on("click", '.play-button span.myx-pause', function(e) {
e.preventDefault();
$('#pause-btn').trigger('click');
});
this._self.progress_element = $('#progress');
},
set: function(key, value) {
this._self[key] = value;
PlayerApp._renderHtml();
this._self.observer();
},
skip: function() {
if (!this.trackSound) {
return false;
}
this._self.getSong(null);
this._self.set('state', 'loading');
},
changeVolume: function(value) {
if (!this._self.trackSound) {
return false;
}
this._self.volume = value;
this._self.trackSound.setVolume(value);
},
prepareSong: function(e) {
var target = $(e.target);
var data = e.data;
var mediaId = null;
var type = null;
var meta = null;
var name = null;
if (data && data.mediaId) {
mediaId = data.mediaId;
type = data.type;
meta = data.meta;
name = data.name;
} else {
mediaId = target.attr('media-id');
type = target.attr('media-type');
meta = target.attr('media-meta');
name = target.attr('media-name');
}
// set the station controller ID to make sure the
// like/dislike buttons work
if (type=='stations' && window.stationController){
window.stationController.stationId = mediaId;
}
$('.play-me').attr('media-meta','');
// if the same media id is already playing we don't need to ask for another song
// should try to play the paused content
current_mediaId = null;
if(this._self.currentMedia) {
current_mediaId = this._self.currentMedia.mediaId;
}
if(mediaId == current_mediaId){
$('#play-btn').trigger('click');
} else {
this._self.getSong({id:mediaId,type:type,meta:meta,name:name});
}
},
getSong: function(media) {
// had to init this var because we need ot call self in the resolveMedia
var _self = this._self;
_self.set('state', 'loading');
if (_self.trackSound) {
_self.stop();
}
$('#player-loading').fadeIn('slow');
PlayerApp.mediaController.resolveMedia(media, function(song, mediaInfo) {
if(song) {
_self.trackSound = soundManager.createSound({
id: 'S-' + song.mediaId,
serverURL: song.mediaUrl,
url: song.mediaResource,
bufferTime: 6,
autoLoad: true,
onconnect: function (bSuccess) {
if(bSuccess) {
_self.play();
_self.set('songsPlayed', _self.songsPlayed + 1);
_self.updateProgress(this.position, this.duration);
// update personalize state
$('.thumbs-up').removeClass('active');
if(song.liked) {
$('.thumbs-up').addClass('active');
}
} else {
// TODO: log and report issue
}
},
onfinish: function () {
_self.stop();
_self.getSong(null);
},
volume: (_self.volume >= 0 ? _self.volume : 75),
whileloading: function () {
},
whileplaying: function () {
_self.updateProgress(this.position, this.duration);
// if (me.state !== 'paused') {
// me.set('state', 'playing');
// }
}
});
_self.set('currentSong', song);
_self.set('currentMedia', mediaInfo);
} else {
// TODO Properly handle no song return
}
});
},
observer: function() {
switch(this._self.state) {
case 'stopped':
console.log('stopped');
$('#player-loading').hide();
$('#pause-btn').hide();
$('#play-btn').show();
$('.play-button span').removeClass('myx-pause').addClass('myx-play');
break;
case 'playing':
console.log('playing');
$('#player-loading').hide();
$('#pause-btn').show();
$('#play-btn').hide();
$('.play-button span').removeClass('myx-pause').addClass('myx-play');
$('.play-button[media-id="'+PlayerApp.streamController.currentMedia.mediaId+'"]'
).removeClass('play-me').children('span').removeClass('myx-play').addClass('myx-pause');
break;
case 'paused':
console.log('paused');
$('#player-loading').hide();
$('#pause-btn').hide();
$('#play-btn').show();
$('.play-button span').removeClass('myx-pause').addClass('myx-play');
$('.play-button[media-id="'+PlayerApp.streamController.currentMedia.mediaId+'"]'
).addClass('play-me');
break;
case 'loading':
console.log('loading');
$('#player-loading').show();
break;
}
}
});
window.PlayerApp = new PlayerApp();
PlayerApp.init();
$(document).ready(function() {
$('.button-like').live('click', function(){
$(this).effect('bounce');
$(this).addClass('active');
PlayerApp.streamController.songAction('like');
});
$('.button-dislike').live('click', function(){
$(this).effect('bounce');
PlayerApp.streamController.songAction('dislike');
});
$( "#volume-slider" ).slider({
orientation: "vertical",
range: "min",
min: 0,
max: 100,
value: 75,
slide: function( event, ui ) {
PlayerApp.streamController.changeVolume(ui.value);
// TODO: Save volume to cookies
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment