/*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([ "underscore" , "backbone" , "toolbox" , "models/dmap-type" , "models/dmap" ], function (_, Backbone, Toolbox, DMAPType, DMAPModel) { "use strict"; var that // TODO: Could be interesting to set a userage, could possibly affect transcoding on the server side , xhr = function (url, responseType, callback) { var xhr = new XMLHttpRequest(); var contentType = "text/plain; charset=utf-8"; if (typeof responseType === "function") { callback = responseType; responseType = "arraybuffer"; } xhr.open("GET", url, true); xhr.responseType = responseType; xhr.timeout = 2000; xhr.setRequestHeader("Content-type", contentType); xhr.overrideMimeType("text/plain; charset=x-user-defined"); // Technically not need with v2 and responseType but for good measures if (!_.isEmpty(that.attributes.basicauth)) { xhr.withCredentials = true; xhr.setRequestHeader("Authorization", "Basic " + that.attributes.basicauth); } try { xhr.onerror = function () {console.log("Error", arguments, this);}; xhr.onabort = function () {console.log("Abort", arguments, this);}; xhr.ontimeout = function () {console.log("Timeout", arguments, this);}; xhr.onload = function (e) { if (this.status === 200) { callback(null, this.response); } else if (this.status === 401) { that.trigger("unauthorized", [this, e]); } else { callback(e.status); } }; xhr.send(); } catch (e) { console.error(e); callback(e, null); } } , fetchXHR = function (path, success, error) { xhr(that.url(path), function __fetchXHRCallback(err, content) { if (err) { if (!_.isFunction(error)) { error = function (err, cont) { throw [err, cont]; }; } error(err, content); } else { success(content); } }); } , fetchContentTypes = function (success, error) { fetchXHR("/content-codes", function __fetchContentTypesCallback(content) { that.collections.contentCodes = new DMAPModel(content); if (_.isFunction(success)) { success(content); } }, error); } , fetchServerInfo = function (success, error) { fetchXHR("/server-info", function __fetchServerInfoCallback(content) { that.collections.serverInfo = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchLogin = function (success, error) { fetchXHR("/login", success, error); } , fetchDatabases = function (success, error) { fetchXHR("/databases", function __fetchDatabasesCallback(content) { that.collections.databasesInfo = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchDatabase = function (success, error, dbId) { if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } fetchXHR("/databases/" + dbId + "/items", function __fetchDatabaseCallback(content) { that.collections.databases[dbId] = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchPlaylists = function (success, error, dbId) { if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } fetchXHR("/databases/" + dbId + "/containers", function __fetchPlaylistsCallback(content) { that.collections.playlistsInfo = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchPlaylist = function (success, error, playlistId, dbId) { if (_.isUndefined(playlistId) || !_.isNumeric(playlistId)) { playlistId = 1; } if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } var requestUri = "/databases/" ; requestUri += dbId; requestUri += "/containers/"; requestUri += playlistId; requestUri += "/items"; requestUri += "?meta=dmap.itemid,dmap.persistentid,dmap.containeritemid"; fetchXHR(requestUri, function __fetchPlaylistCallback(content) { if (!_.isArray(that.collections.playlists[dbId])) { that.collections.playlists[dbId] = []; } that.collections.playlists[dbId][playlistId] = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchBrowse = function (success, error, dbId, type) { // TODO: We need to detect if the server supports browsing or not an implement our own otherwise. if (_.isEmpty(type) || !_.isString(type) || !_.isArray(that.collections.browser[type])) { throw new Error("INVALID_BROWSE_TYPE"); } var requestUri = "/databases/" ; requestUri += dbId; requestUri += "/browse/"; requestUri += type; requestUri += "?meta=dmap.itemid,dmap.persistentid,dmap.containeritemid"; fetchXHR(requestUri, function __fetchBrowseCallback(content) { that.collections.browser[type][dbId] = new DMAPModel(content, { contentCodes: that.collections.contentCodes }); if (_.isFunction(success)) { success(content); } }, error); } , fetchGenres = function (success, error, dbId) { if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } return fetchBrowse(success, error, dbId, "genres"); } , fetchArtists = function (success, error, dbId) { if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } return fetchBrowse(success, error, dbId, "artists"); } , fetchAlbums = function (success, error, dbId) { if (_.isUndefined(dbId) || !_.isNumeric(dbId)) { dbId = 1; } return fetchBrowse(success, error, dbId, "albums"); } , Client = Toolbox.Base.extend({ constructor: function(attributes, options) { that = this; _.extend(that, Client.defaults); _.extend(that.attributes, attributes); that.setAuth(); return this; } , setAuth: function(username, password) { if (!_.isUndefined(username)) { that.attributes.username = username; } if (!_.isUndefined(password)) { that.attributes.password = password; } if (!_.isEmpty(that.attributes.password) || !_.isEmpty(that.attributes.username)) { that.attributes.basicauth = window.btoa((that.attributes.username || "") + ":" + (that.attributes.password || "")); } } , init: function () { var that = this ; that.console.debug("Fetching content types"); fetchContentTypes(function () { that.console.debug("Fetching server info"); fetchServerInfo(function () { that.console.debug("Fetching login"); fetchLogin(function () { // TODO: Here we need to request /update for the database version that.console.debug("Fetching databases info"); fetchDatabases(function () { //that.console.debug("Fetching database 1"); //fetchDatabase(function () { that.console.debug("Fetching playlists info"); fetchPlaylists(function () { //that.console.debug("Fetching playlist 1 of db 1"); //fetchPlaylist(function () { //that.console.debug("Fetching genres of db 1"); //fetchGenres(function () { //that.console.debug("Fetching artists of db 1"); //fetchArtists(function () { //that.console.debug("Fetching albums of db 1"); //fetchAlbums(function () { that.trigger("inited", that.collections); //}); //}); //}); //}); }); //}); }); }); }); }); return this; } ,logout: function () { } , buildRequestUid: function(path, fields, query) { if (_.isEmpty(path) || !_.isString(path)) { throw new Error("INVALID_TYPE_ERROR"); } if (!_.isArray(fields)) { fields = []; } if (!_.isArray(query)) { query = []; } } ,url: function (request) { var uri = "" ; if (typeof request === "string") { uri = request; // Add leading slash here! } if (_.isNumber(this.collections.session.id)) { var prefix = "?"; if (uri.indexOf("?") >= 0) { prefix = "&"; } uri += prefix + "session-id=" + this.collections.session.id; } return this.attributes.protocol + "://" + this.attributes.hostname + ":" + this.attributes.port + uri; } , console: { log: function() { var args = arguments; if (_.isString(args[0])) { args[0] = that.url() + " " + args[0]; } console.log(args); } , debug: function() { var args = arguments; if (_.isString(args[0])) { args[0] = that.url() + " " + args[0]; } console.debug(args); } } }, { defaults: { attributes: { protocol: window.location.protocol.replace(":", "") , hostname: window.location.hostname , port: 3689 , path: "" , username: "" , password: "" } , status: 0 , statusCodes: { disconnected: 0 , connecting: 1 , timedout: 2 , unauthorized: 3 , connected: 4 } , collections: { contentCodes: null , serverInfo: null , session: { id: null } , databasesInfo:null , databases: [] , playlistsInfo:null , playlists: [] , browser: { genres: [] , artists: [] , albums: [] } } } }); _.extend(Client.prototype, Backbone.Events, {}); return Client; });