1
0
Fork 0

It plays stuff, sort off

master
Matthieu Lalonde 12 years ago
parent 08b5a8e62a
commit d7243f5b3b

@ -81,6 +81,8 @@ _
, initialize: function() { , initialize: function() {
_.bindAll(this _.bindAll(this
, "_serversInited"
, "_routerActionAbout" , "_routerActionAbout"
, "_routerActionPlaylist" , "_routerActionPlaylist"
, "_routerActionClient" , "_routerActionClient"
@ -105,14 +107,19 @@ _
this.playlist = new PlaylistCollection(); this.playlist = new PlaylistCollection();
this.servers.on("add", function (server) { var serverLength = 0
server.save(); , serverCbInit = function (server) {
}); if (serverLength > 1) {
--serverLength;
} else {
that._serversInited();
}
};
async.waterfall([ async.waterfall([
function __asyncAppFetchServerCollection(callback) { function __asyncAppFetchServerCollection(callback) {
that.servers.fetch({ that.servers.fetch({
success: function (collection, modelsAttributes) { success: function __fnApEventServersFetched(collection, modelsAttributes) {
if (modelsAttributes.length === 0) { if (modelsAttributes.length === 0) {
console.info("Adding default daap server"); console.info("Adding default daap server");
collection.add(Config.daap); collection.add(Config.daap);
@ -126,11 +133,14 @@ _
} }
, function __asyncAppAttachStateEvents(servers, callback) { , function __asyncAppAttachStateEvents(servers, callback) {
async.forEach(that.servers.models, function (server) { serverLength = servers.length;
that._serverInit(server);
async.forEach(that.servers.models, function __fnAppCbServerInit(server) {
that._serverInit(server, serverCbInit);
}); });
that.servers.on("add", function (server) { that.servers.on("add", function __fnAppCbServerAdded(server) {
server.save();
that._serverInit(server); that._serverInit(server);
}); });
@ -149,6 +159,7 @@ _
that.Views.Player = new PlayerView({ that.Views.Player = new PlayerView({
el: that.Views.App.Layout.panes.north el: that.Views.App.Layout.panes.north
, servers: that.servers
}); });
that.Views.Footer = new FooterView({ that.Views.Footer = new FooterView({
@ -166,12 +177,12 @@ _
that.Views.Main.setView("playlist", that.Views.Playlist); that.Views.Main.setView("playlist", that.Views.Playlist);
that.View.Main.on("action:item", function __fnAppEventMainViewActionItem (event) { that.Views.Main.on("action:item", function __fnAppEventMainViewActionItem (event) {
}); });
that.View.Main.on("action:playorder", function __fnAppEventMainViewActionItem (event) { that.Views.Main.on("action:playorder", function __fnAppEventMainViewActionItem (event) {
that.Views.Player.setPlayIndex(event);
}); });
that.Views.Footer.on("toggle:sidebar", function __fnAppEventTogglerSiderBar (event) { that.Views.Footer.on("toggle:sidebar", function __fnAppEventTogglerSiderBar (event) {
@ -180,11 +191,11 @@ _
}); });
that.Views.Footer.on("toggle:random", function __fnAppEventTogglerRandom (event) { that.Views.Footer.on("toggle:random", function __fnAppEventTogglerRandom (event) {
// TODO:... that.Views.Player.setRandomState(event);
}); });
that.Views.Footer.on("toggle:repeat", function __fnAppEventTogglerRepeater (event) { that.Views.Footer.on("toggle:repeat", function __fnAppEventTogglerRepeater (event) {
// TODO:... that.Views.Player.setRepeatState(event);
}); });
that.Views.Footer.on("show:about", that.__showModalAbout); that.Views.Footer.on("show:about", that.__showModalAbout);
@ -228,6 +239,17 @@ _
return this; return this;
} }
, _serversInited: function () {
var that = this
;
console.debug("All Base Servers Inited!");
that.Views.Player.init();
that.Views.Player.playAtIndex(0);//Math.floor(Math.random() * that.Views.Player._playIndex.length));
}
, _routerDefaultAction: function () { , _routerDefaultAction: function () {
var that = this var that = this
; ;
@ -317,7 +339,7 @@ _
that.Views.Main.showView(server.get("hostname")); that.Views.Main.showView(server.get("hostname"));
} }
, _serverInit: function(server) { , _serverInit: function(server, cbInit) {
var that = this var that = this
; ;
@ -327,6 +349,10 @@ _
server.client.off("all"); server.client.off("all");
server.client.on("inited", function __fnAppEventClientInited(client) {
cbInit(null, client);
});
server.client.on("state", function __fnAppEventClientStateChange(client, state) { server.client.on("state", function __fnAppEventClientStateChange(client, state) {
if (state === ClientModel.defaults._states.loading) { if (state === ClientModel.defaults._states.loading) {
if (that.loadingStates === 0) { if (that.loadingStates === 0) {

@ -0,0 +1,81 @@
/*jslint laxbreak:true */
/*jslint laxcomma:true */
/*jslint loopfunc:true */
/*jslint strict:true */
/*jslint browser:true */
/*jslint devel:true */
/**
* TODO: If the user agrees, set the username/passs in a cookie
**/
define([
], function (
) {
"use strict";
var MIMESClass = function() {};
MIMESClass.prototype.get = function (file) {
var fileExtension = '';
var dotPos = 0;
var audioType = undefined;
if ((dotPos = file.indexOf('.')) >= 0) {
fileExtension = file.substring(dotPos + 1);
} else {
fileExtension = file;
}
switch (fileExtension) {
// TODO: Add ogg/flac (video?)
case "mp3":
audioType = "audio/mpeg";
break;
case "au":
case "snd":
audioType = "audio/basic";
break;
case "wav":
audioType = "audio/x-wav";
break;
case "aif":
case "aifc":
audioType = "audio/aiff";
break;
case "m4a":
case "mp4":
case "mp4a":
audioType = "audio/mp4";
break;
case "ogg":
case "oga":
audioType = "audio/ogg";
break;
case "flac":
audioType = "audio/flac";
break;
case "axa":
audioType = "audio/annodex";
break;
case "vorb":
audioType = "audio/vorbis";
break;
case "spx":
audioType = "audio/speex";
break;
default:
console.info('Unknown type: ' + fileExtension);
break;
}
return audioType;
};
return new MIMESClass();
});

@ -4,8 +4,8 @@
/*jslint strict:true */ /*jslint strict:true */
/*jslint browser:true */ /*jslint browser:true */
/*jslint devel:true */ /*jslint devel:true */
require.config({ requirejs.config({
shim: { shim: {
"jquery-ui": ["jquery"] "jquery-ui": ["jquery"]
, "jquery-event-drag": ["jquery"] , "jquery-event-drag": ["jquery"]
, "jquery-layout": ["jquery", "jquery-ui"] , "jquery-layout": ["jquery", "jquery-ui"]
@ -19,11 +19,11 @@ require.config({
, "bootstrap-contextmenu": ["bootstrap"] , "bootstrap-contextmenu": ["bootstrap"]
, "jquery": { , "jquery": {
exports: "$" exports: "$"
} }
, "backbone": { , "backbone": {
//These script dependencies should be loaded before loading //These script dependencies should be loaded before loading
//backbone.js //backbone.js
deps: [ deps: [
@ -38,16 +38,16 @@ require.config({
deps: ["backbone"] deps: ["backbone"]
} }
, "underscore": { , "underscore": {
exports: "_" exports: "_"
} }
, "toolbox": { , "toolbox": {
exports: "Toolbox" exports: "Toolbox"
, deps: ["underscore"] , deps: ["underscore"]
} }
, "toolbox-extras": { , "toolbox-extras": {
deps: ["toolbox"] deps: ["toolbox"]
} }
@ -60,7 +60,7 @@ require.config({
} }
} }
, paths: { , paths: {
"jquery": "../vendors/jquery/1.8.2/jquery.min" "jquery": "../vendors/jquery/1.8.2/jquery.min"
, "jquery-ui": "../vendors/jquery/ui/1.9.0/jquery-ui-all" , "jquery-ui": "../vendors/jquery/ui/1.9.0/jquery-ui-all"
, "jquery-event-drag": "../vendors/jquery/event-drag/2.2/jquery.event.drag" , "jquery-event-drag": "../vendors/jquery/event-drag/2.2/jquery.event.drag"
@ -88,23 +88,45 @@ require.config({
, "async": "../vendors/async" , "async": "../vendors/async"
} }
, baseUrl: "/resources/js" , baseUrl: "/resources/js"
, urlArgs: "v=0.3.2" , urlArgs: "v=0.3.2"
});
require([ , catchError: true
"app" });
requirejs([
"underscore"
, "jquery" , "jquery"
, "app"
, "text!../templates/app/modal-fatal.html"
] ]
, function __fnMainRequireLoader ( App, $ ) { , function __fnMainRequireLoader (
_
, $
, App
, tmplModalFatal
) {
"use strict"; "use strict";
// JQuery Backwords compatibility fix // JQuery Backwords compatibility fix
$.curCSS = $.css; $.curCSS = $.css;
$("body").ready(function __fnAppRequireLoader () { $("body").ready(function __fnAppRequireLoader () {
// We export App to window for debuging purposes. //try {
window.App = new App(); // We export App to window for debuging purposes.
window.App = new App();
/*} catch (e) {
console.log("LAWL");
$("body").html("");
var modalFatal = $(_.template(tmplModalFatal)({
ERROR_REPORTING: e.toString()
}));
modalFatal.modal();
}*/
}); });
}); });

@ -29,6 +29,7 @@ define([
, "buildRequestUid" , "buildRequestUid"
, "url" , "url"
, "urlHost" , "urlHost"
, "urlMedia"
, "xhr" , "xhr"
, "fetchXHR" , "fetchXHR"
@ -40,7 +41,7 @@ define([
, "fetchPlaylists" , "fetchPlaylists"
, "fetchPlaylist" , "fetchPlaylist"
, "fetchBrowse" , "fetchBrowse"
, "fetchgenres" , "fetchGenres"
, "fetchArtists" , "fetchArtists"
, "fetchAlbums" , "fetchAlbums"
@ -172,14 +173,18 @@ define([
uri = request; // Add leading slash here! uri = request; // Add leading slash here!
} }
if (_.isNumber(this.collections.session.id)) { if (_.isNumber(that.collections.session.id)) {
var prefix = "?"; var prefix = "?";
if (uri.indexOf("?") >= 0) { if (uri.indexOf("?") >= 0) {
prefix = "&"; prefix = "&";
} }
uri += prefix + "session-id=" + this.collections.session.id; uri += prefix + "session-id=" + that.collections.session.id;
}
if (uri.charAt(0) !== "/" && uri.charAt(0) !== "?") {
uri = "/" + uri;
} }
return this.attributes.protocol + "://" + this.urlHost() + uri; return this.attributes.protocol + "://" + this.urlHost() + uri;
@ -192,6 +197,14 @@ define([
return this.attributes.hostname + ":" + this.attributes.port; return this.attributes.hostname + ":" + this.attributes.port;
} }
, urlMedia: function (itemid, type, dbid) {
if (_.isUndefined(dbid) || !_.isNumber(dbid)) {
dbid = 1;
}
return this.url("/databases/" + dbid + "/items/" + itemid + "." + type);
}
// TODO: Could be interesting to set a useragent, could possibly affect transcoding on the server side // TODO: Could be interesting to set a useragent, could possibly affect transcoding on the server side
, xhr: function (url, responseType, callback) { , xhr: function (url, responseType, callback) {
var that = this var that = this
@ -292,7 +305,18 @@ define([
var that = this var that = this
; ;
that.fetchXHR("/login", success, error); // TODO: Check for a cookie here...
that.fetchXHR("/login", function __fetchServerInfoCallback(content) {
var Results = new DMAPModel(content, {
contentCodes: that.collections.contentCodes
});
that.collections.session.id = Results.get("dmap_sessionid");
if (_.isFunction(success)) {
success(that.collections.session);
}
}, error);
} }
, fetchDatabases: function (success, error) { , fetchDatabases: function (success, error) {

@ -32,6 +32,8 @@ define([
// that.save(); // that.save();
} }
that.trigger("inited", that);
//that.client.fetchDatabases(that.client.fetchDatabase); //that.client.fetchDatabases(that.client.fetchDatabase);
}); });

@ -24,13 +24,23 @@ _
, preload: "auto" , preload: "auto"
, controls: false , controls: false
, loop: false , loop: false
, src: "" , src: false
} }
, obj: new Audio() , obj: new Audio()
, $obj: null , $obj: null
, _states: {
stopped: 0
, error: 1
, loading: 2
, playing: 3
, paused: 4
}
, _state: 0
, constructor: function () { , constructor: function () {
var that = this var that = this
; ;
@ -45,6 +55,8 @@ _
, "__audioError" , "__audioError"
, "__audioPause" , "__audioPause"
, "__audioPlay" , "__audioPlay"
, "__audioSeeking"
, "__audioSeeked"
, "__audioTimeUpdate" , "__audioTimeUpdate"
, "__audioLoadStart" , "__audioLoadStart"
, "__audioCanPlay" , "__audioCanPlay"
@ -53,18 +65,40 @@ _
that.$obj = $(that.obj); that.$obj = $(that.obj);
that.obj.attributes = _.extend({}, that.obj.attributes, that._defaultOpts); _.each(that._defaultOpts, function (value, key) {
if (value !== false) {
that.obj.setAttribute(key, value);
}
});
that._bindAudio();
return that; return that;
} }
/** /**
* PUBLIC * PUBLIC
**/ **/
, loadMedia: function (uri) { , loadMedia: function (uri, mime, callback) {
var that = this var that = this
, audioSource = document.createElement('source')
; ;
that.obj.stop(); audioSource.src = uri;
that.obj.src = uri;
audioSource.type = mime;
that.obj.type = mime;
that.obj.innerHTML = "";
that.obj.appendChild(audioSource);
console.debug("Loading media: " + uri + "\t type: " + mime);
that._state = that._states.loading;
that.obj.load();
return callback && callback();
} }
/** /**
* PRIVATE * PRIVATE
@ -81,7 +115,7 @@ _
//that.$obj.on("suspend", that.__audioSuspend); //that.$obj.on("suspend", that.__audioSuspend);
//that.$obj.on("abort", that.__audioAbort); that.$obj.on("abort", that.__audioError);
that.$obj.on("error", that.__audioError); that.$obj.on("error", that.__audioError);
@ -104,9 +138,9 @@ _
//that.$obj.on("canplaythrough", that.__audioCanPlayThrough); //that.$obj.on("canplaythrough", that.__audioCanPlayThrough);
//that.$obj.on("seeking", that.__audioSeeking); that.$obj.on("seeking", that.__audioSeeking);
//that.$obj.on("seeked", that.__audioSeeked); that.$obj.on("seeked", that.__audioSeeked);
that.$obj.on("timeupdate", that.__audioTimeUpdate); that.$obj.on("timeupdate", that.__audioTimeUpdate);
@ -114,7 +148,7 @@ _
//that.$obj.on("ratechange", that.__audioRateChanged); //that.$obj.on("ratechange", that.__audioRateChanged);
//that.$obj.on("durationchange", that.__audioDurationChange); //that.$obj.on("durationchange", that.__audioDurationChange); // TODO: We probably need to implement this!
//that.$obj.on("volumechange", that.__audioVolumeChange); //that.$obj.on("volumechange", that.__audioVolumeChange);
} }
@ -123,34 +157,73 @@ _
* EVENTS * EVENTS
**/ **/
, __audioProgress: function (event) { , __audioProgress: function (event) {
var that = this
;
that.trigger("progress", event);
} }
, __audioError: function (event) { , __audioError: function (event) {
var that = this
;
that._state = that._states.stopped;
that.trigger.apply(that, ["state", that._state]);
} }
, __audioPause: function (event) { , __audioPause: function (event) {
var that = this var that = this
; ;
that._state = that._states.paused;
that.trigger.apply(that, ["state", that._state]);
} }
, __audioPlay: function (event) { , __audioPlay: function (event) {
var that = this var that = this
; ;
that._state = that._states.playing;
that.trigger.apply(that, ["state", that._state]);
}
, __audioSeeking: function (event) {
var that = this
;
that._state = that._states.loading;
that.trigger.apply(that, ["state", that._state]);
}
, __audioSeeked: function (event) {
var that = this
;
that.obj.play();
that._state = that._states.playing;
that.trigger.apply(that, ["state", that._state]);
} }
, __audioTimeUpdate: function (event) { , __audioTimeUpdate: function (event) {
var that = this var that = this
; ;
that.trigger("timeupdate", event);
} }
, __audioLoadStart: function (event) { , __audioLoadStart: function (event) {
var that = this var that = this
; ;
that._state = that._states.loading;
that.trigger.apply(that, ["state", that._state]);
} }
, __audioCanPlay: function (event) { , __audioCanPlay: function (event) {
@ -163,6 +236,9 @@ _
var that = this var that = this
; ;
that._state = that._states.stopped;
that.trigger("ended", event);
} }
}, Backbone.Events)); }, Backbone.Events));

@ -121,6 +121,10 @@ _
, dbId: dbId , dbId: dbId
} }
}); });
that.Views.List.on("action:playorder", function __fnEventClientViewPlayOrder (event) {
that.trigger.apply(that, ["action:playorder", event]);
});
} }
, resize: function () { , resize: function () {

@ -97,7 +97,7 @@ _
if (!that.__timeoutDebounceRepeatButton) { if (!that.__timeoutDebounceRepeatButton) {
that.__timeoutDebounceRepeatButton = setTimeout(function () { that.__timeoutDebounceRepeatButton = setTimeout(function () {
that.trigger("toggle:repeat", that._stateRepeat); that.trigger("toggle:repeat", that._stateRepeat || null);
delete that.__timeoutDebounceRepeatButton; delete that.__timeoutDebounceRepeatButton;
}, 500); }, 500);

@ -480,6 +480,8 @@ console.log(parentWidth, that.$el.innerWidth(), parentHeight, that.$el, parentEl
that.dataTable.fnDraw(); that.dataTable.fnDraw();
that.resize(); that.resize();
that._setPlayOrder();
} }
, hide: function () { , hide: function () {
@ -488,6 +490,39 @@ console.log(parentWidth, that.$el.innerWidth(), parentHeight, that.$el, parentEl
this.$el.hide(); this.$el.hide();
} }
, _setPlayOrder: function () {
var that = this
, playIndex = []
;
playIndex = _.map(that.dataTable.fnSettings().aiDisplay, function (id, index) {
var itemData = that.dataTable.fnGetData(id)
, itemIndex = {}
;
if (that.options.type === "playlist") {
itemIndex.hostname = itemData.server;
itemIndex.dbId = itemData.database;
itemIndex.playlist = true;
} else {
itemIndex.hostname = that.options.client.hostname;
itemIndex.dbId = that.options.client.dbId;
itemIndex.playlist = null;
}
itemIndex.dmap_itemname = itemData["dmap_itemname"];
itemIndex.daap_songartist = itemData["daap_songartist"];
itemIndex.daap_songtime = itemData["daap_songtime"];
itemIndex.type = itemData["daap_songformat"];
itemIndex.id = itemData["dmap_persistantid"] || itemData["dmap_itemid"] || itemData["dmap_containeritemid"] || itemData["id"];
return itemIndex;
});
that.trigger("action:playorder", playIndex);
}
}); });
return List; return List;

@ -35,6 +35,7 @@ _
, "resizeView" , "resizeView"
//, "toggleView" //, "toggleView"
, "destroyView" , "destroyView"
, "_setPlayOrder"
); );
//that.setView("playlist", new ListView(playlistCollection)); //that.setView("playlist", new ListView(playlistCollection));
@ -67,6 +68,8 @@ _
that.$el.append(that.children[name].$el); that.$el.append(that.children[name].$el);
} }
that.children[name].on("action:playorder", that._setPlayOrder);
if (that.children[name].show) { if (that.children[name].show) {
that.children[name].show(); that.children[name].show();
} }
@ -102,9 +105,13 @@ _
that.children[name].$el.hide(); that.children[name].$el.hide();
that.children[name].off("action:player");
setTimeout(function __fnTimeoutMainViewHide() { setTimeout(function __fnTimeoutMainViewHide() {
that.children[name].$el.detach(); that.children[name].$el.detach();
delete that.current;
return callback && callback(); return callback && callback();
}, 50); }, 50);
} }
@ -131,6 +138,13 @@ _
, destroyView: function (name) { , destroyView: function (name) {
} }
, _setPlayOrder: function (event) {
var that = this
;
that.trigger.apply(that, ["action:playorder", event]);
}
}); });
return Main; return Main;

@ -11,6 +11,8 @@ define([
, "modules/webaudio" , "modules/webaudio"
, "libs/mimes"
, "text!../../templates/player/layout.html" , "text!../../templates/player/layout.html"
, "text!../../templates/player/player-status.html" , "text!../../templates/player/player-status.html"
] ]
@ -21,6 +23,8 @@ _
, WebAudio , WebAudio
, MIMES
, tmplPlayerLayout , tmplPlayerLayout
, tmplPlayerStatus , tmplPlayerStatus
) { ) {
@ -50,6 +54,7 @@ _
Player = Backbone.View.extend({ Player = Backbone.View.extend({
elViewport: null elViewport: null
, $elViewport: null , $elViewport: null
, $elVolumeInput: null
, playIndex: [] , playIndex: []
@ -61,6 +66,12 @@ _
, _stateRepeat: null , _stateRepeat: null
, _statesRepeat: {
none: null
, one: false
, all: true
}
, _stateMute: null , _stateMute: null
, _stateVolume: null , _stateVolume: null
@ -76,22 +87,24 @@ _
, paused: 3 , paused: 3
} }
, debouncers: {}
, events: { , events: {
//"click #add-friend": "showPrompt", //"click #add-friend": "showPrompt",
"click div:first-child > a.buttonPrev": "click div:first-child > a.buttonPrev:not(.disabled)":
"__buttonPrevious" "__buttonPrevious"
, "click div:first-child > a.buttonNext": , "click div:first-child > a.buttonNext:not(.disabled)":
"__buttonNext" "__buttonNext"
, "click div:first-child > a.buttonPlay": , "click div:first-child > a.buttonPlay:not(.disabled)":
"__buttonPlayPause" "__buttonPlayPause"
// Volume Down // Volume Down
, "click div:first-child > .playerVolumeWrapper > a:first-child": , "click div:first-child > .playerVolumeWrapper > a:first-child:not(.disabled)":
"__buttonVolumeDown" "__buttonVolumeDown"
// Volume Up // Volume Up
, "click div:first-child > .playerVolumeWrapper > a:last-child": , "click div:first-child > .playerVolumeWrapper > a:last-child:not(.disabled)":
"__buttonVolumeUp" "__buttonVolumeUp"
// Volume click // Volume click
, "click div:first-child > .playerVolumeWrapper > input": , "click div:first-child > .playerVolumeWrapper > input:not(disabled)":
"__buttonVolumeClick" "__buttonVolumeClick"
// Seek input // Seek input
, "click div:last-child > .playerProgressWrapper > progress": , "click div:last-child > .playerProgressWrapper > progress":
@ -103,12 +116,15 @@ _
; ;
_.bindAll(this _.bindAll(this
// Public // Public
, "init"
, "setPlayIndex" , "setPlayIndex"
, "sortPlayIndex"
, "setRandomState" , "setRandomState"
, "setRepeatState" , "setRepeatState"
, "playItem" , "playItem"
// Events , "playAtIndex"
// Events
, "__buttonPlayPause" , "__buttonPlayPause"
, "__buttonNext" , "__buttonNext"
, "__buttonPrevious" , "__buttonPrevious"
@ -116,21 +132,31 @@ _
, "__buttonVolumeDown" , "__buttonVolumeDown"
, "__buttonVolumeClick" , "__buttonVolumeClick"
, "__buttonSeek" , "__buttonSeek"
// Private // Private
, "_waCreate" , "_waCreate"
, "_waBindEvents" , "_waBindEvents"
, "__waStateChanged" , "__waStateChanged"
, "_playerEnded" , "__waEnded"
, "__waTimeUpdate"
, "_playerPlay"
, "_playerLoading" , "_playerLoading"
, "_playNext" , "_playNext"
, "_playPrevious" , "_playPrevious"
, "_playerPause" , "_playerPause"
, "_playerUnpause"
, "_playerStop" , "_playerStop"
, "_playerStart" , "_playerStart"
, "_getVolume"
, "_setVolume" , "_setVolume"
, "_seek"
, "_playBtnSetState"
, "_disableControls"
, "_enableControls"
, "_getItemData" , "_getItemData"
, "_getItemMediaUrl" , "_getItemMediaUrl"
, "_setViewport" , "_setViewport"
, "_progressSetLoadding"
, "_updateViewportProgress" , "_updateViewportProgress"
); );
@ -141,7 +167,9 @@ _
that.elViewport = document.createElement("div"); that.elViewport = document.createElement("div");
that.$elViewport = $(that.elViewport); that.$elViewport = $(that.elViewport);
that.$elViewport.html(_.template(tmplPlayerStatus)({})); that._setViewport();
that.$elVolumeInput = that.$el.find(".playerVolumeWrapper > input");
that.$el.append(that.elViewport); that.$el.append(that.elViewport);
@ -153,18 +181,42 @@ _
/** /**
* PUBLIC * PUBLIC
**/ **/
, setPlayIndex: function (index) { , init: function () {
var that = this var that = this
; ;
that._playIndex = index; that._enableControls();
that._playCursor = 0;
that.$elVolumeInput.val(that.webAudio.obj.volume);
}
if (that._stateRandom) { , setPlayIndex: function (index, cursor) {
that.setRandomState(that._stateRandom); var that = this
;
if (that.webAudio._state === that.webAudio._states.loading) {
that._playerStop();
} }
return that._playIndex; if (that.webAudio._state < that.webAudio._states.loading) {
that._playIndex = index;
that._playCursor = cursor || 0;
if (that._stateRandom) {
that.setRandomState(that._stateRandom);
}
return that._playIndex;
} else {
return undefined;
}
}
, sortPlayIndex: function (index) {
var that = this
;
// TODO
} }
, setRandomState: function (random) { , setRandomState: function (random) {
@ -172,10 +224,13 @@ _
; ;
if (random === true) { if (random === true) {
that._playIndexOrdered = that._playIndex;
that._playIndex.shuffle(); that._playIndex.shuffle();
}
// TODO: Set cursor back to the item that was playing // TODO: Set cursor back to the item that was playing
} else {
that._playIndex = that._playIndexOrdered;
}
return that._stateRandom = random; return that._stateRandom = random;
} }
@ -188,51 +243,123 @@ _
} }
, playItem: function (item) { , playItem: function (item) {
var that = this
;
return that._playerPlay(item);
}
, playAtIndex: function (index) {
var that = this
;
that._playCursor = index;
that.playItem(that._playIndex[that._playCursor]);
} }
/** /**
* EVENTS * EVENTS
**/ **/
, __buttonPlayPause: function (event) { , __buttonPlayPause: function (event) {
var that = this var that = this
, $target = $(event.target)
; ;
switch (that.webAudio._state) {
case that.webAudio._states.stopped:
that._playNext();
break;
case that.webAudio._states.playing:
that._playerPause();
break;
case that.webAudio._states.paused:
that._playerUnpause();
break;
default:
break;
}
} }
, __buttonNext: function (event) { , __buttonNext: function (event) {
var that = this var that = this
; ;
that._playNext();
} }
, __buttonPrevious: function (event) { , __buttonPrevious: function (event) {
var that = this var that = this
; ;
that._playPrevious();
} }
, __buttonVolumeUp: function (event) { , __buttonVolumeUp: function (event) {
var that = this var that = this
, volume = that._getVolume()
; ;
if (volume < 1) {
if ((volume+0.1) > 1) {
volume = 1;
} else {
volume+= 0.1;
}
}
that._setVolume(volume);
} }
, __buttonVolumeDown: function (event) { , __buttonVolumeDown: function (event) {
var that = this var that = this
, volume = that._getVolume()
; ;
if (volume > 0) {
if ((volume-0.1) < 0) {
volume = 0;
} else{
volume-= 0.1;
}
}
that._setVolume(volume);
} }
, __buttonVolumeClick: function (event) { , __buttonVolumeClick: function (event) {
var that = this var that = this
, clientX = event.clientX
, left = event.target.offsetLeft
, clickoffset = clientX - left
, fraction = clickoffset/event.target.offsetWidth
; ;
that._setVolume(fraction);
} }
, __buttonSeek: function (event) { , __buttonSeek: function (event) {
var that = this var that = this
; ;
if (_.isUndefined(that.debouncers["__buttonSeek"])) {
var clientX = event.clientX
, left = event.target.offsetLeft
, clickoffset = clientX - left
, percent = clickoffset/event.target.offsetWidth
, seekTime = percent * that.webAudio.obj.duration
;
that._seek(seekTime);
that.debouncers["__buttonSeek"] = setTimeout(function __fnPlayerViewButtonSeekDebounce () {
clearTimeout(that.debouncers["__buttonSeek"]);
delete that.debouncers["__buttonSeek"];
}, 800);
}
} }
/** /**
@ -243,24 +370,84 @@ _
var that = this var that = this
; ;
return that.webAudio = new WebAudio(); that.webAudio = new WebAudio();
that._waBindEvents();
return that.webAudio;
} }
, _waBindEvents: function () { , _waBindEvents: function () {
var that = this
;
that.webAudio.on("state", function __fnPlayerEventWebAudioState (state) {
that.__waStateChanged.apply(that, arguments);
});
that.webAudio.on("ended", function __fnPlayerEventWebAudioState (state) {
that.__waEnded.apply(that, arguments);
});
that.webAudio.on("timeupdate", function __fnPlayerEventWebAudioState () {
that.__waTimeUpdate.apply(that, arguments);
});
} }
, __waStateChanged: function () { , __waStateChanged: function (state) {
var that = this var that = this
; ;
that._playBtnSetState(state);
switch (state) {
case that.webAudio._states.stopped:
console.debug("Player State Stopped");
//that._setViewport();
that._enableControls();
break;
case that.webAudio._states.error:
console.debug("Player State error");
that._disableControls();
break;
case that.webAudio._states.loading:
console.debug("Player State loading");
that._progressSetLoadding();
that._disableControls();
break;
case that.webAudio._states.playing:
console.debug("Player State playing");
that._enableControls();
break;
case that.webAudio._states.paused:
console.debug("Player State paused");
that._enableControls();
break;
}
} }
// Player Controls , __waEnded: function () {
, _playerEnded: function () {
var that = this var that = this
; ;
that._playNext();
}
, __waTimeUpdate: function (event) {
var that = this
;
that._updateViewportProgress(event.target.currentTime, event.target.duration);
}
// Player Controls
, _playerPlay: function (item) {
var that = this
;
that.webAudio.loadMedia(that._getItemMediaUrl(item), MIMES.get(item.type), function __fnPlayerViewCbLoaded () {
that._setViewport(item);
});
} }
, _playerLoading: function () { , _playerLoading: function () {
@ -273,24 +460,75 @@ _
var that = this var that = this
; ;
switch (that._stateRepeat) {
case that._statesRepeat.all:
case that._statesRepeat.none:
if (that._stateRepeat === that._statesRepeat.all
&& that._playIndex.length === (that._playCursor + 1)) {
that._playCursor = -1;
}
if (that._playIndex.length > (that._playCursor + 1)) {
that._playerPlay(that._playIndex[++that._playCursor]);
} else {
that._playerStop();
}
break;
case that._statesRepeat.one:
that._playerPlay(that._playIndex[that._playCursor]);
break;
}
} }
, _playPrevious: function () { , _playPrevious: function () {
var that = this var that = this
; ;
switch (that._stateRepeat) {
case that._statesRepeat.all:
case that._statesRepeat.none:
if (that._stateRepeat === that._statesRepeat.all
&& that._playCursor === 0) {
that._playCursor = that._playIndex.length;
}
if (that._playCursor > 0) {
that._playerPlay(that._playIndex[--that._playCursor]);
} else {
that._playerStop();
}
break;
case that._statesRepeat.one:
that._playerPlay(that._playIndex[that._playCursor]);
break;
}
} }
, _playerPause: function () { , _playerPause: function () {
var that = this var that = this
; ;
that.webAudio.obj.pause();
}
, _playerUnpause: function () {
var that = this
;
that.webAudio.obj.play();
} }
, _playerStop: function () { , _playerStop: function () {
var that = this var that = this
; ;
that.webAudio.obj.pause();
that.webAudio.obj.src = "";
that.webAudio.obj.innetHTML = "";
that._playCursor = 0;
that._setViewport();
} }
, _playerStart: function () { , _playerStart: function () {
@ -299,35 +537,136 @@ _
} }
, _getVolume: function () {
var that = this
;
return that.webAudio.obj.volume;
}
, _setVolume: function (volume) { , _setVolume: function (volume) {
var that = this var that = this
; ;
that.$elVolumeInput.val(volume);
return that.webAudio.obj.volume = volume;
}
, _seek: function (seek) {
var that = this
;
if (that.webAudio._state === that.webAudio._states.playing) {
console.debug("Seeking player to " + seek);
that.webAudio.obj.currentTime = seek;
}
} }
// Viewport methods // Viewport methods
, _getItemData: function (item) { , _playBtnSetState: function (state) {
var that = this
, $btn = that.$el.find("a.buttonPlay");
$btn.removeClass("paused");
$btn.removeClass("playing");
$btn.removeClass("stopped");
switch (state) {
case that.webAudio._states.stopped:
case that.webAudio._states.paused:
$btn.addClass("paused");
break;
case that.webAudio._states.loading:
case that.webAudio._states.ready:
case that.webAudio._states.playing:
$btn.addClass("playing");
break;
case -1:
$btn.addClass("stopped");
break;
}
}
, _disableControls: function () {
var that = this
;
that.$el.find(".enabled").addClass("disabled");
that.$el.find(".enabled").removeClass("enabled");
that.$el.find("[enabled]").attr("disabled", true);
that.$el.find("[enabled]").removeAttr("enabled");
//that.$el.find("progress").attr("disabled", true);
}
, _enableControls: function () {
var that = this var that = this
; ;
that.$el.find(".disabled").addClass("enabled");
that.$el.find(".disabled").removeClass("disabled");
that.$el.find("[disabled]").attr("enabled", true);
that.$el.find("[disabled]").removeAttr("disabled");
//that.$el.find("progress").removeAttr("disabled");
} }
/*, _getItemData: function (item) {
var that = this
;
console.log(that.options.servers.get(item.hostname).client.collections);
return that.options.servers.get(item.hostname).client.collections.databases[item.id].get("dmap_listing").get(item.dbId);
}
*/
, _getItemMediaUrl: function (item) { , _getItemMediaUrl: function (item) {
var that = this var that = this
; ;
return that.options.servers.get(item.hostname).client.urlMedia(item.id, item.type, item.dbId);
} }
, _setViewport: function (item) { , _setViewport: function (item) {
var that = this var that = this
; ;
item = item || {};
that.$elViewport.html(_.template(tmplPlayerStatus)(item));
}
, _progressSetLoadding: function () {
var that = this
, $progress = that.$el.find(".playerProgressWrapper > progress")
;
$progress.removeAttr("value");
$progress.attr("disabled", true);
} }
, _updateViewportProgress: function (progress, time) { , _updateViewportProgress: function (progress, time) {
var that = this var that = this
; ;
progress = progress || 0;
time = time || 1;
if (that.$el.find("> .playerProgressWrapper")) {
var left = (time - progress)
, frac = progress / time
, precent = frac * 100
, elapsed = Math.floor(progress / 60).toFixed().pad(2, "0") + ":" + (progress % 60).toFixed().pad(2, "0")
, remain = "-" + Math.floor(left / 60).toFixed().pad(2, "0") + ":" + (left % 60).toFixed().pad(2, "0")
, $progress = that.$el.find(".playerProgressWrapper > progress")
;
that.$el.find(".playerProgressWrapper > span:first-child").text(elapsed);
that.$el.find(".playerProgressWrapper > span:last-child").text(remain);
$progress.removeAttr("disabled");
$progress.val(frac);
}
} }
}); });

@ -0,0 +1,18 @@
define(["underscore","jquery","backbone","modules/webaudio","libs/mimes","text!../../templates/player/layout.html","text!../../templates/player/player-status.html"],function(e,g,h,d,a,f,b){if(!e.isFunction(Array.prototype.shuffle)){Array.prototype.shuffle=function(){var j=this.length,l=j;
if(j===0){return false;}while(l--){var m=parseInt(Math.random()*j,10);var k=this[l];this[l]=this[m];this[m]=k;}};}var c=h.View.extend({elViewport:null,$elViewport:null,$elVolumeInput:null,playIndex:[],playCursor:0,webAudio:null,_stateRandom:null,_stateRepeat:null,_stateMute:null,_stateVolume:null,_stateAudio:null,_state:null,_states:{stopped:0,loading:1,playing:2,paused:3},events:{"click div:first-child > a.buttonPrev":"__buttonPrevious","click div:first-child > a.buttonNext":"__buttonNext","click div:first-child > a.buttonPlay":"__buttonPlayPause","click div:first-child > .playerVolumeWrapper > a:first-child":"__buttonVolumeDown","click div:first-child > .playerVolumeWrapper > a:last-child":"__buttonVolumeUp","click div:first-child > .playerVolumeWrapper > input":"__buttonVolumeClick","click div:last-child > .playerProgressWrapper > progress":"__buttonSeek"},initialize:function(i){var j=this;
e.bindAll(this,"init","setPlayIndex","sortPlayIndex","setRandomState","setRepeatState","playItem","__buttonPlayPause","__buttonNext","__buttonPrevious","__buttonVolumeUp","__buttonVolumeDown","__buttonVolumeClick","__buttonSeek","_waCreate","_waBindEvents","__waStateChanged","_playerEnded","_playerLoading","_playNext","_playPrevious","_playerPause","_playerStop","_playerStart","_setVolume","_getItemData","_getItemMediaUrl","_setViewport","_updateViewportProgress");
c.__super__.initialize.apply(j);j.$el.html(f);j.elViewport=document.createElement("div");j.$elViewport=g(j.elViewport);j.$elViewport.html(e.template(b)({}));
j.$elVolumeInput=j.$el.find(".playerVolumeWrapper > input");j.$el.append(j.elViewport);j._waCreate();return j;},init:function(){var i=this;i.$el.find(".disabled").removeClass("disabled");
i.$el.find("[disabled]").removeAttr("disabled");i.$elVolumeInput.val(i.webAudio.obj.volume);},setPlayIndex:function(i,k){var j=this;j._playIndex=i;j._playCursor=k||0;
if(j._stateRandom){j.setRandomState(j._stateRandom);}return j._playIndex;},sortPlayIndex:function(i){var j=this;},setRandomState:function(j){var i=this;
if(j===true){i._playIndex.shuffle();}return i._stateRandom=j;},setRepeatState:function(j){var i=this;return i._stateRepeat=j;},playItem:function(j){var i=this;
i.webAudio.loadMedia(i._getItemMediaUrl(j),a.get(j.type));},__buttonPlayPause:function(j){var i=this;},__buttonNext:function(j){var i=this;},__buttonPrevious:function(j){var i=this;
},__buttonVolumeUp:function(k){var j=this,i=j._getVolume();if(i<1){if((i+0.1)>1){i=1;}else{i+=0.1;}}j._setVolume(i);},__buttonVolumeDown:function(k){var j=this,i=j._getVolume();
if(i>0){if((i-0.1)<0){i=0;}else{i-=0.1;}}j._setVolume(i);},__buttonVolumeClick:function(m){var l=this,k=m.clientX,n=m.target.offsetLeft,i=k-n,j=i/m.target.offsetWidth;
l._setVolume(j);},__buttonSeek:function(n){var m=this,l=m._getItem(),k=n.clientX,o=n.target.offsetLeft,i=k-o,j=i/n.target.offsetWidth,p=(j*(l.daap_songtime/1000));
m._seek(p);},_waCreate:function(){var i=this;i.webAudio=new d();i._waBindEvents();return i.webAudio;},_waBindEvents:function(){},__waStateChanged:function(){var i=this;
},_playerEnded:function(){var i=this;},_playerLoading:function(){var i=this;},_playNext:function(){var i=this;},_playPrevious:function(){var i=this;},_playerPause:function(){var i=this;
},_playerStop:function(){var i=this;},_playerStart:function(){var i=this;},_getVolume:function(){var i=this;return i.webAudio.obj.volume;},_setVolume:function(j){var i=this;
i.$elVolumeInput.val(j);return i.webAudio.obj.volume=j;},_seek:function(i){var j=this;console.debug("Seeking player to "+i);j.webAudio.obj.pause();j.webAudio.obj.currentTime=i;
j.webAudio.obj.play();},_getItemData:function(j){var i=this;},_getItemMediaUrl:function(j){var i=this;return i.options.servers.get(j.hostname).client.urlMedia(j.id,j.type,j.dbId);
},_setViewport:function(j){var i=this;},_updateViewportProgress:function(i,k){var j=this;}});return c;});

@ -5,7 +5,10 @@
<h3 id="myModalLabel">A fatal error has occured</h3> <h3 id="myModalLabel">A fatal error has occured</h3>
</div> </div>
<div class="modal-body" style="font-size: 1.2em"> <div class="modal-body" style="font-size: 1.2em">
You can try to reload the page...
<!--
{{ERROR_REPORTING}}
-->
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-mini btn-primary" data-dismiss="modal" aria-hidden="true"><i class="icon-refresh"></i>&nbsp;Reload</button> <button class="btn btn-mini btn-primary" data-dismiss="modal" aria-hidden="true"><i class="icon-refresh"></i>&nbsp;Reload</button>

@ -1,4 +1,4 @@
<% if (typeof dmap_itemnname !== "undefined") { %> <% if (typeof dmap_itemname !== "undefined") { %>
<div class="daaprPlayerTitleIndicator">{{dmap_itemname}}</div> <div class="daaprPlayerTitleIndicator">{{dmap_itemname}}</div>
<div class="daaprPlayerInfoIndicator">{{daap_songartist}}</div> <div class="daaprPlayerInfoIndicator">{{daap_songartist}}</div>
<div class="playerProgressWrapper"> <div class="playerProgressWrapper">

Loading…
Cancel
Save