diff --git a/mopidy_spotmop/__init__.py b/mopidy_spotmop/__init__.py index 4871ebc..dcb6998 100755 --- a/mopidy_spotmop/__init__.py +++ b/mopidy_spotmop/__init__.py @@ -11,7 +11,7 @@ from services.auth import auth from mopidy import config, ext -__version__ = '2.5.11' +__version__ = '2.5.12' __ext_name__ = 'spotmop' __verbosemode__ = False diff --git a/mopidy_spotmop/static/app.js b/mopidy_spotmop/static/app.js index b8e8f62..11714fa 100644 --- a/mopidy_spotmop/static/app.js +++ b/mopidy_spotmop/static/app.js @@ -35849,8 +35849,7 @@ angular.module('spotmop.services.settings', []) url: 'https://pypi.python.org/pypi/Mopidy-Spotmop/json' }) .success(function( response ){ - //deferred.resolve( response.info.version ); - deferred.resolve( '2.5.12' ); + deferred.resolve( response.info.version ); }) .error(function( response ){ NotifyService.error( response.error.message ); diff --git a/mopidy_spotmop/static/app.min.js b/mopidy_spotmop/static/app.min.js index cc620ff..18243e6 100644 --- a/mopidy_spotmop/static/app.min.js +++ b/mopidy_spotmop/static/app.min.js @@ -16,4 +16,4 @@ b.imageHeight=Math.floor(b.imageHeight),b.imageWidth=Math.floor(b.imageWidth),b} return"unhandledRejection"===a?b.emit(a,c.value,c):b.emit(a,c)}:"undefined"!=typeof self&&"function"==typeof CustomEvent?function(a,b,c){var d=!1;try{var e=new c("unhandledRejection");d=e instanceof c}catch(f){}return d?function(a,d){var e=new c(a,{detail:{reason:d.value,key:d},bubbles:!1,cancelable:!0});return!b.dispatchEvent(e)}:a}(U,self,CustomEvent):U}var W=a.scheduler,X=V(),Y=Object.create||function(a){function b(){}return b.prototype=a,new b};c.resolve=e,c.reject=f,c.never=g,c._defer=h,c._handler=r,c.prototype.then=function(a,b,c){var d=this._handler,e=d.join().state();if("function"!=typeof a&&e>0||"function"!=typeof b&&0>e)return new this.constructor(u,d);var f=this._beget(),g=f._handler;return d.chain(g,d.receiver,a,b,c),f},c.prototype["catch"]=function(a){return this.then(void 0,a)},c.prototype._beget=function(){return i(this._handler,this.constructor)},c.all=j,c.race=p,c._traverse=k,c._visitRemaining=n,u.prototype.when=u.prototype.become=u.prototype.notify=u.prototype.fail=u.prototype._unreport=u.prototype._report=U,u.prototype._state=0,u.prototype.state=function(){return this._state},u.prototype.join=function(){for(var a=this;void 0!==a.handler;)a=a.handler;return a},u.prototype.chain=function(a,b,c,d,e){this.when({resolver:a,receiver:b,fulfilled:c,rejected:d,progress:e})},u.prototype.visit=function(a,b,c,d){this.chain(Z,a,b,c,d)},u.prototype.fold=function(a,b,c,d){this.when(new I(a,b,c,d))},S(u,v),v.prototype.become=function(a){a.fail()};var Z=new v;S(u,w),w.prototype._state=0,w.prototype.resolve=function(a){this.become(r(a))},w.prototype.reject=function(a){this.resolved||this.become(new A(a))},w.prototype.join=function(){if(!this.resolved)return this;for(var a=this;void 0!==a.handler;)if(a=a.handler,a===this)return this.handler=D();return a},w.prototype.run=function(){var a=this.consumers,b=this.handler;this.handler=this.handler.join(),this.consumers=void 0;for(var c=0;c0?c(d.value):b(d.value)}return{pending:a,fulfilled:c,rejected:b,inspect:d}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],21:[function(b,c){!function(a){"use strict";a(function(a){function b(a,b,c,d){var e=x.resolve(a);return arguments.length<2?e:e.then(b,c,d)}function c(a){return new x(a)}function d(a){return function(){for(var b=0,c=arguments.length,d=new Array(c);c>b;++b)d[b]=arguments[b];return y(a,this,d)}}function e(a){for(var b=0,c=arguments.length-1,d=new Array(c);c>b;++b)d[b]=arguments[b+1];return y(a,this,d)}function f(){return new g}function g(){function a(a){d._handler.resolve(a)}function b(a){d._handler.reject(a)}function c(a){d._handler.notify(a)}var d=x._defer();this.promise=d,this.resolve=a,this.reject=b,this.notify=c,this.resolver={resolve:a,reject:b,notify:c}}function h(a){return a&&"function"==typeof a.then}function i(){return x.all(arguments)}function j(a){return b(a,x.all)}function k(a){return b(a,x.settle)}function l(a,c){return b(a,function(a){return x.map(a,c)})}function m(a,c){return b(a,function(a){return x.filter(a,c)})}var n=a("./lib/decorators/timed"),o=a("./lib/decorators/array"),p=a("./lib/decorators/flow"),q=a("./lib/decorators/fold"),r=a("./lib/decorators/inspect"),s=a("./lib/decorators/iterate"),t=a("./lib/decorators/progress"),u=a("./lib/decorators/with"),v=a("./lib/decorators/unhandledRejection"),w=a("./lib/TimeoutError"),x=[o,p,q,s,t,r,u,n,v].reduce(function(a,b){return b(a)},a("./lib/Promise")),y=a("./lib/apply")(x);return b.promise=c,b.resolve=x.resolve,b.reject=x.reject,b.lift=d,b["try"]=e,b.attempt=e,b.iterate=x.iterate,b.unfold=x.unfold,b.join=i,b.all=j,b.settle=k,b.any=d(x.any),b.some=d(x.some),b.race=d(x.race),b.map=l,b.filter=m,b.reduce=d(x.reduce),b.reduceRight=d(x.reduceRight),b.isPromiseLike=h,b.Promise=x,b.defer=f,b.TimeoutError=w,b})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})},{"./lib/Promise":4,"./lib/TimeoutError":6,"./lib/apply":7,"./lib/decorators/array":8,"./lib/decorators/flow":9,"./lib/decorators/fold":10,"./lib/decorators/inspect":11,"./lib/decorators/iterate":12,"./lib/decorators/progress":13,"./lib/decorators/timed":14,"./lib/decorators/unhandledRejection":15,"./lib/decorators/with":16}],22:[function(a,b){function c(a){return this instanceof c?(this._console=this._getConsole(a||{}),this._settings=this._configure(a||{}),this._backoffDelay=this._settings.backoffDelayMin,this._pendingRequests={},this._webSocket=null,d.createEventEmitter(this),this._delegateEvents(),void(this._settings.autoConnect&&this.connect())):new c(a)}var d=a("bane"),e=a("../lib/websocket/"),f=a("when");c.ConnectionError=function(a){this.name="ConnectionError",this.message=a},c.ConnectionError.prototype=Object.create(Error.prototype),c.ConnectionError.prototype.constructor=c.ConnectionError,c.ServerError=function(a){this.name="ServerError",this.message=a},c.ServerError.prototype=Object.create(Error.prototype),c.ServerError.prototype.constructor=c.ServerError,c.WebSocket=e.Client,c.when=f,c.prototype._getConsole=function(a){if("undefined"!=typeof a.console)return a.console;var b="undefined"!=typeof console&&console||{};return b.log=b.log||function(){},b.warn=b.warn||function(){},b.error=b.error||function(){},b},c.prototype._configure=function(a){var b="undefined"!=typeof document&&"https:"===document.location.protocol?"wss://":"ws://",c="undefined"!=typeof document&&document.location.host||"localhost";return a.webSocketUrl=a.webSocketUrl||b+c+"/mopidy/ws",a.autoConnect!==!1&&(a.autoConnect=!0),a.backoffDelayMin=a.backoffDelayMin||1e3,a.backoffDelayMax=a.backoffDelayMax||64e3,"undefined"==typeof a.callingConvention&&this._console.warn("Mopidy.js is using the default calling convention. The default will change in the future. You should explicitly specify which calling convention you use."),a.callingConvention=a.callingConvention||"by-position-only",a},c.prototype._delegateEvents=function(){this.off("websocket:close"),this.off("websocket:error"),this.off("websocket:incomingMessage"),this.off("websocket:open"),this.off("state:offline"),this.on("websocket:close",this._cleanup),this.on("websocket:error",this._handleWebSocketError),this.on("websocket:incomingMessage",this._handleMessage),this.on("websocket:open",this._resetBackoffDelay),this.on("websocket:open",this._getApiSpec),this.on("state:offline",this._reconnect)},c.prototype.connect=function(){if(this._webSocket){if(this._webSocket.readyState===c.WebSocket.OPEN)return;this._webSocket.close()}this._webSocket=this._settings.webSocket||new c.WebSocket(this._settings.webSocketUrl),this._webSocket.onclose=function(a){this.emit("websocket:close",a)}.bind(this),this._webSocket.onerror=function(a){this.emit("websocket:error",a)}.bind(this),this._webSocket.onopen=function(){this.emit("websocket:open")}.bind(this),this._webSocket.onmessage=function(a){this.emit("websocket:incomingMessage",a)}.bind(this)},c.prototype._cleanup=function(a){Object.keys(this._pendingRequests).forEach(function(b){var d=this._pendingRequests[b];delete this._pendingRequests[b];var e=new c.ConnectionError("WebSocket closed");e.closeEvent=a,d.reject(e)}.bind(this)),this.emit("state:offline")},c.prototype._reconnect=function(){this.emit("reconnectionPending",{timeToAttempt:this._backoffDelay}),setTimeout(function(){this.emit("reconnecting"),this.connect()}.bind(this),this._backoffDelay),this._backoffDelay=2*this._backoffDelay,this._backoffDelay>this._settings.backoffDelayMax&&(this._backoffDelay=this._settings.backoffDelayMax)},c.prototype._resetBackoffDelay=function(){this._backoffDelay=this._settings.backoffDelayMin},c.prototype.close=function(){this.off("state:offline",this._reconnect),this._webSocket.close()},c.prototype._handleWebSocketError=function(a){this._console.warn("WebSocket error:",a.stack||a)},c.prototype._send=function(a){switch(this._webSocket.readyState){case c.WebSocket.CONNECTING:return f.reject(new c.ConnectionError("WebSocket is still connecting"));case c.WebSocket.CLOSING:return f.reject(new c.ConnectionError("WebSocket is closing"));case c.WebSocket.CLOSED:return f.reject(new c.ConnectionError("WebSocket is closed"));default:var b=f.defer();return a.jsonrpc="2.0",a.id=this._nextRequestId(),this._pendingRequests[a.id]=b.resolver,this._webSocket.send(JSON.stringify(a)),this.emit("websocket:outgoingMessage",a),b.promise}},c.prototype._nextRequestId=function(){var a=-1;return function(){return a+=1}}(),c.prototype._handleMessage=function(a){try{var b=JSON.parse(a.data);b.hasOwnProperty("id")?this._handleResponse(b):b.hasOwnProperty("event")?this._handleEvent(b):this._console.warn("Unknown message type received. Message was: "+a.data)}catch(c){if(!(c instanceof SyntaxError))throw c;this._console.warn("WebSocket message parsing failed. Message was: "+a.data)}},c.prototype._handleResponse=function(a){if(!this._pendingRequests.hasOwnProperty(a.id))return void this._console.warn("Unexpected response received. Message was:",a);var b,d=this._pendingRequests[a.id];delete this._pendingRequests[a.id],a.hasOwnProperty("result")?d.resolve(a.result):a.hasOwnProperty("error")?(b=new c.ServerError(a.error.message),b.code=a.error.code,b.data=a.error.data,d.reject(b),this._console.warn("Server returned error:",a.error)):(b=new Error("Response without 'result' or 'error' received"),b.data={response:a},d.reject(b),this._console.warn("Response without 'result' or 'error' received. Message was:",a))},c.prototype._handleEvent=function(a){var b=a.event,c=a;delete c.event,this.emit("event:"+this._snakeToCamel(b),c)},c.prototype._getApiSpec=function(){return this._send({method:"core.describe"}).then(this._createApi.bind(this))["catch"](this._handleWebSocketError)},c.prototype._createApi=function(a){var b="by-position-or-by-name"===this._settings.callingConvention,c=function(a){return function(){var c={method:a};return 0===arguments.length?this._send(c):b?arguments.length>1?f.reject(new Error("Expected zero arguments, a single array, or a single object.")):Array.isArray(arguments[0])||arguments[0]===Object(arguments[0])?(c.params=arguments[0],this._send(c)):f.reject(new TypeError("Expected an array or an object.")):(c.params=Array.prototype.slice.call(arguments),this._send(c))}.bind(this)}.bind(this),d=function(a){var b=a.split(".");return b.length>=1&&"core"===b[0]&&(b=b.slice(1)),b},e=function(a){var b=this;return a.forEach(function(a){a=this._snakeToCamel(a),b[a]=b[a]||{},b=b[a]}.bind(this)),b}.bind(this),g=function(b){var f=d(b),g=this._snakeToCamel(f.slice(-1)[0]),h=e(f.slice(0,-1));h[g]=c(b),h[g].description=a[b].description,h[g].params=a[b].params}.bind(this);Object.keys(a).forEach(g),this.emit("state:online")},c.prototype._snakeToCamel=function(a){return a.replace(/(_[a-z])/g,function(a){return a.toUpperCase().replace("_","")})},b.exports=c},{"../lib/websocket/":1,bane:2,when:21}]},{},[22])(22)}),angular.module("spotmop",["ngResource","ngStorage","ngTouch","ui.router","angular-loading-bar","angular-google-analytics","spotmop.directives","spotmop.common.contextmenu","spotmop.common.tracklist","spotmop.services.notify","spotmop.services.settings","spotmop.services.player","spotmop.services.spotify","spotmop.services.mopidy","spotmop.services.echonest","spotmop.services.lastfm","spotmop.services.dialog","spotmop.services.pusher","spotmop.player","spotmop.queue","spotmop.library","spotmop.search","spotmop.settings","spotmop.discover","spotmop.browse","spotmop.browse.artist","spotmop.browse.album","spotmop.browse.playlist","spotmop.browse.user","spotmop.browse.genre","spotmop.browse.featured","spotmop.browse.new"]).config(["$stateProvider","$locationProvider","$urlRouterProvider","$httpProvider","AnalyticsProvider",function(a,b,c,d,e){c.otherwise("queue"),d.interceptors.push("SpotifyServiceIntercepter"),e.useAnalytics(!0),e.setAccount("UA-64701652-3")}]).run(["$rootScope","SettingsService","Analytics",function(a,b,c){}]).controller("ApplicationController",["$scope","$rootScope","$state","$localStorage","$timeout","$location","SpotifyService","MopidyService","EchonestService","PlayerService","SettingsService","NotifyService","PusherService","DialogService","Analytics",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){function p(a){var b=null;return $(a).hasClass("droppable")?b=$(a):$(a).closest(".droppable").length>0&&(b=$(a).closest(".droppable")),b}function q(a){var b=null;return $(a).hasClass("track")?b=$(a):$(a).closest(".track").length>0&&(b=$(a).closest(".track")),b}o.trackEvent("Spotmop","Started"),a.isTouchDevice=function(){return k.getSetting("emulateTouchDevice",!1)?!0:!!("ontouchstart"in window)},a.isSameDomainAsMopidy=function(){var a=k.getSetting("mopidyhost","localhost");return a&&"localhost"!=a?f.host()==a?!0:void 0:!0},a.state=j.state,a.currentTracklist=[],a.spotifyUser={},a.menuCollapsable=!1,a.reloadApp=function(){window.location.reload()},a.playlistsMenu=[],a.myPlaylists={},a.popupVolumeControls=function(){n.create("volumeControls",a)},$(document).on("mouseenter",".playlists-submenu-trigger",function(a){$(document).find(".menu-item.top-level.playlists").addClass("show-submenu")}),$(document).on("mouseleave",".menu-item.top-level.playlists",function(a){$(document).find(".menu-item.top-level.playlists").removeClass("show-submenu")}),a.updatePlaylists=function(b){g.getPlaylists(b,50).then(function(b){a.myPlaylists=b.items;var c=[];$.each(b.items,function(b,d){if(d.owner.id==a.spotifyUser.id){var e=d;e.link="/browse/playlist/"+d.uri,e.link="/browse/playlist/"+d.uri,c.push(e)}}),a.playlistsMenu=c})},a.windowWidth=$(document).width(),a.windowHeight=$(document).height(),a.mediumScreen=function(){return a.windowWidth<=800?!0:!1},a.smallScreen=function(){return a.windowWidth<=450?!0:!1},$(window).resize(function(){$(document).width()!=a.windowWidth&&(a.windowWidth=$(document).width(),$(document).find("body").removeClass("menu-revealed"))}),b.$on("$stateChangeStart",function(b){a.hideMenu(),o.trackPage(f.path())}),$(document).on("click","#body",function(b){$(b.target).closest(".menu-reveal-trigger").length<=0&&a.hideMenu()}),a.showMenu=function(){$(document).find("body").addClass("menu-revealed")},a.hideMenu=function(){$(document).find("body").removeClass("menu-revealed")},a.searchSubmit=function(a){o.trackEvent("Search","Performed search",a);var b=g.uriType(a);b?(l.notify("You've been redirected because that looked like a Spotify URI"),"artist"==b?($(document).find(".search-form input").val(""),c.go("browse.artist.overview",{uri:a})):"album"==b?($(document).find(".search-form input").val(""),c.go("browse.album",{uri:a})):"playlist"==b&&($(document).find(".search-form input").val(""),c.go("browse.playlist",{uri:a}))):c.go("search",{query:a})},a.linkingMode=function(a){var b="";return $.isArray(a)||(a=[a]),angular.forEach(a,function(a){""==b&&(c.is(a)?b="active":c.includes(a)&&(b="section"))}),b},a.$on("mopidy:state:online",function(){o.trackEvent("Mopidy","Online"),b.mopidyOnline=!0,h.getCurrentTlTracks().then(function(b){a.currentTracklist=b}),h.getConsume().then(function(a){k.setSetting("mopidyconsume",a)})}),a.$on("mopidy:state:offline",function(){b.mopidyOnline=!1}),b.spotifyAuthorized=!1,a.$on("spotmop:spotify:authenticationChanged",function(c,d){"client"==d?(b.spotifyAuthorized=!0,a.spotifyUser=k.getSetting("spotifyuser"),a.updatePlaylists(a.spotifyUser.id),o.trackEvent("Spotify","Authorized",a.spotifyUser.id)):(b.spotifyAuthorized=!1,a.playlistsMenu=[])}),a.$on("spotmop:spotify:online",function(){b.spotifyOnline=!0,b.spotifyAuthorized&&(a.spotifyUser=k.getSetting("spotifyuser"),a.updatePlaylists(a.spotifyUser.id))}),a.$on("spotmop:spotify:offline",function(){a.playlistsMenu=[],b.spotifyOnline=!1}),m.start(),b.$on("spotmop:pusher:online",function(b,c){var d=k.getSetting("pushername",null);"undefined"!=typeof d&&d&&""!=d||(n.create("initialsetup",a),o.trackEvent("Core","Initial setup"))}),b.$on("spotmop:pusher:received",function(a,b){var c="";b.spotifyuser=JSON.parse(b.spotifyuser),"undefined"!=typeof b.spotifyuser.images&&b.spotifyuser.images.length>0&&(c=b.spotifyuser.images[0].url),l.browserNotify(b.title,b.body,c),o.trackEvent("Pusher","Notification received",b.body)}),b.$on("mopidy:event:trackPlaybackEnded",function(a,b){k.getSetting("echonestenabled",!1)&&i.addToTasteProfile("play",b.tl_track.track.uri)}),h.start(),g.start(),k.getSetting("echonestenabled",!1)&&i.start(),b.shiftKeyHeld=!1,b.ctrlKeyHeld=!1,$("body").bind("keydown",function(a){if(16===a.which?b.shiftKeyHeld=!0:17===a.which&&(b.ctrlKeyHeld=!0),!$(document).find(":focus").is(":input")&&k.getSetting("keyboardShortcutsEnabled",!1)){var c=new Array(46,32,13,37,38,39,40,27);$.inArray(a.which,c)>-1&&a.preventDefault()}}).bind("keyup",function(a){!$(document).find(":focus").is(":input")&&k.getSetting("keyboardShortcutsEnabled",!1)&&(46===a.which&&b.$broadcast("spotmop:keyboardShortcut:delete"),32===a.which&&b.$broadcast("spotmop:keyboardShortcut:space"),13===a.which&&b.$broadcast("spotmop:keyboardShortcut:enter"),37===a.which&&b.$broadcast("spotmop:keyboardShortcut:left"),38===a.which&&b.$broadcast("spotmop:keyboardShortcut:up"),39===a.which&&b.$broadcast("spotmop:keyboardShortcut:right"),40===a.which&&b.$broadcast("spotmop:keyboardShortcut:down"),27===a.which&&(b.$broadcast("spotmop:keyboardShortcut:esc"),r&&(r=!1,$(document).find(".drag-tracer").hide()))),16===a.which&&(b.shiftKeyHeld=!1),17===a.which&&(b.ctrlKeyHeld=!1)}),$(document).on("mouseup","body",function(a){$(a.target).closest(".tracklist").length<=0&&b.$broadcast("spotmop:contextMenu:hide")});var r=!1,s=30;$(document).on("mousedown","body:not(.touchDevice) track, body:not(.touchDevice) tltrack",function(a){var b=$(a.currentTarget).closest(".tracklist"),c=b.find(".track.selected");r={safetyOff:!1,clientX:a.clientX,clientY:a.clientY,tracks:c}}),$(document).on("mouseup",function(b){if("undefined"!=typeof r&&r.safetyOff){$("body").removeClass("dragging"),$(document).find(".droppable").removeClass("dropping"),$(document).find(".drag-hovering").removeClass("drag-hovering");var c=p(b.target),d=q(b.target),e=!1;if(c&&c.closest(".main-menu").length>0&&(e=!0),c){$(document).find(".drag-tracer").html("Dropping...").fadeOut("fast"),$(document).find(".track.drag-hovering").removeClass("drag-hovering");var f=[];if($.each(r.tracks,function(a,b){f.push($(b).attr("data-uri"))}),e&&"queue"===c.attr("data-type"))f.length>10&&l.notify("Adding "+f.length+" track(s) to queue... this could take some time"),h.addToTrackList(f);else if(e&&"library"===c.attr("data-type")){var i=new Array;$.each(f,function(a,b){i.push(g.getFromUri("trackid",b))}),g.addTracksToLibrary(i)}else if(e&&"playlist"===c.attr("data-type"))g.addTracksToPlaylist(c.attr("data-uri"),f);else if(d){var j=1e3,k=0,m=$(d).parent().index();if($.each(r.tracks,function(a,b){$(b).parent().index()k&&(k=$(b).parent().index())}),d.closest(".tracklist").hasClass("queue-items"))m>=k&&(m-=f.length),h.moveTlTracks(j,k+1,m);else if(d.closest(".tracklist").hasClass("playlist-items")){var n=1;k>j&&(n=k-j,n++),a.$broadcast("spotmop:playlist:reorder",j,n,m)}}}else $(document).find(".drag-tracer").fadeOut("medium")}r=!1}),$(document).on("mousemove",function(a){if(r){var b=r.clientX-s,c=r.clientX+s,d=r.clientY-s,e=r.clientY+s;if(a.clientXc||a.clientYe){$("body").addClass("dragging"),$(document).find(".track.drag-hovering").removeClass("drag-hovering");var f=p(a.target),g=q(a.target),h=$(document).find(".drag-tracer");g&&g.addClass("drag-hovering"),r.safetyOff=!0,h.show(),$(document).find(".droppable").removeClass("dropping"),$(document).find(".dropping-within").removeClass("dropping-within");var i=!1;f&&f.closest(".main-menu").length>0&&(i=!0),f&&i&&"queue"===f.attr("data-type")?f.addClass("dropping"):f&&i&&"library"===f.attr("data-type")?f.addClass("dropping"):f&&i&&"playlists"===f.attr("data-type")?(f.closest(".menu-item.playlists").addClass("dropping-within"),f.addClass("dropping")):f&&i&&"playlist"===f.attr("data-type")?(f.addClass("dropping"),f.closest(".menu-item.playlists").addClass("dropping-within")):h.html("Dragging "+r.tracks.length+" track(s)")}}})}]),angular.module("spotmop.browse.album",[]).config(["$stateProvider",function(a){a.state("browse.album",{url:"/album/:uri",templateUrl:"app/browse/album/template.html",controller:"AlbumController"})}]).controller("AlbumController",["$scope","$rootScope","$stateParams","$filter","MopidyService","SpotifyService",function(a,b,c,d,e,f){function g(b){return"undefined"==typeof b?!1:(h=!0,void f.getUrl(b).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(b.items),a.tracklist.next=b.next,h=!1}))}a.album={},a.tracklist={type:"track"},a.convertedDate=function(){return a.mediumScreen()?d("date")(a.album.release_date,"yyyy"):"day"==a.album.release_date_precision?d("date")(a.album.release_date,"MMMM d, yyyy"):"month"==a.album.release_date_precision?d("date")(a.album.release_date,"MMMM yyyy"):"year"==a.album.release_date_precision?a.album.release_date:null},a.totalTime=function(){var b=0;return"undefined"!=typeof a.tracklist.tracks&&angular.forEach(a.tracklist.tracks,function(a){b+=a.duration_ms}),Math.round(b/1e5)},$(document).find(".browse > .content").on("scroll",function(b){var c=$(this).scrollTop(),d=$(this).outerHeight(),e=$(this).children(".inner").outerHeight(),f=-(c+d-e);100>=f&&a.$broadcast("spotmop:loadMore")}),a.playAlbum=function(){e.playStream(a.album.uri)},a.addToLibrary=function(){var b=[];angular.forEach(a.tracklist.tracks,function(a){b.push(f.getFromUri("trackid",a.uri))}),f.addTracksToLibrary(b)},f.getAlbum(c.uri).then(function(b){a.album=b,a.tracklist=b.tracks,a.tracklist.type="track",a.tracklist.tracks=b.tracks.items,angular.forEach(a.tracklist.tracks,function(b){b.album=a.album});var d=[];angular.forEach(b.artists,function(a){d.push(a.uri)}),f.getArtists(d).then(function(b){a.album.artists=b.artists}),"undefined"!=typeof c.artisturi&&f.getArtist(c.artisturi).then(function(b){a.artist=b})});var h=!1;a.$on("spotmop:loadMore",function(){!h&&"undefined"!=typeof a.tracklist.next&&a.tracklist.next&&g(a.tracklist.next)})}]),angular.module("spotmop.browse.artist",[]).config(["$stateProvider",function(a){a.state("browse.artist",{url:"/artist/:uri","abstract":!0,templateUrl:"app/browse/artist/template.html",controller:["$scope","$state",function(a,b){"browse.artist"===b.current.name&&b.go("browse.artist.overview")}]}).state("browse.artist.overview",{url:"",templateUrl:"app/browse/artist/overview.template.html",controller:"ArtistOverviewController"}).state("browse.artist.related",{url:"/related",templateUrl:"app/browse/artist/related.template.html",controller:"RelatedArtistsController"}).state("browse.artist.biography",{url:"/biography",templateUrl:"app/browse/artist/biography.template.html",controller:"ArtistBiographyController"}).state("browse.artistalbum",{url:"/artist/:artisturi/:uri",templateUrl:"app/browse/album/template.html",controller:"AlbumController"})}]).controller("ArtistController",["$scope","$rootScope","$timeout","$interval","$stateParams","$sce","SpotifyService","SettingsService","EchonestService","NotifyService","LastfmService",function(a,b,c,d,e,f,g,h,i,j,k){a.artist={},a.tracklist={type:"track"},a.albums={},a.relatedArtists={},a.followArtist=function(){g.followArtist(e.uri).then(function(b){a.following=!0})},a.unfollowArtist=function(){g.unfollowArtist(e.uri).then(function(b){a.following=!1})},a.playArtistRadio=function(){j.error("This functionality has not yet been implemented")},g.getArtist(e.uri).then(function(b){a.artist=b}),b.spotifyAuthorized&&g.isFollowingArtist(e.uri,h.getSetting("spotifyuserid",null)).then(function(b){a.following=$.parseJSON(b)}),g.getRelatedArtists(e.uri).then(function(b){a.relatedArtists=b.artists})}]).controller("ArtistOverviewController",["$scope","$timeout","$rootScope","$stateParams","SpotifyService",function(a,b,c,d,e){function f(b){return"undefined"==typeof b?!1:(g=!0,void e.getUrl(b).then(function(b){a.albums.items=a.albums.items.concat(b.items),a.albums.next=b.next,g=!1}))}e.getAlbums(d.uri).then(function(b){a.$parent.albums=b,e.getTopTracks(d.uri).then(function(b){a.tracklist.tracks=b.tracks})});var g=!1;a.$on("spotmop:loadMore",function(){!g&&"undefined"!=typeof a.albums.next&&a.albums.next&&f(a.albums.next)})}]).controller("RelatedArtistsController",["$scope","$timeout","$rootScope",function(a,b,c){}]).controller("ArtistBiographyController",["$scope","$timeout","$rootScope","$stateParams","SpotifyService","LastfmService",function(a,b,c,d,e,f){function g(b){b=b.replace("&","and"),f.artistInfo(b).then(function(b){a.artist.biography=b.artist.bio})}"undefined"==typeof a.artist.name?e.getArtist(d.uri).then(function(a){g(a.name)}):g(a.artist.name)}]),angular.module("spotmop.browse",[]).config(["$stateProvider",function(a){a.state("browse",{url:"/browse",templateUrl:"app/browse/template.html"})}]),angular.module("spotmop.browse.featured",[]).config(["$stateProvider",function(a){a.state("browse.featured",{url:"/featured",templateUrl:"app/browse/featured/template.html",controller:"FeaturedController"}).state("browse.featuredplaylist",{url:"/featured/:uri",templateUrl:"app/browse/playlist/template.html",controller:"PlaylistController"})}]).controller("FeaturedController",["$scope","$rootScope","$filter","SpotifyService","NotifyService",function(a,b,c,d,e){a.playlists=[],a.featured=function(){return a.playlists[0]},a.partofday=function(){var a=parseFloat(c("date")(new Date,"H.m"));return a>=4&&9.3>a?"commute":a>=9.3&&11>a?"morning":a>=11&&13.5>a?"midday":a>=13.5&&17>a?"afternoon":a>=17&&19>a?"evening":a>=19&&21>a?"dinner":a>=21&&23>a||a>=0&&4>a?"late":void 0},d.featuredPlaylists().then(function(b){a.message=b.message,a.playlists=b.playlists.items})}]),angular.module("spotmop.browse.genre",[]).config(["$stateProvider",function(a){a.state("browse.genre",{url:"/genre",templateUrl:"app/browse/genre/template.html",controller:"GenreController"}).state("browse.genrecategory",{url:"/genre/:categoryid",templateUrl:"app/browse/genre/category.template.html",controller:"GenreCategoryController"}).state("browse.categoryplaylist",{url:"/genre/:categoryid/:uri",templateUrl:"app/browse/playlist/template.html",controller:"PlaylistController"})}]).controller("GenreController",["$scope","$rootScope","SpotifyService","NotifyService",function(a,b,c,d){function e(b){return"undefined"==typeof b?!1:(f=!0,void c.getUrl(b).then(function(b){a.categories.items=a.categories.items.concat(b.categories.items),a.categories.next=b.categories.next,f=!1}))}a.categories=[],c.discoverCategories().then(function(b){a.categories=b.categories});var f=!1;a.$on("spotmop:loadMore",function(){!f&&"undefined"!=typeof a.categories.next&&a.categories.next&&e(a.categories.next)})}]).controller("GenreCategoryController",["$scope","$rootScope","SpotifyService","$stateParams",function(a,b,c,d){function e(b){return"undefined"==typeof b?!1:(f=!0,void c.getUrl(b).then(function(b){a.playlists.items=a.playlists.items.concat(b.playlists.items),a.playlists.next=b.playlists.next,f=!1}))}a.category={},a.playlists=[],c.getCategory(d.categoryid).then(function(b){a.category=b,c.getCategoryPlaylists(d.categoryid).then(function(b){a.playlists=b.playlists})});var f=!1;a.$on("spotmop:loadMore",function(){!f&&"undefined"!=typeof a.playlists.next&&a.playlists.next&&e(a.playlists.next)})}]),angular.module("spotmop.browse.new",[]).config(["$stateProvider",function(a){a.state("browse.new",{url:"/new",templateUrl:"app/browse/new/template.html",controller:"NewController"}).state("browse.newalbum",{url:"/new/:uri",templateUrl:"app/browse/album/template.html",controller:"AlbumController"})}]).controller("NewController",["$scope","$element","$rootScope","SpotifyService","MopidyService",function(a,b,c,d,e){function f(b){return"undefined"==typeof b?!1:(g=!0,void d.getUrl(b).then(function(b){a.albums.items=a.albums.items.concat(b.albums.items),a.albums.next=b.albums.next,g=!1}))}a.albums=[],d.newReleases().then(function(b){a.albums=b.albums});var g=!1;a.$on("spotmop:loadMore",function(){!g&&"undefined"!=typeof a.albums.next&&a.albums.next&&f(a.albums.next)})}]),angular.module("spotmop.browse.playlist",[]).config(["$stateProvider",function(a){a.state("browse.playlist",{url:"/playlist/:uri",templateUrl:"app/browse/playlist/template.html",controller:"PlaylistController"})}]).controller("PlaylistController",["$scope","$rootScope","$filter","$state","$stateParams","$sce","SpotifyService","MopidyService","SettingsService","DialogService","NotifyService",function(a,b,c,d,e,f,g,h,i,j,k){function l(a){var b=[];return angular.forEach(a,function(a){var c=a.track;c.added_at=a.added_at,c.added_by=a.added_by,c.is_local=a.is_local,b.push(c)}),b}function m(b){return"undefined"==typeof b?!1:(n=!0,void g.getUrl(b).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(l(b.items)),a.tracklist.next=b.next,n=!1}))}a.playlist={images:[]},a.tracklist={tracks:[],type:"track"},a.totalTime=0,a.following=!1,a.followPlaylist=function(){g.followPlaylist(e.uri).then(function(b){a.following=!0,k.notify("Following playlist"),a.updatePlaylists()})},a.unfollowPlaylist=function(){g.unfollowPlaylist(e.uri).then(function(b){ a.following=!1,k.notify("Playlist removed"),a.updatePlaylists()})},a.recoverPlaylist=function(){g.followPlaylist(e.uri).then(function(b){a.following=!0,k.notify("Playlist recovered"),a.updatePlaylists()})},a.editPlaylist=function(){j.create("editPlaylist",a)},a.playPlaylist=function(){h.playStream(a.playlist.uri,a.tracklist.tracks.length)},a.totalTime=function(){var b=0;return a.tracklist.tracks.length>0&&angular.forEach(a.tracklist.tracks,function(a){"undefined"!=typeof a&&(b+=a.duration_ms)}),Math.round(b/1e5)},$(document).find(".browse > .content").on("scroll",function(b){var c=$(this).scrollTop(),d=$(this).outerHeight(),e=$(this).children(".inner").outerHeight(),f=-(c+d-e);100>=f&&a.$broadcast("spotmop:loadMore")}),a.$on("spotmop:playlist:reorder",function(b,c,e,f){var h=d.params.uri;g.movePlaylistTracks(h,c,e,f);for(var i=[],j=0;e>j;j++)i.push(a.tracklist.tracks[c+j]);f>c&&(f-=e),i.reverse(),a.$apply(function(){a.tracklist.tracks.splice(c,e),angular.forEach(i,function(b){a.tracklist.tracks.splice(f,0,b)})})}),g.getPlaylist(e.uri).then(function(c){a.playlist=c,a.tracklist.next=c.tracks.next,a.tracklist.previous=c.tracks.previous,a.tracklist.offset=c.tracks.offset,a.tracklist.total=c.tracks.total,a.tracklist.tracks=l(c.tracks.items),a.playlist.description=f.trustAsHtml(a.playlist.description),b.spotifyAuthorized&&g.isFollowingPlaylist(e.uri,i.getSetting("spotifyuser",{id:null}).id).then(function(b){a.following=$.parseJSON(b)}),"undefined"!=typeof e.categoryid&&g.getCategory(e.categoryid).then(function(b){a.category=b})}),a.$on("spotmop:keyboardShortcut:delete",function(b){a.playlist.owner.id!==i.getSetting("spotifyuserid")?k.error("Cannot delete from a playlist you don't own"):a.$broadcast("spotmop:tracklist:deleteSelectedTracks")});var n=!1;a.$on("spotmop:loadMore",function(){!n&&"undefined"!=typeof a.tracklist.next&&a.tracklist.next&&m(a.tracklist.next)})}]),angular.module("spotmop.browse.user",[]).config(["$stateProvider",function(a){a.state("browse.user",{url:"/user/:uri",templateUrl:"app/browse/user/template.html",controller:"UserController"})}]).controller("UserController",["$scope","$rootScope","SpotifyService","$stateParams",function(a,b,c,d){function e(b){return"undefined"==typeof b?!1:(f=!0,void c.getUrl(b).then(function(b){a.playlists=a.playlists.concat(b.items),a.next=b.next,f=!1}))}a.user={},a.playlists=[],c.getUser(d.uri).then(function(b){a.user=b,c.getPlaylists(b.id).then(function(b){a.playlists=b.items,a.next=b.next,a.totalPlaylists=b.total})});var f=!1;a.$on("spotmop:loadMore",function(){!f&&"undefined"!=typeof a.next&&a.next&&e(a.next)})}]),angular.module("spotmop.common.contextmenu",[]).directive("contextmenu",function(){return{restrict:"E",templateUrl:"app/common/contextmenu/template.html",link:function(a,b,c){},controller:["$scope","$rootScope","$element",function(a,b,c){a.play=function(){b.$broadcast("spotmop:tracklist:playSelectedTracks"),c.fadeOut("fast"),a.isTouchDevice()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.enqueue=function(){b.$broadcast("spotmop:tracklist:enqueueSelectedTracks"),c.fadeOut("fast"),a.isTouchDevice()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.unqueue=function(){b.$broadcast("spotmop:tracklist:unqueueSelectedTracks"),c.fadeOut("fast"),a.isTouchDevice()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.playNext=function(){b.$broadcast("spotmop:tracklist:enqueueSelectedTracks",!0),c.fadeOut("fast"),a.isTouchDevice()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.addToPlaylist=function(){b.$broadcast("spotmop:tracklist:addSelectedTracksToPlaylist"),c.fadeOut("fast")},a.removeFromPlaylist=function(){b.$broadcast("spotmop:tracklist:deleteSelectedTracks"),c.fadeOut("fast")},a.addToLibrary=function(){b.$broadcast("spotmop:tracklist:addSelectedTracksToLibrary"),c.fadeOut("fast")},a.selectAll=function(){b.$broadcast("spotmop:tracklist:selectAll")},a.unselectAll=function(){b.$broadcast("spotmop:tracklist:unselectAll"),c.fadeOut("fast")},a.$on("spotmop:contextMenu:show",function(b,d,e,f){var g=d.pageY-$(window).scrollTop(),h=d.pageX-window.pageYOffset;"undefined"!=typeof f&&f&&(h-=c.outerWidth()),c.css({top:g,left:h+5}).show(),a.$apply(function(){a.context=e})}),a.$on("spotmop:touchContextMenu:show",function(b,d){c.show(),a.$apply(function(){a.context=d})}),a.$on("spotmop:contextMenu:hide",function(a){c.fadeOut("fast")})}]}}),angular.module("spotmop.directives",[]).config(["cfpLoadingBarProvider",function(a){a.latencyThreshold=250}]).directive("singleclick",function(){return function(a,b,c){b.bind("touchstart click",function(b){b.preventDefault(),b.stopPropagation(),a.$apply(c.singleclick)})}}).directive("switch",["$rootScope","SettingsService",function(a,b){return{restrict:"E",scope:{name:"@"},replace:!0,transclude:!0,link:function(c,d,e){c.on=b.getSetting(c.name,!1),d.bind("touchstart click",function(d){d.preventDefault(),d.stopPropagation(),c.$apply(function(){c.on=!c.on,b.setSetting(c.name,c.on),a.$broadcast("spotmop:settings:changed",{name:c.name,value:c.on})})})},template:''}}]).directive("scrollingPanel",function(){return{restrict:"C",link:function(a,b,c){b.on("scroll",function(b){var c=$(this).scrollTop(),d=$(this).outerHeight(),e=$(this).children(".inner").outerHeight(),f=-(c+d-e);100>=f&&a.$broadcast("spotmop:loadMore")})}}}).directive("thumbnail",["$timeout","$http",function(a,b){return{restrict:"E",scope:{images:"=",size:"="},replace:!0,transclude:!0,link:function(a,c,d){function e(b){if(b.length<=0)return!1;for(var c=0;c=100&&d.height<=200)return d;if(d.height>200&&d.height<=300)return d;if(d.height>300&&d.height<400)return d}else{if(d.height>=200&&d.height<=300)return d;if(d.height>300&&d.height<=500)return d;if(d.height>=150&&d.height<200)return d}}return b[0]}a.image=e(a.images),a.image&&b({method:"GET",url:a.image.url,cache:!0}).success(function(){c.css("background-image","url("+a.image.url+")")})},template:'
'}}]).directive("confirmationButton",function(){return{restrict:"E",controller:["$scope","$element",function(a,b){a.text="Button text",a.confirming=!1,a.text=a.defaultText,$(document).on("click",function(c){c.target==b[0]&&1==c.which?a.confirming?"function"==typeof a.$parent[a.onConfirmation]()&&a.$parent[a.onConfirmation]():(a.confirming=!0,a.text=a.confirmationText,a.$apply()):(a.confirming=!1,a.text=a.defaultText,a.$apply())})}],scope:{text:"@",extraClasses:"@",confirmationText:"@",defaultText:"@",onConfirmation:"@"},replace:!0,transclude:!0,template:''}}).directive("textOverImage",function(){return{restrict:"A",link:function(a,b){a.$on("spotmop:detectBackgroundColor",function(a){BackgroundCheck.init({targets:$.merge($(b).parent(),$(document).find("#utilities")),images:b.closest(".intro").find(".image")}),BackgroundCheck.refresh()})}}}).directive("preloadedimage",["$rootScope","$timeout",function(a,b){return{restrict:"E",scope:{url:"@",useproxy:"@",detectbackground:"@",opacity:"@"},link:function(a,b,c){function d(){var c="";c+=a.url;var d=$('');d.load(function(){b.attr("style",'background-image: url("'+c+'");');var d=1;"undefined"!=typeof a.opacity&&(d=a.opacity),b.animate({opacity:d},200)})}b.attr("watch")&&a.$watch("url",function(a,b){a&&d()},!0),d()},template:""}}]).directive("backgroundparallax",["$rootScope","$timeout","$interval","$http",function(a,b,c,d){return{restrict:"E",terminal:!0,scope:{image:"@",useproxy:"@",detectbackground:"@",opacity:"@"},link:function(a,b,d){function e(a){var c=b.outerWidth(),d=b.outerHeight();if((h.canvas.width!=c||h.canvas.height!=d)&&(h.canvas.width=c,h.canvas.height=d),a.widthc){var e=c/a.width;a.width=a.width*e,a.height=a.height*e}if(a.heightf&&e(i)}})},10)},template:''}}]).filter("nullOrUndefined",[function(){return function(a,b){for(var c=[],d=0;d=b&&(b="0"+b);var c=Math.floor(a/6e4%60);return c+":"+b}}).filter("stripAccents",function(){return function(a){for(var b=[/[\300-\306]/g,/[\340-\346]/g,/[\310-\313]/g,/[\350-\353]/g,/[\314-\317]/g,/[\354-\357]/g,/[\322-\330]/g,/[\362-\370]/g,/[\331-\334]/g,/[\371-\374]/g,/[\321]/g,/[\361]/g,/[\307]/g,/[\347]/g],c=["A","a","E","e","I","i","O","o","U","u","N","n","C","c"],d=0;d=200&&c.height<=300)return c.url;if(c.height>300&&c.height<=500)return c.url;if(c.height>=150&&c.height<200)return c.url}return a[0].url}}),angular.module("spotmop.common.tracklist",["spotmop.services.mopidy"]).directive("track",function(){return{restrict:"E",templateUrl:"app/common/tracklist/track.template.html",controller:["$element","$scope","$rootScope","MopidyService","NotifyService",function(a,b,c,d,e){a.mouseup(function(a){1===a.which?(b.isTouchDevice()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$emit("spotmop:track:clicked",b)):b.track.selected&&3===a.which&&b.$emit("spotmop:contextMenu:show",a,"track")}),a.dblclick(function(a){for(var c=b.tracklist.tracks.indexOf(b.track),f=[],g=c+1;g0){var a="Adding "+f.length+" tracks";f.length>10&&(a+="... this could take some time"),e.notify(a),d.addToTrackList(f)}})})}]}}).directive("tltrack",function(){return{restrict:"E",templateUrl:"app/common/tracklist/tltrack.template.html",link:function(a,b,c){},controller:["$element","$scope","$rootScope","MopidyService","PlayerService",function(a,b,c,d,e){b.state=e.state,a.mouseup(function(a){1===a.which?(b.isTouchDevice()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$emit("spotmop:track:clicked",b)):b.track.selected&&3===a.which&&b.$emit("spotmop:contextMenu:show",a,"tltrack")}),a.dblclick(function(a){d.getCurrentTlTracks().then(function(a){$.each(a,function(a,c){return c.tlid==b.track.tlid?d.playTlTrack({tl_track:c}):void 0})})})}]}}).directive("localtrack",function(){return{restrict:"E",templateUrl:"app/common/tracklist/localtrack.template.html",link:function(a,b,c){},controller:["$element","$scope","$rootScope","MopidyService","PlayerService","NotifyService",function(a,b,c,d,e,f){b.state=e.state,a.mouseup(function(a){1===a.which?(b.isTouchDevice()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$emit("spotmop:track:clicked",b)):b.track.selected&&3===a.which&&b.$emit("spotmop:contextMenu:show",a,"localtrack")}),a.dblclick(function(a){for(var c=b.tracklist.tracks.indexOf(b.track),e=[],g=c+1;g0){var a="Adding "+e.length+" tracks";e.length>10&&(a+="... this could take some time"),f.notify(a),d.addToTrackList(e)}})})}]}}).controller("TracklistController",["$element","$scope","$filter","$rootScope","$stateParams","MopidyService","SpotifyService","DialogService","NotifyService",function(a,b,c,d,e,f,g,h,i){function j(){var a=c("filter")(b.tracklist.tracks,{selected:!0}),d=a[0];if("tltrack"==b.tracklist.type)f.getCurrentTlTracks().then(function(a){$.each(a,function(a,b){return b.tlid==d.tlid?f.playTlTrack({tl_track:b}):void 0})});else{for(var e=[],g=1;g10&&(h+="... this could take some time"),i.notify(h),f.playTrack([d.uri],0).then(function(){e.length>0&&f.addToTrackList(e)})}}$(document).contextmenu(function(a){return $(a.target).closest(".tracklist").length>0?!1:void 0}),b.$on("spotmop:track:dragging",function(a){}),b.$on("spotmop:track:clicked",function(a,e){if(d.ctrlKeyHeld||b.isTouchDevice()?e.track.selected?e.$apply(function(){e.track.selected=!1}):e.$apply(function(){e.track.selected=!0}):d.ctrlKeyHeld||(angular.forEach(b.tracklist.tracks,function(a){a.selected=!1}),e.$apply(function(){e.track.selected=!0})),d.shiftKeyHeld){var f="undefined"!=typeof b.lastSelectedTrack?b.lastSelectedTrack.$index:0,g=e.$index;e.$index=h;h++)b.tracklist.tracks[h].selected=!0;b.$apply()}b.lastSelectedTrack=e,b.isTouchDevice()&&(c("filter")(b.tracklist.tracks,{selected:!0}).length>0?d.$broadcast("spotmop:touchContextMenu:show",b.tracklist.type):d.$broadcast("spotmop:contextMenu:hide"))}),b.$on("spotmop:tracklist:enqueueSelectedTracks",function(a,d){var e=null;if("undefined"!=typeof d&&1==d){e=0;var g=b.state().currentTlTrack;if(g){var h=c("filter")(b.currentTracklist,{tlid:g.tlid});h.length>0&&(e=b.currentTracklist.indexOf(h[0])+1)}}var j=c("filter")(b.tracklist.tracks,{selected:!0}),k=[];angular.forEach(j,function(a){k.push(a.uri)});var l="Adding "+j.length+" tracks to queue";j.length>10&&(l+="... this could take some time"),i.notify(l),f.addToTrackList(k,e)}),b.$on("spotmop:tracklist:playSelectedTracks",function(){j()}),b.$on("spotmop:keyboardShortcut:enter",function(){j()}),b.$on("spotmop:tracklist:unqueueSelectedTracks",function(a){var d=c("filter")(b.tracklist.tracks,{selected:!0}),e=[];angular.forEach(d,function(a){e.push(a.tlid)}),f.removeFromTrackList(e)}),b.$on("spotmop:tracklist:deleteSelectedTracks",function(a){var d=c("filter")(b.tracklist.tracks,{selected:!0}),f=[];angular.forEach(d,function(a,c){f.push(b.tracklist.tracks.indexOf(a)),a.transitioning=!0}),g.deleteTracksFromPlaylist(e.uri,b.playlist.snapshot_id,f).then(function(a){"undefined"!=typeof a.error?(i.error(a.error.message),angular.forEach(d,function(a,b){a.transitioning=!1})):(b.tracklist.tracks=c("nullOrUndefined")(b.tracklist.tracks,"selected"),b.playlist.snapshot_id=a.snapshot_id)})}),b.$on("spotmop:tracklist:addSelectedTracksToPlaylist",function(a){var d=c("filter")(b.tracklist.tracks,{selected:!0}),e=[];angular.forEach(d,function(a){"undefined"!=typeof a.track?e.push(a.track.uri):e.push(a.uri)}),h.create("addToPlaylist",b)}),b.$on("spotmop:tracklist:addSelectedTracksToLibrary",function(a){var d=c("filter")(b.tracklist.tracks,{selected:!0}),e=[];angular.forEach(d,function(a){"undefined"!=typeof a.track?e.push(g.getFromUri("trackid",a.track.uri)):e.push(g.getFromUri("trackid",a.uri))}),g.addTracksToLibrary(e)}),b.$on("spotmop:tracklist:selectAll",function(a){angular.forEach(b.tracklist.tracks,function(a){a.selected=!0})}),b.$on("spotmop:tracklist:unselectAll",function(a){angular.forEach(b.tracklist.tracks,function(a){a.selected=!1})})}]),angular.module("spotmop.common.tracklist.service",[]).factory("TracklistService",["$rootScope",function(a){return{getSelectedTracks:function(){console.log("triggered getSelectedTracks")}}}]),angular.module("spotmop.discover",[]).config(["$stateProvider",function(a){a.state("discover",{url:"/discover",templateUrl:"app/discover/template.html",controller:"DiscoverController"})}]).controller("DiscoverController",["$scope","$rootScope","SpotifyService","EchonestService","SettingsService","NotifyService",function(a,b,c,d,e,f){if(a.artists=[],a.playlists=[],a.albums=[],a.recommendations={currentArtist:{artists:[],recommendations:[]},suggestions:[]},e.getSetting("echonestenabled",!1)){if("undefined"!=typeof a.state().currentTlTrack.track){var g=[];angular.forEach(a.state().currentTlTrack.track.artists,function(a){g.push({name:a.name,name_encoded:encodeURIComponent(a.name),uri:a.uri})}),a.recommendations.currentArtist.artists=g,d.recommendedArtists(a.recommendations.currentArtist.artists).then(function(b){var d=b.response.artists,e=[];d.length<=0?f.error("Your taste profile is empty. Play some more music!"):(angular.forEach(d,function(a){"undefined"!=typeof a.foreign_ids&&a.foreign_ids.length>0&&e.push(a.foreign_ids[0].foreign_id)}),c.getArtists(e).then(function(b){a.recommendations.currentArtist.recommendations=b.artists}))})}d.recommendedArtists().then(function(b){var d=[];"undefined"!=typeof b.response&&"undefined"!=typeof b.response.artists&&(d=b.response.artists);var e=[];d.length<=0?f.error("Your taste profile is empty. Play some more music!"):(angular.forEach(d,function(a){e.push(a.foreign_ids[0].foreign_id)}),c.getArtists(e).then(function(b){a.recommendations.suggestions=b.artists}))})}}]),angular.module("spotmop.library",[]).config(["$stateProvider",function(a){a.state("library",{url:"/library",templateUrl:"app/library/template.html"}).state("library.playlists",{url:"/playlists",templateUrl:"app/library/playlists.template.html",controller:"LibraryPlaylistsController"}).state("library.playlist",{url:"/playlist/:uri",templateUrl:"app/browse/playlist/template.html",controller:"PlaylistController"}).state("library.tracks",{url:"/tracks",templateUrl:"app/library/tracks.template.html",controller:"LibraryTracksController"}).state("library.artists",{url:"/artists",templateUrl:"app/library/artists.template.html",controller:"LibraryArtistsController"}).state("library.albums",{url:"/albums",templateUrl:"app/library/albums.template.html",controller:"LibraryAlbumsController"}).state("library.files",{url:"/files/:folder",templateUrl:"app/library/files.template.html",controller:"LibraryFilesController"})}]).controller("LibraryTracksController",["$scope","$rootScope","$filter","SpotifyService","SettingsService","DialogService",function(a,b,c,d,e,f){function g(a){var b=[];return angular.forEach(a,function(a){var c=a.track;c.added_at=a.added_at,b.push(c)}),b}function h(b){return"undefined"==typeof b?!1:(j=!0,void d.getUrl(b).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(g(b.items)),a.tracklist.next=b.next,j=!1}))}a.tracklist={tracks:[]};var i=e.getSetting("spotifyuserid",a.$parent.spotifyUser.id);d.getMyTracks(i).then(function(b){a.tracklist=b,a.tracklist.tracks=g(b.items),"undefined"!=typeof b.error&&401==b.error.status&&Spotify.refreshToken()}),a.$on("spotmop:keyboardShortcut:delete",function(b){var e=c("filter")(a.tracklist.tracks,{selected:!0}),f=[];angular.forEach(e,function(a,b){f.push(d.getFromUri("trackid",a.uri))}),d.deleteTracksFromLibrary(f).then(function(b){a.tracklist.tracks=c("filter")(a.tracklist.tracks,{selected:!1})})});var j=!1;a.$on("spotmop:loadMore",function(){!j&&"undefined"!=typeof a.tracklist.next&&a.tracklist.next&&h(a.tracklist.next)})}]).controller("LibraryFilesController",["$scope","$rootScope","$filter","$stateParams","SpotifyService","SettingsService","DialogService","MopidyService",function(a,b,c,d,e,f,g,h){function i(){h.getLibraryItems(k).then(function(b){var e=c("filter")(b,{type:"track"});a.tracklist.tracks=e;var f=j(c("filter")(b,{type:"directory"}));"local:directory"!=d.folder&&f.unshift({name:"..",uri:l,type:"directory",isParentFolder:!0}),a.folders=f})}function j(a){for(var b=0;b-1?e.lookup(a.track.uri).then(function(a){b(a[0])}):b(a))})}function o(){var a=p.currentTlTrack.track,b="No track playing";if(a){var c="■ ",d="";$.each(a.artists,function(a,b){""!=d&&(d+=", "),d+=b.name}),p.playing&&(c="▶ "),b=c+" "+a.name+" - "+d}document.title=b}var p={playing:!1,isRepeat:!1,isRandom:!1,isMute:!1,volume:100,playPosition:0,currentTlTrack:!1,playPositionPercent:function(){return p.currentTlTrack?(p.playPosition/p.currentTlTrack.track.length*100).toFixed(2):0}};a.$on("mopidy:state:online",function(){j(),n(),m(),l(),e.getState().then(function(a){"playing"==a?p.playing=!0:p.playing=!1})}),a.$on("mopidy:event:optionsChanged",function(a,b){j()}),a.$on("mopidy:event:playbackStateChanged",function(a,b){m(b.new_state)}),a.$on("mopidy:event:seeked",function(a,b){k(b.time_position)}),a.$on("mopidy:event:volumeChanged",function(a,b){b.volume!=p.volume&&l(b.volume)}),a.$on("mopidy:event:trackPlaybackStarted",function(a,b){("undefined"==typeof p.currentTlTrack.track||p.currentTlTrack.track.uri!=b.tl_track.track.uri)&&(p.currentTlTrack=b.tl_track,n(b.tl_track),m())}),b(function(){p.playing&&"undefined"!=typeof p.currentTlTrack&&p.playPosition=100&&(p.volume=100),q.setVolume(p.volume),h.shortcut("volume-up"))}),a.$on("spotmop:keyboardShortcut:down",function(b){a.ctrlKeyHeld&&(p.volume-=10,p.volume<0&&(p.volume=0),q.setVolume(p.volume),h.shortcut("volume-down"))});var q={state:function(){return p},playPause:function(){p.playing?(e.pause(),p.playing=!1):(e.play(),p.playing=!0)},stop:function(){e.stopPlayback(),p.playing=!1},next:function(){d.getSetting("echonestenabled",!1)&&g.addToTasteProfile("skip",p.currentTlTrack.track.uri),e.play(),e.next()},previous:function(){e.previous()},seek:function(a){p.playPosition=a,e.seek(a)},setVolume:function(a){p.volume=a,e.setVolume(a)},toggleRepeat:function(){p.isRepeat?e.setRepeat(!1).then(function(a){p.isRepeat=!1}):e.setRepeat(!0).then(function(a){p.isRepeat=!0}),console.log(p)},toggleRandom:function(){p.isRandom?e.setRandom(!1).then(function(a){p.isRandom=!1}):e.setRandom(!0).then(function(a){p.isRandom=!0})},toggleMute:function(){p.isMute?e.setMute(!1).then(function(a){p.isMute=!1}):e.setMute(!0).then(function(a){p.isMute=!0})}};return q}]),angular.module("spotmop.queue",[]).config(["$stateProvider",function(a){a.state("queue",{url:"/queue",templateUrl:"app/queue/template.html",controller:"QueueController"})}]).controller("QueueController",["$scope","$rootScope","$filter","$timeout","$state","MopidyService","SpotifyService",function(a,b,c,d,e,f,g){function h(b){var c=0;$.each(b,function(a,b){c+=b.track.length}),a.totalTime=Math.round(c/1e5)}a.totalTime=0,a.tracklist={type:"tltrack",tracks:a.$parent.currentTracklist},a.$watch(function(a){return a.$parent.currentTracklist},function(b,c){a.tracklist.tracks=b,h(b)}),a.$on("spotmop:keyboardShortcut:delete",function(b){var d=c("filter")(a.tracklist.tracks,{selected:!0}),e=[];angular.forEach(d,function(a,b){e.push(a.tlid)}),a.$apply(function(){a.tracklist.tracks=c("filter")(a.tracklist.tracks,{selected:!1})}),f.removeFromTrackList(e)})}]),angular.module("spotmop.search",[]).config(["$stateProvider",function(a){a.state("search",{url:"/search/:query/:type",templateUrl:"app/search/template.html",controller:"SearchController",params:{type:{squash:!0,value:"all"},query:{squash:!0,value:null}}})}]).controller("SearchController",["$scope","$rootScope","$state","$stateParams","$timeout","$filter","SpotifyService",function(a,b,c,d,e,f,g){function h(b,c){if("undefined"==typeof b)var b=a.type;switch(b){case"track":g.getSearchResults("track",c,50).then(function(b){a.tracklist=b.tracks,a.tracklist.tracks=b.tracks.items,a.tracklist.type="track",a.next=b.tracks.next});break;case"album":g.getSearchResults("album",c,50).then(function(b){a.albums=b.albums,a.next=b.albums.next});break;case"artist":g.getSearchResults("artist",c,50).then(function(b){a.artists=b.artists,a.next=b.artists.next});break;case"playlist":g.getSearchResults("playlist",c,50).then(function(b){a.playlists=b.playlists,a.next=b.playlists.next});break;default:g.getSearchResults("track",c,50).then(function(b){a.tracklist=b.tracks,a.tracklist.type="track",a.tracklist.tracks=b.tracks.items}),g.getSearchResults("album",c,50).then(function(b){a.albums=b.albums}),g.getSearchResults("artist",c,50).then(function(b){a.artists=b.artists}),g.getSearchResults("playlist",c,50).then(function(b){a.playlists=b.playlists})}}function i(b){return"undefined"==typeof b?!1:(j=!0,void g.getUrl(b).then(function(b){switch(a.type){case"artist":a.artists.items=a.artists.items.concat(b.artists.items),a.next=b.artists.next;break;case"album":a.albums.items=a.albums.items.concat(b.albums.items),a.next=b.albums.next;break;case"track":a.tracklist.tracks=a.tracklist.tracks.concat(b.tracks.items),a.next=b.tracks.next;break;case"playlist":a.playlists.items=a.playlists.items.concat(b.playlists.items),a.next=b.playlists.next}j=!1}))}a.tracklist={tracks:[],type:"track"},a.albums=[],a.artists=[],a.playlists=[],a.type=d.type,a.query=f("stripAccents")(d.query),a.loading=!1;a.isTouchDevice()||$(document).find(".search-form input.query").focus(),a.query&&h(a.type,a.query);var j=!1;a.$on("spotmop:loadMore",function(){!j&&"undefined"!=typeof a.next&&a.next&&i(a.next)})}]),angular.module("spotmop.services.dialog",[]).factory("DialogService",["$rootScope","$compile","$interval","$timeout",function(a,b,c,d){return{create:function(a,c){"undefined"==typeof c&&(c=!1),$("body").children(".dialog").length>0&&console.log("A dialog already exists..."),$("body").append(b('')(c))},remove:function(){$("body").children(".dialog").fadeOut(200,function(){$(this).remove()})}}}]).directive("dialog",["$compile",function(a){return{restrict:"E",replace:!0,transclude:!0,scope:{type:"@"},templateUrl:"app/services/dialog/template.html",link:function(b,c){c.find(".content").html(a("<"+b.type+"dialog />")(b))},controller:["$scope","$element","DialogService",function(a,b,c){a.closeDisabled=!1,"initialsetup"==a.type&&(a.closeDisabled=!0),a.closeDialog=function(){c.remove()},a.$on("spotmop:keyboardShortcut:esc",function(b){a.closeDisabled||c.remove()})}]}}]).directive("createplaylistdialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/createplaylist.template.html",controller:["$scope","$element","$rootScope","DialogService","SettingsService","SpotifyService",function(a,b,c,d,e,f){a.saving=!1,a.playlistPublic="true",a.savePlaylist=function(){a.saving=!0,"true"==a.playlistPublic?a.playlistPublic=!0:a.playlistPublic=!1,f.createPlaylist(a.$parent.spotifyUser.id,{name:a.playlistName,"public":a.playlistPublic}).then(function(b){a.$parent.playlists.items.push(b),a.$parent.updatePlaylists(),d.remove(),c.$broadcast("spotmop:notifyUser",{id:"saved",message:"Saved",autoremove:!0})})}}]}}).directive("editplaylistdialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/editplaylist.template.html",controller:["$scope","$element","$rootScope","DialogService","SpotifyService",function(a,b,c,d,e){a.playlistNewName=a.$parent.playlist.name,a.playlistNewPublic=a.$parent.playlist["public"].toString(),a.saving=!1,a.savePlaylist=function(){a.saving=!0,"true"==a.playlistNewPublic?a.playlistNewPublic=!0:a.playlistNewPublic=!1,e.updatePlaylist(a.$parent.playlist.uri,{name:a.playlistNewName,"public":a.playlistNewPublic }).then(function(b){a.$parent.playlist.name=a.playlistNewName,a.$parent.playlist["public"]=a.playlistNewPublic,a.$parent.updatePlaylists(),d.remove(),c.$broadcast("spotmop:notifyUser",{id:"saved",message:"Saved",autoremove:!0})})}}]}}).directive("addtoplaylistdialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/addtoplaylist.template.html",controller:["$scope","$element","$rootScope","$filter","DialogService","SpotifyService","SettingsService",function(a,b,c,d,e,f,g){a.playlists=[];var h=g.getSetting("spotifyuser",{id:"undefined"}).id;f.getPlaylists(h,50).then(function(b){a.playlists=d("filter")(b.items,{owner:{id:h}})}),a.playlistSelected=function(b){var g=d("filter")(a.$parent.tracklist.tracks,{selected:!0}),h=[];angular.forEach(g,function(a){"undefined"!=typeof a.track?h.push(a.track.uri):h.push(a.uri)}),f.addTracksToPlaylist(b.uri,h).then(function(b){e.remove(),c.$broadcast("spotmop:tracklist:unselectAll"),a.$emit("spotmop:notifyUser",{id:"adding-to-playlist",message:"Added "+h.length+" tracks",autoremove:!0})})}}]}}).directive("volumecontrolsdialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/volumecontrols.template.html",controller:["$scope","$element","$rootScope","$filter","DialogService","PlayerService",function(a,b,c,d,e,f){a.state=function(){return f.state()},a.setVolume=function(a){var b,c,d,e;b=$(a.target).hasClass("slider")?$(a.target):$(a.target).closest(".slider"),c=b.offset(),d=a.pageX-c.left,e=d/b.innerWidth()*100,e=parseInt(e),f.setVolume(e)}}]}}).directive("initialsetupdialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/initialsetup.template.html",controller:["$scope","$element","$rootScope","$filter","DialogService","SettingsService","SpotifyService",function(a,b,c,d,e,f,g){f.setSetting("attemptSpotifyAuthorization",!0),a.saving=!1,a.save=function(){a.name&&""!=a.name?(a.saving=!0,f.getSetting("attemptSpotifyAuthorization",!1)&&g.authorize(),f.setSetting("pushername",a.name),e.remove()):a.error=!0}}]}}),angular.module("spotmop.services.echonest",[]).factory("EchonestService",["$rootScope","$resource","$localStorage","$http","$interval","$timeout","$cacheFactory","$q","SettingsService",function(a,b,c,d,e,f,g,h,i){var j="http://developer.echonest.com/api/v4/",k=i.getSetting("echonestapikey","YVW64VSEPEV93M4EG");return{isOnline:!1,start:function(){i.setSetting("echonestenabled",!0),i.getSetting("echonesttasteprofileid",!1)?this.getTasteProfile(i.getSetting("echonesttasteprofileid",!1)).success(function(b){this.isOnline=!0,a.echonestOnline=!0,c.echonesttasteprofile=b.response.catalog}).error(function(b){this.isOnline=!1,a.echonestOnline=!1}):this.createTasteProfile().success(function(b){i.setSetting("echonesttasteprofileid",b.response.id),this.isOnline=!0,a.echonestOnline=!0}).error(function(b){this.isOnline=!1,a.echonestOnline=!1})},stop:function(){i.setSetting("echonestenabled",!1),a.echonestOnline=!1},createTasteProfile:function(){return $.ajax({url:j+"catalog/create",method:"POST",data:{api_key:k,format:"json",type:"general",name:"spotmop:"+Date.now()+Math.round(1e3*(Math.random()+1))}})},getTasteProfile:function(){var a=i.getSetting("echonesttasteprofileid",!1);return $.ajax({url:j+"tasteprofile/read?api_key="+k+"&id="+a,method:"GET"})},addToTasteProfile:function(a,b){var c=i.getSetting("echonesttasteprofileid",!1),d=[],e=[];return e="string"==typeof b?[b]:b,angular.forEach(e,function(b){d.push({action:a,item:{track_id:b}})}),$.ajax({url:j+"tasteprofile/update",method:"POST",data:{api_key:k,format:"json",data_type:"json",id:c,data:JSON.stringify(d)}})},getArtistBiography:function(b){var c=h.defer();return d({cache:!0,method:"GET",url:j+"artist/biographies?api_key="+k+"&format=json&results=1&id="+b}).success(function(a){c.resolve(a)}).error(function(b){a.$broadcast("spotmop:notifyUser",{type:"bad",id:"getArtistBiography",message:b.error.message}),c.reject(b.error.message)}),c.promise},recommendedArtists:function(b){var c=i.getSetting("echonesttasteprofileid",!1);if("undefined"==typeof b||!b||b.length<=0)var e="&seed_catalog="+c;else{var e="";angular.forEach(b,function(a){e+="&name="+a.name_encoded})}var f=h.defer();return d.get(j+"artist/similar?api_key="+k+e+"&format=json&bucket=id:spotify&results=10").success(function(a){f.resolve(a)}).error(function(b){a.$broadcast("spotmop:notifyUser",{type:"bad",id:"catalogRadio",message:b.error.message}),f.reject("Failed to get albums")}),f.promise},favoriteArtists:function(){var b=i.getSetting("echonesttasteprofileid",!1),c=h.defer();return d.get(j+"playlist/static?api_key="+k+"&type=catalog&seed_catalog="+b+"&bucket=id:spotify&format=json&results=20&adventurousness=0").success(function(a){c.resolve(a)}).error(function(b){a.$broadcast("spotmop:notifyUser",{type:"bad",id:"favoriteArtists",message:b.error.message}),c.reject("Failed to get albums")}),c.promise},catalogRadio:function(){var b=i.getSetting("echonesttasteprofileid",!1),c=h.defer();return d.get(j+"playlist/static?api_key="+k+"&type=catalog-radio&seed_catalog="+b+"&bucket=artist_discovery&bucket=id:spotify&format=json&results=20").success(function(a){c.resolve(a)}).error(function(b){a.$broadcast("spotmop:notifyUser",{type:"bad",id:"catalogRadio",message:b.error.message}),c.reject("Failed to get albums")}),c.promise},startArtistRadio:function(b){var c=h.defer();return d.get(j+"playlist/dynamic/create?api_key="+k+"&type=artist-radio&artist="+b+"&bucket=tracks&bucket=id:spotify&results=1").success(function(a){c.resolve(a)}).error(function(b){a.$broadcast("spotmop:notifyUser",{type:"bad",id:"artistRadio",message:b.error.message}),c.reject("Failed to create artist radio")}),c.promise}}}]),angular.module("spotmop.services.lastfm",[]).factory("LastfmService",["$rootScope","$resource","$localStorage","$http","$interval","$timeout","$filter","$q","SettingsService","NotifyService",function(a,b,c,d,e,f,g,h,i,j){var k={sendRequest:function(a){var b=h.defer();return d({cache:!0,method:"GET",url:l+"?format=json&api_key="+m+"&"+a}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},trackInfo:function(a,b){return this.sendRequest("method=track.getInfo&track="+b+"&artist="+a)},albumInfo:function(a,b){return this.sendRequest("method=album.getInfo&album="+b+"&artist="+a)},artistInfo:function(a){return this.sendRequest("method=artist.getInfo&artist="+a)}},l="http://ws.audioscrobbler.com/2.0",m=i.getSetting("lastfmkey","4320a3ef51c9b3d69de552ac083c55e3");return k}]),angular.module("spotmop.services.mopidy",[]).factory("MopidyService",["$q","$rootScope","$cacheFactory","$location","$timeout","SettingsService","EchonestService","PusherService",function(a,b,c,d,e,f,g,h){function i(c,d){return function(){var e=a.defer(),f=Array.prototype.slice.call(arguments),g=d||this;return b.$broadcast("spotmop:callingmopidy",{name:c,args:f}),g.isConnected?j(c,g,f).then(function(a){e.resolve(a),b.$broadcast("spotmop:calledmopidy",{name:c,args:f})},function(a){e.reject(a),b.$broadcast("spotmop:errormopidy",{name:c,args:f,err:a})}):j(c,g,f).then(function(a){e.resolve(a),b.$broadcast("spotmop:calledmopidy",{name:c,args:f})},function(a){e.reject(a),b.$broadcast("spotmop:errormopidy",{name:c,args:f,err:a})}),e.promise}}function j(a,b,c){for(var d=a.split("."),e=d.pop(),f=0;f'+a+"");$("#notifications").append(c),b&&d(function(){c.fadeOut(200,function(){c.remove()})},b)},error:function(a,b){if("undefined"==typeof b)var b=2500;var c=$(''+a+"");$("#notifications").append(c),b&&d(function(){c.fadeOut(200,function(){c.remove()})},b)},spotifyAuthenticationError:function(){this.error("Please authenticate with Spotify - you can find this under settings")},shortcut:function(a){$("#notifications").find("notification.keyboard-shortcut").remove();var b=$('');$("#notifications").append(b),d(function(){b.fadeOut(200,function(){b.remove()})},1500)},browserNotify:function(a,b,c){if(e.getSetting("notificationsDisabled",!1))return!1;var d=window.Notification||window.mozNotification||window.webkitNotification;if("undefined"==typeof d)return!1;if("undefined"!=typeof d&&d.requestPermission(function(a){}),"undefined"==typeof c)var c="";new d(a,{body:b,dir:"auto",lang:"EN",tag:"spotmopNotification",icon:c});return!0}}}]).directive("notification",function(){return{restrict:"AE",link:function(a,b,c){console.log(b)}}}),angular.module("spotmop.services.pusher",[]).factory("PusherService",["$rootScope","$http","$q","$localStorage","$cacheFactory","$templateCache","SettingsService","NotifyService",function(a,b,c,d,e,f,g,h){"undefined"==typeof d.pusher&&(d.pusher={});var i="http://"+g.getSetting("mopidyhost",window.location.hostname);i+=":"+g.getSetting("mopidyport","6680"),i+="/spotmop/";var j={pusher:{},isConnected:!1,start:function(){var b=g.getSetting("mopidyhost",window.location.hostname),c=g.getSetting("pusherport","6681");try{var d="ws://"+b+":"+c+"/pusher",i=new WebSocket(d);i.onopen=function(){a.$broadcast("spotmop:pusher:online"),this.isConnected=!0},i.onmessage=function(b){var c=JSON.parse(b.data);if(c.pusher)if(c.startup){console.info("Pusher connected as "+c.details.id),g.setSetting("pusherid",c.details.id),g.setSetting("pusherip",c.details.ip),g.getSetting("version",0,"installed")!=c.version&&(h.notify("New version detected, clearing caches..."),e.get("$http").removeAll(),f.removeAll(),g.setSetting("version",c.version,"installed"));var d=g.getSetting("pushername",null);d&&j.setMe(d)}else c.id==g.getSetting("pusherid",null)||g.getSetting("pusherdisabled",!1)||a.$broadcast("spotmop:pusher:received",c)},i.onclose=function(){a.$broadcast("spotmop:pusher:offline"),j.isConnected=!1,setTimeout(function(){j.start()},5e3)},j.pusher=i}catch(k){console.log("Connecting with Pusher failed with the following error message: "+k)}},stop:function(){this.pusher=null,this.isConnected=!1},send:function(a){a.pusher=!0,a.id=g.getSetting("pusherid",null),j.pusher.send(JSON.stringify(a))},setMe:function(a){var b=g.getSetting("pusherid",null);$.ajax({method:"GET",cache:!1,url:i+"pusher/me?id="+b+"&name="+a})},getConnections:function(){var a=c.defer();return b({method:"GET",cache:!1,url:i+"pusher/connections"}).success(function(b){a.resolve(b)}).error(function(b){h.error(b.error.message),a.reject(b.error.message)}),a.promise}};return j}]),angular.module("spotmop.services.spotify",[]).factory("SpotifyService",["$rootScope","$resource","$localStorage","$http","$interval","$timeout","$filter","$q","SettingsService","NotifyService",function(a,b,c,d,e,f,g,h,i,j){var k={authenticationMethod:"server",start:function(){var b=$('');$(body).append(b),"undefined"==typeof c.spotify&&(c.spotify={}),"undefined"==typeof c.spotify.AccessToken&&(c.spotify.AccessToken=null),"undefined"==typeof c.spotify.RefreshToken&&(c.spotify.RefreshToken=null),"undefined"==typeof c.spotify.AuthorizationCode&&(c.spotify.AuthorizationCode=null),"undefined"==typeof c.spotify.AccessTokenExpiry&&(c.spotify.AccessTokenExpiry=null),window.addEventListener("message",function(b){if("http://jamesbarnsley.co.nz"!==b.origin)return!1;var d=JSON.parse(b.data);console.info("Spotify authorization successful"),c.spotify.AuthorizationCode=d.authorization_code,c.spotify.AccessToken=d.access_token,c.spotify.RefreshToken=d.refresh_token,a.spotifyOnline=!0,this.authenticationMethod="client",k.getMe().then(function(b){i.setSetting("spotifyuser",b),a.$broadcast("spotmop:spotify:authenticationChanged",this.authenticationMethod)})},!1),this.isAuthorized()?(a.spotifyAuthorized=!0,this.authenticationMethod="client"):(i.setSetting("spotifyuser",!1),a.spotifyAuthorized=!1,this.authenticationMethod="server"),a.$broadcast("spotmop:spotify:online")},logout:function(){c.spotify={},this.authenticationMethod="server",this.refreshToken(),a.$broadcast("spotmop:spotify:authenticationChanged",this.authenticationMethod)},authorize:function(){var a=$(document).find("#authorization-frame");a.attr("src","http://jamesbarnsley.co.nz/spotmop.php?action=authorize&app="+location.protocol+"//"+window.location.host)},isAuthorized:function(){return c.spotify.AuthorizationCode&&c.spotify.RefreshToken?!0:!1},refreshToken:function(){var b=h.defer(),e="";if("client"==this.authenticationMethod)e="http://jamesbarnsley.co.nz/spotmop.php?action=refresh&refresh_token="+c.spotify.RefreshToken;else{if("server"!=this.authenticationMethod)return!1;var f=i.getSetting("mopidyhost",window.location.hostname),g=i.getSetting("mopidyport","6680");e="http://"+f+":"+g+"/spotmop/auth"}return d({method:"GET",url:e,dataType:"json",async:!1,timeout:1e4}).success(function(d){"undefined"!=typeof d.error?(j.error("Spotify authorization error: "+d.error_description),a.spotifyOnline=!1,b.reject(d.error.message)):(c.spotify.AccessToken=d.access_token,c.spotify.AccessTokenExpiry=(new Date).getTime()+36e5,a.spotifyOnline=!0,b.resolve(d))}),b.promise},getFromUri:function(a,b){var c=b.split(":");return"userid"==a&&"user"==c[1]?c[2]:"playlistid"==a&&"playlist"==c[3]?c[4]:"artistid"==a&&"artist"==c[1]?c[2]:"albumid"==a&&"album"==c[1]?c[2]:"trackid"==a&&"track"==c[1]?c[2]:null},uriType:function(a){var b=a.split(":");return"spotify"==b[0]&&"artist"==b[1]?"artist":"spotify"==b[0]&&"album"==b[1]?"album":"spotify"==b[0]&&"user"==b[1]&&"playlist"==b[3]?"playlist":null},getUrl:function(a){var b=h.defer();return d({method:"GET",url:a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},getMe:function(){var a=h.defer();return this.isAuthorized()?(d({method:"GET",url:l+"me/",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(b){a.resolve(b)}).error(function(b){j.error(b.error.message),a.reject(b.error.message)}),a.promise):(a.reject(),a.promise)},getUser:function(a){var b=this.getFromUri("userid",a),c=h.defer();return d({method:"GET",url:l+"users/"+b}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},isFollowing:function(a,b){var e=this.getFromUri(a+"id",b),f=h.defer();return this.isAuthorized()?(d({method:"GET",url:l+"me/following/contains?type="+a+"&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise):(f.reject(),f.promise)},getTrack:function(a){var b=this.getFromUri("trackid",a),c=h.defer();return d({method:"GET",url:l+"tracks/"+b}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},getMyTracks:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"GET",url:l+"me/tracks/",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},addTracksToLibrary:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"PUT",url:l+"me/tracks",dataType:"json",data:JSON.stringify({ids:a}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},deleteTracksFromLibrary:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"DELETE",url:l+"me/tracks",dataType:"json",data:JSON.stringify({ids:a}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},getMyArtists:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"GET",url:l+"me/following?type=artist",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},isFollowingArtist:function(a,b){var e=this.getFromUri("artistid",a),f=h.defer();return this.isAuthorized()?(d({cache:!1,method:"GET",url:l+"me/following/contains?type=artist&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise):(f.reject(),f.promise)},followArtist:function(a){var b=this.getFromUri("artistid",a),e=h.defer();return this.isAuthorized()?(d({method:"PUT",cache:!1,url:l+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise):(e.reject(),e.promise)},unfollowArtist:function(a){var b=this.getFromUri("artistid",a),e=h.defer();return this.isAuthorized()?(d({method:"DELETE",cache:!1,url:l+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise):(e.reject(),e.promise)},getPlaylists:function(a,b){"undefined"==typeof b&&(b=40);var e=h.defer();return d({cache:!1,method:"GET",url:l+"users/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise},getPlaylist:function(a){var b=this.getFromUri("userid",a),e=this.getFromUri("playlistid",a),f=h.defer();return d({cache:!0,method:"GET",url:l+"users/"+b+"/playlists/"+e+"?market="+m,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise},isFollowingPlaylist:function(a,b){var e=this.getFromUri("userid",a),f=this.getFromUri("playlistid",a),g=h.defer();return this.isAuthorized()?(d({cache:!0,method:"GET",url:l+"users/"+e+"/playlists/"+f+"/followers/contains?ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){j.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},followPlaylist:function(a){var b=this.getFromUri("userid",a),e=this.getFromUri("playlistid",a),f=h.defer();return this.isAuthorized()?(d({method:"PUT",url:l+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise):(f.reject(),f.promise)},unfollowPlaylist:function(a){var b=this.getFromUri("userid",a),e=this.getFromUri("playlistid",a),f=h.defer();return this.isAuthorized()?(d({method:"DELETE",url:l+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise):(f.reject(),f.promise)},featuredPlaylists:function(a){"undefined"==typeof a&&(a=40);var b=g("date")(new Date,"yyyy-MM-ddTHH:mm:ss"),e=i.getSetting("countrycode","NZ"),f=h.defer();return d({cache:!0,method:"GET",url:l+"browse/featured-playlists?timestamp="+b+"&country="+e+"&limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise},addTracksToPlaylist:function(a,b){var e=this.getFromUri("userid",a),f=this.getFromUri("playlistid",a),g=h.defer();return this.isAuthorized()?(d({method:"POST",url:l+"users/"+e+"/playlists/"+f+"/tracks",dataType:"json",data:JSON.stringify({uris:b}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){j.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},movePlaylistTracks:function(a,b,e,f){var g=this.getFromUri("userid",a),k=this.getFromUri("playlistid",a);if(g!=i.getSetting("spotifyuserid",null))return!1;if(!this.isAuthorized())return m.reject(),m.promise;var m=h.defer();return d({method:"PUT",url:l+"users/"+g+"/playlists/"+k+"/tracks",dataType:"json",data:JSON.stringify({range_start:b,range_length:e,insert_before:f}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){m.resolve(a)}).error(function(a){j.error(a.error.message),m.reject(a.error.message)}),m.promise},deleteTracksFromPlaylist:function(a,b,e){var f=this.getFromUri("userid",a),g=this.getFromUri("playlistid",a),i=h.defer();return d({method:"DELETE",url:l+"users/"+f+"/playlists/"+g+"/tracks",dataType:"json",data:JSON.stringify({snapshot_id:b,positions:e}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){i.resolve(a)}).error(function(a){j.error(a.error.message),i.reject(a.error.message)}),i.promise},createPlaylist:function(a,b){var e=h.defer();return this.isAuthorized()?(d({method:"POST",url:l+"users/"+a+"/playlists/",dataType:"json",data:b,contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise):(e.reject(),e.promise)},updatePlaylist:function(a,b){var e=this.getFromUri("userid",a),f=this.getFromUri("playlistid",a),g=h.defer();return this.isAuthorized()?(d({method:"PUT",url:l+"users/"+e+"/playlists/"+f,dataType:"json",data:b,contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){j.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},newReleases:function(a){"undefined"==typeof a&&(a=40);var b=h.defer();return d({cache:!0,method:"GET",url:l+"browse/new-releases?country="+m+"&limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},discoverCategories:function(a){"undefined"==typeof a&&(a=40);var b=h.defer();return d({cache:!0,method:"GET",url:l+"browse/categories?limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},getCategory:function(a){var b=h.defer();return d({cache:!0,method:"GET",url:l+"browse/categories/"+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},getCategoryPlaylists:function(a,b){"undefined"==typeof b&&(b=40);var e=h.defer();return d({cache:!0,method:"GET",url:l+"browse/categories/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise},getArtist:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:l+"artists/"+b}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},getArtists:function(a){var b=this,c="";angular.forEach(a,function(a){""!=c&&(c+=","),c+=b.getFromUri("artistid",a)});var e=h.defer();return d({method:"GET",url:l+"artists/?ids="+c}).success(function(a){e.resolve(a)}).error(function(a){j.error(a.error.message),e.reject(a.error.message)}),e.promise},getAlbums:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:l+"artists/"+b+"/albums?album_type=album,single&market="+m}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},getAlbum:function(a){var b=h.defer(),c=this.getFromUri("albumid",a);return d({method:"GET",url:l+"albums/"+c}).success(function(a){b.resolve(a)}).error(function(a){j.error(a.error.message),b.reject(a.error.message)}),b.promise},getTopTracks:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:l+"artists/"+b+"/top-tracks?country="+m}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},getRelatedArtists:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:l+"artists/"+b+"/related-artists"}).success(function(a){c.resolve(a)}).error(function(a){j.error(a.error.message),c.reject(a.error.message)}),c.promise},getSearchResults:function(a,b,e){"undefined"==typeof e&&(e=10);var f=h.defer();return d({cache:!0,method:"GET",url:l+"search?q="+b+"&type="+a+"&country="+m+"&limit="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){j.error(a.error.message),f.reject(a.error.message)}),f.promise}},l="https://api.spotify.com/v1/",m=i.getSetting("spotifycountry","NZ");i.getSetting("spotifylocale","en_NZ");return k}]).factory("SpotifyServiceIntercepter",["$q","$rootScope","$injector","$localStorage",function(a,b,c,d){"use strict";function e(a,b,d){function e(a){b.resolve(a)}function f(a){b.reject(a)}var g=c.get("$http");a.headers={Authorization:"Bearer "+d},g(a).then(e,f)}var f=0,g={responseError:function(b){if(401==b.status&&b.config.url.search("https://api.spotify.com/")>=0&&3>f){f++;var d=a.defer();return c.get("SpotifyService").refreshToken().then(function(a){return"undefined"!=typeof a.error?b:(f--,void e(b.config,d,a.access_token))}),d.promise}return b}};return g}]),angular.module("spotmop.settings",[]).config(["$stateProvider",function(a){a.state("settings",{url:"/settings",templateUrl:"app/settings/template.html"})}]).controller("SettingsController",["$scope","$http","$rootScope","$timeout","MopidyService","SpotifyService","EchonestService","SettingsService","NotifyService","PusherService",function(a,b,c,d,e,f,g,h,i,j){a.version,a.settings=h.getSettings(),a.currentSubpage="mopidy",a.subpageNavigate=function(b){a.currentSubpage=b},a.authorizeSpotify=function(){f.authorize()},a.refreshSpotifyToken=function(){i.notify("Refreshing token"),f.refreshToken().then(function(){})},a.spotifyLogout=function(){f.logout()},a.upgradeCheck=function(){i.notify("Checking for updates"),h.upgradeCheck().then(function(a){ -h.setSetting("version",a,"latest"),h.getSetting("version",0,"installed")