From b1921041f0db4cd975f311a0719ac6773aa84da4 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 10 Jun 2016 15:23:31 +1200 Subject: [PATCH 01/16] When ajax completes check for short pages that need more items lazy-loaded, ie playlists library page --- src/app/app.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/app.js b/src/app/app.js index 6d00342..2d285aa 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -203,7 +203,7 @@ angular.module('spotmop', [ * Lazy loading **/ - $scope.checkForLazyLoading = function(){ + $scope.checkForLazyLoading = function(){ // get our ducks in a row - these are all the numbers we need var scrollPosition = $(document).scrollTop(); var frameHeight = $(window).height(); @@ -213,7 +213,13 @@ angular.module('spotmop', [ if( distanceFromBottom <= 100 ) $scope.$broadcast('spotmop:loadMore'); } + + // listen for completion from our loading bar (which intercepts all http requests) + $rootScope.$on('cfpLoadingBar:completed', function(event){ + $scope.checkForLazyLoading(); + }); + // listen for scrolling to load more stuff $(document).on('scroll', function( event ){ $scope.checkForLazyLoading(); From 719bbd1a702d7f14faf993739ca97190eba737f6 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 10 Jun 2016 15:49:32 +1200 Subject: [PATCH 02/16] Consume on player --- src/app/app.js | 3 --- src/app/player/controller.js | 3 +++ src/app/player/service.js | 12 ++++++++++++ src/app/queue/template.html | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 2d285aa..4ba88c1 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -299,9 +299,6 @@ angular.module('spotmop', [ $scope.$on('mopidy:state:online', function(){ Analytics.trackEvent('Mopidy', 'Online'); $rootScope.mopidyOnline = true; - MopidyService.getConsume().then( function( isConsume ){ - SettingsService.setSetting('mopidy',isConsume,'consume'); - }); }); $scope.$on('mopidy:state:offline', function(){ diff --git a/src/app/player/controller.js b/src/app/player/controller.js index 223cb39..b515e98 100644 --- a/src/app/player/controller.js +++ b/src/app/player/controller.js @@ -72,6 +72,9 @@ angular.module('spotmop.player', [ $scope.toggleMute = function(){ PlayerService.toggleMute(); }; + $scope.toggleConsume = function(){ + PlayerService.toggleConsume(); + }; /** diff --git a/src/app/player/service.js b/src/app/player/service.js index a0cb7df..fed9dcd 100644 --- a/src/app/player/service.js +++ b/src/app/player/service.js @@ -14,6 +14,7 @@ angular.module('spotmop.services.player', []) isRepeat: false, isRandom: false, isMute: false, + isConsume: false, volume: 100, playPosition: 0, currentTlTrack: false, @@ -58,6 +59,11 @@ angular.module('spotmop.services.player', []) else state.playing = false; }); + + // get consume mode + MopidyService.getConsume().then( function( isConsume ){ + state.isConsume = isConsume; + }); }); $rootScope.$on('mopidy:event:tracklistChanged', function(event, options){ @@ -437,6 +443,12 @@ angular.module('spotmop.services.player', []) MopidyService.setMute( false ).then( function(response){ state.isMute = false; } ); else MopidyService.setMute( true ).then( function(response){ state.isMute = true; } ); + }, + toggleConsume: function(){ + if( state.isConsume ) + MopidyService.setConsume( false ).then( function(response){ state.isConsume = false; } ); + else + MopidyService.setConsume( true ).then( function(response){ state.isConsume = true; } ); } }; diff --git a/src/app/queue/template.html b/src/app/queue/template.html index 3636af4..1c3aad0 100644 --- a/src/app/queue/template.html +++ b/src/app/queue/template.html @@ -39,6 +39,9 @@

Now Playing

+ + + From 8fa98b8a34894b86b65d3a1dcb92a06fe57ed6b0 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 13 Jun 2016 08:02:32 +1200 Subject: [PATCH 03/16] Moving consume toggle to player; adding tooltips --- src/app/player/service.js | 8 +++---- src/app/queue/template.html | 9 +++++--- src/app/settings/template.html | 7 ------ src/assets/css/core.css | 42 ++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/app/player/service.js b/src/app/player/service.js index fed9dcd..0125e48 100644 --- a/src/app/player/service.js +++ b/src/app/player/service.js @@ -59,11 +59,6 @@ angular.module('spotmop.services.player', []) else state.playing = false; }); - - // get consume mode - MopidyService.getConsume().then( function( isConsume ){ - state.isConsume = isConsume; - }); }); $rootScope.$on('mopidy:event:tracklistChanged', function(event, options){ @@ -99,6 +94,9 @@ angular.module('spotmop.services.player', []) MopidyService.getMute().then( function(isMute){ state.isMute = isMute; }); + MopidyService.getConsume().then( function( isConsume ){ + state.isConsume = isConsume; + }); } // listen for current track changes diff --git a/src/app/queue/template.html b/src/app/queue/template.html index 1c3aad0..0a242f7 100644 --- a/src/app/queue/template.html +++ b/src/app/queue/template.html @@ -39,14 +39,17 @@

Now Playing

- + + Consume mode - + + Randomise - + + Repeat all
diff --git a/src/app/settings/template.html b/src/app/settings/template.html index 13bcf04..b6e1ca2 100644 --- a/src/app/settings/template.html +++ b/src/app/settings/template.html @@ -113,13 +113,6 @@

-
-
Consume mode
-
- -
-
-
diff --git a/src/assets/css/core.css b/src/assets/css/core.css index 53dc221..de6bf7d 100644 --- a/src/assets/css/core.css +++ b/src/assets/css/core.css @@ -1653,6 +1653,48 @@ slider .item-container > .square-panel { vertical-align: top; } + +/** + * Tooltips + * Revealed on hover of parental .has-tooltip + **/ + +.tooltip { + position: absolute; + top: -25px; + left: 50%; + min-width: 66px; + margin-left: -37px; + padding: 4px; + background: #333333; + color: #FFFFFF; + font-size: 11px; + display: none; +} + +.tooltip:before { + content: ''; + width: 6px; + height: 6px; + background: #333333; + position: absolute; + bottom: -3px; + left: 50%; + margin-left: -3px; + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.has-tooltip { + position: relative; +} + +#app:not(.touchDevice) .has-tooltip:hover .tooltip { + display: block; +} + /* ====================================================================== PAGE-SPECIFIC =========== */ From 6b69a321b235b4e658ad01f3936fb32b25e53f83 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 13 Jun 2016 08:04:42 +1200 Subject: [PATCH 04/16] Fixing clear-both bug --- src/app/browse/artist/related.template.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/browse/artist/related.template.html b/src/app/browse/artist/related.template.html index 0597cd1..b5c2745 100644 --- a/src/app/browse/artist/related.template.html +++ b/src/app/browse/artist/related.template.html @@ -14,6 +14,7 @@

Related Artists

+
From 566359880f824480b30588ad42f8832699ff98d9 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 13 Jun 2016 08:16:20 +1200 Subject: [PATCH 05/16] Cleaning buttons in page-header --- src/app/library/playlists.template.html | 2 +- src/assets/css/core.css | 8 ++++++-- src/assets/css/responsive.css | 8 +++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/app/library/playlists.template.html b/src/app/library/playlists.template.html index e60ed10..fb5ad34 100644 --- a/src/app/library/playlists.template.html +++ b/src/app/library/playlists.template.html @@ -4,7 +4,7 @@

+
diff --git a/mopidy_spotmop/static/app/library/playlists.template.html b/mopidy_spotmop/static/app/library/playlists.template.html index e60ed10..fb5ad34 100644 --- a/mopidy_spotmop/static/app/library/playlists.template.html +++ b/mopidy_spotmop/static/app/library/playlists.template.html @@ -4,7 +4,7 @@ -
-
Consume mode
-
- -
-
-
diff --git a/mopidy_spotmop/static/assets/css/style.css b/mopidy_spotmop/static/assets/css/style.css index 0290232..2b504c9 100644 --- a/mopidy_spotmop/static/assets/css/style.css +++ b/mopidy_spotmop/static/assets/css/style.css @@ -1165,7 +1165,8 @@ h1 .flag { .body .button, .dialog .button.primary, -.dialog .button.secondary { +.dialog .button.secondary, +.dialog .button.transparent { display: inline-block; padding: 12px 22px; margin-right: -3px; @@ -1176,10 +1177,13 @@ h1 .flag { } .body .button, -.dialog .button.secondary { background: #9b9b9b; } +.dialog .button.secondary { background: #9b9b9b; } .body .button:hover, .dialog .button.secondary:hover { background: #8B8B8B; } +.body .button.transparent, +.body .button.transparent:hover { background: transparent; color: #000000; } + .body .button .fa { margin-top: 2px; margin-left: -2px; @@ -1787,6 +1791,48 @@ slider .item-container > .square-panel { vertical-align: top; } + +/** + * Tooltips + * Revealed on hover of parental .has-tooltip + **/ + +.tooltip { + position: absolute; + top: -25px; + left: 50%; + min-width: 66px; + margin-left: -37px; + padding: 4px; + background: #333333; + color: #FFFFFF; + font-size: 11px; + display: none; +} + +.tooltip:before { + content: ''; + width: 6px; + height: 6px; + background: #333333; + position: absolute; + bottom: -3px; + left: 50%; + margin-left: -3px; + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.has-tooltip { + position: relative; +} + +#app:not(.touchDevice) .has-tooltip:hover .tooltip { + display: block; +} + /* ====================================================================== PAGE-SPECIFIC =========== */ @@ -3480,10 +3526,16 @@ input[type="submit"]{ font-size: 18px; } + .page-header .fa { + color: #FFFFFF; + } + .page-header .button, .page-header .button:hover, .page-header .button.primary, - .page-header .button.primary:hover { + .page-header .button.primary:hover + .page-header .button.transparent, + .page-header .button.transparent:hover { margin: 3px -10px 0 0; padding: 8px 11px; background: transparent; diff --git a/mopidy_spotmop/static/assets/css/style.min.css b/mopidy_spotmop/static/assets/css/style.min.css index 3cf5d90..b6990b9 100644 --- a/mopidy_spotmop/static/assets/css/style.min.css +++ b/mopidy_spotmop/static/assets/css/style.min.css @@ -1,4 +1,4 @@ -.button,.menu-item,.noselect,body.dragging *{-webkit-touch-callout:none;-khtml-user-select:none}.fa-ul,.main-menu .submenu>.menu-item{list-style-type:none}.contextmenu{position:fixed;display:none;top:0;left:0;z-index:10;background:#222;color:#FFF;min-width:110px}.contextmenu .menu-item{display:block;padding:8px 14px 8px 10px;border-bottom:1px solid rgba(255,255,255,.05);position:relative}.contextmenu .menu-item.has-submenu i{position:absolute;top:8px;right:8px}.contextmenu .menu-item:hover{background:#333;cursor:pointer}.contextmenu .menu-item:hover>.sub-menu{display:block}.contextmenu .sub-menu{display:none;position:absolute;right:-150px;background:#333;top:0;width:150px;max-height:306px;overflow-y:scroll}.contextmenu.close-right .sub-menu,.contextmenu.hard-right .sub-menu{right:auto;left:-150px}#sidebar,.contextmenu.touch{position:fixed;left:0;bottom:0}.contextmenu.close-bottom .sub-menu,.contextmenu.hard-bottom .sub-menu{top:auto;bottom:0}.contextmenu .sub-menu>.menu-item:hover{background:#414141}.contextmenu.click .menu-item i{font-size:8px;padding-right:5px;vertical-align:top;margin-top:5px}.contextmenu.touch{padding-left:5px;top:auto;right:0;z-index:99;background:#32b5f2}.contextmenu.touch .menu-item{display:block;float:left;padding:14px 0 12px;width:45px;text-align:center;border:0}.contextmenu.touch .menu-item.cancel{opacity:.5;float:right}.contextmenu.touch .menu-item .icon{font-size:16px}.contextmenu.touch .menu-item .text{font-size:8px;display:block;text-transform:uppercase;padding-top:5px}body,html{background:#f5f5f5;color:#000;font-family:'Archivo Narrow',Helvetica,Arial,sans-serif;font-size:14px}body{overflow-y:scroll;overflow-x:hidden}*{border:0;padding:0;margin:0}.button,.menu-item,body.dragging *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.noselect,.tracklist .track{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}body.dragging,body.dragging *,body.dragging .body,body.dragging .body *{cursor:-webkit-grabbing!important;cursor:-moz-grabbing!important}#body,#sidebar{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0);-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}#sidebar{top:0;width:20%;overflow:hidden;background:#111;z-index:1}#sidebar>.background-image{position:absolute;top:-50px;right:0;bottom:-50px;left:-50px;opacity:.3;z-index:1}#sidebar>.background-image .image{position:absolute;top:0;left:0;bottom:0;right:0;opacity:0;background-position:0 50%;background-size:cover}#sidebar>.inner{z-index:2;top:0;left:0;bottom:0;right:0;position:absolute;overflow-x:hidden;overflow-y:auto}#player{position:fixed;bottom:20px;left:0;width:20%;z-index:3}#body{padding-left:20%;position:relative;min-height:100vh}.page>.inner{padding:40px}.col{float:left;min-height:1px}.col.w5{width:5%}.col.w10{width:10%}.col.w15{width:15%}.col.w20{width:20%}.col.w25{width:25%}.col.w30{width:30%}.col.w35{width:35%}.col.w40{width:40%}.col.w45{width:45%}.col.w50{width:50%}.col.w55{width:55%}.col.w60{width:60%}.col.w65{width:65%}.col.w70{width:70%}.col.w75{width:75%}.col.w80{width:80%}.col.w85{width:85%}.col.w90{width:90%}.col.w95{width:95%}.col.w100{width:100%}.min-width{display:inline-block}.min-width.w50{min-width:50px}.min-width.w100{min-width:100px}.min-width.w150{min-width:150px}.min-width.w200{min-width:200px}.transitioning,.transitioning:hover{opacity:.2}.noselect{user-select:none}.main-menu .divider{padding:20px 0 5px 10px;font-size:11px;color:#FFF;opacity:.4;text-transform:uppercase}.main-menu .divider.spacer{height:0}.main-menu .menu-item:last-child{padding-bottom:20px}.main-menu a.unavailable{opacity:.5}.main-menu .menu-item>a{display:block;padding:8px 0 8px 10px;color:#FFF;text-decoration:none;font-size:16px;background-image:url(../svg/white-diamond.svg);background-position:110% 50%;background-repeat:no-repeat;border-left:4px solid transparent}.main-menu .menu-item>a.droppable.dropping,.main-menu .menu-item>a.droppable.dropping:hover{background-color:#08d58f}.main-menu .menu-item .info{font-size:12px;opacity:.5;padding:2px 20px 0 0;float:right}.main-menu>.menu-item>a>i.services-alert{float:right;padding:3px 12px 0 0}.main-menu .menu-item.active>a{background-color:rgba(0,0,0,.15);border-color:#08d58f}.main-menu .menu-item:not(.active)>a:hover{background-color:rgba(255,255,255,.05)}.main-menu .playlists-submenu-trigger{float:right;display:block;opacity:.5;margin-top:-7px;padding:6px 15px}.main-menu .playlists-submenu-trigger i{font-size:12px}.menu-reveal-trigger{position:absolute;top:1px;left:0;display:none;color:#FFF;font-size:17px;padding:16px;cursor:pointer;z-index:9}.main-menu .dragging-note{display:none;float:right;color:#222;font-size:12px;padding-right:7px;padding-top:2px}.dragging .main-menu .dropping>.dragging-note,.dragging .main-menu :hover>.dragging-note{display:block}.main-menu .submenu{display:none}.main-menu .menu-item.active .submenu,.main-menu .menu-item.section .submenu{display:block}.main-menu .submenu>.menu-item a{padding-left:39px}.main-menu .submenu.playlists{position:absolute;top:0;right:0;bottom:0;left:100%;overflow:hidden;background:rgba(48,48,48,.95);padding:20px 0;z-index:1;display:block}.main-menu .submenu.playlists .menu-item>a{color:#FFF;font-size:16px;padding:10px 0 10px 20px}.dragging .main-menu .menu-item.top-level.playlists.dropping-within .submenu.playlists,.main-menu .menu-item.top-level.playlists.show-submenu .submenu.playlists{left:20%}.sub-page-navigation{margin-bottom:35px;margin-top:-15px}.sub-page-navigation .menu-item{padding:12px 0;margin-right:25px;border-bottom:3px solid transparent;display:inline-block;font-size:18px;text-transform:capitalize}.breadcrumbs,.capitalize,.info-text,.list .list-item.header,.player .track-info,h4.section-title{text-transform:uppercase}.sub-page-navigation .menu-item>i{font-size:6px;vertical-align:middle;margin-top:-4px;padding-right:2px}.sub-page-navigation .menu-item:hover{border-color:rgba(255,255,255,.5);cursor:pointer}.search-page .sub-page-navigation .menu-item:hover{border-color:#AAA}.sub-page-navigation .menu-item.active{border-color:#f5f5f5}.critical-services-status{padding-left:29px;padding-top:5px}#loading-bar .bar{left:20%!important;right:0!important}#loading-bar-spinner{right:10px!important;left:auto!important}#dropzones{display:none;position:fixed;top:0;left:0;bottom:0;width:20%;z-index:98;background:rgba(0,0,0,.75)}.dragging #dropzones{display:block}#dropzones>.dropzone{background:#444;text-align:center;font-size:20px;color:#FFF;margin:20px 20px 0;line-height:20px}#dropzones>.dropzone.disabled{background:#222}#dropzones .dropzone .dropzone.dropping,#dropzones .dropzone .menu-item.dropping,#dropzones .dropzone.dropping-within>.liner:not(.hover-content),#dropzones .dropzone.dropping>.liner:not(.hover-content){background:#08d58f}#dropzones>.dropzone.disabled>.liner{opacity:.3}#dropzones .dropzone>.liner{padding:50px 20px}#dropzones .dropzone.dropping .default-content,#dropzones .dropzone.dropping-within .default-content,#dropzones .dropzone:not(.dropping):not(.dropping-within) .hover-content{display:none}#dropzones .dropzone.dropping .hover-content,#dropzones .dropzone.dropping-within .hover-content{display:block!important}#dropzones .dropzone .label{padding-top:20px}#dropzones .dropzone .menu-item{display:block;text-align:left;padding:10px 20px;color:#FFF;text-decoration:none;font-size:16px}.drag-tracer .text,.drag-tracer .track-title{font-size:12px;vertical-align:top;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.drag-tracer,.drag-tracer .track-title{background:#32b5f2;box-shadow:1px 1px 5px rgba(0,0,0,.2)}#dropzones .dropzone .menu-item:not(:last-child){border-bottom:1px solid rgba(255,255,255,.1)}#dropzones .dropzone.playlists>.liner.hover-content,#dropzones .dropzone.queue>.liner.hover-content{padding:0}#dropzones .dropzone.queue .dropzone.add-to-queue{padding:30px 20px 20px}#dropzones .dropzone.queue .dropzone.add-to-queue-next{padding:14.5px 20px;border-top:1px solid rgba(255,255,255,.1)}#dropzones .dropzone.queue .dropzone.add-to-queue-next .label{padding:0}.clear-both{clear:both}.clear-left{clear:left}.clear-right{clear:right}.hide{display:none!important}.invisible{visibility:hidden!important}:focus{outline:0}.spacer{height:40px}.animate,.button,.main-menu a,.opacity-hover,button,input[type=submit]{-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.loading .animate,.loading .button,.loading .main-menu a,.loading .opacity-hover,.loading button,.loading input[type=submit]{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;transition:none!important}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}.fadereveal{-webkit-animation:fadereveal .2s linear;-moz-animation:fadereveal .2s linear;-o-animation:fadereveal .2s linear;animation:fadereveal .2s linear;-webkit-animation-fill-mode:forward;-moz-animation-fill-mode:forward;-o-animation-fill-mode:forward;animation-fill-mode:forward}@-moz-keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}@-webkit-keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}@keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}.opacity-hover{opacity:.5}.opacity-hover:hover{opacity:1}.blur{-webkit-filter:blur(10px);filter:blur(10px)}.invert{-webkit-filter:invert(100%);filter:invert(100%)}.drag-tracer{position:fixed;color:#FFF;z-index:99;display:none;pointer-events:none}.drag-tracer .track-title{padding:8px 12px;position:absolute;top:0;left:0;width:100px;z-index:3}.drag-tracer .track-title:nth-child(2){top:5px;left:5px;z-index:2;background:#29abe8}.drag-tracer .track-title:nth-child(3){top:10px;left:10px;z-index:1;background:#23a4e0}.drag-tracer .thumbnail{float:left;width:40px;height:40px;background-position:50% 50%;background-repeat:no-repeat;background-size:cover}.drag-tracer .text{float:left;padding:12px 15px;max-width:150px}.tooltip-wrapper{z-index:2;position:relative}.tooltip-wrapper .tooltip{display:none;position:absolute;top:0;right:0;background:#DDD;color:#222;font-size:11px;padding:2px 5px}.tooltip-wrapper:hover .tooltip{display:block}#notifications .notification,.flag,.heading-wrapper>h1{display:inline-block}.popularity .tooltip{z-index:-1;top:-5px;right:-8px;padding:5px 16px 5px 8px}.popularity:hover .bar-track{background:#FFF}#notifications{position:fixed;z-index:9;top:15px;left:20%;right:0;text-align:center;pointer-events:none}#notifications .notification{color:#FFF;padding:10px 18px;background-color:rgba(0,0,0,.6);margin:0 1px}#notifications .notification.keyboard-shortcut{position:fixed;top:50%;left:50%;width:300px;margin:-150px 0 0 -150px;text-align:center;border-radius:10px}#notifications .notification.keyboard-shortcut i{line-height:300px;font-size:120px}#notifications .notification:not(.keyboard-shortcut):first-child{border-radius:100px 0 0 100px}#notifications .notification:not(.keyboard-shortcut):last-child{border-radius:0 100px 100px 0}#notifications .notification:not(.keyboard-shortcut):only-child{border-radius:100px}#notifications .notification.bad,#notifications .notification.error{background-color:rgba(214,47,47,.9)}#notifications .notification.good{background-color:rgba(53,204,53,.9)}.page-notification{margin:-40px -40px 30px;padding:20px 40px;font-size:16px}h1{font-size:40px;font-weight:200;padding-bottom:35px;margin-top:-10px}h2{font-size:20px;font-weight:300}h3{font-size:18px;font-weight:600}h4{font-size:14px;font-weight:400}h4.section-title{font-weight:600;padding-bottom:20px}.bold-text,.no-items{font-weight:700}.underline{border-bottom:1px solid #999;padding-bottom:5px;margin-bottom:5px}.body a{color:inherit;text-decoration:none;border-bottom:1px dotted transparent;cursor:pointer}.body a:hover{border-color:inherit}.info-text{color:#AAA;padding-top:5px}.breadcrumbs{margin-top:-20px;color:#CCC}.breadcrumbs .divider{padding:0 3px}.white-text{color:#FFF!important}.black-text{color:#000!important}.grey-text{color:#AAA!important}.red-text{color:#d62f2f!important}.green-text{color:#35cc35!important}.primary-colour-text{color:#08d58f!important}.white-background{background-color:#FFF!important}.grey-background{background-color:#DDD!important}.black-background{background-color:#000!important}.red-background{background-color:#d62f2f!important}.green-background{background-color:#35cc35!important}.primary-colour-background{background-color:#08d58f!important}.italic-text{font-style:italic}.no-items{text-align:center;font-size:16px;color:#CCC;padding-top:50px}.flag{background:#EEE;border-radius:3px;padding:3px 6px;font-size:11px;font-weight:400;margin-left:10px;margin-right:-10px}h1 .flag{vertical-align:bottom;margin-bottom:8px}.flag.blue{background:#32b5f2;color:#FFF}.flag.green,.flag.primary{background:#08d58f;color:#FFF}.flag.bad{background:#d62f2f;color:#FFF}.flag.clickable:hover{background:rgba(0,0,0,.65);color:rgba(255,255,255,.85)}.flag.dark{background:rgba(0,0,0,.4);color:rgba(255,255,255,.5)}.flag.black{background:rgba(0,0,0,.55);color:rgba(255,255,255,.8)}.flag.red{background:rgba(214,47,47,.9);color:#FFF}.flag.green{background:rgba(53,204,53,.9);color:#FFF}.flag.clickable{cursor:pointer}.flag.clickable.destructive:hover{background:rgba(214,47,47,.9);color:#FFF;cursor:pointer}.body .button,.dialog .button.primary,.dialog .button.secondary{display:inline-block;padding:12px 22px;margin-right:-3px;cursor:pointer;color:#FFF;border:0}.body .button,.dialog .button.secondary{background:#9b9b9b}.body .button:hover,.dialog .button.secondary:hover{background:#8B8B8B}.body .button .fa{margin-top:2px;margin-left:-2px;vertical-align:top}.body .heading-wrapper .button{vertical-align:top;margin-left:10px}.body .button.primary,.dialog .button.primary{background:#08d58f}.body .button.primary:hover,.dialog .button.primary:hover{background:#03c784}.body .button.destructive{background:#cf2d2d}.body .button.destructive:hover{background:#bc1f1f}.bar-track,.body :not(.touchDevice) .button.tertiary:hover{background:#DDD}.body .button.tertiary{background:#DDD;color:#AAA}.body .button.disabled,.body .button.disabled:hover{cursor:not-allowed;opacity:.5}.body .button.float-right{float:right}.body .follow-unfollow .unfollow{min-width:50px;text-align:center}.body .follow-unfollow.following>.follow,.body .follow-unfollow:not(.following)>.unfollow{display:none}.bar-track{display:inline-block;width:5px;position:relative;height:12px}.bar-track .bar{position:absolute;left:0;right:0;bottom:0;background:#666}.artist-grid .artist .image,.artist-list .artist .thumbnail{background-image:url(../svg/no-image.svg);background-repeat:no-repeat;background-position:50% 50%;background-size:cover;display:block}.info-text .bar-track{vertical-align:top;margin-top:7px}.artist-list .artist{display:block;clear:both;padding:10px 0;margin-bottom:5px;border:0!important}.artist-list .artist .thumbnail{width:50px;height:50px;border-radius:100px;float:left;margin-right:14px;background-color:#E9E9E9;border:2px solid #f5f5f5}.artist-list .artist:hover .thumbnail{opacity:.75;border-color:#08d58f}.artist-list .artist .name{padding-top:15px;padding-left:65px;font-weight:300;font-size:15px;display:block}.artist-grid{padding:0}.artist-grid .artist{display:block;float:left;border:0!important;width:50%;position:relative}.artist-grid .artist .image{width:100%;padding-bottom:100%;background-color:#777}.artist-grid .artist .name-wrapper{position:absolute;top:0;left:0;bottom:-.5px;right:0;text-align:center;color:#FFF;opacity:0;background:rgba(0,0,0,.8)}.image-container .image.placeholder,.square-panel .image-container .image,.thumbnail.placeholder{background-color:#E9E9E9;background-image:url(../svg/no-image.svg);background-position:50% 50%}.artist-grid .artist:hover .name-wrapper{opacity:1}.artist-grid .artist .name{padding-top:45%;font-weight:700}.square-panels{margin-left:-2%;margin-right:-2%}.square-panel{width:16%;margin:0 2% 3%;display:block;float:left;text-decoration:none;color:inherit;border:none!important}.square-panel .image-container{position:relative;width:100%;padding-bottom:100%}.square-panel .image-container .image{position:absolute;top:0;right:0;bottom:0;left:0;background-repeat:no-repeat;background-size:cover}.square-panel .image-container .overlay{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;max-width:100%;max-height:100%}.image-container .image.placeholder,.thumbnail.placeholder{background-size:80% 80%}.square-panel:hover .image-container .image{opacity:.75}.square-panel .info{padding-top:10px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-top:3px solid transparent;margin-top:-3px;position:relative;height:50px}.square-panel .info.smaller{height:30px}.square-panel:hover .info{border-color:#08d58f}.square-panel .info .secondary{padding-top:2px;color:#AAA}.square-panel .info .name,.square-panel .info .tracks{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.square-panels.smaller{margin-left:-1%;margin-right:-1%}.square-panels.smaller .square-panel{width:12.28%;margin:0 1% 3%}.square-panel.category .name{position:absolute;padding-bottom:20%;border-bottom:3px solid transparent;left:0;right:0;bottom:0;text-align:center;color:#FFF;font-weight:700;font-size:16px}.square-panel.category:hover .name{border-color:#08d58f;padding-bottom:21%}.square-panel.library-album{width:90%;margin:0}.list .list-item,.tracklist .track{margin-bottom:-1px;-webkit-touch-callout:none;-khtml-user-select:none}.square-panel.library-album:hover .image{opacity:1}.tracklist .track{display:block;padding:10px;border-top:1px solid #EEE;border-bottom:1px solid #EEE;cursor:pointer;position:relative;user-select:none}.track .album,.track .artist,.track .info,.track .title{float:left;min-height:1px}.track .source{display:none}.track .album,.track .artist,.track .title{width:30%}.track .info{width:10%;text-align:right}.track .info .duration{display:inline-block;padding-right:20px}.track .info .popularity{position:absolute;top:11px;right:10px}.track .source{position:absolute;top:9px;right:5px}.tracklist.queue-tracks .track .source,.tracklist.search-results.other .track .source{display:inline-block}body:not(.dragging):not(.touchDevice) .tracklist .track:not(.selected):hover{background:#F4F4F4;border-color:#EEE}body.dragging .tracklist .track.selected{opacity:.5}.tracklist .track.selected,.tracklist .track.selected:hover{background:#FFF39C}.tracklist .track.playing{font-weight:700}body.dragging .tracklist .track.dropping,body.dragging .tracklist .track:hover{border-top:3px solid #32b5f2;margin-top:-3px}.track.folder .icon{width:24px;float:left}.track.folder .title{width:auto}.list .list-item{display:block;padding:10px;border-top:1px solid #EEE;border-bottom:1px solid #EEE;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.list .list-item.header{color:#CCC;border-top:0;font-size:11px;padding-bottom:2px}.list .list-item:not(.header):hover{background:#F4F4F4;border-color:#EEE;cursor:pointer}.list .list-item .si{margin-top:0;vertical-align:bottom}.list .list-item .fa{margin-right:6px}.list .list-item .info{width:5%;text-align:right;float:right}#full-player,.fa-fw,.fa-li,.fa-stack-1x,.fa-stack-2x,.player .track-info{text-align:center}@media (max-width:800px){.list.album-items .name .si,.list.album-items .release-date{display:none}.list.album-items .artists,.list.album-items .name{width:40%}}.intro preloadedimage{position:absolute;top:-30px;right:-30px;bottom:-30px;left:-30px;overflow:hidden;opacity:0;background-position:50% -100px;background-repeat:no-repeat;background-size:cover}slider{height:250px;display:block;position:relative;margin-bottom:40px}slider.square-panels{margin-left:0;margin-right:-40px}slider .controls{position:absolute;top:-40px;right:40px;z-index:5}slider .controls .si{cursor:pointer;margin:5px;opacity:.7}slider .controls .si:hover{opacity:1}slider .slides{overflow:hidden;position:relative;height:100%}slider .slides-content{position:absolute;top:0;left:0;width:500%}slider .item-container{float:left;width:4%}slider .item-container>.square-panel{width:80%;margin:0}.page-header{margin:-40px -40px 40px;background:#EEE;padding:20px 40px}.page-header h1{padding:0;margin:0;font-size:22px;display:inline-block}.page-header h1 .si{width:1em;height:1em;margin:3px 5px 0 0}.page-header .utilities{margin:0 -25px 0 0;float:right}.page-header .utilities.has-buttons{margin-top:-8px}.library-albums .utilities .view-options label{padding:0 5px}.utilities .si{width:22px;height:22px}.utilities .filter-option.active,.utilities .filter-option:hover{opacity:1;border:none!important}.utilities .filter-option{margin-left:15px;opacity:.5}.utilities .filter-option .label{display:inline-block;vertical-align:bottom;margin-bottom:3px}.page-header .flag{display:inline-block;padding:3px 6px;margin-top:4px;vertical-align:top}.queue-intro{padding-bottom:20px}.now-playing-page .page-header{display:none}.album-intro h1{padding:20px 0 0}.album-intro .square-panel{margin:0 30px 20px 0;width:250px;height:250px}.album-intro .image{background-color:#EEE;background-size:cover;background-position:50% 50%;opacity:1!important}.album-intro .info-text{padding-top:20px}.album-page .intro,.playlist-page .intro{position:relative;margin:0 0 50px}.asset-sidebar{width:20%;position:absolute;top:0;left:20%;bottom:0;background:#EEE}.content.has-asset-sidebar{padding-left:25%}.content.has-asset-sidebar>.inner{padding:40px 20px}.album-page .album.thumbnail,.playlist-page .playlist.thumbnail{width:100%;padding-bottom:100%;margin:0;background-image:url(../svg/no-image.svg);background-color:#E9E9E9;background-position:50% 50%;background-size:cover}.album-page h1,.playlist-page h1{padding-bottom:0;padding-top:15px;margin:0}.album-page h2,.playlist-page h2{font-style:italic;color:#888;font-weight:100;padding-top:5px}.album-page .asset-sidebar .info,.playlist-page .asset-sidebar .info{padding:14px 20px;margin-top:1px}.album-page .asset-sidebar .info>.info-item,.playlist-page .asset-sidebar .info>.info-item{padding:2px 0;color:#AAA}.album-page .asset-sidebar .info .bar-track,.playlist-page .asset-sidebar .info .bar-track{vertical-align:top;margin-top:7px;margin-left:6px}.playlist-owner{display:block;padding-top:10px;border:0!important}.playlist-owner:hover .thumbnail .border{border-color:#08d58f}.playlist-owner .name{display:block;font-size:15px;font-weight:300;padding-left:40px;padding-top:5px}.playlist-owner .thumbnail .border{display:block;position:absolute;top:-1px;left:-1px;bottom:-1px;right:-1px;border:2px solid #eee;border-radius:60px;z-index:2}.playlist-owner .thumbnail{background-color:#e9e9e9;background-image:url(../svg/no-image.svg);background-position:50% 50%;background-repeat:no-repeat;background-size:cover;border-radius:60px;display:block;float:left;height:30px;margin-right:8px;width:30px;position:relative}.artist-intro{position:relative;margin:-40px -40px 30px;padding:0 20px;height:50vh}.artist-intro h1{padding-bottom:10px}.artist-intro .menu-item,.artist-intro h1{color:#FFF}.artist-intro .image-container{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;z-index:-1;background:#444}.artist-intro .image-container .image{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0}.artist-intro .image-container canvas{background-color:#444}.artist-page .title-panel{position:absolute;bottom:0;left:0;padding-left:330px}.artist-page .sub-page-navigation{margin:0}.artist-page .info-panel{padding-left:290px;margin-bottom:50px;position:relative}.artist-page .info-panel .thumbnail{width:250px;height:250px;background-image:url(../svg/no-image.svg);background-color:#E9E9E9;background-size:cover;background-position:50% 50%;position:absolute;bottom:0;left:0}.artist-page .info-panel .buttons{padding-right:20px}.artist-page .info-panel .info-text{display:inline-block;vertical-align:top}.tracklist.top-track-items{padding-bottom:30px}.gallery-item img{max-width:90%}.biography .content{font:inherit;width:100%;font-size:18px;line-height:1.4em;white-space:pre-wrap}.player .track-info .artist,.player .track-info .track{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.biography .details{padding:20px 0;color:#666}.discover .discover-section{clear:both;padding-bottom:20px}.discover .discover-section .section-title{padding-bottom:20px}.library-albums .full-album{padding-bottom:40px}.library-albums .full-album .album-title{padding:0 10px 15px}.featured-playlists-intro{position:relative;margin:-40px -40px 40px;padding:0 20px;height:30vh;background:#303030}.featured-playlists-intro>.inner{z-index:1;position:relative;color:#FFF;text-align:center;padding-top:13vh}.search-results-section.tracks,.user-intro .info{padding-top:30px}.featured-playlists-intro>.image-container{position:absolute;top:0;left:0;right:0;bottom:0}.featured-playlists-intro>.image-container>.image{position:absolute;top:0;left:0;right:0;bottom:0;opacity:0}.user-intro{padding-bottom:30px}.user-intro .info-text{margin-top:-20px}.user-intro .image-container .image{width:120px;height:120px;border-radius:120px;float:left;background-size:cover;background-position:50% 50%;margin-right:20px}.search .loading{margin:50px auto;width:70px;height:70px}.search .loading img{width:100%;height:100%}.search .sub-page-navigation{margin:-10px 0 30px}.search-results-section.albums,.search-results-section.artists,.search-results-section.playlists{width:30.6667%;float:left}.search-results-section.albums,.search-results-section.artists{padding-right:4%}.search-results-section .square-panel{width:46%}.search-results-section .square-panel .info{height:60px}.settings>.section{padding-bottom:40px}.settings .section-title .state-label{display:inline-block;padding:1px 3px;font-size:11px;margin-left:5px}.actions{clear:both;padding:40px 0 0 15%}.sub-page{padding:10px 0 20px}.settings .field.current-user .input{padding-top:8px}.settings .field.current-user .image-container>.image{width:36px;height:36px;float:left;border-radius:36px;margin-right:10px;margin-top:-10px;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-color:#CCC}.settings .field .view-my-profile{display:inline-block;vertical-align:top;position:relative;z-index:1;margin-top:1px;margin-left:-35px;padding:10px;border:0}.settings .field.shortcut-keys .shortcuts{padding-top:15px}.settings .field.shortcut-keys .row{padding-bottom:5px}.settings .field.shortcut-keys .row .flag{margin-left:0}#player{color:#FFF}#player>.background-image{display:none}.player .button{padding:5px;margin:0 5px;font-size:14px;opacity:.75;display:inline-block;background:0 0}.player .button.active,.player .button:hover{opacity:1;cursor:pointer}.player .button.active{color:#08d58f}.player .track-info{font-size:16px;padding-bottom:20px;padding-left:15px;padding-right:15px}.player .track-info .artist{opacity:.5}.player .track-info .artist a{text-decoration:none;color:#FFF;border-bottom:1px dotted transparent}.player .track-info .artist a:hover{border-color:#FFF}#player .playback{float:left;padding-left:15px}#player .volume{float:right;padding-right:20px}#player .volume.touch-friendly{display:none}#player .volume .slider{display:inline-block;width:40px;vertical-align:middle;padding:8px 0}.player .slider{cursor:pointer}#player .slider.progress{padding-top:5px;position:fixed;bottom:0;left:0;right:0;z-index:8}#player .slider.progress .track{height:4px;background:0 0}#player .slider.progress:hover .track{height:12px;background:rgba(0,0,0,.15)}.player .slider .track{position:relative;height:2px;background:rgba(255,255,255,.3)}.player .slider .track .fill{position:absolute;top:0;left:0;bottom:0;background:#08d58f;max-width:100%}.player .slider .track .fill.animate{-webkit-transition:all 1s;-moz-transition:all 1s;-o-transition:all 1s;transition:all 1s}#full-player .artwork{width:400px;padding-bottom:400px;margin:0 auto 20px;position:relative;background:#EEE;display:block;border:0}#full-player .controls{width:400px;margin:0 auto}#full-player .artwork .image{position:absolute;top:0;right:0;bottom:0;left:0;background-image:url(../svg/no-image.svg);background-size:cover;background-position:50% 50%}#full-player .track-info{color:#000;font-weight:600}#full-player .track-info .artist a{color:#000;display:inline-block}#full-player .track-info .artist a:hover{border-color:#000}#full-player .button{color:#000;font-size:20px}#full-player .button.active{color:#08d58f}#full-player .button:hover{opacity:1;background:0 0}#full-player .track-timer{float:right;margin-top:12px}#full-player .track-timer .current{opacity:.5;padding-right:2px;display:inline-block}#full-player .volume,.dialog .field.radio input{display:none}#full-player .progress.slider{margin:35px 0;position:relative}#full-player .slider .track{background:#DDD;height:4px}.dialog .dialog-title{padding-bottom:20px}.dialog .background{background:rgba(0,0,0,.95);position:fixed;top:0;right:0;bottom:0;left:0;z-index:11}.dialog .content{position:fixed;top:0;right:0;bottom:0;left:0;padding:6% 20%;color:#FFF;z-index:12;overflow-y:auto}.dialog .button.close-dialog{position:fixed;top:20px;right:20px;font-size:30px;cursor:pointer;z-index:13;color:#FFF;width:30px}.dialog .button.close-dialog img{max-width:100%}.dialog .button.destructive:hover{color:#d62f2f}.dialog .button.productive:hover{color:#35cc35}.dialog .field .label{font-size:16px}.dialog .field.text input{padding:5px 0;background:0 0;font-family:Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:200;color:#FFF;border:0;border-bottom:2px solid #FFF}.dialog .field.text input:focus{border-color:#1cf4c4}.dialog .field.large input{padding:10px 0;font-size:30px;width:70%}.dialog .field.switch .label{padding-top:6px}.dialog .field.radio .label,.fa,.fa-stack{display:inline-block}.dialog .field.radio .label{float:none;width:auto;padding:5px 30px;position:relative;cursor:pointer}.dialog .field.radio input+.label:before{content:' ';display:inline-block;width:16px;height:16px;border-radius:50%;border:2px solid #FFF;position:absolute;top:4px;left:0}.dialog .field.radio input:checked+.label:before{background:#FFF;box-shadow:inset 0 0 0 5px #111}.dialog .switch-button:not(.on)>.switch-track>.indicator{background:#FFF}.dialog .switch-button.on>.switch-track,.dialog .switch-button>.switch-track{border-color:#FFF}.dialog .actions{padding-left:0;padding-top:30px}.dialog .actions .working{padding-top:5px;width:30px;height:30px}.add-to-playlist-dialog .select-playlist{padding-top:15px}.add-to-playlist-dialog .playlist-item{font-size:16px;padding:10px 3%;border-top:1px solid #333;width:42%;float:left}.add-to-playlist-dialog .playlist-item:active,.add-to-playlist-dialog .playlist-item:focus{background:#08d58f}.add-to-playlist-dialog .playlist-item:nth-child(2n){margin-left:4%}.volume-controls-dialog .volume{padding-top:50px}.volume-controls-dialog .slider .track{height:30px}.dialog .initial-setup-dialog .dialog-title{padding-bottom:0}/*! +.button,.menu-item,.noselect,body.dragging *{-webkit-touch-callout:none;-khtml-user-select:none}.fa-ul,.main-menu .submenu>.menu-item{list-style-type:none}.contextmenu{position:fixed;display:none;top:0;left:0;z-index:10;background:#222;color:#FFF;min-width:110px}.contextmenu .menu-item{display:block;padding:8px 14px 8px 10px;border-bottom:1px solid rgba(255,255,255,.05);position:relative}.contextmenu .menu-item.has-submenu i{position:absolute;top:8px;right:8px}.contextmenu .menu-item:hover{background:#333;cursor:pointer}.contextmenu .menu-item:hover>.sub-menu{display:block}.contextmenu .sub-menu{display:none;position:absolute;right:-150px;background:#333;top:0;width:150px;max-height:306px;overflow-y:scroll}.contextmenu.close-right .sub-menu,.contextmenu.hard-right .sub-menu{right:auto;left:-150px}#sidebar,.contextmenu.touch{position:fixed;left:0;bottom:0}.contextmenu.close-bottom .sub-menu,.contextmenu.hard-bottom .sub-menu{top:auto;bottom:0}.contextmenu .sub-menu>.menu-item:hover{background:#414141}.contextmenu.click .menu-item i{font-size:8px;padding-right:5px;vertical-align:top;margin-top:5px}.contextmenu.touch{padding-left:5px;top:auto;right:0;z-index:99;background:#32b5f2}.contextmenu.touch .menu-item{display:block;float:left;padding:14px 0 12px;width:45px;text-align:center;border:0}.contextmenu.touch .menu-item.cancel{opacity:.5;float:right}.contextmenu.touch .menu-item .icon{font-size:16px}.contextmenu.touch .menu-item .text{font-size:8px;display:block;text-transform:uppercase;padding-top:5px}body,html{background:#f5f5f5;color:#000;font-family:'Archivo Narrow',Helvetica,Arial,sans-serif;font-size:14px}body{overflow-y:scroll;overflow-x:hidden}*{border:0;padding:0;margin:0}.button,.menu-item,body.dragging *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.noselect,.tracklist .track{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}body.dragging,body.dragging *,body.dragging .body,body.dragging .body *{cursor:-webkit-grabbing!important;cursor:-moz-grabbing!important}#body,#sidebar{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0);-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}#sidebar{top:0;width:20%;overflow:hidden;background:#111;z-index:1}#sidebar>.background-image{position:absolute;top:-50px;right:0;bottom:-50px;left:-50px;opacity:.3;z-index:1}#sidebar>.background-image .image{position:absolute;top:0;left:0;bottom:0;right:0;opacity:0;background-position:0 50%;background-size:cover}#sidebar>.inner{z-index:2;top:0;left:0;bottom:0;right:0;position:absolute;overflow-x:hidden;overflow-y:auto}#player{position:fixed;bottom:20px;left:0;width:20%;z-index:3}#body{padding-left:20%;position:relative;min-height:100vh}.page>.inner{padding:40px}.col{float:left;min-height:1px}.col.w5{width:5%}.col.w10{width:10%}.col.w15{width:15%}.col.w20{width:20%}.col.w25{width:25%}.col.w30{width:30%}.col.w35{width:35%}.col.w40{width:40%}.col.w45{width:45%}.col.w50{width:50%}.col.w55{width:55%}.col.w60{width:60%}.col.w65{width:65%}.col.w70{width:70%}.col.w75{width:75%}.col.w80{width:80%}.col.w85{width:85%}.col.w90{width:90%}.col.w95{width:95%}.col.w100{width:100%}.min-width{display:inline-block}.min-width.w50{min-width:50px}.min-width.w100{min-width:100px}.min-width.w150{min-width:150px}.min-width.w200{min-width:200px}.transitioning,.transitioning:hover{opacity:.2}.noselect{user-select:none}.main-menu .divider{padding:20px 0 5px 10px;font-size:11px;color:#FFF;opacity:.4;text-transform:uppercase}.main-menu .divider.spacer{height:0}.main-menu .menu-item:last-child{padding-bottom:20px}.main-menu a.unavailable{opacity:.5}.main-menu .menu-item>a{display:block;padding:8px 0 8px 10px;color:#FFF;text-decoration:none;font-size:16px;background-image:url(../svg/white-diamond.svg);background-position:110% 50%;background-repeat:no-repeat;border-left:4px solid transparent}.main-menu .menu-item>a.droppable.dropping,.main-menu .menu-item>a.droppable.dropping:hover{background-color:#08d58f}.main-menu .menu-item .info{font-size:12px;opacity:.5;padding:2px 20px 0 0;float:right}.main-menu>.menu-item>a>i.services-alert{float:right;padding:3px 12px 0 0}.main-menu .menu-item.active>a{background-color:rgba(0,0,0,.15);border-color:#08d58f}.main-menu .menu-item:not(.active)>a:hover{background-color:rgba(255,255,255,.05)}.main-menu .playlists-submenu-trigger{float:right;display:block;opacity:.5;margin-top:-7px;padding:6px 15px}.main-menu .playlists-submenu-trigger i{font-size:12px}.menu-reveal-trigger{position:absolute;top:1px;left:0;display:none;color:#FFF;font-size:17px;padding:16px;cursor:pointer;z-index:9}.main-menu .dragging-note{display:none;float:right;color:#222;font-size:12px;padding-right:7px;padding-top:2px}.dragging .main-menu .dropping>.dragging-note,.dragging .main-menu :hover>.dragging-note{display:block}.main-menu .submenu{display:none}.main-menu .menu-item.active .submenu,.main-menu .menu-item.section .submenu{display:block}.main-menu .submenu>.menu-item a{padding-left:39px}.main-menu .submenu.playlists{position:absolute;top:0;right:0;bottom:0;left:100%;overflow:hidden;background:rgba(48,48,48,.95);padding:20px 0;z-index:1;display:block}.main-menu .submenu.playlists .menu-item>a{color:#FFF;font-size:16px;padding:10px 0 10px 20px}.dragging .main-menu .menu-item.top-level.playlists.dropping-within .submenu.playlists,.main-menu .menu-item.top-level.playlists.show-submenu .submenu.playlists{left:20%}.sub-page-navigation{margin-bottom:35px;margin-top:-15px}.sub-page-navigation .menu-item{padding:12px 0;margin-right:25px;border-bottom:3px solid transparent;display:inline-block;font-size:18px;text-transform:capitalize}.breadcrumbs,.capitalize,.info-text,.list .list-item.header,.player .track-info,h4.section-title{text-transform:uppercase}.sub-page-navigation .menu-item>i{font-size:6px;vertical-align:middle;margin-top:-4px;padding-right:2px}.sub-page-navigation .menu-item:hover{border-color:rgba(255,255,255,.5);cursor:pointer}.search-page .sub-page-navigation .menu-item:hover{border-color:#AAA}.sub-page-navigation .menu-item.active{border-color:#f5f5f5}.critical-services-status{padding-left:29px;padding-top:5px}#loading-bar .bar{left:20%!important;right:0!important}#loading-bar-spinner{right:10px!important;left:auto!important}#dropzones{display:none;position:fixed;top:0;left:0;bottom:0;width:20%;z-index:98;background:rgba(0,0,0,.75)}.dragging #dropzones{display:block}#dropzones>.dropzone{background:#444;text-align:center;font-size:20px;color:#FFF;margin:20px 20px 0;line-height:20px}#dropzones>.dropzone.disabled{background:#222}#dropzones .dropzone .dropzone.dropping,#dropzones .dropzone .menu-item.dropping,#dropzones .dropzone.dropping-within>.liner:not(.hover-content),#dropzones .dropzone.dropping>.liner:not(.hover-content){background:#08d58f}#dropzones>.dropzone.disabled>.liner{opacity:.3}#dropzones .dropzone>.liner{padding:50px 20px}#dropzones .dropzone.dropping .default-content,#dropzones .dropzone.dropping-within .default-content,#dropzones .dropzone:not(.dropping):not(.dropping-within) .hover-content{display:none}#dropzones .dropzone.dropping .hover-content,#dropzones .dropzone.dropping-within .hover-content{display:block!important}#dropzones .dropzone .label{padding-top:20px}#dropzones .dropzone .menu-item{display:block;text-align:left;padding:10px 20px;color:#FFF;text-decoration:none;font-size:16px}.drag-tracer .text,.drag-tracer .track-title{font-size:12px;vertical-align:top;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.drag-tracer,.drag-tracer .track-title{background:#32b5f2;box-shadow:1px 1px 5px rgba(0,0,0,.2)}#dropzones .dropzone .menu-item:not(:last-child){border-bottom:1px solid rgba(255,255,255,.1)}#dropzones .dropzone.playlists>.liner.hover-content,#dropzones .dropzone.queue>.liner.hover-content{padding:0}#dropzones .dropzone.queue .dropzone.add-to-queue{padding:30px 20px 20px}#dropzones .dropzone.queue .dropzone.add-to-queue-next{padding:14.5px 20px;border-top:1px solid rgba(255,255,255,.1)}#dropzones .dropzone.queue .dropzone.add-to-queue-next .label{padding:0}.clear-both{clear:both}.clear-left{clear:left}.clear-right{clear:right}.hide{display:none!important}.invisible{visibility:hidden!important}:focus{outline:0}.spacer{height:40px}.animate,.button,.main-menu a,.opacity-hover,button,input[type=submit]{-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.loading .animate,.loading .button,.loading .main-menu a,.loading .opacity-hover,.loading button,.loading input[type=submit]{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;transition:none!important}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}.fadereveal{-webkit-animation:fadereveal .2s linear;-moz-animation:fadereveal .2s linear;-o-animation:fadereveal .2s linear;animation:fadereveal .2s linear;-webkit-animation-fill-mode:forward;-moz-animation-fill-mode:forward;-o-animation-fill-mode:forward;animation-fill-mode:forward}@-moz-keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}@-webkit-keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}@keyframes fadereveal{0%{display:none;opacity:0}99%{display:block}100%{display:block;opacity:1}}.opacity-hover{opacity:.5}.opacity-hover:hover{opacity:1}.blur{-webkit-filter:blur(10px);filter:blur(10px)}.invert{-webkit-filter:invert(100%);filter:invert(100%)}.drag-tracer{position:fixed;color:#FFF;z-index:99;display:none;pointer-events:none}.drag-tracer .track-title{padding:8px 12px;position:absolute;top:0;left:0;width:100px;z-index:3}.drag-tracer .track-title:nth-child(2){top:5px;left:5px;z-index:2;background:#29abe8}.drag-tracer .track-title:nth-child(3){top:10px;left:10px;z-index:1;background:#23a4e0}.drag-tracer .thumbnail{float:left;width:40px;height:40px;background-position:50% 50%;background-repeat:no-repeat;background-size:cover}.drag-tracer .text{float:left;padding:12px 15px;max-width:150px}.tooltip-wrapper{z-index:2;position:relative}.tooltip-wrapper .tooltip{display:none;position:absolute;top:0;right:0;background:#DDD;color:#222;font-size:11px;padding:2px 5px}.tooltip-wrapper:hover .tooltip{display:block}#notifications .notification,.flag,.heading-wrapper>h1{display:inline-block}.popularity .tooltip{z-index:-1;top:-5px;right:-8px;padding:5px 16px 5px 8px}.popularity:hover .bar-track{background:#FFF}#notifications{position:fixed;z-index:9;top:15px;left:20%;right:0;text-align:center;pointer-events:none}#notifications .notification{color:#FFF;padding:10px 18px;background-color:rgba(0,0,0,.6);margin:0 1px}#notifications .notification.keyboard-shortcut{position:fixed;top:50%;left:50%;width:300px;margin:-150px 0 0 -150px;text-align:center;border-radius:10px}#notifications .notification.keyboard-shortcut i{line-height:300px;font-size:120px}#notifications .notification:not(.keyboard-shortcut):first-child{border-radius:100px 0 0 100px}#notifications .notification:not(.keyboard-shortcut):last-child{border-radius:0 100px 100px 0}#notifications .notification:not(.keyboard-shortcut):only-child{border-radius:100px}#notifications .notification.bad,#notifications .notification.error{background-color:rgba(214,47,47,.9)}#notifications .notification.good{background-color:rgba(53,204,53,.9)}.page-notification{margin:-40px -40px 30px;padding:20px 40px;font-size:16px}h1{font-size:40px;font-weight:200;padding-bottom:35px;margin-top:-10px}h2{font-size:20px;font-weight:300}h3{font-size:18px;font-weight:600}h4{font-size:14px;font-weight:400}h4.section-title{font-weight:600;padding-bottom:20px}.bold-text,.no-items{font-weight:700}.underline{border-bottom:1px solid #999;padding-bottom:5px;margin-bottom:5px}.body a{color:inherit;text-decoration:none;border-bottom:1px dotted transparent;cursor:pointer}.body a:hover{border-color:inherit}.info-text{color:#AAA;padding-top:5px}.breadcrumbs{margin-top:-20px;color:#CCC}.breadcrumbs .divider{padding:0 3px}.white-text{color:#FFF!important}.black-text{color:#000!important}.grey-text{color:#AAA!important}.red-text{color:#d62f2f!important}.green-text{color:#35cc35!important}.primary-colour-text{color:#08d58f!important}.white-background{background-color:#FFF!important}.grey-background{background-color:#DDD!important}.black-background{background-color:#000!important}.red-background{background-color:#d62f2f!important}.green-background{background-color:#35cc35!important}.primary-colour-background{background-color:#08d58f!important}.italic-text{font-style:italic}.no-items{text-align:center;font-size:16px;color:#CCC;padding-top:50px}.flag{background:#EEE;border-radius:3px;padding:3px 6px;font-size:11px;font-weight:400;margin-left:10px;margin-right:-10px}h1 .flag{vertical-align:bottom;margin-bottom:8px}.flag.blue{background:#32b5f2;color:#FFF}.flag.green,.flag.primary{background:#08d58f;color:#FFF}.flag.bad{background:#d62f2f;color:#FFF}.flag.clickable:hover{background:rgba(0,0,0,.65);color:rgba(255,255,255,.85)}.flag.dark{background:rgba(0,0,0,.4);color:rgba(255,255,255,.5)}.flag.black{background:rgba(0,0,0,.55);color:rgba(255,255,255,.8)}.flag.red{background:rgba(214,47,47,.9);color:#FFF}.flag.green{background:rgba(53,204,53,.9);color:#FFF}.flag.clickable{cursor:pointer}.flag.clickable.destructive:hover{background:rgba(214,47,47,.9);color:#FFF;cursor:pointer}.body .button,.dialog .button.primary,.dialog .button.secondary,.dialog .button.transparent{display:inline-block;padding:12px 22px;margin-right:-3px;cursor:pointer;color:#FFF;border:0}.body .button,.dialog .button.secondary{background:#9b9b9b}.body .button:hover,.dialog .button.secondary:hover{background:#8B8B8B}.body .button.transparent,.body .button.transparent:hover{background:0 0;color:#000}.body .button .fa{margin-top:2px;margin-left:-2px;vertical-align:top}.body .heading-wrapper .button{vertical-align:top;margin-left:10px}.body .button.primary,.dialog .button.primary{background:#08d58f}.body .button.primary:hover,.dialog .button.primary:hover{background:#03c784}.body .button.destructive{background:#cf2d2d}.body .button.destructive:hover{background:#bc1f1f}.bar-track,.body :not(.touchDevice) .button.tertiary:hover{background:#DDD}.body .button.tertiary{background:#DDD;color:#AAA}.body .button.disabled,.body .button.disabled:hover{cursor:not-allowed;opacity:.5}.body .button.float-right{float:right}.body .follow-unfollow .unfollow{min-width:50px;text-align:center}.body .follow-unfollow.following>.follow,.body .follow-unfollow:not(.following)>.unfollow{display:none}.bar-track{display:inline-block;width:5px;position:relative;height:12px}.bar-track .bar{position:absolute;left:0;right:0;bottom:0;background:#666}.artist-grid .artist .image,.artist-list .artist .thumbnail{background-image:url(../svg/no-image.svg);background-repeat:no-repeat;background-position:50% 50%;background-size:cover;display:block}.info-text .bar-track{vertical-align:top;margin-top:7px}.artist-list .artist{display:block;clear:both;padding:10px 0;margin-bottom:5px;border:0!important}.artist-list .artist .thumbnail{width:50px;height:50px;border-radius:100px;float:left;margin-right:14px;background-color:#E9E9E9;border:2px solid #f5f5f5}.artist-list .artist:hover .thumbnail{opacity:.75;border-color:#08d58f}.artist-list .artist .name{padding-top:15px;padding-left:65px;font-weight:300;font-size:15px;display:block}.artist-grid{padding:0}.artist-grid .artist{display:block;float:left;border:0!important;width:50%;position:relative}.artist-grid .artist .image{width:100%;padding-bottom:100%;background-color:#777}.artist-grid .artist .name-wrapper{position:absolute;top:0;left:0;bottom:-.5px;right:0;text-align:center;color:#FFF;opacity:0;background:rgba(0,0,0,.8)}.image-container .image.placeholder,.square-panel .image-container .image,.thumbnail.placeholder{background-color:#E9E9E9;background-image:url(../svg/no-image.svg);background-position:50% 50%}.artist-grid .artist:hover .name-wrapper{opacity:1}.artist-grid .artist .name{padding-top:45%;font-weight:700}.square-panels{margin-left:-2%;margin-right:-2%}.square-panel{width:16%;margin:0 2% 3%;display:block;float:left;text-decoration:none;color:inherit;border:none!important}.square-panel .image-container{position:relative;width:100%;padding-bottom:100%}.square-panel .image-container .image{position:absolute;top:0;right:0;bottom:0;left:0;background-repeat:no-repeat;background-size:cover}.square-panel .image-container .overlay{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;max-width:100%;max-height:100%}.image-container .image.placeholder,.thumbnail.placeholder{background-size:80% 80%}.square-panel:hover .image-container .image{opacity:.75}.square-panel .info{padding-top:10px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-top:3px solid transparent;margin-top:-3px;position:relative;height:50px}.square-panel .info.smaller{height:30px}.square-panel:hover .info{border-color:#08d58f}.square-panel .info .secondary{padding-top:2px;color:#AAA}.square-panel .info .name,.square-panel .info .tracks{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.square-panels.smaller{margin-left:-1%;margin-right:-1%}.square-panels.smaller .square-panel{width:12.28%;margin:0 1% 3%}.square-panel.category .name{position:absolute;padding-bottom:20%;border-bottom:3px solid transparent;left:0;right:0;bottom:0;text-align:center;color:#FFF;font-weight:700;font-size:16px}.square-panel.category:hover .name{border-color:#08d58f;padding-bottom:21%}.square-panel.library-album{width:90%;margin:0}.list .list-item,.tracklist .track{margin-bottom:-1px;-webkit-touch-callout:none;-khtml-user-select:none}.square-panel.library-album:hover .image{opacity:1}.tracklist .track{display:block;padding:10px;border-top:1px solid #EEE;border-bottom:1px solid #EEE;cursor:pointer;position:relative;user-select:none}.track .album,.track .artist,.track .info,.track .title{float:left;min-height:1px}.track .source{display:none}.track .album,.track .artist,.track .title{width:30%}.track .info{width:10%;text-align:right}.track .info .duration{display:inline-block;padding-right:20px}.track .info .popularity{position:absolute;top:11px;right:10px}.track .source{position:absolute;top:9px;right:5px}.tracklist.queue-tracks .track .source,.tracklist.search-results.other .track .source{display:inline-block}body:not(.dragging):not(.touchDevice) .tracklist .track:not(.selected):hover{background:#F4F4F4;border-color:#EEE}body.dragging .tracklist .track.selected{opacity:.5}.tracklist .track.selected,.tracklist .track.selected:hover{background:#FFF39C}.tracklist .track.playing{font-weight:700}body.dragging .tracklist .track.dropping,body.dragging .tracklist .track:hover{border-top:3px solid #32b5f2;margin-top:-3px}.track.folder .icon{width:24px;float:left}.track.folder .title{width:auto}.list .list-item{display:block;padding:10px;border-top:1px solid #EEE;border-bottom:1px solid #EEE;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.list .list-item.header{color:#CCC;border-top:0;font-size:11px;padding-bottom:2px}.list .list-item:not(.header):hover{background:#F4F4F4;border-color:#EEE;cursor:pointer}.list .list-item .si{margin-top:0;vertical-align:bottom}.list .list-item .fa{margin-right:6px}.list .list-item .info{width:5%;text-align:right;float:right}#full-player,.fa-fw,.fa-li,.fa-stack-1x,.fa-stack-2x,.player .track-info{text-align:center}@media (max-width:800px){.list.album-items .name .si,.list.album-items .release-date{display:none}.list.album-items .artists,.list.album-items .name{width:40%}}.intro preloadedimage{position:absolute;top:-30px;right:-30px;bottom:-30px;left:-30px;overflow:hidden;opacity:0;background-position:50% -100px;background-repeat:no-repeat;background-size:cover}slider{height:250px;display:block;position:relative;margin-bottom:40px}slider.square-panels{margin-left:0;margin-right:-40px}slider .controls{position:absolute;top:-40px;right:40px;z-index:5}slider .controls .si{cursor:pointer;margin:5px;opacity:.7}slider .controls .si:hover{opacity:1}slider .slides{overflow:hidden;position:relative;height:100%}slider .slides-content{position:absolute;top:0;left:0;width:500%}slider .item-container{float:left;width:4%}slider .item-container>.square-panel{width:80%;margin:0}.page-header{margin:-40px -40px 40px;background:#EEE;padding:20px 40px}.tooltip,.tooltip:before{background:#333;position:absolute;left:50%}.page-header h1{padding:0;margin:0;font-size:22px;display:inline-block}.page-header h1 .si{width:1em;height:1em;margin:3px 5px 0 0}.page-header .utilities{margin:0 -25px 0 0;float:right}.page-header .utilities.has-buttons{margin-top:-8px}.library-albums .utilities .view-options label{padding:0 5px}.utilities .si{width:22px;height:22px}.utilities .filter-option.active,.utilities .filter-option:hover{opacity:1;border:none!important}.utilities .filter-option{margin-left:15px;opacity:.5}.utilities .filter-option .label{display:inline-block;vertical-align:bottom;margin-bottom:3px}.page-header .flag{display:inline-block;padding:3px 6px;margin-top:4px;vertical-align:top}.tooltip{top:-25px;min-width:66px;margin-left:-37px;padding:4px;color:#FFF;font-size:11px;display:none}.tooltip:before{content:'';width:6px;height:6px;bottom:-3px;margin-left:-3px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.has-tooltip{position:relative}#app:not(.touchDevice) .has-tooltip:hover .tooltip{display:block}.queue-intro{padding-bottom:20px}.now-playing-page .page-header{display:none}.album-intro h1{padding:20px 0 0}.album-intro .square-panel{margin:0 30px 20px 0;width:250px;height:250px}.album-intro .image{background-color:#EEE;background-size:cover;background-position:50% 50%;opacity:1!important}.album-intro .info-text{padding-top:20px}.album-page .intro,.playlist-page .intro{position:relative;margin:0 0 50px}.asset-sidebar{width:20%;position:absolute;top:0;left:20%;bottom:0;background:#EEE}.content.has-asset-sidebar{padding-left:25%}.content.has-asset-sidebar>.inner{padding:40px 20px}.album-page .album.thumbnail,.playlist-page .playlist.thumbnail{width:100%;padding-bottom:100%;margin:0;background-image:url(../svg/no-image.svg);background-color:#E9E9E9;background-position:50% 50%;background-size:cover}.album-page h1,.playlist-page h1{padding-bottom:0;padding-top:15px;margin:0}.album-page h2,.playlist-page h2{font-style:italic;color:#888;font-weight:100;padding-top:5px}.album-page .asset-sidebar .info,.playlist-page .asset-sidebar .info{padding:14px 20px;margin-top:1px}.album-page .asset-sidebar .info>.info-item,.playlist-page .asset-sidebar .info>.info-item{padding:2px 0;color:#AAA}.album-page .asset-sidebar .info .bar-track,.playlist-page .asset-sidebar .info .bar-track{vertical-align:top;margin-top:7px;margin-left:6px}.playlist-owner{display:block;padding-top:10px;border:0!important}.playlist-owner:hover .thumbnail .border{border-color:#08d58f}.playlist-owner .name{display:block;font-size:15px;font-weight:300;padding-left:40px;padding-top:5px}.playlist-owner .thumbnail .border{display:block;position:absolute;top:-1px;left:-1px;bottom:-1px;right:-1px;border:2px solid #eee;border-radius:60px;z-index:2}.playlist-owner .thumbnail{background-color:#e9e9e9;background-image:url(../svg/no-image.svg);background-position:50% 50%;background-repeat:no-repeat;background-size:cover;border-radius:60px;display:block;float:left;height:30px;margin-right:8px;width:30px;position:relative}.artist-intro{position:relative;margin:-40px -40px 30px;padding:0 20px;height:50vh}.artist-intro h1{padding-bottom:10px}.artist-intro .menu-item,.artist-intro h1{color:#FFF}.artist-intro .image-container{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;z-index:-1;background:#444}.artist-intro .image-container .image{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0}.artist-intro .image-container canvas{background-color:#444}.artist-page .title-panel{position:absolute;bottom:0;left:0;padding-left:330px}.artist-page .sub-page-navigation{margin:0}.artist-page .info-panel{padding-left:290px;margin-bottom:50px;position:relative}.artist-page .info-panel .thumbnail{width:250px;height:250px;background-image:url(../svg/no-image.svg);background-color:#E9E9E9;background-size:cover;background-position:50% 50%;position:absolute;bottom:0;left:0}.artist-page .info-panel .buttons{padding-right:20px}.artist-page .info-panel .info-text{display:inline-block;vertical-align:top}.tracklist.top-track-items{padding-bottom:30px}.gallery-item img{max-width:90%}.biography .content{font:inherit;width:100%;font-size:18px;line-height:1.4em;white-space:pre-wrap}.player .track-info .artist,.player .track-info .track{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.biography .details{padding:20px 0;color:#666}.discover .discover-section{clear:both;padding-bottom:20px}.discover .discover-section .section-title{padding-bottom:20px}.library-albums .full-album{padding-bottom:40px}.library-albums .full-album .album-title{padding:0 10px 15px}.featured-playlists-intro{position:relative;margin:-40px -40px 40px;padding:0 20px;height:30vh;background:#303030}.featured-playlists-intro>.inner{z-index:1;position:relative;color:#FFF;text-align:center;padding-top:13vh}.search-results-section.tracks,.user-intro .info{padding-top:30px}.featured-playlists-intro>.image-container{position:absolute;top:0;left:0;right:0;bottom:0}.featured-playlists-intro>.image-container>.image{position:absolute;top:0;left:0;right:0;bottom:0;opacity:0}.user-intro{padding-bottom:30px}.user-intro .info-text{margin-top:-20px}.user-intro .image-container .image{width:120px;height:120px;border-radius:120px;float:left;background-size:cover;background-position:50% 50%;margin-right:20px}.search .loading{margin:50px auto;width:70px;height:70px}.search .loading img{width:100%;height:100%}.search .sub-page-navigation{margin:-10px 0 30px}.search-results-section.albums,.search-results-section.artists,.search-results-section.playlists{width:30.6667%;float:left}.search-results-section.albums,.search-results-section.artists{padding-right:4%}.search-results-section .square-panel{width:46%}.search-results-section .square-panel .info{height:60px}.settings>.section{padding-bottom:40px}.settings .section-title .state-label{display:inline-block;padding:1px 3px;font-size:11px;margin-left:5px}.actions{clear:both;padding:40px 0 0 15%}.sub-page{padding:10px 0 20px}.settings .field.current-user .input{padding-top:8px}.settings .field.current-user .image-container>.image{width:36px;height:36px;float:left;border-radius:36px;margin-right:10px;margin-top:-10px;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-color:#CCC}.settings .field .view-my-profile{display:inline-block;vertical-align:top;position:relative;z-index:1;margin-top:1px;margin-left:-35px;padding:10px;border:0}.settings .field.shortcut-keys .shortcuts{padding-top:15px}.settings .field.shortcut-keys .row{padding-bottom:5px}.settings .field.shortcut-keys .row .flag{margin-left:0}#player{color:#FFF}#player>.background-image{display:none}.player .button{padding:5px;margin:0 5px;font-size:14px;opacity:.75;display:inline-block;background:0 0}.player .button.active,.player .button:hover{opacity:1;cursor:pointer}.player .button.active{color:#08d58f}.player .track-info{font-size:16px;padding-bottom:20px;padding-left:15px;padding-right:15px}.player .track-info .artist{opacity:.5}.player .track-info .artist a{text-decoration:none;color:#FFF;border-bottom:1px dotted transparent}.player .track-info .artist a:hover{border-color:#FFF}#player .playback{float:left;padding-left:15px}#player .volume{float:right;padding-right:20px}#player .volume.touch-friendly{display:none}#player .volume .slider{display:inline-block;width:40px;vertical-align:middle;padding:8px 0}.player .slider{cursor:pointer}#player .slider.progress{padding-top:5px;position:fixed;bottom:0;left:0;right:0;z-index:8}#player .slider.progress .track{height:4px;background:0 0}#player .slider.progress:hover .track{height:12px;background:rgba(0,0,0,.15)}.player .slider .track{position:relative;height:2px;background:rgba(255,255,255,.3)}.player .slider .track .fill{position:absolute;top:0;left:0;bottom:0;background:#08d58f;max-width:100%}.player .slider .track .fill.animate{-webkit-transition:all 1s;-moz-transition:all 1s;-o-transition:all 1s;transition:all 1s}#full-player .artwork{width:400px;padding-bottom:400px;margin:0 auto 20px;position:relative;background:#EEE;display:block;border:0}#full-player .controls{width:400px;margin:0 auto}#full-player .artwork .image{position:absolute;top:0;right:0;bottom:0;left:0;background-image:url(../svg/no-image.svg);background-size:cover;background-position:50% 50%}#full-player .track-info{color:#000;font-weight:600}#full-player .track-info .artist a{color:#000;display:inline-block}#full-player .track-info .artist a:hover{border-color:#000}#full-player .button{color:#000;font-size:20px}#full-player .button.active{color:#08d58f}#full-player .button:hover{opacity:1;background:0 0}#full-player .track-timer{float:right;margin-top:12px}#full-player .track-timer .current{opacity:.5;padding-right:2px;display:inline-block}#full-player .volume,.dialog .field.radio input{display:none}#full-player .progress.slider{margin:35px 0;position:relative}#full-player .slider .track{background:#DDD;height:4px}.dialog .dialog-title{padding-bottom:20px}.dialog .background{background:rgba(0,0,0,.95);position:fixed;top:0;right:0;bottom:0;left:0;z-index:11}.dialog .content{position:fixed;top:0;right:0;bottom:0;left:0;padding:6% 20%;color:#FFF;z-index:12;overflow-y:auto}.dialog .button.close-dialog{position:fixed;top:20px;right:20px;font-size:30px;cursor:pointer;z-index:13;color:#FFF;width:30px}.dialog .button.close-dialog img{max-width:100%}.dialog .button.destructive:hover{color:#d62f2f}.dialog .button.productive:hover{color:#35cc35}.dialog .field .label{font-size:16px}.dialog .field.text input{padding:5px 0;background:0 0;font-family:Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:200;color:#FFF;border:0;border-bottom:2px solid #FFF}.dialog .field.text input:focus{border-color:#1cf4c4}.dialog .field.large input{padding:10px 0;font-size:30px;width:70%}.dialog .field.switch .label{padding-top:6px}.dialog .field.radio .label,.fa,.fa-stack{display:inline-block}.dialog .field.radio .label{float:none;width:auto;padding:5px 30px;position:relative;cursor:pointer}.dialog .field.radio input+.label:before{content:' ';display:inline-block;width:16px;height:16px;border-radius:50%;border:2px solid #FFF;position:absolute;top:4px;left:0}.dialog .field.radio input:checked+.label:before{background:#FFF;box-shadow:inset 0 0 0 5px #111}.dialog .switch-button:not(.on)>.switch-track>.indicator{background:#FFF}.dialog .switch-button.on>.switch-track,.dialog .switch-button>.switch-track{border-color:#FFF}.dialog .actions{padding-left:0;padding-top:30px}.dialog .actions .working{padding-top:5px;width:30px;height:30px}.add-to-playlist-dialog .select-playlist{padding-top:15px}.add-to-playlist-dialog .playlist-item{font-size:16px;padding:10px 3%;border-top:1px solid #333;width:42%;float:left}.add-to-playlist-dialog .playlist-item:active,.add-to-playlist-dialog .playlist-item:focus{background:#08d58f}.add-to-playlist-dialog .playlist-item:nth-child(2n){margin-left:4%}.volume-controls-dialog .volume{padding-top:50px}.volume-controls-dialog .slider .track{height:30px}.dialog .initial-setup-dialog .dialog-title{padding-bottom:0}/*! * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */@font-face{font-family:FontAwesome;src:url(../fonts/fontawesome-webfont.eot?v=4.3.0);src:url(../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0) format('embedded-opentype'),url(../fonts/fontawesome-webfont.woff2?v=4.3.0) format('woff2'),url(../fonts/fontawesome-webfont.woff?v=4.3.0) format('woff'),url(../fonts/fontawesome-webfont.ttf?v=4.3.0) format('truetype'),url(../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}.fa{font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em}.fa-ul{padding-left:0;margin-left:2.14285714em}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{filter:none}.fa-stack{position:relative;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before,.fa-genderless:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.field{clear:both;padding-top:20px;text-align:top}.field .label{float:left;width:13%;padding-top:8px;text-align:right;padding-right:2%}.note{display:block;padding:4px 0 5px;font-family:Roboto;font-size:12px;font-weight:300;color:#777}.field .input{float:left;width:85%}.field .input.readonly{padding-top:8.5px}.field input{padding:10px 16px;font-family:Roboto,Helvetica,Arial,sans-serif;font-size:12px;width:50%;background:#FFF}button,input[type=submit]{font-family:"Archivo Narrow",Helvetica,Arial,sans-serif}.field input[readonly=true]{border-color:#999;background:#EEE}.field .autosave-success{display:none;color:#46D938;padding:8px;font-size:18px}.field .authentication-token>*,.field .connection-status .status{padding:8px 8px 8px 0;display:inline-block}.field .connection-status.offline .status.connected,.field .connection-status.online .status,.field .connection-status.online .status.disconnected{display:none}.field .connection-status.offline .status.disconnected,.field .connection-status.online .status.connected{display:block}.field.switch .input{float:left;width:auto;padding-right:15px}.field.switch .label{float:left;text-align:left;width:auto}.switch-button{cursor:pointer}.switch-button>.switch-track{margin-top:6px;width:30px;height:12px;padding:3px;border-radius:20px;position:relative;display:inline-block;border:2px solid #000}.switch-button>.switch-track>.indicator{width:12px;height:12px;position:absolute;top:3px;left:3px;background:#000;border-radius:14px}.switch-button.on>.switch-track>.indicator{left:auto;right:3px;background:#08d58f}.switch-button-wrapper{display:block;padding:4px 16px 0 0}.switch-button-wrapper .label{vertical-align:top;display:inline-block;margin:7px 5px 0 10px}.field.radio .input label{padding-top:2px;display:inline-block}.field.radio input{display:none}.field.radio label .label{display:inline-block;float:none;width:auto;padding:5px 30px;position:relative;cursor:pointer}.field.radio input+.label:before{content:' ';display:inline-block;width:14px;height:14px;border-radius:50%;border:2px solid #000;position:absolute;top:4px;left:0}.field.radio input:checked+.label:before{background:#000;box-shadow:inset 0 0 0 3px #f5f5f5}.search-form .query,.search-form .submit{background:0 0;color:#FFF;font-size:16px}.field.icon-radio{padding:0}.field.icon-radio input{display:none}.field.icon-radio label,.si,.utilities .field{display:inline-block}.field.icon-radio .label{opacity:.3;width:auto;padding:0;margin:0;cursor:pointer}.field.icon-radio .label:hover{opacity:.5}.field.icon-radio input:checked+.label{opacity:1}.search-form .query{font-family:"Archivo Narrow";font-weight:100!important;border-bottom:1px solid #FFF;width:90%;padding:10px 10% 10px 0}.search-form .query:focus{border-color:#1cf4c4}.search-form{margin:20px 15px 30px;position:relative}.search-form .submit{position:absolute;top:10px;right:0;cursor:pointer}#body .search-form{width:100%;margin:0 0 20px}#body .search-form input{color:#333;border-color:#CCC}#body .search-form .submit{color:#333}.list-filter{padding:10px;font-family:"Archivo Narrow",Helvetica,Arial,sans-serif}.utilities .list-filter{vertical-align:top;margin:-5px 20px 0 0;width:200px}.si{width:16px;height:16px;background-position:50% 50%;background-repeat:no-repeat;vertical-align:top;margin-top:2px;margin-right:5px;padding:0;background-size:contain}.si.doublesize{width:32px;height:32px}.si.play{background-image:url(../icons/play.svg)}.si.compass{background-image:url(../icons/compass.svg)}.si.playlist{background-image:url(../icons/playlist.svg)}.si.music{background-image:url(../icons/music.svg)}.si.cog{background-image:url(../icons/cog.svg)}.si.folder{background-image:url(../icons/folder.svg)}.si.leaf{background-image:url(../icons/leaf.svg)}.si.star{background-image:url(../icons/star.svg)}.si.mic{background-image:url(../icons/mic.svg)}.si.cd{background-image:url(../icons/cd.svg)}.si.grid{background-image:url(../icons/grid.svg)}.si.search{background-image:url(../icons/search.svg)}.si.chevron-right{background-image:url(../icons/chevron-right.svg)}.si.chevron-left{background-image:url(../icons/chevron-left.svg)}.si.sections{background-image:url(../icons/sections.svg)}.si.list{background-image:url(../icons/list.svg)}.si.spotify{background-image:url(../icons/spotify.svg)}.si.soundcloud{background-image:url(../icons/soundcloud.svg)}.si.local{background-image:url(../icons/local.svg)}.si.filter{background-image:url(../icons/filter.svg)}.si.white{-webkit-filter:invert(1);-moz-filter:invert(1);filter:invert(1)}@media (max-width:800px){.si.mobile-white{-webkit-filter:invert(1);-moz-filter:invert(1);filter:invert(1)}}.si.light{-webkit-filter:invert(1) brightness(75%);-moz-filter:invert(1) brightness(75%);filter:invert(1) brightness(75%)}.si.yellow{-webkit-filter:invert(60%) sepia(50%) hue-rotate(360deg) saturate(510%) brightness(110%);-moz-filter:invert(60%) sepia(50%) hue-rotate(360deg) saturate(510%) brightness(110%);filter:invert(60%) sepia(50%) hue-rotate(360deg) saturate(510%) brightness(110%)}.si.red{-webkit-filter:invert(45%) sepia(50%) hue-rotate(320deg) saturate(720%) brightness(90%);-moz-filter:invert(45%) sepia(50%) hue-rotate(320deg) saturate(720%) brightness(90%);filter:invert(45%) sepia(50%) hue-rotate(320deg) saturate(720%) brightness(90%)}.si.green{-webkit-filter:invert(50%) sepia(50%) hue-rotate(50deg) saturate(450%) brightness(110%);-moz-filter:invert(50%) sepia(50%) hue-rotate(50deg) saturate(450%) brightness(110%);filter:invert(50%) sepia(50%) hue-rotate(50deg) saturate(450%) brightness(110%)}/*! @@ -6,4 +6,4 @@ * https://chieffancypants.github.io/angular-loading-bar * Copyright (c) 2015 Wes Cruver * License: MIT - */#loading-bar,#loading-bar-spinner{pointer-events:none;-webkit-pointer-events:none;-webkit-transition:350ms linear all;-moz-transition:350ms linear all;-o-transition:350ms linear all;transition:350ms linear all}#loading-bar-spinner.ng-enter,#loading-bar-spinner.ng-leave.ng-leave-active,#loading-bar.ng-enter,#loading-bar.ng-leave.ng-leave-active{opacity:0}#loading-bar-spinner.ng-enter.ng-enter-active,#loading-bar-spinner.ng-leave,#loading-bar.ng-enter.ng-enter-active,#loading-bar.ng-leave{opacity:1}#loading-bar .bar{-webkit-transition:width 350ms;-moz-transition:width 350ms;-o-transition:width 350ms;transition:width 350ms;background:#29d;position:fixed;z-index:10002;top:0;width:100%;height:3px;border-bottom-right-radius:1px;border-top-right-radius:1px}#loading-bar .peg{position:absolute;width:70px;right:0;top:0;height:3px;opacity:.45;-moz-box-shadow:#29d 1px 0 6px 1px;-ms-box-shadow:#29d 1px 0 6px 1px;-webkit-box-shadow:#29d 1px 0 6px 1px;box-shadow:#29d 1px 0 6px 1px;-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}#loading-bar-spinner{display:block;position:fixed;z-index:10002;top:10px}#loading-bar-spinner .spinner-icon{width:14px;height:14px;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:loading-bar-spinner .4s linear infinite;-moz-animation:loading-bar-spinner .4s linear infinite;-ms-animation:loading-bar-spinner .4s linear infinite;-o-animation:loading-bar-spinner .4s linear infinite;animation:loading-bar-spinner .4s linear infinite}@-webkit-keyframes loading-bar-spinner{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes loading-bar-spinner{0%{-moz-transform:rotate(0);transform:rotate(0)}100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes loading-bar-spinner{0%{-o-transform:rotate(0);transform:rotate(0)}100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes loading-bar-spinner{0%{-ms-transform:rotate(0);transform:rotate(0)}100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-bar-spinner{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.mobile-only,.mobile-show{display:none}@media(max-height:740px){.main-menu .menu-item>a{padding-top:7px;padding-bottom:7px}.main-menu .divider{padding-top:10px}.main-menu .divider.spacer{height:0}#body{padding-bottom:50px}}@media(min-width:800px){.mobile-show{display:none!important}}@media (max-width:800px),(max-height:650px){#sidebar>.inner{bottom:54px}#player{position:fixed;bottom:0;right:0;left:0;width:auto;height:40px;padding:12px 0 2px;background-color:#222;overflow:hidden;line-height:1.2em}.player .button{margin:0 3px}#player .button.previous,#player .volume:not(.touch-friendly){display:none!important}#player .volume.touch-friendly{display:inline-block!important;position:absolute;top:14px;right:-10px}#player .volume.touch-friendly .button{font-size:18px}#player .track-info{padding:0;font-size:13px;padding-left:80px;padding-right:80px}#player .playback{position:absolute;padding-left:10px;top:16px}#player>.background-image{display:block;position:absolute;top:-20px;right:-20px;bottom:-20px;left:-20px;z-index:-1;opacity:.3}#player>.background-image .image{position:absolute;top:0;right:0;bottom:0;left:0;background-position:0 50%;background-size:cover}#player .slider.progress{position:absolute;top:0;left:0;right:0;bottom:auto;padding:0}#player .slider.progress .track,#player .slider.progress:hover .track{height:2px}}@media (max-width:800px){#notifications,.menu-revealed #sidebar{left:0}.mobile-show{display:block!important}.button.mobile-show,span.mobile-show{display:inline-block!important}.mobile-hide{display:none!important}.breadcrumbs{display:none}.page:not(.search-page) .sub-page-navigation .menu-item.active{border-color:#FFF}.list .list-item,.tracklist .track{padding-right:20px;margin-left:-20px;margin-right:-20px}#sidebar{width:30%;left:-30%;z-index:4}#sidebar>.inner{bottom:0}#body{width:100%;padding:0 0 50px}.menu-reveal-trigger{display:block}#loading-bar .bar{display:none}#loading-bar-spinner{top:50%!important;left:50%!important;right:auto!important;margin-left:-40px;margin-top:-40px;background:#29d;padding:20px;border-radius:50px;width:50px;height:50px}#loading-bar-spinner .spinner-icon{width:90%!important;height:90%!important;border-color:#FFF transparent transparent #FFF!important}#sidebar .main-menu{padding-top:15px}#sidebar .main-menu .divider.spacer{height:0}.page>.inner{padding:20px}.page-header{display:block;position:relative;margin:-20px -20px 20px;background:#222;color:#FFF;padding:15px 20px}.album-page .page-header,.playlist-page .page-header{margin:0}.page-header h1{padding:1px 0 0 30px;margin:0;font-size:18px}.page-header .button,.page-header .button.primary,.page-header .button.primary:hover,.page-header .button:hover{margin:3px -10px 0 0;padding:8px 11px;background:0 0}.page-header .utilities .filter .trigger{display:block;color:#FFF;cursor:pointer}.page-header .utilities .filter .trigger .label{display:inline-block;padding-top:3px}.page-header .utilities .filter .options-wrapper{display:none;position:absolute;top:52px;right:0;left:0;background:#EEE;padding:10px;z-index:5}.page-header .utilities .filter.expanded .options-wrapper{display:block}.page-header .utilities .filter-option{color:#000;display:block;float:left;width:55px;margin:0;border:0;padding:5px 0;text-align:center}.page-header .utilities .filter-option .si{display:inline-block;margin:0}.page-header .utilities .filter-option .label{display:block;text-align:center;margin:3px 0 0}.album-page .artist-grid,.album-page .info:not(.show),.playlist-page .artist-grid,.playlist-page .info:not(.show){display:none}.page-header .utilities .switch-button>.switch-track{border-color:#FFF}.page-header .utilities .switch-button:not(.on)>.switch-track>.indicator{background:#FFF}.page-header .utilities input[type=text]{margin:-7px -12px 0 0;width:100px;background:rgba(255,255,255,.15);color:#FFF}.page-notification{margin-top:-20px;padding:10px 20px;text-align:center}.album-intro .square-panel{width:180px;height:180px}.asset-sidebar{position:static;width:auto;overflow:visible;background:0 0}.content.has-asset-sidebar{padding-left:0;overflow:visible}.content.has-asset-sidebar>.inner{padding-top:25px}.album-page .intro,.playlist-page .intro{margin-bottom:25px}.album-page .info,.playlist-page .info{margin-top:-1px!important;background:#DDD}.thumbnail-wrapper.slim-intro-wrapper{background:#222;overflow:hidden;position:relative}.thumbnail-wrapper.slim-intro-wrapper>.thumbnail{opacity:.25;padding-bottom:0;width:auto;border-position:50% 50%;position:absolute;top:-20px;right:-20px;bottom:-20px;left:-20px;-webkit-filter:blur(10px);filter:blur(10px)}.thumbnail-wrapper.slim-intro-wrapper .slim-intro{z-index:2;text-align:center;position:relative;padding:60px 20px 40px}.thumbnail-wrapper.slim-intro-wrapper .slim-intro .thumbnail{display:block;width:180px;height:180px;margin:0 auto;padding-bottom:0;margin-bottom:10px}#full-player .progress.slider,#full-player .track-timer,.artist-page .info-panel .thumbnail,slider .controls{display:none}.field>.input,.field>.label{width:auto;float:none}.thumbnail-wrapper.slim-intro-wrapper .slim-intro h1{color:#FFF;font-size:20px}.thumbnail-wrapper.slim-intro-wrapper .slim-intro h2{font-size:16px}.artist-page .artist-intro{margin-bottom:0;margin-left:-20px;margin-right:-20px;margin-top:-20px}.artist-page .title-panel{padding-left:20px}.artist-page .info-panel{padding-left:0;margin-top:20px}.artist-page .info-panel .buttons{padding-right:10px}.featured-playlists-intro{margin-left:-20px;margin-right:-20px;margin-top:-20px}.field>.label{text-align:left;padding:0 0 5px;font-weight:700}.field input{width:94%;padding-left:3%;padding-right:3%}.square-panels{margin-left:-3.5%;margin-right:-3.5%}.square-panel{width:21%;margin-bottom:5%}.square-panel.category .name,.square-panel.category:hover .name{padding-bottom:12%}slider.square-panels{margin-bottom:10px;margin-right:-20px}slider .slides{overflow-x:scroll;-webkit-overflow-scrolling:touch}slider .slides-content{width:1100%}.dialog .field.large input{width:100%}.dialog .content{padding-left:15%;padding-right:15%}#full-player .controls{padding-bottom:15px}#full-player .volume{display:inline-block}.library-albums .col.info,.library-albums .col.main{float:none;width:auto;clear:both}.library-albums .col.main{padding-top:20px}.library-albums .col.info .square-panel{width:25%;float:left;margin-right:20px;margin-left:-10px}.discover-section .section-title{text-align:center}.discover-section .section-title .artist-list{display:block}}@media(max-width:600px){.actions,.edit-playlist-dialog .actions{padding-left:0}#sidebar{width:50%;left:-50%}.collapse-for-mobile .col{width:100%;float:none;padding-top:2px}.tracklist .track{padding-right:20px}.tracklist .track .duration,.tracklist .track .popularity{display:none}.tracklist .track .title{width:40%}.tracklist.album-items .track .artist,.tracklist.album-items .track .title{width:50%}.artist-page .info-panel{margin-left:-20px;margin-top:0}.artist-intro{height:60vh}.square-panel.category .name,.square-panel.category:hover .name{padding-bottom:8%;font-size:13px}.square-panels.smaller .square-panel{width:21%;margin:0 2% 5%}.dialog input.large{width:100%}.add-to-playlist-dialog .playlist-item{float:none;width:94%;margin-left:0!important}.edit-playlist-dialog .actions .toggle-public{margin-left:0}.actions{display:block}.sub-page-navigation{margin-top:0}.search-page .sub-page-navigation .menu-item{padding:5px 0}.page-header .utilities{margin-right:0}.page-header .utilities .list-filter{display:none}.search-page .search-results-section{float:none;width:100%;margin-right:0;padding-right:0}.search-page .search-results-section .square-panel{width:21%}}@media(max-width:450px){.mobile-hide{display:none}h1{font-size:30px}#sidebar{width:70%;left:-70%}#full-player .artwork{width:100%;padding-bottom:100%}#full-player .controls{width:100%}#full-player .button{padding:3px 6px}.browse.album .album-intro .square-panel{width:100%;height:auto}.browse.album .album-intro{padding-bottom:20px}.playlist-intro>.inner{padding:0}.playlist-intro .thumbnail{width:100%;height:1px;padding-bottom:100%;margin:0}.playlist-intro .content{clear:both;padding-left:0}.playlist-intro .buttons,.playlist-intro .description{padding-top:10px}.square-panel{width:29%;margin-bottom:5%}.square-panel .info{padding-top:5px;height:60px}.dialog .content{padding-left:10%;padding-right:10%}.add-to-playlist-dialog .playlist{width:29.3333%}.tracklist .track .artist,.tracklist .track .title{width:50%}.tracklist .track .album{clear:left;width:auto;padding-left:50%;padding-right:10px;opacity:.5}}.touchDevice #full-player .volume,.touchDevice #player .volume.touch-friendly{display:inline-block}#app:not(.touchDevice) #player .volume.touch-friendly,.touchDevice #player .volume:not(.touch-friendly),.tracklist .track .selected-state{display:none}.touchDevice .tracklist .track{padding-left:30px}.touchDevice .tracklist .track .selected-state{display:block;width:10px;position:absolute;top:2px;left:0;padding:10px;font-size:14px}.tracklist-context-menu{background:rgba(50,50,50,.95);color:#FFF;z-index:9;position:fixed;top:0;right:0;left:0;box-shadow:0 2px 10px rgba(0,0,0,.5)}.tracklist-context-menu .menu-item:first-child{margin-left:6px}.tracklist-context-menu .menu-item{display:block;float:left;text-align:center;padding:20px 16px;margin-right:5px;font-weight:700;text-transform:uppercase;cursor:pointer}.tracklist-context-menu .menu-item .fa{display:block;font-size:16px}.tracklist-context-menu .menu-item .text{padding-top:5px;display:block;font-size:10px}.tracklist-context-menu .menu-item.cancel{float:right;opacity:.5} \ No newline at end of file + */#loading-bar,#loading-bar-spinner{pointer-events:none;-webkit-pointer-events:none;-webkit-transition:350ms linear all;-moz-transition:350ms linear all;-o-transition:350ms linear all;transition:350ms linear all}#loading-bar-spinner.ng-enter,#loading-bar-spinner.ng-leave.ng-leave-active,#loading-bar.ng-enter,#loading-bar.ng-leave.ng-leave-active{opacity:0}#loading-bar-spinner.ng-enter.ng-enter-active,#loading-bar-spinner.ng-leave,#loading-bar.ng-enter.ng-enter-active,#loading-bar.ng-leave{opacity:1}#loading-bar .bar{-webkit-transition:width 350ms;-moz-transition:width 350ms;-o-transition:width 350ms;transition:width 350ms;background:#29d;position:fixed;z-index:10002;top:0;width:100%;height:3px;border-bottom-right-radius:1px;border-top-right-radius:1px}#loading-bar .peg{position:absolute;width:70px;right:0;top:0;height:3px;opacity:.45;-moz-box-shadow:#29d 1px 0 6px 1px;-ms-box-shadow:#29d 1px 0 6px 1px;-webkit-box-shadow:#29d 1px 0 6px 1px;box-shadow:#29d 1px 0 6px 1px;-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}#loading-bar-spinner{display:block;position:fixed;z-index:10002;top:10px}#loading-bar-spinner .spinner-icon{width:14px;height:14px;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:loading-bar-spinner .4s linear infinite;-moz-animation:loading-bar-spinner .4s linear infinite;-ms-animation:loading-bar-spinner .4s linear infinite;-o-animation:loading-bar-spinner .4s linear infinite;animation:loading-bar-spinner .4s linear infinite}@-webkit-keyframes loading-bar-spinner{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes loading-bar-spinner{0%{-moz-transform:rotate(0);transform:rotate(0)}100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes loading-bar-spinner{0%{-o-transform:rotate(0);transform:rotate(0)}100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes loading-bar-spinner{0%{-ms-transform:rotate(0);transform:rotate(0)}100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-bar-spinner{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.mobile-only,.mobile-show{display:none}@media(max-height:740px){.main-menu .menu-item>a{padding-top:7px;padding-bottom:7px}.main-menu .divider{padding-top:10px}.main-menu .divider.spacer{height:0}#body{padding-bottom:50px}}@media(min-width:800px){.mobile-show{display:none!important}}@media (max-width:800px),(max-height:650px){#sidebar>.inner{bottom:54px}#player{position:fixed;bottom:0;right:0;left:0;width:auto;height:40px;padding:12px 0 2px;background-color:#222;overflow:hidden;line-height:1.2em}.player .button{margin:0 3px}#player .button.previous,#player .volume:not(.touch-friendly){display:none!important}#player .volume.touch-friendly{display:inline-block!important;position:absolute;top:14px;right:-10px}#player .volume.touch-friendly .button{font-size:18px}#player .track-info{padding:0;font-size:13px;padding-left:80px;padding-right:80px}#player .playback{position:absolute;padding-left:10px;top:16px}#player>.background-image{display:block;position:absolute;top:-20px;right:-20px;bottom:-20px;left:-20px;z-index:-1;opacity:.3}#player>.background-image .image{position:absolute;top:0;right:0;bottom:0;left:0;background-position:0 50%;background-size:cover}#player .slider.progress{position:absolute;top:0;left:0;right:0;bottom:auto;padding:0}#player .slider.progress .track,#player .slider.progress:hover .track{height:2px}}@media (max-width:800px){#notifications,.menu-revealed #sidebar{left:0}.mobile-show{display:block!important}.button.mobile-show,span.mobile-show{display:inline-block!important}.mobile-hide{display:none!important}.breadcrumbs{display:none}.page:not(.search-page) .sub-page-navigation .menu-item.active{border-color:#FFF}.list .list-item,.tracklist .track{padding-right:20px;margin-left:-20px;margin-right:-20px}#sidebar{width:30%;left:-30%;z-index:4}#sidebar>.inner{bottom:0}#body{width:100%;padding:0 0 50px}.menu-reveal-trigger{display:block}#loading-bar .bar{display:none}#loading-bar-spinner{top:50%!important;left:50%!important;right:auto!important;margin-left:-40px;margin-top:-40px;background:#29d;padding:20px;border-radius:50px;width:50px;height:50px}#loading-bar-spinner .spinner-icon{width:90%!important;height:90%!important;border-color:#FFF transparent transparent #FFF!important}#sidebar .main-menu{padding-top:15px}#sidebar .main-menu .divider.spacer{height:0}.page>.inner{padding:20px}.page-header{display:block;position:relative;margin:-20px -20px 20px;background:#222;color:#FFF;padding:15px 20px}.album-page .page-header,.playlist-page .page-header{margin:0}.page-header h1{padding:1px 0 0 30px;margin:0;font-size:18px}.page-header .fa{color:#FFF}.page-header .button,.page-header .button.primary,.page-header .button.primary:hover .page-header .button.transparent,.page-header .button.transparent:hover,.page-header .button:hover{margin:3px -10px 0 0;padding:8px 11px;background:0 0}.page-header .utilities .filter .trigger{display:block;color:#FFF;cursor:pointer}.page-header .utilities .filter .trigger .label{display:inline-block;padding-top:3px}.page-header .utilities .filter .options-wrapper{display:none;position:absolute;top:52px;right:0;left:0;background:#EEE;padding:10px;z-index:5}.page-header .utilities .filter.expanded .options-wrapper{display:block}.page-header .utilities .filter-option{color:#000;display:block;float:left;width:55px;margin:0;border:0;padding:5px 0;text-align:center}.page-header .utilities .filter-option .si{display:inline-block;margin:0}.page-header .utilities .filter-option .label{display:block;text-align:center;margin:3px 0 0}.album-page .artist-grid,.album-page .info:not(.show),.playlist-page .artist-grid,.playlist-page .info:not(.show){display:none}.page-header .utilities .switch-button>.switch-track{border-color:#FFF}.page-header .utilities .switch-button:not(.on)>.switch-track>.indicator{background:#FFF}.page-header .utilities input[type=text]{margin:-7px -12px 0 0;width:100px;background:rgba(255,255,255,.15);color:#FFF}.page-notification{margin-top:-20px;padding:10px 20px;text-align:center}.album-intro .square-panel{width:180px;height:180px}.asset-sidebar{position:static;width:auto;overflow:visible;background:0 0}.content.has-asset-sidebar{padding-left:0;overflow:visible}.content.has-asset-sidebar>.inner{padding-top:25px}.album-page .intro,.playlist-page .intro{margin-bottom:25px}.album-page .info,.playlist-page .info{margin-top:-1px!important;background:#DDD}.thumbnail-wrapper.slim-intro-wrapper{background:#222;overflow:hidden;position:relative}.thumbnail-wrapper.slim-intro-wrapper>.thumbnail{opacity:.25;padding-bottom:0;width:auto;border-position:50% 50%;position:absolute;top:-20px;right:-20px;bottom:-20px;left:-20px;-webkit-filter:blur(10px);filter:blur(10px)}.thumbnail-wrapper.slim-intro-wrapper .slim-intro{z-index:2;text-align:center;position:relative;padding:60px 20px 40px}.thumbnail-wrapper.slim-intro-wrapper .slim-intro .thumbnail{display:block;width:180px;height:180px;margin:0 auto;padding-bottom:0;margin-bottom:10px}#full-player .progress.slider,#full-player .track-timer,.artist-page .info-panel .thumbnail,slider .controls{display:none}.field>.input,.field>.label{width:auto;float:none}.thumbnail-wrapper.slim-intro-wrapper .slim-intro h1{color:#FFF;font-size:20px}.thumbnail-wrapper.slim-intro-wrapper .slim-intro h2{font-size:16px}.artist-page .artist-intro{margin-bottom:0;margin-left:-20px;margin-right:-20px;margin-top:-20px}.artist-page .title-panel{padding-left:20px}.artist-page .info-panel{padding-left:0;margin-top:20px}.artist-page .info-panel .buttons{padding-right:10px}.featured-playlists-intro{margin-left:-20px;margin-right:-20px;margin-top:-20px}.field>.label{text-align:left;padding:0 0 5px;font-weight:700}.field input{width:94%;padding-left:3%;padding-right:3%}.square-panels{margin-left:-3.5%;margin-right:-3.5%}.square-panel{width:21%;margin-bottom:5%}.square-panel.category .name,.square-panel.category:hover .name{padding-bottom:12%}slider.square-panels{margin-bottom:10px;margin-right:-20px}slider .slides{overflow-x:scroll;-webkit-overflow-scrolling:touch}slider .slides-content{width:1100%}.dialog .field.large input{width:100%}.dialog .content{padding-left:15%;padding-right:15%}#full-player .controls{padding-bottom:15px}#full-player .volume{display:inline-block}.library-albums .col.info,.library-albums .col.main{float:none;width:auto;clear:both}.library-albums .col.main{padding-top:20px}.library-albums .col.info .square-panel{width:25%;float:left;margin-right:20px;margin-left:-10px}.discover-section .section-title{text-align:center}.discover-section .section-title .artist-list{display:block}}@media(max-width:600px){.actions,.edit-playlist-dialog .actions{padding-left:0}#sidebar{width:50%;left:-50%}.collapse-for-mobile .col{width:100%;float:none;padding-top:2px}.tracklist .track{padding-right:20px}.tracklist .track .duration,.tracklist .track .popularity{display:none}.tracklist .track .title{width:40%}.tracklist.album-items .track .artist,.tracklist.album-items .track .title{width:50%}.artist-page .info-panel{margin-left:-20px;margin-top:0}.artist-intro{height:60vh}.square-panel.category .name,.square-panel.category:hover .name{padding-bottom:8%;font-size:13px}.square-panels.smaller .square-panel{width:21%;margin:0 2% 5%}.dialog input.large{width:100%}.add-to-playlist-dialog .playlist-item{float:none;width:94%;margin-left:0!important}.edit-playlist-dialog .actions .toggle-public{margin-left:0}.actions{display:block}.sub-page-navigation{margin-top:0}.search-page .sub-page-navigation .menu-item{padding:5px 0}.page-header .utilities{margin-right:0}.page-header .utilities .list-filter{display:none}.search-page .search-results-section{float:none;width:100%;margin-right:0;padding-right:0}.search-page .search-results-section .square-panel{width:21%}}@media(max-width:450px){.mobile-hide{display:none}h1{font-size:30px}#sidebar{width:70%;left:-70%}#full-player .artwork{width:100%;padding-bottom:100%}#full-player .controls{width:100%}#full-player .button{padding:3px 6px}.browse.album .album-intro .square-panel{width:100%;height:auto}.browse.album .album-intro{padding-bottom:20px}.playlist-intro>.inner{padding:0}.playlist-intro .thumbnail{width:100%;height:1px;padding-bottom:100%;margin:0}.playlist-intro .content{clear:both;padding-left:0}.playlist-intro .buttons,.playlist-intro .description{padding-top:10px}.square-panel{width:29%;margin-bottom:5%}.square-panel .info{padding-top:5px;height:60px}.dialog .content{padding-left:10%;padding-right:10%}.add-to-playlist-dialog .playlist{width:29.3333%}.tracklist .track .artist,.tracklist .track .title{width:50%}.tracklist .track .album{clear:left;width:auto;padding-left:50%;padding-right:10px;opacity:.5}}.touchDevice #full-player .volume,.touchDevice #player .volume.touch-friendly{display:inline-block}#app:not(.touchDevice) #player .volume.touch-friendly,.touchDevice #player .volume:not(.touch-friendly),.tracklist .track .selected-state{display:none}.touchDevice .tracklist .track{padding-left:30px}.touchDevice .tracklist .track .selected-state{display:block;width:10px;position:absolute;top:2px;left:0;padding:10px;font-size:14px}.tracklist-context-menu{background:rgba(50,50,50,.95);color:#FFF;z-index:9;position:fixed;top:0;right:0;left:0;box-shadow:0 2px 10px rgba(0,0,0,.5)}.tracklist-context-menu .menu-item:first-child{margin-left:6px}.tracklist-context-menu .menu-item{display:block;float:left;text-align:center;padding:20px 16px;margin-right:5px;font-weight:700;text-transform:uppercase;cursor:pointer}.tracklist-context-menu .menu-item .fa{display:block;font-size:16px}.tracklist-context-menu .menu-item .text{padding-top:5px;display:block;font-size:10px}.tracklist-context-menu .menu-item.cancel{float:right;opacity:.5} \ No newline at end of file From 5e0eb456a2edabf8753739c83aacb36e14786e7f Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 20 Jun 2016 08:31:31 +1200 Subject: [PATCH 07/16] Loader for playing entire playlist --- src/app/services/mopidy/service.js | 47 ++++++++++------------------- src/app/services/spotify/service.js | 4 +-- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/app/services/mopidy/service.js b/src/app/services/mopidy/service.js index 3363866..930ed93 100755 --- a/src/app/services/mopidy/service.js +++ b/src/app/services/mopidy/service.js @@ -221,39 +221,24 @@ angular.module('spotmop.services.mopidy', [ }, playStream: function( streamUri, expectedTrackCount ){ + cfpLoadingBar.start(); + cfpLoadingBar.set(0.25); + var self = this; - // pre-fetch our playlist tracks - self.mopidy.library.lookup({ uri: streamUri }) - .then( function(tracks){ - - // if we haven't got as many tracks as expected - // wait 2s before adding to tracklist (to allow mopidy to continue loading them in the background) - if( typeof(expectedTrackCount) !== 'undefined' && tracks.length != expectedTrackCount ){ - console.info(streamUri+ ' expecting '+expectedTrackCount+' tracks, got '+tracks.length+'. Waiting 1 second for server to pre-load playlist...'); - $timeout( function(){ - playStream(); - }, 1000 ); - - // we have the expected track count already (already loaded/cached), go-go-gadget! - }else{ - playStream(); - } - }, consoleError ); - - // play the stream - function playStream(){ - self.stopPlayback(true) - .then(function() { - self.mopidy.tracklist.clear(); - }, consoleError) - .then(function() { - self.mopidy.tracklist.add({ at_position: 0, uri: streamUri }); - }, consoleError) - .then(function() { - self.mopidy.playback.play(); - }, consoleError); - } + self.stopPlayback(true) + .then(function() { + self.mopidy.tracklist.clear(); + }, consoleError) + .then(function() { + self.mopidy.tracklist.add({ at_position: 0, uri: streamUri }) + .then( function(){ + cfpLoadingBar.complete(); + }); + }, consoleError) + .then(function() { + self.mopidy.playback.play(); + }, consoleError); }, play: function(){ return wrapMopidyFunc("mopidy.playback.play", this)(); diff --git a/src/app/services/spotify/service.js b/src/app/services/spotify/service.js index c474d05..51c1fbd 100644 --- a/src/app/services/spotify/service.js +++ b/src/app/services/spotify/service.js @@ -545,6 +545,8 @@ angular.module('spotmop.services.spotify', []) getMyAlbums: function( userid, limit, offset ){ + var deferred = $q.defer(); + if( !this.isAuthorized() ){ deferred.reject(); return deferred.promise; @@ -552,8 +554,6 @@ angular.module('spotmop.services.spotify', []) if( typeof( limit ) === 'undefined' || !limit ) limit = 40; if( typeof( offset ) === 'undefined' ) offset = 0; - - var deferred = $q.defer(); $http({ cache: true, From a47ae29f2ce31c6e93dc31616538d6b7205ad128 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 20 Jun 2016 08:31:49 +1200 Subject: [PATCH 08/16] Buildout --- mopidy_spotmop/static/app.js | 51 +++++++++++--------------------- mopidy_spotmop/static/app.min.js | 4 +-- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/mopidy_spotmop/static/app.js b/mopidy_spotmop/static/app.js index bd67111..5eb777a 100644 --- a/mopidy_spotmop/static/app.js +++ b/mopidy_spotmop/static/app.js @@ -36111,39 +36111,24 @@ angular.module('spotmop.services.mopidy', [ }, playStream: function( streamUri, expectedTrackCount ){ + cfpLoadingBar.start(); + cfpLoadingBar.set(0.25); + var self = this; - // pre-fetch our playlist tracks - self.mopidy.library.lookup({ uri: streamUri }) - .then( function(tracks){ - - // if we haven't got as many tracks as expected - // wait 2s before adding to tracklist (to allow mopidy to continue loading them in the background) - if( typeof(expectedTrackCount) !== 'undefined' && tracks.length != expectedTrackCount ){ - console.info(streamUri+ ' expecting '+expectedTrackCount+' tracks, got '+tracks.length+'. Waiting 1 second for server to pre-load playlist...'); - $timeout( function(){ - playStream(); - }, 1000 ); - - // we have the expected track count already (already loaded/cached), go-go-gadget! - }else{ - playStream(); - } - }, consoleError ); - - // play the stream - function playStream(){ - self.stopPlayback(true) - .then(function() { - self.mopidy.tracklist.clear(); - }, consoleError) - .then(function() { - self.mopidy.tracklist.add({ at_position: 0, uri: streamUri }); - }, consoleError) - .then(function() { - self.mopidy.playback.play(); - }, consoleError); - } + self.stopPlayback(true) + .then(function() { + self.mopidy.tracklist.clear(); + }, consoleError) + .then(function() { + self.mopidy.tracklist.add({ at_position: 0, uri: streamUri }) + .then( function(){ + cfpLoadingBar.complete(); + }); + }, consoleError) + .then(function() { + self.mopidy.playback.play(); + }, consoleError); }, play: function(){ return wrapMopidyFunc("mopidy.playback.play", this)(); @@ -37047,6 +37032,8 @@ angular.module('spotmop.services.spotify', []) getMyAlbums: function( userid, limit, offset ){ + var deferred = $q.defer(); + if( !this.isAuthorized() ){ deferred.reject(); return deferred.promise; @@ -37054,8 +37041,6 @@ angular.module('spotmop.services.spotify', []) if( typeof( limit ) === 'undefined' || !limit ) limit = 40; if( typeof( offset ) === 'undefined' ) offset = 0; - - var deferred = $q.defer(); $http({ cache: true, diff --git a/mopidy_spotmop/static/app.min.js b/mopidy_spotmop/static/app.min.js index 1afe644..4c20f07 100644 --- a/mopidy_spotmop/static/app.min.js +++ b/mopidy_spotmop/static/app.min.js @@ -16,5 +16,5 @@ H.windowEvents=d(a.windowEvents,!0),H.maxDuration=d(a.maxDuration,500),H.mask=d( this._queue[a]=void 0;for(this._queueLen=0,this._running=!1,a=0;a>>0,j=i,k=[],l=0;i>l;++l)if(f=b[l],void 0!==f||l in b){if(e=a._handler(f),e.state()>0){h.become(e),a._visitRemaining(b,l,e);break}e.visit(h,c,d)}else--j;return 0===j&&h.reject(new RangeError("any(): array must not be empty")),g}function e(b,c){function d(a){this.resolved||(k.push(a),0===--n&&(l=null,this.resolve(k)))}function e(a){this.resolved||(l.push(a),0===--f&&(k=null,this.reject(l)))}var f,g,h,i=a._defer(),j=i._handler,k=[],l=[],m=b.length>>>0,n=0;for(h=0;m>h;++h)g=b[h],(void 0!==g||h in b)&&++n;for(c=Math.max(c,0),f=n-c+1,n=Math.min(c,n),c>n?j.reject(new RangeError("some(): array must contain at least "+c+" item(s), but had "+n)):0===n&&j.resolve(k),h=0;m>h;++h)g=b[h],(void 0!==g||h in b)&&a._handler(g).visit(j,d,e,j.notify);return i}function f(b,c){return a._traverse(c,b)}function g(b,c){var d=s.call(b);return a._traverse(c,d).then(function(a){return h(d,a)})}function h(b,c){for(var d=c.length,e=new Array(d),f=0,g=0;d>f;++f)c[f]&&(e[g++]=a._handler(b[f]).value);return e.length=g,e}function i(a){return p(a.map(j))}function j(c){var d=a._handler(c);return 0===d.state()?o(c).then(b.fulfilled,b.rejected):(d._unreport(),b.inspect(d))}function k(a,b){return arguments.length>2?q.call(a,m(b),arguments[2]):q.call(a,m(b))}function l(a,b){return arguments.length>2?r.call(a,m(b),arguments[2]):r.call(a,m(b))}function m(a){return function(b,c,d){return n(a,void 0,[b,c,d])}}var n=c(a),o=a.resolve,p=a.all,q=Array.prototype.reduce,r=Array.prototype.reduceRight,s=Array.prototype.slice;return a.any=d,a.some=e,a.settle=i,a.map=f,a.filter=g,a.reduce=k,a.reduceRight=l,a.prototype.spread=function(a){return this.then(p).then(function(b){return a.apply(this,b)})},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})},{"../apply":7,"../state":20}],9:[function(b,c){!function(a){"use strict";a(function(){function a(){throw new TypeError("catch predicate must be a function")}function b(a,b){return c(b)?a instanceof b:b(a)}function c(a){return a===Error||null!=a&&a.prototype instanceof Error}function d(a){return("object"==typeof a||"function"==typeof a)&&null!==a}function e(a){return a}return function(c){function f(a,c){return function(d){return b(d,c)?a.call(this,d):j(d)}}function g(a,b,c,e){var f=a.call(b);return d(f)?h(f,c,e):c(e)}function h(a,b,c){return i(a).then(function(){return b(c)})}var i=c.resolve,j=c.reject,k=c.prototype["catch"];return c.prototype.done=function(a,b){this._handler.visit(this._handler.receiver,a,b)},c.prototype["catch"]=c.prototype.otherwise=function(b){return arguments.length<2?k.call(this,b):"function"!=typeof b?this.ensure(a):k.call(this,f(arguments[1],b))},c.prototype["finally"]=c.prototype.ensure=function(a){return"function"!=typeof a?this:this.then(function(b){return g(a,this,e,b)},function(b){return g(a,this,j,b)})},c.prototype["else"]=c.prototype.orElse=function(a){return this.then(void 0,function(){return a})},c.prototype["yield"]=function(a){return this.then(function(){return a})},c.prototype.tap=function(a){return this.then(a)["yield"](this)},c}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],10:[function(b,c){!function(a){"use strict";a(function(){return function(a){return a.prototype.fold=function(b,c){var d=this._beget();return this._handler.fold(function(c,d,e){a._handler(c).fold(function(a,c,d){d.resolve(b.call(this,c,a))},d,this,e)},c,d._handler.receiver,d._handler),d},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],11:[function(b,c){!function(a){"use strict";a(function(a){var b=a("../state").inspect;return function(a){return a.prototype.inspect=function(){return b(a._handler(this))},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})},{"../state":20}],12:[function(b,c){!function(a){"use strict";a(function(){return function(a){function b(a,b,d,e){return c(function(b){return[b,a(b)]},b,d,e)}function c(a,b,e,f){function g(f,g){return d(e(f)).then(function(){return c(a,b,e,g)})}return d(f).then(function(c){return d(b(c)).then(function(b){return b?c:d(a(c)).spread(g)})})}var d=a.resolve;return a.iterate=b,a.unfold=c,a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],13:[function(b,c){!function(a){"use strict";a(function(){return function(a){return a.prototype.progress=function(a){return this.then(void 0,void 0,a)},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],14:[function(b,c){!function(a){"use strict";a(function(a){function b(a,b,d,e){return c.setTimer(function(){a(d,e,b)},b)}var c=a("../env"),d=a("../TimeoutError");return function(a){function e(a,c,d){b(f,a,c,d)}function f(a,b){b.resolve(a)}function g(a,b,c){var e="undefined"==typeof a?new d("timed out after "+c+"ms"):a;b.reject(e)}return a.prototype.delay=function(a){var b=this._beget();return this._handler.fold(e,a,void 0,b._handler),b},a.prototype.timeout=function(a,d){var e=this._beget(),f=e._handler,h=b(g,a,d,e._handler);return this._handler.visit(f,function(a){c.clearTimer(h),this.resolve(a)},function(a){c.clearTimer(h),this.reject(a)},f.notify),e},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})},{"../TimeoutError":6,"../env":17}],15:[function(b,c){!function(a){"use strict";a(function(a){function b(a){throw a}function c(){}var d=a("../env").setTimer,e=a("../format");return function(a){function f(a){a.handled||(n.push(a),k("Potentially unhandled rejection ["+a.id+"] "+e.formatError(a.value)))}function g(a){var b=n.indexOf(a);b>=0&&(n.splice(b,1),l("Handled previous rejection ["+a.id+"] "+e.formatObject(a.value)))}function h(a,b){m.push(a,b),null===o&&(o=d(i,0))}function i(){for(o=null;m.length>0;)m.shift()(m.shift())}var j,k=c,l=c;"undefined"!=typeof console&&(j=console,k="undefined"!=typeof j.error?function(a){j.error(a)}:function(a){j.log(a)},l="undefined"!=typeof j.info?function(a){j.info(a)}:function(a){j.log(a)}),a.onPotentiallyUnhandledRejection=function(a){h(f,a)},a.onPotentiallyUnhandledRejectionHandled=function(a){h(g,a)},a.onFatalRejection=function(a){h(b,a.value)};var m=[],n=[],o=null;return a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})},{"../env":17,"../format":18}],16:[function(b,c){!function(a){"use strict";a(function(){return function(a){return a.prototype["with"]=a.prototype.withThis=function(a){var b=this._beget(),c=b._handler;return c.receiver=a,this._handler.chain(c,a),b},a}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],17:[function(b,c){(function(d){!function(a){"use strict";a(function(a){function b(){return"undefined"!=typeof d&&null!==d&&"function"==typeof d.nextTick}function c(){return"function"==typeof MutationObserver&&MutationObserver||"function"==typeof WebKitMutationObserver&&WebKitMutationObserver}function e(a){function b(){var a=c;c=void 0,a()}var c,d=document.createTextNode(""),e=new a(b);e.observe(d,{characterData:!0});var f=0;return function(a){c=a,d.data=f^=1}}var f,g="undefined"!=typeof setTimeout&&setTimeout,h=function(a,b){return setTimeout(a,b)},i=function(a){return clearTimeout(a)},j=function(a){return g(a,0)};if(b())j=function(a){return d.nextTick(a)};else if(f=c())j=e(f);else if(!g){var k=a,l=k("vertx");h=function(a,b){return l.setTimer(b,a)},i=l.cancelTimer,j=l.runOnLoop||l.runOnContext}return{setTimer:h,clearTimer:i,asap:j}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a(b)})}).call(this,b("FWaASH"))},{FWaASH:3}],18:[function(b,c){!function(a){"use strict";a(function(){function a(a){var c="object"==typeof a&&null!==a&&a.stack?a.stack:b(a);return a instanceof Error?c:c+" (WARNING: non-Error used)"}function b(a){var b=String(a);return"[object Object]"===b&&"undefined"!=typeof JSON&&(b=c(a,b)),b}function c(a,b){try{return JSON.stringify(a)}catch(c){return b}}return{formatError:a,formatObject:b,tryStringify:c}})}("function"==typeof a&&a.amd?a:function(a){c.exports=a()})},{}],19:[function(b,c){(function(b){!function(a){"use strict";a(function(){return function(a){function c(a,b){this._handler=a===u?b:d(a)}function d(a){function b(a){e.resolve(a)}function c(a){e.reject(a)}function d(a){e.notify(a)}var e=new w;try{a(b,c,d)}catch(f){c(f)}return e}function e(a){return J(a)?a:new c(u,new x(r(a)))}function f(a){return new c(u,new x(new A(a)))}function g(){return aa}function h(){return new c(u,new w)}function i(a,b){var c=new w(a.receiver,a.join().context);return new b(u,c)}function j(a){return l(T,null,a)}function k(a,b){return l(O,a,b)}function l(a,b,d){function e(c,e,g){g.resolved||m(d,f,c,a(b,e,c),g)}function f(a,b,c){k[a]=b,0===--j&&c.become(new z(k))}for(var g,h="function"==typeof b?e:f,i=new w,j=d.length>>>0,k=new Array(j),l=0;l0?b(c,f.value,e):(e.become(f),n(a,c+1,f))}else b(c,d,e)}function n(a,b,c){for(var d=b;dc&&a._unreport()}}function p(a){return"object"!=typeof a||null===a?f(new TypeError("non-iterable passed to race()")):0===a.length?g():1===a.length?e(a[0]):q(a)}function q(a){var b,d,e,f=new w;for(b=0;b0||"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)}),function(){"use strict";var a,b,c="ngclipboard";"object"==typeof module&&module.exports?(a=require("angular"),b=require("clipboard"),module.exports=c):(a=window.angular,b=window.Clipboard),a.module(c,[]).directive("ngclipboard",["$rootScope",function(a){return{restrict:"A",scope:{ngclipboardSuccess:"&",ngclipboardError:"&"},link:function(c,d){var e=new b(d[0],{text:function(b){return a.selectedTrackURIs}});e.on("success",function(a){c.$apply(function(){c.ngclipboardSuccess({e:a})})}),e.on("error",function(a){c.$apply(function(){c.ngclipboardError({e:a})})})}}}])}(),angular.module("spotmop",["ngResource","ngStorage","ngTouch","ui.router","angular-loading-bar","angular-google-analytics","ngclipboard","spotmop.directives","spotmop.common.contextmenu","spotmop.common.track","spotmop.common.tracklist","spotmop.services.notify","spotmop.services.settings","spotmop.services.player","spotmop.services.spotify","spotmop.services.mopidy","spotmop.services.lastfm","spotmop.services.dialog","spotmop.services.pusher","spotmop.player","spotmop.queue","spotmop.library","spotmop.local","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","cfpLoadingBarProvider",function(a,b,c,d,e,f){c.otherwise("queue"),d.interceptors.push("SpotifyServiceIntercepter"),e.useAnalytics(!0),e.setAccount("UA-64701652-3"),f.parentSelector="body"}]).run(["$rootScope","SettingsService","Analytics",function(a,b,c){}]).controller("ApplicationController",["$scope","$rootScope","$state","$localStorage","$timeout","$location","SpotifyService","MopidyService","PlayerService","SettingsService","NotifyService","PusherService","DialogService","Analytics",function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){n.trackEvent("Spotmop","Started"),b.isTouchDevice=function(){return!!("ontouchstart"in window)},b.isTouchMode=function(){var a=j.getSetting("spotmop",!1,"pointerMode");return"touch"==a?!0:"click"==a?!1:b.isTouchDevice()},a.isSameDomainAsMopidy=function(){var a=j.getSetting("mopidyhost","localhost");return a&&"localhost"!=a?f.host()==a?!0:void 0:!0},a.state=i.state,b.currentTracklist=[],a.spotifyUser={},a.menuCollapsable=!1,a.reloadApp=function(){window.location.reload()},a.playlistsMenu=[],a.myPlaylists={},a.popupVolumeControls=function(){m.create("volumeControls",a)},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(),a.$broadcast("spotmop:contextMenu:hide"),n.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.checkForLazyLoading=function(){var b=$(document).scrollTop(),c=$(window).height(),d=$(document).height(),e=d-(b+c);100>=e&&a.$broadcast("spotmop:loadMore")},b.$on("cfpLoadingBar:completed",function(b){a.checkForLazyLoading()}),$(document).on("scroll",function(c){a.checkForLazyLoading(),b.isTouchMode()||b.$broadcast("spotmop:contextMenu:hide")}),a.searchSubmit=function(a){n.trackEvent("Search","Performed search",a);var b=g.uriType(a);b?(k.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(){n.trackEvent("Mopidy","Online"),b.mopidyOnline=!0}),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=j.getSetting("spotifyuser"),a.updatePlaylists(a.spotifyUser.id),n.trackEvent("Spotify","Authorized",a.spotifyUser.id)):(b.spotifyAuthorized=!1,a.playlistsMenu=[])}),a.$on("spotmop:spotify:online",function(){b.spotifyOnline=!0,b.spotifyAuthorized&&(a.spotifyUser=j.getSetting("spotifyuser"),a.updatePlaylists(a.spotifyUser.id))}),a.$on("spotmop:spotify:offline",function(){a.playlistsMenu=[],b.spotifyOnline=!1}),b.$on("spotmop:settings:changed",function(a,b){switch(b.name){case"mopidy.consume":h.setConsume(b.value)}}),b.$on("mopidy:event:optionsChanged",function(a,b){h.getConsume().then(function(a){j.setSetting("mopidy",a,"consume")})}),l.start(),b.$on("spotmop:pusher:online",function(b,c){var d=j.getSetting("pushername",null);"undefined"!=typeof d&&d&&""!=d||(m.create("initialsetup",a), n.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),k.browserNotify(b.title,b.body,c),n.trackEvent("Pusher","Notification received",b.body)}),h.start(),g.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")&&j.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")&&j.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"),dragging&&(dragging=!1,$(document).find(".drag-tracer").hide()))),16===a.which&&(b.shiftKeyHeld=!1),17===a.which&&(b.ctrlKeyHeld=!1)})}]),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","$state","MopidyService","SpotifyService","NotifyService","LastfmService",function(a,b,c,d,e,f,g,h,i){function j(){g.getAlbum(m).then(function(b){a.album=b,a.album.totalTracks=b.tracks.total,a.album.images=d("sizedImages")(b.images),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 e=[];angular.forEach(b.artists,function(a){e.push(a.uri)}),g.getArtists(e).then(function(b){if(a.album.artists=[],b.artists)for(var c=0;c0)a.album.images=d("sizedImages")(e);else if("undefined"!=typeof a.album.musicbrainz_id)i.albumInfoByMbid(a.album.musicbrainz_id).then(function(b){"undefined"!=typeof b.album&&(a.album.images=d("sizedImages")(b.album.image))});else{var f=c[Object.keys(c)[0]];i.albumInfo(f.name.trim(),a.album.name.trim()).then(function(b){"undefined"!=typeof b.album&&(a.album.images=d("sizedImages")(b.album.image))})}})})}function l(b){return"undefined"==typeof b?!1:(n=!0,void g.getUrl(b).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(b.items),a.tracklist.next=b.next,n=!1}))}a.album={},a.tracklist={tracks:[]};var m=c.uri;m=m=m.replace("|","/"),a.origin=d("assetOrigin")(m),a.convertedDate=function(){if("undefined"!=typeof a.album.release_date){if(a.mediumScreen())return d("date")(a.album.release_date,"yyyy");if("day"==a.album.release_date_precision)return d("date")(a.album.release_date,"MMMM d, yyyy");if("month"==a.album.release_date_precision)return d("date")(a.album.release_date,"MMMM yyyy");if("year"==a.album.release_date_precision)return a.album.release_date}else if("undefined"!=typeof a.album.date)return a.album.date;return null},a.totalTime=function(){var b=0;return"undefined"!=typeof a.tracklist.tracks&&angular.forEach(a.tracklist.tracks,function(a){"undefined"!=typeof a.duration_ms?b+=a.duration_ms:"undefined"!=typeof a.length&&(b+=a.length)}),Math.round(b/1e5)},a.playAlbum=function(){f.playStream(m)},"spotify"==a.origin?(a.addToLibrary=function(){g.addAlbumsToLibrary(a.album.id).then(function(){a.isInLibrary=!0})},a.removeFromLibrary=function(){g.removeAlbumsFromLibrary(a.album.id).then(function(){a.isInLibrary=!1})},j(),a.$on("spotmop:loadMore",function(){!n&&"undefined"!=typeof a.tracklist.next&&a.tracklist.next&&l(a.tracklist.next)})):a.mopidyOnline?k():a.$on("mopidy:state:online",function(){k()});var n=!1}]),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","$filter","SpotifyService","SettingsService","MopidyService","NotifyService","LastfmService",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(){j.getArtist(n).then(function(b){return b.length<=0?void k.error("Could not load artist: "+n):(a.artist=b[0].artists[0],a.artist.type="localartist","undefined"!=typeof a.artist.musicbrainz_id?l.artistInfoByMbid(a.artist.musicbrainz_id).then(function(b){a.artist.images=g("sizedImages")(b.artist.image),a.artist.stats=b.artist.stats}):l.artistInfo(a.artist.name).then(function(b){a.artist.images=g("sizedImages")(b.artist.image),a.artist.stats=b.artist.stats}),a.tracklist.type="localtrack",void(a.tracklist.tracks=g("limitTo")(b,10)))}),j.getLibraryItems(n).then(function(b){a.albums.items=g("filter")(b,{type:"directory"}&&{type:"album"});for(var c=0;c-1&&(a.albums.items[c].uri=d(a.albums.items[c].uri));var e=function(b){return function(c){"undefined"!=typeof c.album&&(a.albums.items[b].images=g("sizedImages")(c.album.image))}}(c);a.albums.items[c].mbid?l.albumInfoByMbid(a.albums.items[c].mbid).then(e):l.albumInfo(a.albums.items[c].artist.name.trim(),a.albums.items[c].name.trim()).then(e)}})}a.artist={},a.tracklist={type:"track"},a.albums={items:[]},a.relatedArtists={};var n=e.uri;n=n=n.replace("|","/"),a.origin=g("assetOrigin")(n),"spotify"==a.origin?(a.followArtist=function(){h.followArtist(e.uri).then(function(b){a.following=!0})},a.unfollowArtist=function(){h.unfollowArtist(e.uri).then(function(b){a.following=!1})},a.playArtistRadio=function(){k.notify("Playing all top tracks"),h.getTopTracks(e.uri).then(function(a){for(var b=[],c=0;c=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(50).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.browseCategories().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){console.log("loading"),h=!0,d.newReleases(!1,b).then(function(b){a.albums.items=a.albums.items.concat(b.albums.items),g=b.albums.offset+b.albums.limit,h=!1})}a.albums=[],d.newReleases().then(function(b){a.albums=b.albums,a.checkForLazyLoading()});var g=50,h=!1;a.$on("spotmop:loadMore",function(){!h&&g&&f(g)})}]),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(){var b=d.params.uri,e=g.getFromUri("userid",b),f=i.getSetting("spotifyuser",{id:null}).id;if(e!=f)return k.error("Cannot modify to a playlist you don't own"),!1;var h=c("filter")(a.tracklist.tracks,{selected:!0}),j=[];angular.forEach(h,function(b,c){j.push(a.tracklist.tracks.indexOf(b)),b.transitioning=!0}),g.deleteTracksFromPlaylist(a.playlist.uri,a.playlist.snapshot_id,j).then(function(b){"undefined"!=typeof b.error?(k.error(b.error.message),angular.forEach(h,function(a,b){a.transitioning=!1})):(a.tracklist.tracks=c("nullOrUndefined")(a.tracklist.tracks,"selected"),a.playlist.snapshot_id=b.snapshot_id)})}function m(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 n(b){return"undefined"==typeof b?!1:(o=!0,void g.getUrl(b).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(m(b.items)),a.tracklist.next=b.next,o=!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)},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=m(c.tracks.items),a.playlist.description=f.trustAsHtml(a.playlist.description),b.spotifyAuthorized&&g.getUser(a.playlist.owner.uri).then(function(b){a.playlist.owner=b}),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:playlist:reorder",function(b,c,e,f){var h=d.params.uri,j=g.getFromUri("userid",h),l=i.getSetting("spotifyuser",{id:null}).id;if(j!=l)k.error("Cannot edit a playlist you don't own");else{g.movePlaylistTracks(h,c,e,f);for(var m=[],n=0;e>n;n++)m.push(a.tracklist.tracks[c+n]);f>c&&(f-=e),m.reverse(),a.$apply(function(){a.tracklist.tracks.splice(c,e),angular.forEach(m,function(b){a.tracklist.tracks.splice(f,0,b)})})}}),a.$on("spotmop:playlist:deleteSelectedTracks",function(a){l()}),a.$on("spotmop:keyboardShortcut:delete",function(a){l()});var o=!1;a.$on("spotmop:loadMore",function(){!o&&"undefined"!=typeof a.tracklist.next&&a.tracklist.next&&n(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",replace:!0,templateUrl:"app/common/contextmenu/template.html",link:function(a,b,c){},controller:["$scope","$rootScope","$element","$timeout","NotifyService",function(a,b,c,d,e){$(document).on("click",function(a){if(!b.isTouchMode()&&1===a.which){var c=$(a.target);c.is("contextmenu")||(c=c.closest("contextmenu")),c.is("contextmenu")||b.$broadcast("spotmop:contextMenu:hide")}}),a.triggerEvent="",a.play=function(){b.$broadcast("spotmop:tracklist:playSelectedTracks"),c.fadeOut("fast"),a.isTouchMode()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.enqueue=function(){b.$broadcast("spotmop:tracklist:enqueueSelectedTracks"),c.fadeOut("fast"),a.isTouchMode()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.unqueue=function(){b.$broadcast("spotmop:tracklist:unqueueSelectedTracks"),c.fadeOut("fast"),a.isTouchMode()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.playNext=function(){b.$broadcast("spotmop:tracklist:enqueueSelectedTracks",!0),c.fadeOut("fast"),a.isTouchMode()&&b.$broadcast("spotmop:tracklist:unselectAll")},a.addToPlaylist=function(){b.$broadcast("spotmop:tracklist:addSelectedTracksToPlaylist"),c.fadeOut("fast")},a.addToPlaylistByUri=function(a){b.$broadcast("spotmop:tracklist:addSelectedTracksToPlaylistByUri",a),c.fadeOut("fast")},a.removeFromPlaylist=function(){b.$broadcast("spotmop:playlist:deleteSelectedTracks"),c.fadeOut("fast")},a.addToLibrary=function(){b.$broadcast("spotmop:tracklist:addSelectedTracksToLibrary"),c.fadeOut("fast")},a.copyURIs=function(){b.$broadcast("spotmop:tracklist:copyURIsToClipboard"),c.fadeOut("fast")},a.copiedToClipboard=function(a){e.notify("Copied selected track URIs to clipboard"),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(e,f,g){return b.isTouchMode()?!1:void a.$apply(function(){a.context=g,a.triggerEvent="click",d(function(){var a=f.pageY-$(window).scrollTop(),b=f.pageX,d=c.outerWidth(),e=c.outerHeight();b+d>$(window).width()?(b-=d-10,c.addClass("hard-right")):b+d+150>$(window).width()?c.addClass("close-right"):c.removeClass("hard-right close-right"),a+e>$(window).height()?(a-=e,c.addClass("hard-bottom")):a+e+306>$(window).height()?c.addClass("close-bottom"):c.removeClass("hard-bottom close-bottom"),c.css({top:a,left:b+5}).show()})})}),a.$on("spotmop:touchContextMenu:show",function(b,d){c.show(),a.triggerEvent="touch",c.removeClass("hard-bottom close-bottom hard-right close-right"),c.css({top:"auto",left:0}),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("candrag",["$rootScope","$filter","MopidyService","SpotifyService","NotifyService","PlayerService",function(a,b,c,d,e,f){return{restrict:"A",scope:{dragobj:"="},link:function(e,g,h){function i(c){a.dragging=!0;var d=!1;if(v.dragActive||(d=!0),v.dragActive=!0,$(document).find(".dropping").removeClass("dropping"),$(document).find(".dropping-within").removeClass("dropping-within"),d){$("body").addClass("dragging");var f="";if("album"==e.dragobj.type||"localalbum"==e.dragobj.type||"artist"==e.dragobj.type||"localartist"==e.dragobj.type||"playlist"==e.dragobj.type){var g=!1;if("undefined"!=typeof e.dragobj.images.small)var g=e.dragobj.images;else if(e.dragobj.images.length>0)var g=b("sizedImages")(e.dragobj.images);g&&(f='
'),f+='
'+e.dragobj.name+"
"}else if("track"==e.dragobj.type||"tltrack"==e.dragobj.type||"localtrack"==e.dragobj.type)for(var h=$(document).find(".track.selected"),i=0;ii;i++)f+='
'+h.eq(i).find(".title").html()+"
";u.html(f),u.show(),$.each($(document).find("#dropzones > .dropzone"),function(a,b){t($(b))?$(b).removeClass("disabled"):$(b).addClass("disabled")})}u.css({left:c.clientX,top:c.clientY});var j=s(c),k=t(j);if(k){j.addClass("dropping");var l=$(c.target);l.hasClass("track")||(l=l.closest(".track")),l.hasClass("track")&&l.addClass("dropping"),j.parent().closest(".droppable").addClass("dropping-within")}}function j(b){a.$broadcast("spotmop:contextMenu:hide"),u.fadeOut("medium"),$("body").removeClass("dragging"),$(document).find(".dropping").removeClass("dropping");var c=s(b),d=t(c);if(d)switch(c.attr("droptype")){case"queue":k();break;case"queuenext":var g=f.state().currentTracklistPosition();k(g);break;case"playlist":l(b);break;case"library":"track"==e.dragobj.type?n():"tltrack"==e.dragobj.type?n():"album"==e.dragobj.type?m():"artist"==e.dragobj.type?o():"playlist"==e.dragobj.type&&p();break;case"queuetracklist":q(b);break;case"playlisttracklist":r(b)}a.dragging=!1}function k(a){if("undefined"==typeof a)var a=null;switch(e.dragobj.type){case"album":c.addToTrackList([e.dragobj.uri],a);break;case"localalbum":c.addToTrackList([e.dragobj.uri],a);break;case"track":for(var b=[],d=$(document).find(".track.selected"),f=0;fg&&(e-=d.length),c.moveTlTracks(f,g,e)}function r(b){var c=$(b.target);c.hasClass("track")||(c=c.closest(".track"));var d=$(v.domobj).closest(".tracklist").find(".track.selected"),e=(c.closest(".tracklist").attr("playlisturi"),Number(c.parent().attr("data-index"))),f=Number(d.first().parent().attr("data-index")),g=Number(d.length);a.$broadcast("spotmop:playlist:reorder",f,g,e)}function s(a){var b=$(a.target);return b.hasClass("droppable")||(b=b.closest(".droppable")),b?b:!1}function t(a){var b=a.attr("dropaccept");return b?(b=JSON.parse(b),b.indexOf(e.dragobj.type)>=0?!0:!1):!1}var u=$(document).find(".drag-tracer"),v={threshold:30,dragStarted:!1,dragActive:!1,startX:!1,starY:!1};g.on("mousedown",function(a){v.dragStarted=!0,v.startX=a.clientX,v.startY=a.clientY,v.domobj=a.currentTarget,"undefined"!=typeof e.dragobj.__model__&&"undefined"==typeof e.dragobj.type&&(e.dragobj.type=e.dragobj.__model__.toLowerCase())}),$(document).on("mouseup",function(a){v.dragActive&&j(a),v.dragStarted=!1,v.dragActive=!1,v.startX=!1,v.startY=!1,v.domobj=!1}),$(document).on("mousemove",function(a){if(v.dragStarted){var b=v.startX-v.threshold,c=v.startX+v.threshold,d=v.startY-v.threshold,e=v.startY+v.threshold;(a.clientXc||a.clientYe)&&i(a)}})}}}]).directive("switch",["$rootScope","SettingsService",function(a,b){return{restrict:"E",scope:{name:"@",label:"@",value:"="},replace:!0,transclude:!0,controller:["$scope","$element","$attrs",function(b,c,d){c.bind("touchstart click",function(c){c.preventDefault(),c.stopPropagation(),b.$apply(function(){b.value=!b.value,a.$broadcast("spotmop:settings:changed",{name:b.name,value:b.value})})})}],template:''}}]).directive("artistlist",["$rootScope","SettingsService",function(a,b){return{restrict:"E",scope:{artists:"="},link:function(a,b,c){a.nolinks=c.hasOwnProperty("nolinks"),a.sentence=c.hasOwnProperty("sentence")},replace:!0,transclude:!0,templateUrl:"app/common/artistlist.template.html"}}]).directive("thumbnail",["$timeout","$http",function(a,b){return{restrict:"E",scope:{images:"=",size:"="},replace:!0,transclude:!0,link:function(a,c,d){function e(){a.image=f(a.images),a.image&&b({method:"GET",url:a.image.url,cache:!0}).success(function(){c.css("background-image","url("+a.image.url+")")})}function f(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]}e(),a.$watch("images",function(a,b){e()})},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("slider",["$timeout",function(a){return{restrict:"E",scope:{items:"="},link:function(b,c){function d(a){return"prev"==a&&0>=g?!1:"next"==a&&g>=h?!1:!0}function e(){var a=c.find(".item-container").children().first().height();c.css({height:a+"px"})}var f=c.find(".slides-content"),g=0,h=b.items.length/5-1;b.prev=function(){d("prev")&&(g--,f.animate({left:100*-g+"%"},120))},b.next=function(){d("next")&&(g++,f.animate({left:100*-g+"%"},120))},a(function(){e()},0),$(window).resize(function(){e()})},templateUrl:"app/common/slider.template.html"}}]).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("splitstring",[function(){return function(a,b){var c=a.split(":");return c[b]}}]).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}}).filter("sizedImages",["SettingsService",function(a){return function(b){if(b.length<=0)return!1;for(var c={},d=0;d=650?c.large=e.url:e.height<=650&&e.height>=250?(c.medium=e.url,c.large||(c.large=e.url)):(c.small||(c.small=e.url),c.medium||(c.medium=e.url),c.large||(c.large=e.url))}else if("undefined"!=typeof e.height)e.height>=650?c.large=e.url:e.height<=650&&e.height>=250?(c.medium=e.url,c.large||(c.large=e.url)):(c.small||(c.small=e.url),c.medium||(c.medium=e.url),c.large||(c.large=e.url));else if("undefined"!=typeof e["#text"]){if(e["#text"]&&e["#text"].length>0&&""!=e.size)switch(e.size){case"mega":c.large=e["#text"];break;case"extralarge":c.medium=e["#text"],c.large||(c.large=e["#text"]);break;case"large":c.small=e["#text"],c.medium||(c.medium=e["#text"]),c.large||(c.large=e["#text"]);break;case"medium": c.small=e["#text"],c.medium||(c.medium=e["#text"]),c.large||(c.large=e["#text"]);break;case"small":c.small=e["#text"],c.medium||(c.medium=e["#text"]),c.large||(c.large=e["#text"])}}else c.large=e,c.medium=e,c.small=e}return c}}]).filter("shuffle",function(){return function(a){var b,c,d;for(b=a.length-1;b>0;b--)c=Math.floor(Math.random()*(b+1)),d=a[b],a[b]=a[c],a[c]=d;return a}}).filter("assetOrigin",function(){return function(a){if("undefined"==typeof a)return!1;var b=a.split(":");return b.length<=0?!1:b[0]}}).filter("assetType",function(){return function(a){if("undefined"==typeof a)return!1;var b=a.split(":");return b.length<=1?!1:b[1]}}).filter("mbid",function(){return function(a){if("undefined"==typeof a)return!1;var b=a.indexOf(":mbid:")+6,c=a.length;return a.substr(b,c)}}),angular.module("spotmop.common.tracklist.service",[]).factory("TracklistService",["$rootScope",function(a){return{getSelectedTracks:function(){console.log("triggered getSelectedTracks")}}}]),angular.module("spotmop.common.track",[]).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?(c.isTouchMode()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$parent.trackClicked(b)):3===a.which&&(b.track.selected||b.$parent.trackClicked(b),b.$emit("spotmop:contextMenu:show",a,"track"))}),a.dblclick(function(a){d.playTrack([b.track.uri],0)})}]}}).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,b.isCurrentlyPlaying=function(){return b.track.tlid==b.state().currentTlTrack.tlid},b.sourceIconClasses=function(){if("undefined"==typeof b.track.track)return!1;var a=b.track.track.uri.split(":")[0],c="light";return b.isCurrentlyPlaying()&&("spotify"==a&&(c="green"),"local"==a&&(c="yellow"),"soundcloud"==a&&(c="red")),a+" "+c},a.mouseup(function(a){1===a.which?(c.isTouchMode()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$parent.trackClicked(b)):3===a.which&&(b.track.selected||b.$parent.trackClicked(b),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?(c.isTouchMode()||b.$emit("spotmop:contextMenu:hide"),$(a.target).is("a")||b.$parent.trackClicked(b)):3===a.which&&(b.track.selected||b.$parent.trackClicked(b),b.$emit("spotmop:contextMenu:show",a,"localtrack"))}),a.dblclick(function(a){d.playTrack([b.track.uri],0)})}]}}),angular.module("spotmop.common.tracklist",[]).directive("tracklist",["$compile",function(a){return{restrict:"E",templateUrl:"app/common/tracklist/template.html",scope:{tracks:"=",type:"@",limit:"@"},link:function(a,b,c){},controller:["$element","$scope","$filter","$rootScope","$stateParams","MopidyService","SpotifyService","DialogService","NotifyService","SettingsService","PlayerService",function(a,b,c,d,e,f,g,h,i,j,k){function l(){var a=c("filter")(b.tracks,{selected:!0}),e=[];angular.forEach(a,function(a){"undefined"!=typeof a.track?e.push(a.track.uri):e.push(a.uri)}),d.selectedTrackURIs=e}function m(){if(d.tracklistInFocus===b.$id){var a=c("filter")(b.tracks,{selected:!0}),e=a[0];if("tltrack"==b.type)f.getCurrentTlTracks().then(function(a){$.each(a,function(a,b){return b.tlid==e.tlid?f.playTlTrack({tl_track:b}):void 0})});else{for(var g=[],h=1;h10&&(j+="... this could take some time"),i.notify(j),f.playTrack([e.uri],0).then(function(){g.length>0&&f.addToTrackList(g,1)})}}}function n(){angular.forEach(b.tracks,function(a){a.selected=!1})}d.selectedTrackURIs=[],$(document).contextmenu(function(a){return $(a.target).closest(".tracklist").length>0?!1:void 0}),b.tracksWrapper=function(){return b.limit&&b.limit>0?c("limitTo")(b.tracks,parseInt(b.limit)):b.tracks},b.$on("spotmop:track:dragging",function(a){});var o=d.$on("spotmop:tracklist:focusChanged",function(a,c){d.tracklistInFocus=c,b.$id!=c&&n()});b.$on("$destroy",o),b.trackClicked=function(a){if(d.$broadcast("spotmop:tracklist:focusChanged",b.$id),!d.dragging){if(d.ctrlKeyHeld||d.isTouchMode()?a.track.selected?a.$apply(function(){a.track.selected=!1}):a.$apply(function(){a.track.selected=!0}):d.ctrlKeyHeld||(angular.forEach(b.tracks,function(a){a.selected=!1}),a.$apply(function(){a.track.selected=!0})),d.shiftKeyHeld){if("undefined"==typeof b.lastSelectedTrack)return void a.$apply(function(){a.track.selected=!0});var e=b.lastSelectedTrack.$index,f=a.$index;a.$index=g;g++)b.tracks[g].selected=!0;b.$apply()}b.lastSelectedTrack=a,d.isTouchMode()&&(c("filter")(b.tracks,{selected:!0}).length>0?d.$broadcast("spotmop:touchContextMenu:show",b.type):d.$broadcast("spotmop:contextMenu:hide")),l()}},b.$on("spotmop:tracklist:enqueueSelectedTracks",function(a,e){if(d.tracklistInFocus===b.$id){var g=null;"undefined"!=typeof e&&1==e&&(g=k.state().currentTracklistPosition());var h=c("filter")(b.tracks,{selected:!0}),j=[];angular.forEach(h,function(a){j.push(a.uri)});var l="Adding "+h.length+" tracks to queue";h.length>10&&(l+="... this could take some time"),i.notify(l),f.addToTrackList(j,g)}}),b.$on("spotmop:tracklist:playSelectedTracks",function(){m()}),b.$on("spotmop:keyboardShortcut:enter",function(){m()}),b.$on("spotmop:tracklist:unqueueSelectedTracks",function(a){if(d.tracklistInFocus===b.$id){var e=c("filter")(b.tracks,{selected:!0}),g=[];angular.forEach(e,function(a){g.push(a.tlid)}),f.removeFromTrackList(g)}}),b.$on("spotmop:tracklist:addSelectedTracksToPlaylist",function(a){if(d.tracklistInFocus===b.$id){var e=c("filter")(b.tracks,{selected:!0}),f=[];angular.forEach(e,function(a){"undefined"!=typeof a.track?f.push(a.track.uri):f.push(a.uri)}),h.create("addToPlaylist",b)}}),b.$on("spotmop:tracklist:addSelectedTracksToPlaylistByUri",function(a,e){if(d.tracklistInFocus===b.$id){var f=c("filter")(b.tracks,{selected:!0}),h=[],j=0;if(angular.forEach(f,function(a){"undefined"!=typeof a.track?"local:"==a.track.uri.substring(0,6)?j++:h.push(a.track.uri):"local:"==a.uri.substring(0,6)?j++:h.push(a.uri)}),j>0){if(h.length<=0)return i.error("Cannot add local tracks to a Spotify playlist"),!1;i.error(j+" local tracks not added to Spotify playlist")}g.addTracksToPlaylist(e,h).then(function(a){i.notify("Added "+h.length+" tracks to playlist")})}}),b.$on("spotmop:tracklist:addSelectedTracksToLibrary",function(a){if(d.tracklistInFocus===b.$id){var e=c("filter")(b.tracks,{selected:!0}),f=[];angular.forEach(e,function(a){"undefined"!=typeof a.track?f.push(g.getFromUri("trackid",a.track.uri)):f.push(g.getFromUri("trackid",a.uri))}),g.addTracksToLibrary(f)}}),b.$on("spotmop:tracklist:selectAll",function(a){n()}),b.$on("spotmop:tracklist:unselectAll",function(a){n()}),b.$on("spotmop:tracklist:copyURIsToClipboard",function(a){var d=c("filter")(b.tracks,{selected:!0}),e="";angular.forEach(d,function(a){""!=e&&(e+=","),e+="undefined"!=typeof a.track?a.track.uri:a.uri}),console.log(e)})}]}}]),angular.module("spotmop.discover",[]).config(["$stateProvider",function(a){a.state("discover",{url:"/discover",templateUrl:"app/discover/template.html",controller:"DiscoverController"})}]).controller("DiscoverController",["$scope","$rootScope","$filter","SpotifyService","SettingsService","NotifyService",function(a,b,c,d,e,f){function g(b){var c=[],e="";angular.forEach(b.track.artists,function(a){c.push({name:a.name,name_encoded:encodeURIComponent(a.name),uri:a.uri}),""!=e&&(e+=","),e+=d.getFromUri("artistid",a.uri)}),a.current.artists=c,d.getRecommendations(!1,!1,e).then(function(b){var c=[];angular.forEach(b.tracks,function(a){var b=a.album;b.artists=a.artists,c.push(b)}),a.current.items=c})}a.favorites=[],a.current=[],a.sections=[],d.getMyFavorites("artists",50,!1,"long_term").then(function(b){a.favorites.items=c("shuffle")(b.items)}),d.getMyFavorites("tracks",50,!1,"short_term").then(function(b){var e=b.items;e=c("shuffle")(b.items),e=c("limitTo")(b.items,5),angular.forEach(e,function(b){d.getRecommendations(!1,!1,!1,!1,b.id).then(function(c){var d=[];angular.forEach(c.tracks,function(a){var b=a.album;b.artists=a.artists,d.push(b)});var e={title:"Because you listened to ",artists:b.artists,items:d};a.sections.push(e)})})}),"undefined"!=typeof a.state().currentTlTrack.track&&g(a.state().currentTlTrack),b.$on("spotmop:currenttrack:loaded",function(a,b){g(b)})}]),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"})}]).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:[],type:"track"};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("LibraryArtistsController",["$scope","$rootScope","$filter","SpotifyService","SettingsService","DialogService",function(a,b,c,d,e,f){function g(b){return"undefined"==typeof b?!1:(i=!0,void d.getUrl(b).then(function(b){a.artists.items=a.artists.items.concat(b.artists.items),a.artists.next=b.artists.next,i=!1}))}a.artists=[];var h=e.getSetting("spotifyuserid",a.$parent.spotifyUser.id);d.getMyArtists(h).then(function(b){a.artists=b.artists,"undefined"!=typeof b.error&&401==b.error.status&&Spotify.refreshToken()});var i=!1;a.$on("spotmop:loadMore",function(){!i&&"undefined"!=typeof a.artists.next&&a.artists.next&&g(a.artists.next)})}]).controller("LibraryAlbumsController",["$scope","$rootScope","$filter","SpotifyService","SettingsService","DialogService","MopidyService","NotifyService",function(a,b,c,d,e,f,g,h){function i(b){return"undefined"==typeof b?!1:(k=!0,void d.getUrl(b).then(function(b){a.albums.items=a.albums.items.concat(b.items),a.albums.next=b.next,k=!1}))}a.settings=e.getSettings(),a.albums={items:[]};var j=e.getSetting("spotifyuser",{id:null}).id;b.spotifyAuthorized&&d.getMyAlbums(j).then(function(b){a.albums=b}),a.playAlbum=function(a){g.playStream(a.uri)},a.removeFromLibrary=function(b){b.transitioning=!0,d.removeAlbumsFromLibrary(b.id).then(function(c){"undefined"==typeof c.error?a.albums.items.splice(a.albums.items.indexOf(b),1):(h.error(c.error.message),b.transitioning=!1)})};var k=!1;a.$on("spotmop:loadMore",function(){!k&&"undefined"!=typeof a.albums.next&&a.albums.next&&i(a.albums.next)})}]).controller("LibraryPlaylistsController",["$scope","$rootScope","$filter","SpotifyService","SettingsService","DialogService","MopidyService","NotifyService",function(a,b,c,d,e,f,g,h){function i(){g.getPlaylists().then(function(b){angular.forEach(b,function(b,c){d.getPlaylist(b.uri).then(function(b){a.playlists.items.push(b)})})})}function j(b){return"undefined"==typeof b?!1:(l=!0,void d.getUrl(b).then(function(b){a.playlists.items=a.playlists.items.concat(b.items),a.playlists.next=b.next,l=!1}))}a.createPlaylist=function(){f.create("createPlaylist",a)},a.settings=e.getSettings(),a.playlists={items:[]},a.show=function(b){return"undefined"!=typeof a.settings.playlists&&"undefined"!=typeof a.settings.playlists.onlyshowowned&&a.settings.playlists.onlyshowowned?"jaedb"==b.owner.id?!0:!1:!0};var k=e.getSetting("spotifyuser",{id:null}).id;b.spotifyAuthorized?d.getPlaylists(k).then(function(b){a.playlists=b,"undefined"!=typeof b.error&&401==b.error.status&&Spotify.refreshToken()}):(h.notify("Fetching from Mopidy as you haven't authorized Spotify. This will take a while!"),b.mopidyOnline?i():a.$on("mopidy:state:online",function(){i()}));var l=!1;a.$on("spotmop:loadMore",function(){!l&&"undefined"!=typeof a.playlists.next&&a.playlists.next&&j(a.playlists.next)})}]),angular.module("spotmop.local",[]).config(["$stateProvider",function(a){a.state("local",{url:"/local",templateUrl:"app/local/template.html"}).state("local.index",{url:"/index",templateUrl:"app/local/index.html",controller:"LocalController"}).state("local.directory",{url:"/directory/:uri",templateUrl:"app/local/directory.html",controller:"LocalDirectoryController"}).state("local.albums",{url:"/albums",templateUrl:"app/local/albums.html",controller:"LocalAlbumsController"}).state("local.artists",{url:"/artists",templateUrl:"app/local/artists.html",controller:"LocalArtistsController"})}]).controller("LocalController",["$scope","$rootScope","$filter","$stateParams","$localStorage","SpotifyService","SettingsService","DialogService","MopidyService",function(a,b,c,d,e,f,g,h,i){function j(){i.getLibraryItems("local:directory").then(function(b){for(var d=c("filter")(b,{type:"track"}),e=[],f=0;f0&&i.getTracks(e).then(function(b){var c=[];for(var d in b){var e=b[d][0];e.type="localtrack",c.push(e)}a.tracks=c,a.allTracks=c});var g=[];for(f=0;f0){var e=c("filter")(a.allAlbums,{uri:d}),f=a.allAlbums.indexOf(e[0]);a.allAlbums[f].images=c("sizedImages")(b[d])}})}a.settings=h.getSettings(),a.allAlbums=[];var n=50;a.$watch("filterTerm",function(b){n=50,a.albums=c("filter")(a.allAlbums,b),a.albums=c("limitTo")(a.albums,n),a.albums.length>0&&m(a.albums)}),a.mopidyOnline?l():a.$on("mopidy:state:online",function(){l()});var o=!1;a.$on("spotmop:loadMore",function(){o||(o=!0,n+=50,a.filterTerm?(a.albums=c("filter")(a.allAlbums,a.filterTerm),a.albums=c("limitTo")(a.albums,n)):a.albums=c("limitTo")(a.allAlbums,n),f(function(){o=!1,a.albums.length>0&&m(a.albums)},1))})}]).controller("LocalDirectoryController",["$scope","$rootScope","$filter","$stateParams","$localStorage","SpotifyService","SettingsService","DialogService","MopidyService",function(a,b,c,d,e,f,g,h,i){function j(){i.getLibraryItems(l).then(function(b){for(var d=c("filter")(b,{type:"track"}),e=[],f=0;f0&&i.getTracks(e).then(function(b){var c=[];for(var d in b){var e=b[d][0];e.type="localtrack",c.push(e)}a.tracks=c,a.allTracks=c});var g=[];for(f=0;f-1||l.indexOf("local:directory:")>-1)){var m=l.substring(16,l.length);if(""!=m&&(m=m.split("|")),m.length>0)for(var n=0;n=o;o++)"local:directory:"!=l&&(l+="|"),l+=m[o];a.path.push({title:decodeURIComponent(m[n]),uri:l})}l=l.replace("|","/")}a.mopidyOnline?j():a.$on("mopidy:state:online",function(){j()})}]),angular.module("spotmop.player",["spotmop.services.player","spotmop.services.spotify","spotmop.services.mopidy"]).controller("PlayerController",["$scope","$rootScope","$timeout","$interval","$element","PlayerService","MopidyService","SpotifyService","SettingsService",function(a,b,c,d,e,f,g,h,i){a.state=f.state,a.playPause=function(){f.playPause()},a.stop=function(){f.stop()},a.next=function(){f.next()},a.previous=function(){f.previous()},a.seek=function(b){var c,d,e,g,h;c=$(b.target).hasClass("slider")?$(b.target):$(b.target).closest(".slider"),d=c.offset(),e=b.pageX-d.left,g=e/c.innerWidth(),h=Math.round(g*a.state().currentTlTrack.track.length),f.seek(h)},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)},a.toggleRepeat=function(){f.toggleRepeat()},a.toggleRandom=function(){f.toggleRandom()},a.toggleMute=function(){f.toggleMute()},a.toggleConsume=function(){f.toggleConsume()},a.$on("mopidy:event:tracklistChanged",function(b){g.getCurrentTlTracks().then(function(b){a.$parent.currentTracklist=b})})}]),angular.module("spotmop.services.player",[]).factory("PlayerService",["$rootScope","$interval","$filter","SettingsService","MopidyService","SpotifyService","NotifyService","LastfmService",function(a,b,c,d,e,f,g,h){function i(){e.getRepeat().then(function(a){p.isRepeat=a}),e.getRandom().then(function(a){p.isRandom=a}),e.getMute().then(function(a){p.isMute=a}),e.getConsume().then(function(a){p.isConsume=a})}function j(a){"undefined"==typeof a?e.getTimePosition().then(function(a){p.playPosition=a}):p.playPosition=a}function k(a){"undefined"!=typeof a?p.volume=a:e.getVolume().then(function(a){p.volume=a})}function l(a){"undefined"!=typeof a?("playing"==a?p.playing=!0:p.playing=!1,o()):e.getState().then(function(a){"playing"==a?p.playing=!0:p.playing=!1,o()})}function m(b){var d=function(b){if(p.currentTlTrack=b,"undefined"!=typeof b.track.album.images&&b.track.album.images.length>0){var d=[{__model__:"Image",uri:b.track.album.images}];p.currentTlTrack.track.images=c("sizedImages")(d),a.$broadcast("spotmop:currenttrack:loaded",p.currentTlTrack)}else if("spotify:"==b.track.uri.substring(0,8))f.getTrack(b.track.uri).then(function(b){"undefined"!=typeof b.album&&(p.currentTlTrack.track.images=c("sizedImages")(b.album.images)),a.$broadcast("spotmop:currenttrack:loaded",p.currentTlTrack)});else{var e=encodeURIComponent(b.track.artists[0].name),g=encodeURIComponent(b.track.album.name);e&&g&&h.albumInfo(e,g).then(function(b){p.currentTlTrack.track.image=!1,"undefined"!=typeof b.album&&(p.currentTlTrack.track.images=c("sizedImages")(b.album.image)),a.$broadcast("spotmop:currenttrack:loaded",p.currentTlTrack)})}j(),o()};"undefined"!=typeof b?d(b):e.getCurrentTlTrack().then(function(a){null!==a&&void 0!==a&&(a.track.name.indexOf("[loading]")>-1?e.lookup(a.track.uri).then(function(a){d(a[0])}):d(a))})}function n(){e.getCurrentTlTracks().then(function(b){a.currentTracklist=b,(!b||b.length<=0)&&(p.currentTlTrack=!1,o())})}function o(){var a=p.currentTlTrack.track,b="No track playing";if(a){var c="\u25a0 ",d="";$.each(a.artists,function(a,b){""!=d&&(d+=", "),d+=b.name}),p.playing&&(c="\u25b6 "),b=c+" "+a.name+" - "+d}document.title=b}var p={playing:!1,isRepeat:!1,isRandom:!1,isMute:!1,isConsume:!1,volume:100,playPosition:0,currentTlTrack:!1,currentTracklistPosition:function(){if(p.currentTlTrack){var b=c("filter")(a.currentTracklist,{tlid:p.currentTlTrack.tlid}),d=0;return b.length>0&&(d=a.currentTracklist.indexOf(b[0])+1),d}return null},playPositionPercent:function(){return p.currentTlTrack?(p.playPosition/p.currentTlTrack.track.length*100).toFixed(2):0}};a.$on("mopidy:state:online",function(){i(),m(),l(),k(),n(),e.getState().then(function(a){"playing"==a?p.playing=!0:p.playing=!1})}),a.$on("mopidy:event:tracklistChanged",function(a,b){n()}),a.$on("mopidy:event:optionsChanged",function(a,b){i()}),a.$on("mopidy:event:playbackStateChanged",function(a,b){l(b.new_state)}),a.$on("mopidy:event:seeked",function(a,b){j(b.time_position)}),a.$on("mopidy:event:volumeChanged",function(a,b){b.volume!=p.volume&&k(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,m(b.tl_track),l())}),b(function(){p.playing&&"undefined"!=typeof p.currentTlTrack&&"undefined"!=typeof p.currentTlTrack.track&&p.playPosition=100&&(p.volume=100),q.setVolume(p.volume),g.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),g.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(){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})},toggleConsume:function(){p.isConsume?e.setConsume(!1).then(function(a){p.isConsume=!1}):e.setConsume(!0).then(function(a){p.isConsume=!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","DialogService",function(a,b,c,d,e,f,g,h){function i(b){var c=0;$.each(b,function(a,b){c+=b.track.length}),a.totalTime=Math.round(c/1e5)}a.totalTime=0,a.tracks=b.currentTracklist,a.limit=50;var j=!1;a.$on("spotmop:loadMore",function(){!j&&a.tracks.length>=a.limit&&(a.limit+=50,j=!0,d(function(){j=!1},100))}),a.addUri=function(){h.create("addbyuri",a)},a.clearQueue=function(){f.clearCurrentTrackList()},b.$watch(function(a){return a.currentTracklist},function(b,c){a.tracks=b,i(b)}),a.$on("spotmop:keyboardShortcut:delete",function(b){var d=c("filter")(a.tracks,{selected:!0}),e=[];angular.forEach(d,function(a,b){e.push(a.tlid)}),a.$apply(function(){a.tracks=c("filter")(a.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","MopidyService",function(a,b,c,d,e,f,g,h){function i(c,d){if("undefined"==typeof c)var c=a.type;switch(c){case"track":g.getSearchResults("track",d,50).then(function(b){a.tracklist.tracks=a.tracklist.tracks.concat(b.tracks.items),a.tracklist.type="track",a.tracklist.next=b.tracks.next,l=b.tracks.next?b.tracks.offset+b.tracks.limit:!1});break;case"album":g.getSearchResults("album",d,50).then(function(b){a.albums=b.albums,l=b.albums.next?b.albums.offset+b.albums.limit:!1});break;case"artist":g.getSearchResults("artist",d,50).then(function(b){a.artists=b.artists,a.next=b.artists.next,a.offset=b.artists.offset});break;case"playlist":g.getSearchResults("playlist",d,50).then(function(b){a.playlists=b.playlists,a.next=b.playlists.next,a.offset=b.playlists.offset});break;case"other":b.mopidyOnline?j(a.query):b.$on("mopidy:state:online",function(){j(a.query)});break;default:g.getSearchResults("track",d,50).then(function(b){a.tracklist=b.tracks,a.tracklist.type="track",a.tracklist.tracks=b.tracks.items}),g.getSearchResults("album",d,50).then(function(b){a.albums=b.albums}),g.getSearchResults("artist",d,50).then(function(b){a.artists=b.artists}),g.getSearchResults("playlist",d,50).then(function(b){a.playlists=b.playlists})}}function j(b){h.search(b,!1,["soundcloud:","local:"]).then(function(b){for(var c=0;c0&&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.playlistPublic="true",a.savePlaylist=function(){a.playlistName&&""!=a.playlistName?(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})})):a.error=!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.playlistNewName&&""!=a.playlistNewName?(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})})):a.error=!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","NotifyService",function(a,b,c,d,e,f,g,h){a.playlists=[];var i=g.getSetting("spotifyuser",{id:"undefined"}).id;f.getPlaylists(i,50).then(function(b){a.playlists=d("filter")(b.items,{owner:{id:i}})}),a.playlistSelected=function(b){var g=d("filter")(a.$parent.tracks,{selected:!0}),i=[];angular.forEach(g,function(a){"undefined"!=typeof a.track?i.push(a.track.uri):i.push(a.uri)}),f.addTracksToPlaylist(b.uri,i).then(function(a){ -e.remove(),c.$broadcast("spotmop:tracklist:unselectAll"),h.notify(i.length+" tracks added to "+b.name)})}}]}}).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){a.settings=f.getSettings(),f.setSetting("spotify",!0,"authorizationenabled"),f.setSetting("spotmop","default","pointerMode"),a.saving=!1,a.save=function(){a.name&&""!=a.name?(a.saving=!0,f.getSetting("spotify",!1,"authorizationenabled")&&g.authorize(),f.setSetting("pushername",a.name),e.remove()):a.error=!0}}]}}).directive("addbyuridialog",function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"app/services/dialog/addbyuri.template.html",controller:["$scope","$element","DialogService","SpotifyService","MopidyService",function(a,b,c,d,e){a.saving=!1,a.add=function(){a.uri&&""!=a.uri?(a.error=!1,a.saving=!0,e.addToTrackList([a.uri])["catch"](function(b){a.saving=!1,a.error=!0}).then(function(b){a.error||c.remove()})):a.error=!0}}]}}),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 a=encodeURIComponent(a),this.sendRequest("method=track.getInfo&track="+b+"&artist="+a)},albumInfo:function(a,b){return a=encodeURIComponent(a),b=encodeURIComponent(b),this.sendRequest("method=album.getInfo&album="+b+"&artist="+a)},albumInfoByMbid:function(a){return this.sendRequest("method=album.getInfo&mbid="+a)},artistInfo:function(a){return a=encodeURIComponent(a),this.sendRequest("method=artist.getInfo&artist="+a)},artistInfoByMbid:function(a){return this.sendRequest("method=artist.getInfo&mbid="+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","PusherService","NotifyService","cfpLoadingBar",function(a,b,c,d,e,f,g,h,i){function j(b,c){return function(){var d=a.defer(),e=Array.prototype.slice.call(arguments),f=c||this;return i.start(),i.set(.25),k(b,f,e).then(function(a){i.complete(),d.resolve(a)},function(a){h.error(a),d.reject(a)}),d.promise}}function k(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"),g.runUpgrade());var d=g.getSetting("pushername","");d&&j.setMe(d)}else c.id==g.getSetting("pusherid","")||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","$cacheFactory","SettingsService","NotifyService",function(a,b,c,d,e,f,g,h,i,j,k){var l={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",l.getMe().then(function(b){j.setSetting("spotifyuser",b),a.$broadcast("spotmop:spotify:authenticationChanged",this.authenticationMethod)})},!1),this.isAuthorized()?(a.spotifyAuthorized=!0,this.authenticationMethod="client"):(j.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=j.getSetting("mopidyhost",window.location.hostname),g=j.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?(k.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},serviceUnavailable:function(){k.error("Request failed. Spotify API may be temporarily unavailable.")},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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getMe:function(){var a=h.defer();return this.isAuthorized()?(d({method:"GET",url:m+"me/",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(b){a.resolve(b)}).error(function(b){k.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:m+"users/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"me/following/contains?type="+a+"&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"tracks/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"me/tracks/?limit=50",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},addTracksToLibrary:function(a){var b=h.defer();if(!this.isAuthorized())return b.reject(),b.promise;var e=i.get("$http");return e.remove(m+"me/tracks/?limit=50"),d({method:"PUT",url:m+"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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},addAlbumsToLibrary:function(a){if(!this.isAuthorized())return e.reject(),e.promise;var b=i.get("$http");b.remove(m+"me/albums?limit=40&offset=0");var e=h.defer();return"array"!=typeof a&&(a=[a]),d({method:"PUT",url:m+"me/albums",dataType:"json",data:JSON.stringify({ids:a}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},removeAlbumsFromLibrary:function(a){if(!this.isAuthorized())return b.reject(),b.promise;var b=h.defer();return"array"!=typeof a&&(a=[a]),d({method:"DELETE",url:m+"me/albums",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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},deleteTracksFromLibrary:function(a){var b=h.defer();if(!this.isAuthorized())return b.reject(),b.promise;var e=i.get("$http");return e.remove(m+"me/tracks/?limit=50"),d({method:"DELETE",url:m+"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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getMyArtists:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"GET",url:m+"me/following?type=artist",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},getMyAlbums:function(a,b,e){if(!this.isAuthorized())return f.reject(),f.promise;"undefined"!=typeof b&&b||(b=40),"undefined"==typeof e&&(e=0);var f=h.defer();return d({cache:!0,method:"GET",url:m+"me/albums?limit="+b+"&offset="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){for(var b=[],c=Math.ceil(a.items.length/20),d=1;c>=d;d++){var e=a.items.splice(0,20),g=[],h=20;e.length<20&&(h=e.length);for(var i=0;h>i;i++)g.push(e[i].album.id);l.getAlbums(g).then(function(e){b=b.concat(e.albums),d>=c&&(a.items=b,f.resolve(a))})}}).error(function(a){k.error(a.error.message),f.reject(a.error.message)}),f.promise},isFollowingArtist:function(a,b){var e=this.getFromUri("artistid",a),f=h.defer();return this.isAuthorized()?(d({cache:!1,method:"GET",url:m+"me/following/contains?type=artist&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"users/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"?market="+n,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"users/"+e+"/playlists/"+f+"/followers/contains?ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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=j.getSetting("countrycode","NZ"),f=h.defer();return d({cache:!0,method:"GET",url:m+"browse/featured-playlists?timestamp="+b+"&country="+e+"&limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"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){k.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},movePlaylistTracks:function(a,b,e,f){if(!this.isAuthorized())return l.reject(),l.promise;var g=this.getFromUri("userid",a),i=this.getFromUri("playlistid",a);if(g!=j.getSetting("spotifyuser",{id:null}).id)return!1;var l=h.defer();return d({method:"PUT",url:m+"users/"+g+"/playlists/"+i+"/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){l.resolve(a)}).error(function(a){k.error(a.error.message),l.reject(a.error.message)}),l.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:m+"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){k.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:m+"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){k.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:m+"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){k.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},newReleases:function(a,b){"undefined"!=typeof a&&a||(a=40),"undefined"==typeof b&&(b=0);var e=h.defer();return d({cache:!0,method:"GET",url:m+"browse/new-releases?country="+n+"&limit="+a+"&offset="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){for(var b=[],c=Math.ceil(a.albums.items.length/20),d=1;c>d;d++){for(var f=a.albums.items.splice(0,20),g=[],h=0;20>h;h++)g.push(f[h].id);l.getAlbums(g).then(function(f){b=b.concat(f.albums),d>=c&&(a.albums.items=b,e.resolve(a))})}}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},browseCategories:function(a){"undefined"==typeof a&&(a=40);var b=h.defer();return d({cache:!0,method:"GET",url:m+"browse/categories?limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.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:m+"browse/categories/"+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.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:m+"browse/categories/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},getMyFavorites:function(a,b,e,f){if("undefined"==typeof b||!b)var b=25;if("undefined"==typeof e||!e)var e=0;if("undefined"==typeof f||!f)var f="long_term";var g=h.defer();return d({cache:!0,method:"GET",url:m+"me/top/"+a+"?limit="+b+"&offset="+e+"&time_range="+f,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){k.error(a.error.message),g.reject(a.error.message)}),g.promise},getRecommendations:function(a,b,e,f,g){var i=m+"recommendations/?";"undefined"!=typeof a&&a&&(i+="limit="+a),"undefined"!=typeof b&&b&&(i+="&offset="+b),"undefined"!=typeof e&&e&&(i+="&seed_artists="+e),"undefined"!=typeof f&&f&&(i+="&seed_albums="+f),"undefined"!=typeof g&&g&&(i+="&seed_tracks="+g);var j=h.defer();return d({cache:!0,method:"GET",url:i,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){j.resolve(a)}).error(function(a){k.error(a.error.message),j.reject(a.error.message)}),j.promise},getArtist:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"artists/?ids="+c}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},getTopTracks:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b+"/top-tracks?country="+n}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"artists/"+b+"/related-artists"}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"albums/"+c}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getAlbums:function(a){for(var b=h.defer(),c="",e=0;e0&&(c+=","),c+=a[e];return d({cache:!0,method:"GET",url:m+"albums?ids="+c+"&market="+n}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getArtistAlbums:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b+"/albums?album_type=album,single&market="+n}).success(function(a){c.resolve(a)}).error(function(a){k.error(a.error.message),c.reject(a.error.message)}),c.promise},isAlbumInLibrary:function(a){for(var b=h.defer(),e="",f=0;f0&&(e+=","),e+=a[f];return this.isAuthorized()?(d({method:"GET",url:m+"me/albums/contains?ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},getSearchResults:function(a,b,e,f){"undefined"==typeof e&&(e=10),"undefined"==typeof f&&(f=0);var g=h.defer();return d({cache:!0,method:"GET",url:m+"search?q="+b+"&type="+a+"&country="+n+"&limit="+e+"&offset="+f,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(b){if("album"==a)for(var c=[],d=Math.ceil(b.albums.items.length/20),e=1;d>e;e++){for(var f=b.albums.items.splice(0,20),h=[],i=0;20>i;i++)h.push(f[i].id);l.getAlbums(h).then(function(a){c=c.concat(a.albums),e>=d&&(b.albums.items=c,g.resolve(b))})}else g.resolve(b)}).error(function(a){k.error(a.error.message),g.reject(a.error.message)}),g.promise}},m="https://api.spotify.com/v1/",n=j.getSetting("spotifycountry","NZ");j.getSetting("spotifylocale","en_NZ");return l}]).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(b.config.url.search("https://api.spotify.com/")>=0&&3>f){if(401==b.status){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}if(0==b.status){var d=a.defer();return c.get("SpotifyService").serviceUnavailable(),d.promise}}return b}};return g}]),angular.module("spotmop.settings",[]).config(["$stateProvider",function(a){a.state("settings",{url:"/settings",templateUrl:"app/settings/template.html"}).state("testing",{url:"/testing",templateUrl:"app/settings/testing.template.html"})}]).controller("SettingsController",["$scope","$http","$rootScope","$timeout","MopidyService","SpotifyService","SettingsService","NotifyService","PusherService",function(a,b,c,d,e,f,g,h,i){a.version,a.settings=g.getSettings(),a.currentSubpage="mopidy",a.subpageNavigate=function(b){a.currentSubpage=b},a.authorizeSpotify=function(){f.authorize()},a.refreshSpotifyToken=function(){h.notify("Refreshing token"), -f.refreshToken().then(function(){})},a.spotifyLogout=function(){f.logout()},a.upgradeCheck=function(){h.notify("Checking for updates"),g.upgradeCheck().then(function(a){g.setSetting("version",a,"latest"),g.getSetting("version",0,"installed")'+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"),g.runUpgrade());var d=g.getSetting("pushername","");d&&j.setMe(d)}else c.id==g.getSetting("pusherid","")||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","$cacheFactory","SettingsService","NotifyService",function(a,b,c,d,e,f,g,h,i,j,k){var l={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",l.getMe().then(function(b){j.setSetting("spotifyuser",b),a.$broadcast("spotmop:spotify:authenticationChanged",this.authenticationMethod)})},!1),this.isAuthorized()?(a.spotifyAuthorized=!0,this.authenticationMethod="client"):(j.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=j.getSetting("mopidyhost",window.location.hostname),g=j.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?(k.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},serviceUnavailable:function(){k.error("Request failed. Spotify API may be temporarily unavailable.")},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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getMe:function(){var a=h.defer();return this.isAuthorized()?(d({method:"GET",url:m+"me/",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(b){a.resolve(b)}).error(function(b){k.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:m+"users/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"me/following/contains?type="+a+"&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"tracks/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"me/tracks/?limit=50",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},addTracksToLibrary:function(a){var b=h.defer();if(!this.isAuthorized())return b.reject(),b.promise;var e=i.get("$http");return e.remove(m+"me/tracks/?limit=50"),d({method:"PUT",url:m+"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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},addAlbumsToLibrary:function(a){if(!this.isAuthorized())return e.reject(),e.promise;var b=i.get("$http");b.remove(m+"me/albums?limit=40&offset=0");var e=h.defer();return"array"!=typeof a&&(a=[a]),d({method:"PUT",url:m+"me/albums",dataType:"json",data:JSON.stringify({ids:a}),contentType:"application/json; charset=utf-8",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},removeAlbumsFromLibrary:function(a){if(!this.isAuthorized())return b.reject(),b.promise;var b=h.defer();return"array"!=typeof a&&(a=[a]),d({method:"DELETE",url:m+"me/albums",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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},deleteTracksFromLibrary:function(a){var b=h.defer();if(!this.isAuthorized())return b.reject(),b.promise;var e=i.get("$http");return e.remove(m+"me/tracks/?limit=50"),d({method:"DELETE",url:m+"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){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getMyArtists:function(a){var b=h.defer();return this.isAuthorized()?(d({method:"GET",url:m+"me/following?type=artist",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},getMyAlbums:function(a,b,e){var f=h.defer();return this.isAuthorized()?("undefined"!=typeof b&&b||(b=40),"undefined"==typeof e&&(e=0),d({cache:!0,method:"GET",url:m+"me/albums?limit="+b+"&offset="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){for(var b=[],c=Math.ceil(a.items.length/20),d=1;c>=d;d++){var e=a.items.splice(0,20),g=[],h=20;e.length<20&&(h=e.length);for(var i=0;h>i;i++)g.push(e[i].album.id);l.getAlbums(g).then(function(e){b=b.concat(e.albums),d>=c&&(a.items=b,f.resolve(a))})}}).error(function(a){k.error(a.error.message),f.reject(a.error.message)}),f.promise):(f.reject(),f.promise)},isFollowingArtist:function(a,b){var e=this.getFromUri("artistid",a),f=h.defer();return this.isAuthorized()?(d({cache:!1,method:"GET",url:m+"me/following/contains?type=artist&ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"me/following?type=artist&ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"users/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"?market="+n,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"users/"+e+"/playlists/"+f+"/followers/contains?ids="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"users/"+b+"/playlists/"+e+"/followers",headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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=j.getSetting("countrycode","NZ"),f=h.defer();return d({cache:!0,method:"GET",url:m+"browse/featured-playlists?timestamp="+b+"&country="+e+"&limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){f.resolve(a)}).error(function(a){k.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:m+"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){k.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},movePlaylistTracks:function(a,b,e,f){if(!this.isAuthorized())return l.reject(),l.promise;var g=this.getFromUri("userid",a),i=this.getFromUri("playlistid",a);if(g!=j.getSetting("spotifyuser",{id:null}).id)return!1;var l=h.defer();return d({method:"PUT",url:m+"users/"+g+"/playlists/"+i+"/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){l.resolve(a)}).error(function(a){k.error(a.error.message),l.reject(a.error.message)}),l.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:m+"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){k.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:m+"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){k.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:m+"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){k.error(a.error.message),g.reject(a.error.message)}),g.promise):(g.reject(),g.promise)},newReleases:function(a,b){"undefined"!=typeof a&&a||(a=40),"undefined"==typeof b&&(b=0);var e=h.defer();return d({cache:!0,method:"GET",url:m+"browse/new-releases?country="+n+"&limit="+a+"&offset="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){for(var b=[],c=Math.ceil(a.albums.items.length/20),d=1;c>d;d++){for(var f=a.albums.items.splice(0,20),g=[],h=0;20>h;h++)g.push(f[h].id);l.getAlbums(g).then(function(f){b=b.concat(f.albums),d>=c&&(a.albums.items=b,e.resolve(a))})}}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},browseCategories:function(a){"undefined"==typeof a&&(a=40);var b=h.defer();return d({cache:!0,method:"GET",url:m+"browse/categories?limit="+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.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:m+"browse/categories/"+a,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.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:m+"browse/categories/"+a+"/playlists?limit="+b,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},getMyFavorites:function(a,b,e,f){if("undefined"==typeof b||!b)var b=25;if("undefined"==typeof e||!e)var e=0;if("undefined"==typeof f||!f)var f="long_term";var g=h.defer();return d({cache:!0,method:"GET",url:m+"me/top/"+a+"?limit="+b+"&offset="+e+"&time_range="+f,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){g.resolve(a)}).error(function(a){k.error(a.error.message),g.reject(a.error.message)}),g.promise},getRecommendations:function(a,b,e,f,g){var i=m+"recommendations/?";"undefined"!=typeof a&&a&&(i+="limit="+a),"undefined"!=typeof b&&b&&(i+="&offset="+b),"undefined"!=typeof e&&e&&(i+="&seed_artists="+e),"undefined"!=typeof f&&f&&(i+="&seed_albums="+f),"undefined"!=typeof g&&g&&(i+="&seed_tracks="+g);var j=h.defer();return d({cache:!0,method:"GET",url:i,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){j.resolve(a)}).error(function(a){k.error(a.error.message),j.reject(a.error.message)}),j.promise},getArtist:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"artists/?ids="+c}).success(function(a){e.resolve(a)}).error(function(a){k.error(a.error.message),e.reject(a.error.message)}),e.promise},getTopTracks:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b+"/top-tracks?country="+n}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"artists/"+b+"/related-artists"}).success(function(a){c.resolve(a)}).error(function(a){k.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:m+"albums/"+c}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getAlbums:function(a){for(var b=h.defer(),c="",e=0;e0&&(c+=","),c+=a[e];return d({cache:!0,method:"GET",url:m+"albums?ids="+c+"&market="+n}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise},getArtistAlbums:function(a){var b=this.getFromUri("artistid",a),c=h.defer();return d({cache:!0,method:"GET",url:m+"artists/"+b+"/albums?album_type=album,single&market="+n}).success(function(a){c.resolve(a)}).error(function(a){k.error(a.error.message),c.reject(a.error.message)}),c.promise},isAlbumInLibrary:function(a){for(var b=h.defer(),e="",f=0;f0&&(e+=","),e+=a[f];return this.isAuthorized()?(d({method:"GET",url:m+"me/albums/contains?ids="+e,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(a){b.resolve(a)}).error(function(a){k.error(a.error.message),b.reject(a.error.message)}),b.promise):(b.reject(),b.promise)},getSearchResults:function(a,b,e,f){"undefined"==typeof e&&(e=10),"undefined"==typeof f&&(f=0);var g=h.defer();return d({cache:!0,method:"GET",url:m+"search?q="+b+"&type="+a+"&country="+n+"&limit="+e+"&offset="+f,headers:{Authorization:"Bearer "+c.spotify.AccessToken}}).success(function(b){if("album"==a)for(var c=[],d=Math.ceil(b.albums.items.length/20),e=1;d>e;e++){for(var f=b.albums.items.splice(0,20),h=[],i=0;20>i;i++)h.push(f[i].id);l.getAlbums(h).then(function(a){c=c.concat(a.albums),e>=d&&(b.albums.items=c,g.resolve(b))})}else g.resolve(b)}).error(function(a){k.error(a.error.message),g.reject(a.error.message)}),g.promise}},m="https://api.spotify.com/v1/",n=j.getSetting("spotifycountry","NZ");j.getSetting("spotifylocale","en_NZ");return l}]).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(b.config.url.search("https://api.spotify.com/")>=0&&3>f){if(401==b.status){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}if(0==b.status){var d=a.defer();return c.get("SpotifyService").serviceUnavailable(),d.promise}}return b}};return g}]),angular.module("spotmop.settings",[]).config(["$stateProvider",function(a){a.state("settings",{url:"/settings",templateUrl:"app/settings/template.html"}).state("testing",{url:"/testing",templateUrl:"app/settings/testing.template.html"})}]).controller("SettingsController",["$scope","$http","$rootScope","$timeout","MopidyService","SpotifyService","SettingsService","NotifyService","PusherService",function(a,b,c,d,e,f,g,h,i){a.version,a.settings=g.getSettings(),a.currentSubpage="mopidy",a.subpageNavigate=function(b){a.currentSubpage=b},a.authorizeSpotify=function(){f.authorize()},a.refreshSpotifyToken=function(){h.notify("Refreshing token"),f.refreshToken().then(function(){})},a.spotifyLogout=function(){f.logout()},a.upgradeCheck=function(){h.notify("Checking for updates"),g.upgradeCheck().then(function(a){g.setSetting("version",a,"latest"), +g.getSetting("version",0,"installed") Date: Fri, 24 Jun 2016 08:42:10 +1200 Subject: [PATCH 09/16] Fixing display issue when first loading local playlists; Need to wait for backend to complete auth before fetching artwork... --- src/app/library/controller.js | 48 +++++++++++++++++-------- src/app/library/playlists.template.html | 11 +++--- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/app/library/controller.js b/src/app/library/controller.js index 0bd4c96..a45c3d9 100644 --- a/src/app/library/controller.js +++ b/src/app/library/controller.js @@ -296,10 +296,10 @@ angular.module('spotmop.library', []) $scope.show = function( playlist ){ if( - typeof($scope.settings.playlists) === 'undefined' || - typeof($scope.settings.playlists.onlyshowowned) === 'undefined' || - !$scope.settings.playlists.onlyshowowned ){ - return true; + typeof($scope.settings.playlists) === 'undefined' || + typeof($scope.settings.playlists.onlyshowowned) === 'undefined' || + !$scope.settings.playlists.onlyshowowned ){ + return true; } if( playlist.owner.id == 'jaedb' ) return true; @@ -323,19 +323,38 @@ angular.module('spotmop.library', []) }); // not authorized, so have to fetch via backend first - }else{ - - NotifyService.notify('Fetching from Mopidy as you haven\'t authorized Spotify. This will take a while!'); + }else{ function fetchPlaylists(){ MopidyService.getPlaylists() - .then( function( response ){ - // fetch more detail from each playlist (individually, d'oh!) - angular.forEach( response, function(value, key){ - SpotifyService.getPlaylist( value.uri ) - .then( function( playlist ){ - $scope.playlists.items.push( playlist ); - }); + .then( function( response ){ + + // add them to our list + $scope.playlists.items = response; + + // now go get the extra info (and artwork) from Spotify + // need to do this individually as there is no bulk endpoint, curses! + angular.forEach( response, function(playlist, i){ + + // process it and add to our $scope + var callback = function(i){ + return function( response ){ + + // make sure our response was not an error + if( typeof(response.error) === 'undefined' ){ + + // construct our image-ified and updated playlist + var playlist = response; + playlist.images = $filter('sizedImages')(response.images); + + // update the existing playlist item with our updated data + $scope.playlists.items[i] = playlist; + } + }; + }(i); + + // run the actual request + SpotifyService.getPlaylist( playlist.uri ).then( callback ); }); }); } @@ -347,6 +366,7 @@ angular.module('spotmop.library', []) $scope.$on('mopidy:state:online', function(){ fetchPlaylists(); }); } + /** * Load more of the album's tracks * Triggered by scrolling to the bottom diff --git a/src/app/library/playlists.template.html b/src/app/library/playlists.template.html index fb5ad34..e55f481 100644 --- a/src/app/library/playlists.template.html +++ b/src/app/library/playlists.template.html @@ -3,8 +3,8 @@