')
98 | .attr('id', this.containerId)
99 | .html(html)
100 |
101 | $(document.body).append(container)
102 | return container
103 | }
104 |
105 | jasmine.Fixtures.prototype.addToContainer_ = function (html){
106 | var container = $(document.body).find('#'+this.containerId).append(html)
107 |
108 | if (!container.length) {
109 | this.createContainer_(html)
110 | }
111 | }
112 |
113 | jasmine.Fixtures.prototype.getFixtureHtml_ = function (url) {
114 | if (typeof this.fixturesCache_[url] === 'undefined') {
115 | this.loadFixtureIntoCache_(url)
116 | }
117 | return this.fixturesCache_[url]
118 | }
119 |
120 | jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
121 | var self = this
122 | , url = this.makeFixtureUrl_(relativeUrl)
123 | , htmlText = ''
124 | , request = $.ajax({
125 | async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
126 | cache: false,
127 | url: url,
128 | success: function (data, status, $xhr) {
129 | htmlText = $xhr.responseText
130 | }
131 | }).fail(function ($xhr, status, err) {
132 | throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
133 | })
134 |
135 | var scripts = $($.parseHTML(htmlText, true)).find('script[src]') || [];
136 |
137 | scripts.each(function(){
138 | $.ajax({
139 | async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
140 | cache: false,
141 | dataType: 'script',
142 | url: $(this).attr('src'),
143 | success: function (data, status, $xhr) {
144 | htmlText += ''
145 | },
146 | error: function ($xhr, status, err) {
147 | throw new Error('Script could not be loaded: ' + scriptSrc + ' (status: ' + status + ', message: ' + err.message + ')')
148 | }
149 | });
150 | })
151 |
152 | self.fixturesCache_[relativeUrl] = htmlText;
153 | }
154 |
155 | jasmine.Fixtures.prototype.makeFixtureUrl_ = function (relativeUrl){
156 | return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
157 | }
158 |
159 | jasmine.Fixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
160 | return this[methodName].apply(this, passedArguments)
161 | }
162 |
163 |
164 | jasmine.StyleFixtures = function () {
165 | this.fixturesCache_ = {}
166 | this.fixturesNodes_ = []
167 | this.fixturesPath = 'spec/javascripts/fixtures'
168 | }
169 |
170 | jasmine.StyleFixtures.prototype.set = function (css) {
171 | this.cleanUp()
172 | this.createStyle_(css)
173 | }
174 |
175 | jasmine.StyleFixtures.prototype.appendSet = function (css) {
176 | this.createStyle_(css)
177 | }
178 |
179 | jasmine.StyleFixtures.prototype.preload = function () {
180 | this.read_.apply(this, arguments)
181 | }
182 |
183 | jasmine.StyleFixtures.prototype.load = function () {
184 | this.cleanUp()
185 | this.createStyle_(this.read_.apply(this, arguments))
186 | }
187 |
188 | jasmine.StyleFixtures.prototype.appendLoad = function () {
189 | this.createStyle_(this.read_.apply(this, arguments))
190 | }
191 |
192 | jasmine.StyleFixtures.prototype.cleanUp = function () {
193 | while(this.fixturesNodes_.length) {
194 | this.fixturesNodes_.pop().remove()
195 | }
196 | }
197 |
198 | jasmine.StyleFixtures.prototype.createStyle_ = function (html) {
199 | var styleText = $('
').html(html).text()
200 | , style = $('')
201 |
202 | this.fixturesNodes_.push(style)
203 | $('head').append(style)
204 | }
205 |
206 | jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
207 | jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
208 | jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
209 | jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
210 | jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
211 | jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
212 |
213 | jasmine.getJSONFixtures = function () {
214 | return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
215 | }
216 |
217 | jasmine.JSONFixtures = function () {
218 | this.fixturesCache_ = {}
219 | this.fixturesPath = 'spec/javascripts/fixtures/json'
220 | }
221 |
222 | jasmine.JSONFixtures.prototype.load = function () {
223 | this.read.apply(this, arguments)
224 | return this.fixturesCache_
225 | }
226 |
227 | jasmine.JSONFixtures.prototype.read = function () {
228 | var fixtureUrls = arguments
229 |
230 | for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
231 | this.getFixtureData_(fixtureUrls[urlIndex])
232 | }
233 |
234 | return this.fixturesCache_
235 | }
236 |
237 | jasmine.JSONFixtures.prototype.clearCache = function () {
238 | this.fixturesCache_ = {}
239 | }
240 |
241 | jasmine.JSONFixtures.prototype.getFixtureData_ = function (url) {
242 | if (!this.fixturesCache_[url]) this.loadFixtureIntoCache_(url)
243 | return this.fixturesCache_[url]
244 | }
245 |
246 | jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
247 | var self = this
248 | , url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
249 |
250 | $.ajax({
251 | async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
252 | cache: false,
253 | dataType: 'json',
254 | url: url,
255 | success: function (data) {
256 | self.fixturesCache_[relativeUrl] = data
257 | },
258 | error: function ($xhr, status, err) {
259 | throw new Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
260 | }
261 | })
262 | }
263 |
264 | jasmine.JSONFixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
265 | return this[methodName].apply(this, passedArguments)
266 | }
267 |
268 | jasmine.jQuery = function () {}
269 |
270 | jasmine.jQuery.browserTagCaseIndependentHtml = function (html) {
271 | return $('
').append(html).html()
272 | }
273 |
274 | jasmine.jQuery.elementToString = function (element) {
275 | return $(element).map(function () { return this.outerHTML; }).toArray().join(', ')
276 | }
277 |
278 | var data = {
279 | spiedEvents: {}
280 | , handlers: []
281 | }
282 |
283 | jasmine.jQuery.events = {
284 | spyOn: function (selector, eventName) {
285 | var handler = function (e) {
286 | data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
287 | }
288 |
289 | $(selector).on(eventName, handler)
290 | data.handlers.push(handler)
291 |
292 | return {
293 | selector: selector,
294 | eventName: eventName,
295 | handler: handler,
296 | reset: function (){
297 | delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
298 | }
299 | }
300 | },
301 |
302 | args: function (selector, eventName) {
303 | var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
304 |
305 | if (!actualArgs) {
306 | throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."
307 | }
308 |
309 | return actualArgs
310 | },
311 |
312 | wasTriggered: function (selector, eventName) {
313 | return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
314 | },
315 |
316 | wasTriggeredWith: function (selector, eventName, expectedArgs, util, customEqualityTesters) {
317 | var actualArgs = jasmine.jQuery.events.args(selector, eventName).slice(1)
318 |
319 | if (Object.prototype.toString.call(expectedArgs) !== '[object Array]')
320 | actualArgs = actualArgs[0]
321 |
322 | return util.equals(expectedArgs, actualArgs, customEqualityTesters)
323 | },
324 |
325 | wasPrevented: function (selector, eventName) {
326 | var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
327 | , e = args ? args[0] : undefined
328 |
329 | return e && e.isDefaultPrevented()
330 | },
331 |
332 | wasStopped: function (selector, eventName) {
333 | var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
334 | , e = args ? args[0] : undefined
335 | return e && e.isPropagationStopped()
336 | },
337 |
338 | cleanUp: function () {
339 | data.spiedEvents = {}
340 | data.handlers = []
341 | }
342 | }
343 |
344 | var hasProperty = function (actualValue, expectedValue) {
345 | if (expectedValue === undefined)
346 | return actualValue !== undefined
347 |
348 | return actualValue === expectedValue
349 | }
350 |
351 | beforeEach(function () {
352 | jasmine.addMatchers({
353 | toHaveClass: function () {
354 | return {
355 | compare: function (actual, className) {
356 | return { pass: $(actual).hasClass(className) }
357 | }
358 | }
359 | },
360 |
361 | toHaveCss: function () {
362 | return {
363 | compare: function (actual, css) {
364 | for (var prop in css){
365 | var value = css[prop]
366 | // see issue #147 on gh
367 | ;if (value === 'auto' && $(actual).get(0).style[prop] === 'auto') continue
368 | if ($(actual).css(prop) !== value) return { pass: false }
369 | }
370 | return { pass: true }
371 | }
372 | }
373 | },
374 |
375 | toBeVisible: function () {
376 | return {
377 | compare: function (actual) {
378 | return { pass: $(actual).is(':visible') }
379 | }
380 | }
381 | },
382 |
383 | toBeHidden: function () {
384 | return {
385 | compare: function (actual) {
386 | return { pass: $(actual).is(':hidden') }
387 | }
388 | }
389 | },
390 |
391 | toBeSelected: function () {
392 | return {
393 | compare: function (actual) {
394 | return { pass: $(actual).is(':selected') }
395 | }
396 | }
397 | },
398 |
399 | toBeChecked: function () {
400 | return {
401 | compare: function (actual) {
402 | return { pass: $(actual).is(':checked') }
403 | }
404 | }
405 | },
406 |
407 | toBeEmpty: function () {
408 | return {
409 | compare: function (actual) {
410 | return { pass: $(actual).is(':empty') }
411 | }
412 | }
413 | },
414 |
415 | toBeInDOM: function () {
416 | return {
417 | compare: function (actual) {
418 | return { pass: $.contains(document.documentElement, $(actual)[0]) }
419 | }
420 | }
421 | },
422 |
423 | toExist: function () {
424 | return {
425 | compare: function (actual) {
426 | return { pass: $(actual).length }
427 | }
428 | }
429 | },
430 |
431 | toHaveLength: function () {
432 | return {
433 | compare: function (actual, length) {
434 | return { pass: $(actual).length === length }
435 | }
436 | }
437 | },
438 |
439 | toHaveAttr: function () {
440 | return {
441 | compare: function (actual, attributeName, expectedAttributeValue) {
442 | return { pass: hasProperty($(actual).attr(attributeName), expectedAttributeValue) }
443 | }
444 | }
445 | },
446 |
447 | toHaveProp: function () {
448 | return {
449 | compare: function (actual, propertyName, expectedPropertyValue) {
450 | return { pass: hasProperty($(actual).prop(propertyName), expectedPropertyValue) }
451 | }
452 | }
453 | },
454 |
455 | toHaveId: function () {
456 | return {
457 | compare: function (actual, id) {
458 | return { pass: $(actual).attr('id') == id }
459 | }
460 | }
461 | },
462 |
463 | toHaveHtml: function () {
464 | return {
465 | compare: function (actual, html) {
466 | return { pass: $(actual).html() == jasmine.jQuery.browserTagCaseIndependentHtml(html) }
467 | }
468 | }
469 | },
470 |
471 | toContainHtml: function () {
472 | return {
473 | compare: function (actual, html) {
474 | var actualHtml = $(actual).html()
475 | , expectedHtml = jasmine.jQuery.browserTagCaseIndependentHtml(html)
476 |
477 | return { pass: (actualHtml.indexOf(expectedHtml) >= 0) }
478 | }
479 | }
480 | },
481 |
482 | toHaveText: function () {
483 | return {
484 | compare: function (actual, text) {
485 | var actualText = $(actual).text()
486 | var trimmedText = $.trim(actualText)
487 |
488 | if (text && $.isFunction(text.test)) {
489 | return { pass: text.test(actualText) || text.test(trimmedText) }
490 | } else {
491 | return { pass: (actualText == text || trimmedText == text) }
492 | }
493 | }
494 | }
495 | },
496 |
497 | toContainText: function () {
498 | return {
499 | compare: function (actual, text) {
500 | var trimmedText = $.trim($(actual).text())
501 |
502 | if (text && $.isFunction(text.test)) {
503 | return { pass: text.test(trimmedText) }
504 | } else {
505 | return { pass: trimmedText.indexOf(text) != -1 }
506 | }
507 | }
508 | }
509 | },
510 |
511 | toHaveValue: function () {
512 | return {
513 | compare: function (actual, value) {
514 | return { pass: $(actual).val() === value }
515 | }
516 | }
517 | },
518 |
519 | toHaveData: function () {
520 | return {
521 | compare: function (actual, key, expectedValue) {
522 | return { pass: hasProperty($(actual).data(key), expectedValue) }
523 | }
524 | }
525 | },
526 |
527 | toContainElement: function () {
528 | return {
529 | compare: function (actual, selector) {
530 | if (window.debug) debugger
531 | return { pass: $(actual).find(selector).length }
532 | }
533 | }
534 | },
535 |
536 | toBeMatchedBy: function () {
537 | return {
538 | compare: function (actual, selector) {
539 | return { pass: $(actual).filter(selector).length }
540 | }
541 | }
542 | },
543 |
544 | toBeDisabled: function () {
545 | return {
546 | compare: function (actual, selector) {
547 | return { pass: $(actual).is(':disabled') }
548 | }
549 | }
550 | },
551 |
552 | toBeFocused: function (selector) {
553 | return {
554 | compare: function (actual, selector) {
555 | return { pass: $(actual)[0] === $(actual)[0].ownerDocument.activeElement }
556 | }
557 | }
558 | },
559 |
560 | toHandle: function () {
561 | return {
562 | compare: function (actual, event) {
563 | var events = $._data($(actual).get(0), "events")
564 |
565 | if (!events || !event || typeof event !== "string") {
566 | return { pass: false }
567 | }
568 |
569 | var namespaces = event.split(".")
570 | , eventType = namespaces.shift()
571 | , sortedNamespaces = namespaces.slice(0).sort()
572 | , namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
573 |
574 | if (events[eventType] && namespaces.length) {
575 | for (var i = 0; i < events[eventType].length; i++) {
576 | var namespace = events[eventType][i].namespace
577 |
578 | if (namespaceRegExp.test(namespace))
579 | return { pass: true }
580 | }
581 | } else {
582 | return { pass: (events[eventType] && events[eventType].length > 0) }
583 | }
584 |
585 | return { pass: false }
586 | }
587 | }
588 | },
589 |
590 | toHandleWith: function () {
591 | return {
592 | compare: function (actual, eventName, eventHandler) {
593 | var normalizedEventName = eventName.split('.')[0]
594 | , stack = $._data($(actual).get(0), "events")[normalizedEventName]
595 |
596 | for (var i = 0; i < stack.length; i++) {
597 | if (stack[i].handler == eventHandler) return { pass: true }
598 | }
599 |
600 | return { pass: false }
601 | }
602 | }
603 | },
604 |
605 | toHaveBeenTriggeredOn: function () {
606 | return {
607 | compare: function (actual, selector) {
608 | var result = { pass: jasmine.jQuery.events.wasTriggered(selector, actual) }
609 |
610 | result.message = result.pass ?
611 | "Expected event " + $(actual) + " not to have been triggered on " + selector :
612 | "Expected event " + $(actual) + " to have been triggered on " + selector
613 |
614 | return result;
615 | }
616 | }
617 | },
618 |
619 | toHaveBeenTriggered: function (){
620 | return {
621 | compare: function (actual) {
622 | var eventName = actual.eventName
623 | , selector = actual.selector
624 | , result = { pass: jasmine.jQuery.events.wasTriggered(selector, eventName) }
625 |
626 | result.message = result.pass ?
627 | "Expected event " + eventName + " not to have been triggered on " + selector :
628 | "Expected event " + eventName + " to have been triggered on " + selector
629 |
630 | return result
631 | }
632 | }
633 | },
634 |
635 | toHaveBeenTriggeredOnAndWith: function (j$, customEqualityTesters) {
636 | return {
637 | compare: function (actual, selector, expectedArgs) {
638 | var wasTriggered = jasmine.jQuery.events.wasTriggered(selector, actual)
639 | , result = { pass: wasTriggered && jasmine.jQuery.events.wasTriggeredWith(selector, actual, expectedArgs, j$, customEqualityTesters) }
640 |
641 | if (wasTriggered) {
642 | var actualArgs = jasmine.jQuery.events.args(selector, actual, expectedArgs)[1]
643 | result.message = result.pass ?
644 | "Expected event " + actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs) :
645 | "Expected event " + actual + " to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
646 |
647 | } else {
648 | // todo check on this
649 | result.message = result.pass ?
650 | "Expected event " + actual + " not to have been triggered on " + selector :
651 | "Expected event " + actual + " to have been triggered on " + selector
652 | }
653 |
654 | return result
655 | }
656 | }
657 | },
658 |
659 | toHaveBeenPreventedOn: function () {
660 | return {
661 | compare: function (actual, selector) {
662 | var result = { pass: jasmine.jQuery.events.wasPrevented(selector, actual) }
663 |
664 | result.message = result.pass ?
665 | "Expected event " + actual + " not to have been prevented on " + selector :
666 | "Expected event " + actual + " to have been prevented on " + selector
667 |
668 | return result
669 | }
670 | }
671 | },
672 |
673 | toHaveBeenPrevented: function () {
674 | return {
675 | compare: function (actual) {
676 | var eventName = actual.eventName
677 | , selector = actual.selector
678 | , result = { pass: jasmine.jQuery.events.wasPrevented(selector, eventName) }
679 |
680 | result.message = result.pass ?
681 | "Expected event " + eventName + " not to have been prevented on " + selector :
682 | "Expected event " + eventName + " to have been prevented on " + selector
683 |
684 | return result
685 | }
686 | }
687 | },
688 |
689 | toHaveBeenStoppedOn: function () {
690 | return {
691 | compare: function (actual, selector) {
692 | var result = { pass: jasmine.jQuery.events.wasStopped(selector, actual) }
693 |
694 | result.message = result.pass ?
695 | "Expected event " + actual + " not to have been stopped on " + selector :
696 | "Expected event " + actual + " to have been stopped on " + selector
697 |
698 | return result;
699 | }
700 | }
701 | },
702 |
703 | toHaveBeenStopped: function () {
704 | return {
705 | compare: function (actual) {
706 | var eventName = actual.eventName
707 | , selector = actual.selector
708 | , result = { pass: jasmine.jQuery.events.wasStopped(selector, eventName) }
709 |
710 | result.message = result.pass ?
711 | "Expected event " + eventName + " not to have been stopped on " + selector :
712 | "Expected event " + eventName + " to have been stopped on " + selector
713 |
714 | return result
715 | }
716 | }
717 | }
718 | })
719 |
720 | jasmine.getEnv().addCustomEqualityTester(function(a, b) {
721 | if (a && b) {
722 | if (a instanceof $ || jasmine.isDomNode(a)) {
723 | var $a = $(a)
724 |
725 | if (b instanceof $)
726 | return $a.length == b.length && a.is(b)
727 |
728 | return $a.is(b);
729 | }
730 |
731 | if (b instanceof $ || jasmine.isDomNode(b)) {
732 | var $b = $(b)
733 |
734 | if (a instanceof $)
735 | return a.length == $b.length && $b.is(a)
736 |
737 | return $(b).is(a);
738 | }
739 | }
740 | })
741 |
742 | jasmine.getEnv().addCustomEqualityTester(function (a, b) {
743 | if (a instanceof $ && b instanceof $ && a.size() == b.size())
744 | return a.is(b)
745 | })
746 | })
747 |
748 | afterEach(function () {
749 | jasmine.getFixtures().cleanUp()
750 | jasmine.getStyleFixtures().cleanUp()
751 | jasmine.jQuery.events.cleanUp()
752 | })
753 |
754 | window.readFixtures = function () {
755 | return jasmine.getFixtures().proxyCallTo_('read', arguments)
756 | }
757 |
758 | window.preloadFixtures = function () {
759 | jasmine.getFixtures().proxyCallTo_('preload', arguments)
760 | }
761 |
762 | window.loadFixtures = function () {
763 | jasmine.getFixtures().proxyCallTo_('load', arguments)
764 | }
765 |
766 | window.appendLoadFixtures = function () {
767 | jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
768 | }
769 |
770 | window.setFixtures = function (html) {
771 | return jasmine.getFixtures().proxyCallTo_('set', arguments)
772 | }
773 |
774 | window.appendSetFixtures = function () {
775 | jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
776 | }
777 |
778 | window.sandbox = function (attributes) {
779 | return jasmine.getFixtures().sandbox(attributes)
780 | }
781 |
782 | window.spyOnEvent = function (selector, eventName) {
783 | return jasmine.jQuery.events.spyOn(selector, eventName)
784 | }
785 |
786 | window.preloadStyleFixtures = function () {
787 | jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
788 | }
789 |
790 | window.loadStyleFixtures = function () {
791 | jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
792 | }
793 |
794 | window.appendLoadStyleFixtures = function () {
795 | jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
796 | }
797 |
798 | window.setStyleFixtures = function (html) {
799 | jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
800 | }
801 |
802 | window.appendSetStyleFixtures = function (html) {
803 | jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
804 | }
805 |
806 | window.loadJSONFixtures = function () {
807 | return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
808 | }
809 |
810 | window.getJSONFixture = function (url) {
811 | return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
812 | }
813 | }(window, window.jasmine, window.jQuery);
814 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-spotify
2 |
3 | [](https://travis-ci.org/eddiemoore/angular-spotify) [](http://codecov.io/github/eddiemoore/angular-spotify?branch=master) [](https://coveralls.io/r/eddiemoore/angular-spotify) [](https://david-dm.org/eddiemoore/angular-spotify#info=devDependencies) [](https://codeclimate.com/github/eddiemoore/angular-spotify)
4 | [](https://greenkeeper.io/)
5 | [](https://gitter.im/eddiemoore/angular-spotify?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6 |
7 | angular service to connect to the [Spotify Web API](https://developer.spotify.com/web-api/)
8 |
9 | angular-spotify makes heavy use of promises throughout the service
10 |
11 | ## Usage
12 |
13 | Install angular-spotify via bower. Use the --save property to save into your bower.json file.
14 | ```shell
15 | bower install angular-spotify --save
16 | ```
17 | Also available on npm
18 | ```shell
19 | npm install angular-spotify --save
20 | ```
21 |
22 | Include spotify into your angular module
23 | ```js
24 | var app = angular.module('example', ['spotify']);
25 | ```
26 |
27 | Most of the functions in Spotify do not require you to authenticate your application. However if you do need to gain access to playlists or a user's data then configure it like this:
28 | ```js
29 | app.config(function (SpotifyProvider) {
30 | SpotifyProvider.setClientId('
');
31 | SpotifyProvider.setRedirectUri('');
32 | SpotifyProvider.setScope('');
33 | // If you already have an auth token
34 | SpotifyProvider.setAuthToken('');
35 | });
36 | ```
37 | For example:
38 | ```js
39 | app.config(function (SpotifyProvider) {
40 | SpotifyProvider.setClientId('ABC123DEF456GHI789JKL');
41 | SpotifyProvider.setRedirectUri('http://www.example.com/callback.html');
42 | SpotifyProvider.setScope('user-read-private playlist-read-private playlist-modify-private playlist-modify-public');
43 | // If you already have an auth token
44 | SpotifyProvider.setAuthToken('zoasliu1248sdfuiknuha7882iu4rnuwehifskmkiuwhjg23');
45 | });
46 | ```
47 |
48 |
49 | Inject Spotify into a controller to gain access to all the functions available
50 | ```js
51 | app.controller('MainCtrl', function (Spotify) {
52 |
53 | });
54 | ```
55 |
56 |
57 | ### Albums
58 |
59 | #### Get an Album
60 | Get Spotify catalog information for a single album.
61 | ```js
62 | Spotify.getAlbum('AlbumID or Spotify Album URI');
63 | ```
64 | Example:
65 | ```js
66 | Spotify.getAlbum('0sNOF9WDwhWunNAHPD3Baj').then(function (data) {
67 | console.log(data);
68 | });
69 | ```
70 |
71 |
72 | #### Get Several Albums
73 | Get Spotify catalog information for multiple albums identified by their Spotify IDs.
74 | ```js
75 | Spotify.getAlbums('Array or comma separated list of Album IDs');
76 | ```
77 | Example:
78 | ```js
79 | Spotify
80 | .getAlbums('41MnTivkwTO3UUJ8DrqEJJ,6JWc4iAiJ9FjyK0B59ABb4,6UXCm6bOO4gFlDQZV5yL37')
81 | .then(function (data) {
82 | console.log(data);
83 | });
84 | ```
85 |
86 |
87 | #### Get an Album’s Tracks
88 | Get Spotify catalog information about an album’s tracks. Optional parameters can be used to limit the number of tracks returned.
89 | ```js
90 | Spotify.getAlbumTracks('AlbumID or Spotify Album URI', options);
91 | ```
92 | ##### Options Object (Optional)
93 | - limit - Optional. The maximum number of tracks to return. Default: 20. Minimum: 1. Maximum: 50.
94 | - offset - Optional. The index of the first track to return. Default: 0 (the first object). Use with limit to get the next set of tracks.
95 |
96 | Example:
97 | ```js
98 | Spotify.getAlbumTracks('6akEvsycLGftJxYudPjmqK').then(function (data) {
99 | console.log(data);
100 | });
101 | ```
102 |
103 |
104 | ### Artists
105 | #### Get an Artist
106 | Get Spotify catalog information for a single artist identified by their unique Spotify ID or Spotify URI.
107 |
108 | ```js
109 | Spotify.getArtist('Artist Id or Spotify Artist URI');
110 | ```
111 | Example
112 | ```js
113 | Spotify.getArtist('0LcJLqbBmaGUft1e9Mm8HV').then(function (data) {
114 | console.log(data);
115 | });
116 | ```
117 |
118 | #### Get Several Artists
119 | Get Spotify catalog information for several artists based on their Spotify IDs.
120 | ```js
121 | Spotify.getArtists('Comma separated string or array of Artist Ids');
122 | ```
123 | Example:
124 | ```js
125 | Spotify
126 | .getArtists('0oSGxfWSnnOXhD2fKuz2Gy,3dBVyJ7JuOMt4GE9607Qin')
127 | .then(function (data) {
128 | console.log(data);
129 | });
130 | ```
131 |
132 | #### Get an Artist’s Albums
133 | Get Spotify catalog information about an artist’s albums. Optional parameters can be passed in to filter and sort the response.
134 | ```js
135 | Spotify.getArtistAlbums('Artist Id or Spotify Artist URI', options);
136 | ```
137 |
138 | ##### Options Object (Optional)
139 | - album_type - Optional A comma-separated list of keywords that will be used to filter the response. If not supplied, all album types will be returned. Valid values are:
140 | - album
141 | - single
142 | - appears_on
143 | - compilation
144 |
145 | Example: { album_type: 'album,single' }
146 | - country - Optional. An ISO 3166-1 alpha-2 country code. Supply this parameter to limit the response to one particular country. Note if you do not provide this field, you are likely to get duplicate results per album, one for each country in which the album is available!
147 | - limit - The number of album objects to return. Default: 20. Minimum: 1. Maximum: 50. For example: { limit: 2 }
148 | - offset - Optional. The index of the first album to return. Default: 0 (i.e., the first album). Use with limit to get the next set of albums.
149 |
150 |
151 | Example:
152 | ```js
153 | Spotify.getArtistAlbums('1vCWHaC5f2uS3yhpwWbIA6').then(function (data) {
154 | console.log(data);
155 | });
156 | ```
157 |
158 |
159 | #### Get an Artist’s Top Tracks
160 | Get Spotify catalog information about an artist’s top tracks by country.
161 | ```js
162 | Spotify.getArtistTopTracks('Artist Id or Spotify Artist URI', 'Country Code');
163 | ```
164 | - The country: an ISO 3166-1 alpha-2 country code.
165 |
166 |
167 | Example:
168 | ```js
169 | Spotify
170 | .getArtistTopTracks('1vCWHaC5f2uS3yhpwWbIA6', 'AU')
171 | .then(function (data) {
172 | console.log(data);
173 | });
174 | ```
175 |
176 |
177 | #### Get an Artist’s Related Artists
178 | Get Spotify catalog information about artists similar to a given artist. Similarity is based on analysis of the Spotify community’s listening history.
179 | ```js
180 | Spotify.getRelatedArtists('Artist Id or Spotify Artist URI');
181 | ```
182 | Example:
183 | ```js
184 | Spotify.getRelatedArtists('1vCWHaC5f2uS3yhpwWbIA6').then(function (data) {
185 | console.log(data);
186 | });
187 | ```
188 |
189 |
190 | ### Browse
191 | Discover new releases and featured playlists. User needs to be logged in to gain access to these features.
192 |
193 | #### Get the featured playlists
194 | Get a list of Spotify featured playlists
195 | ```js
196 | Spotify.getFeaturedPlaylists(options);
197 | ```
198 | ##### Options Object (Optional)
199 | - locale - string - Optional. The desired language, consisting of a lowercase ISO 639 language code and an uppercase ISO 3166-1 alpha-2 country code, joined by an underscore. For example: es_MX, meaning "Spanish (Mexico)". Provide this parameter if you want the results returned in a particular language (where available).
200 | - country - string - Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
201 | - timestamp - string - Optional. A timestamp in ISO 8601 format: yyyy-MM-ddTHH:mm:ss. Use this parameter to specify the user's local time to get results tailored for that specific date and time in the day. If not provided, the response defaults to the current UTC time. Example: "2014-10-23T09:00:00" for a user whose local time is 9AM.
202 |
203 | Example:
204 | ```js
205 | Spotify
206 | .getFeaturedPlaylists({ locale: "nl_NL", country: "NL" })
207 | .then(function (data) {
208 | console.log(data);
209 | });
210 | ```
211 |
212 | #### Get new releases
213 | Get a list of new album releases featured in Spotify
214 | ```js
215 | Spotify.getNewReleases(options);
216 | ```
217 | ##### Options Object (Optional)
218 | - country - string - Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
219 |
220 | Example:
221 | ```js
222 | Spotify.getNewReleases({ country: "NL" }).then(function (data) {
223 | console.log(data);
224 | });
225 | ```
226 |
227 | #### Get categories
228 | Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab).
229 | ```js
230 | Spotify.getCategories(options);
231 | ```
232 |
233 | ##### Options Object (Optional)
234 | - country - string - Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
235 | - locale - string - Optional. The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. For example: es_MX, meaning "Spanish (Mexico)". Provide this parameter if you want the category metadata returned in a particular language.
236 | - limit - number - Optional. The maximum number of categories to return. Default: 20. Minimum: 1. Maximum: 50.
237 | - offset - number - Optional. The index of the first item to return. Default: 0 (the first object). Use with ```limit``` to get the next set of categories.
238 |
239 | Example:
240 | ```js
241 | Spotify.getCategories({ country: 'SG' }).then(function (data) {
242 | console.log(data);
243 | });
244 | ```
245 |
246 | #### Get category
247 | Get a single category used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab).
248 | ```js
249 | Spotify.getCategory(category_id, options);
250 | ```
251 |
252 | ##### Required
253 | - category_id - The Spotify category ID for the category.
254 |
255 | ##### Options Object (Optional)
256 | - country - string - Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
257 | - locale - string - Optional. The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. For example: es_MX, meaning "Spanish (Mexico)". Provide this parameter if you want the category metadata returned in a particular language.
258 |
259 | Example:
260 | ```js
261 | Spotify.getCategory('party').then(function (data) {
262 | console.log(data);
263 | })
264 | ```
265 |
266 | #### Get category playlists
267 | Get a list of Spotify playlists tagged with a particular category.
268 | ```js
269 | Spotify.getCategoryPlaylists(category_id, options);
270 | ```
271 |
272 | ##### Required
273 | - category_id - The Spotify category ID for the category.
274 |
275 | ##### Options Object (Optional)
276 | - country - string - Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
277 | - limit - number - Optional. The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50.
278 | - offset - number - Optional. The index of the first item to return. Default: 0 (the first object). Use with ```limit``` to get the next set of items.
279 |
280 | Example:
281 | ```js
282 | Spotify.getCategoryPlaylists('party').then(function (data) {
283 | console.log(data);
284 | })
285 | ```
286 |
287 | #### Get Recommendations
288 | Create a playlist-style listening experience based on seed artists, tracks and genres.
289 | ```js
290 | Spotify.getRecommendations(options);
291 | ```
292 |
293 | ##### Options Object
294 | - limit - number - Optional. The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100.
295 | - market - string - Optional. An ISO 3166-1 alpha-2 country code.
296 | - max_* - number - Optional. Multiple values. For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided. See tunable track attributes below for the list of available options. For example, max_instrumentalness=0.35 would filter out most tracks that are likely to be instrumental.
297 | - min_* - number Optional. Multiple values. For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided. See tunable track attributes below for the list of available options. For example, min_tempo=140 would restrict results to only those tracks with a tempo of greater than 140 beats per minute.
298 | - seed_artists - A comma separated list of Spotify IDs for seed artists.
299 | Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres.
300 | - seed_genres - A comma separated list of any genres in the set of available genre seeds.
301 | Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres.
302 | - seed_tracks - A comma separated list of Spotify IDs for a seed track.
303 | Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres.
304 | - target_* - Optional. Multiple values. For each of the tunable track attributes (below) a target value may be provided. Tracks with the attribute values nearest to the target values will be preferred. For example, you might request target_energy=0.6 and target_danceability=0.8. All target values will be weighed equally in ranking results.
305 |
306 | Example:
307 | ```js
308 | Spotify.getRecommendations({ seed_artists: '4NHQUGzhtTLFvgF5SZesLK' }).then(function (data) {
309 | console.log(data);
310 | });
311 | ```
312 |
313 | #### Get Available Genre Seeds
314 | Retrieve a list of available genres seed parameter values for recommendations.
315 | ```js
316 | Spotify.getAvailableGenreSeeds();
317 | ```
318 |
319 | Example:
320 | ```js
321 | Spotify.getAvailableGenreSeeds().then(function (data) {
322 | console.log(data);
323 | });
324 | ```
325 |
326 |
327 | ### Follow
328 | These endpoints allow you manage the list of artists and users that a logged in user follows. Following and unfollowing requires the ```user-follow-modify``` scope. Check if Current User Follows requires the ```user-follow-read``` scope.
329 |
330 | #### Get User’s Followed Artists
331 | Get the current user’s followed artists.
332 |
333 | ```js
334 | Spotify.following('type', options)
335 | ```
336 | - type: Required. currently only ```artist``` is supported.
337 |
338 |
339 | ```js
340 | Spotify.following('artists', { limit: 10 }).then(function (artists) {
341 | console.log(artists);
342 | })
343 | ```
344 |
345 | #### Follow Artists or Users
346 | Add the current user as a follower of one or more artists or other Spotify users.
347 | ```js
348 | Spotify.follow('type', 'ids');
349 | ```
350 | - type: Required. either ```artist``` or ```user```
351 |
352 | Example:
353 | ```js
354 | Spotify.follow('user', 'exampleuser01').then(function () {
355 | // no response from Spotify
356 | });
357 | ```
358 |
359 | #### Unfollow Artists or Users
360 | Remove the current user as a follower of one or more artists or other Spotify users.
361 | ```js
362 | Spotify.unfollow('type', 'ids');
363 | ```
364 | - type: Required. either ```artist``` or ```user```
365 |
366 | Example:
367 | ```js
368 | Spotify.unfollow('user', 'exampleuser01').then(function () {
369 | // no response from Spotify
370 | });
371 | ```
372 |
373 | #### Check if Current User Follows
374 | Check to see if the current user is following one or more artists or other Spotify users.
375 | ```js
376 | Spotify.userFollowingContains('type', 'ids');
377 | ```
378 | - type: Required. either ```artist``` or ```user```
379 | - ids: Required. comma-separated list.
380 |
381 | Example:
382 | ```js
383 | Spotify.userFollowingContains('user', 'exampleuser01').then(function (data) {
384 | console.log(data);
385 | });
386 | ```
387 |
388 | #### Follow a Playlist
389 | Add the current user as a follower of a playlist. Requires ```playlist-modify-public``` or ```playlist-modify-private``` scope to work.
390 | ```js
391 | Spotify.followPlaylist('owner_id', 'playlist_id', isPublic);
392 | ```
393 | - owner_id: The Spotify user ID of the person who owns the playlist.
394 | - playlist_id: The Spotify ID of the playlist. Any playlist can be followed, regardless of its public/private status, as long as you know its playlist ID.
395 | - isPublic: Boolean (Optional), default true. If true the playlist will be included in user's public playlists, if false it will remain private.
396 |
397 | Example:
398 | ```js
399 | Spotify
400 | .followPlaylist('jmperezperez', '2v3iNvBX8Ay1Gt2uXtUKUT', false)
401 | .then(function (data) {
402 | console.log(data);
403 | });
404 | ```
405 |
406 | #### Unfollow a Playlist
407 | Remove the current user as a follower of a playlist. Requires ```playlist-modify-public``` or ```playlist-modify-private``` scope to work.
408 | ```js
409 | Spotify.unfollowPlaylist('owner_id', 'playlist_id', isPublic);
410 | ```
411 | - owner_id: The Spotify user ID of the person who owns the playlist.
412 | - playlist_id: The Spotify ID of the playlist that is to be no longer followed.
413 |
414 | Example:
415 | ```js
416 | Spotify
417 | .unfollowPlaylist('jmperezperez', '2v3iNvBX8Ay1Gt2uXtUKUT')
418 | .then(function (data) {
419 | console.log(data);
420 | });
421 | ```
422 |
423 | #### Check if Users Follow a Playlist
424 | Check to see if one or more Spotify users are following a specified playlist.Following a playlist can be done publicly or privately. Checking if a user publicly follows a playlist doesn't require any scopes; if the user is publicly following the playlist, this endpoint returns true.
425 |
426 | Checking if the user is privately following a playlist is only possible for the current user when that user has granted access to the ```playlist-read-private``` scope.
427 | ```js
428 | Spotify
429 | .playlistFollowingContains('owner_id', 'playlist_id', 'comma separated string or array of user ids');
430 | ```
431 | Example:
432 | ```js
433 | Spotify.playlistFollowingContains('jmperezperez', '2v3iNvBX8Ay1Gt2uXtUKUT', 'possan,elogain').then(function (data) {
434 | console.log(data);
435 | });
436 | ```
437 |
438 |
439 | ### Library *(may have name changes in next version)*
440 | #### Get Current User’s Saved Tracks
441 | Get a list of the songs saved in the current Spotify user’s “Your Music” library. Requires the ```user-library-read``` scope.
442 | ```js
443 | Spotify.getSavedUserTracks(options);
444 | ```
445 | ##### Options Object (Optional)
446 |
447 | - limit - Optional. The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50.
448 | - offset - Optional. The index of the first object to return. Default: 0 (i.e., the first object). Use with limit to get the next set of objects.
449 |
450 | ```js
451 | Spotify.getSavedUserTracks().then(function (data) {
452 | console.log(data);
453 | });
454 | ```
455 |
456 |
457 | #### Check Current User’s Saved Tracks
458 | Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library. Requires the ```user-library-read``` scope.
459 |
460 | ```js
461 | Spotify.userTracksContains('comma separated string or array of spotify track ids');
462 | ```
463 | Example:
464 | ```js
465 | Spotify
466 | .userTracksContains('0udZHhCi7p1YzMlvI4fXoK,3SF5puV5eb6bgRSxBeMOk9')
467 | .then(function (data) {
468 | console.log(data);
469 | });
470 | ```
471 |
472 |
473 | #### Save Tracks for Current User
474 | Save one or more tracks to the current user’s “Your Music” library. Requires the ```user-library-modify``` scope.
475 | ```js
476 | Spotify.saveUserTracks('comma separated string or array of spotify track ids');
477 | ```
478 | Example:
479 | ```js
480 | Spotify
481 | .saveUserTracks('0udZHhCi7p1YzMlvI4fXoK,3SF5puV5eb6bgRSxBeMOk9')
482 | .then(function (data) {
483 | console.log(data);
484 | });
485 | ```
486 |
487 |
488 | #### Remove Tracks for Current User
489 | Remove one or more tracks from the current user’s “Your Music” library. Requires the ```user-library-modify``` scope.
490 | ```js
491 | Spotify.removeUserTracks('comma separated string or array of spotify track ids');
492 | ```
493 | Example:
494 | ```js
495 | Spotify
496 | .removeUserTracks('0udZHhCi7p1YzMlvI4fXoK,3SF5puV5eb6bgRSxBeMOk9')
497 | .then(function (data) {
498 | console.log(data);
499 | });
500 | ```
501 |
502 |
503 | #### Save Albums for Current User
504 | Save one or more albums to the current user’s “Your Music” library. Requires the ```user-library-modify``` scope.
505 | ```js
506 | Spotify.saveUserAlbums('comma separated string or array of spotify album ids');
507 | ```
508 | Example:
509 | ```js
510 | Spotify
511 | .saveUserAlbums('4iV5W9uYEdYUVa79Axb7Rh,1301WleyT98MSxVHPZCA6M')
512 | .then(function (data) {
513 | console.log(data);
514 | });
515 | ```
516 |
517 | #### Get Current User’s Saved Albums
518 | Get a list of the albums saved in the current Spotify user’s “Your Music” library. Requires the ```user-library-read``` scope.
519 | ```js
520 | Spotify.getSavedUserAlbums(options);
521 | ```
522 | ##### Options Object (Optional)
523 |
524 | - limit - Optional. The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50.
525 | - offset - Optional. The index of the first object to return. Default: 0 (i.e., the first object). Use with limit to get the next set of objects.
526 | - market - Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
527 |
528 | ```js
529 | Spotify.getSavedUserAlbums().then(function (data) {
530 | console.log(data);
531 | });
532 | ```
533 |
534 | #### Remove Albums for Current User
535 | Remove one or more albums from the current user’s “Your Music” library. Requires the ```user-library-modify``` scope.
536 | ```js
537 | Spotify.removeUserAlbums('comma separated string or array of spotify album ids');
538 | ```
539 | Example:
540 | ```js
541 | Spotify
542 | .removeUserAlbums('4iV5W9uYEdYUVa79Axb7Rh,1301WleyT98MSxVHPZCA6M')
543 | .then(function (data) {
544 | console.log(data);
545 | });
546 | ```
547 |
548 |
549 | #### Check User’s Saved Albums
550 | Check if one or more albums is already saved in the current Spotify user’s “Your Music” library. Requires the ```user-library-read``` scope.
551 |
552 | ```js
553 | Spotify.userAlbumsContains('comma separated string or array of spotify album ids');
554 | ```
555 | Example:
556 | ```js
557 | Spotify
558 | .userAlbumsContains('4iV5W9uYEdYUVa79Axb7Rh,1301WleyT98MSxVHPZCA6M')
559 | .then(function (data) {
560 | console.log(data);
561 | });
562 | ```
563 |
564 |
565 | ### Personalization
566 | Endpoints for retrieving information about the user’s listening habits.
567 |
568 | #### Get a User’s Top Artists
569 | Get the current user’s top artists based on calculated affinity.
570 | ```js
571 | Spotify.getUserTopArtists(options);
572 | ```
573 |
574 | ##### Options Object (Optional)
575 | - limit - number - Optional. The number of entities to return. Default: 20. Minimum: 1. Maximum: 50.
576 | - offset - number - Optional. The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities.
577 | - time_range - Optional. Over what time frame the affinities are computed. Valid values: long_term (calculated from several years of data and including all new data as it becomes available), medium_term (approximately last 6 months), short_term (approximately last 4 weeks). Default: medium_term.
578 |
579 | Example:
580 | ```js
581 | Spotify.getUserTopArtists({ limit: 50 }).then(function (data) {
582 | console.log(data);
583 | });
584 | ```
585 |
586 | #### Get a User’s Top Tracks
587 | Get the current user’s top tracks based on calculated affinity.
588 | ```js
589 | Spotify.getUserTopTracks(options);
590 | ```
591 |
592 | ##### Options Object (Optional)
593 | - limit - number - Optional. The number of entities to return. Default: 20. Minimum: 1. Maximum: 50.
594 | - offset - number - Optional. The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities.
595 | - time_range - Optional. Over what time frame the affinities are computed. Valid values: long_term (calculated from several years of data and including all new data as it becomes available), medium_term (approximately last 6 months), short_term (approximately last 4 weeks). Default: medium_term.
596 |
597 | Example:
598 | ```js
599 | Spotify.getUserTopTracks({ limit: 50 }).then(function (data) {
600 | console.log(data);
601 | });
602 | ```
603 |
604 |
605 | ### Playlists
606 | User needs to be logged in to gain access to playlists
607 |
608 | #### Get a List of a User’s Playlists
609 | Get a list of the playlists owned by a Spotify user. Requires the ```playlist-read-private``` scope
610 | ```js
611 | Spotify.getUserPlaylists('user_id', options);
612 | ```
613 | ##### Options Object (Optional)
614 | - limit - Optional. The maximum number of playlists to return. Default: 20. Minimum: 1. Maximum: 50.
615 | - offset - Optional. The index of the first playlist to return. Default: 0 (the first object). Use with limit to get the next set of playlists.
616 |
617 | Example:
618 | ```js
619 | Spotify.getUserPlaylists('wizzler').then(function (data) {
620 | console.log(data);
621 | });
622 | ```
623 |
624 |
625 | #### Get a Playlist
626 | Get a playlist owned by a Spotify user.
627 | ```js
628 | Spotify.getPlaylist('user_id', 'playlist_id', options);
629 | ```
630 | ##### Options Object (Optional)
631 | - fields - Optional. Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are returned. Sub-fields can be excluded by prefixing them with an exclamation mark. [More Info](https://developer.spotify.com/web-api/get-playlist/)
632 |
633 | ```js
634 | Spotify
635 | .getPlaylist('1176458919', '6Df19VKaShrdWrAnHinwVO')
636 | .then(function (data) {
637 | console.log(data);
638 | });
639 | ```
640 |
641 |
642 | #### Get a Playlist’s Tracks
643 | Get full details of the tracks of a playlist owned by a Spotify user. Requires the ```playlist-read-private``` scope.
644 | ```js
645 | Spotify.getPlaylistTracks('user_id', 'playlist_id', options);
646 | ```
647 | Example:
648 | ```js
649 | Spotify
650 | .getPlaylistTracks('1176458919', '6Df19VKaShrdWrAnHinwVO')
651 | .then(function (data) {
652 | console.log(data);
653 | });
654 | ```
655 |
656 | #### Create a Playlist
657 | Create a playlist for a Spotify user. (The playlist will be empty until you add tracks.) Creating a public playlist requires the ```playlist-modify-public``` scope. Creating a private playlist requires the ```playlist-modify-private``` scope.
658 | ```js
659 | Spotify.createPlaylist('user_id', options);
660 | ```
661 | ##### Options Object
662 | - name - string - Required. The name for the new playlist, for example "Your Coolest Playlist". This name does not need to be unique; a user may have several playlists with the same name.
663 | - public - boolean - Optional, default true. If true the playlist will be public, if false it will be private. To be able to create private playlists, the user must have granted the playlist-modify-private scope.
664 |
665 |
666 | Example:
667 | ```js
668 | Spotify
669 | .createPlaylist('1176458919', { name: 'Awesome Mix Vol. 1' })
670 | .then(function (data) {
671 | console.log('playlist created');
672 | });
673 | ```
674 |
675 |
676 | #### Add Tracks to a Playlist
677 | Add one or more tracks to a user’s playlist. Adding tracks to a public playlist requires the ```playlist-modify-public``` scope. Adding tracks to a private playlist requires the ```playlist-modify-private``` scope.
678 | ```js
679 | Spotify.addPlaylistTracks('user_id', 'playlist_id', 'comma separated string or array of spotify track uris');
680 | ```
681 | ##### Options Object (Optional)
682 | - position - integer - Optional. The position to insert the tracks, a zero-based index. For example, to insert the tracks in the first position: position=0; to insert the tracks in the third position: position=2. If omitted, the tracks will be appended to the playlist. Tracks are added in the order they are listed in the query string or request body.
683 |
684 |
685 | Example:
686 | ```js
687 | Spotify
688 | .addPlaylistTracks('1176458919', '2TkWjGCu8jurholsfdWtG4', 'spotify:track:4iV5W9uYEdYUVa79Axb7Rh, spotify:track:1301WleyT98MSxVHPZCA6M')
689 | .then(function (data) {
690 | console.log('tracks added to playlist');
691 | });
692 | ```
693 |
694 |
695 | #### Remove Tracks from a Playlist
696 | Remove one or more tracks from a user’s playlist. Removing tracks from a public playlist requires the ```playlist-modify-public``` scope. Removing tracks from a private playlist requires the ```playlist-modify-private``` scope.
697 | ```js
698 | Spotify.removePlaylistTracks('user_id', 'playlist_id', 'comma separated string or array of spotify track ids or uris');
699 | ```
700 | Example:
701 | ```js
702 | Spotify
703 | .removePlaylistTracks('1176458919', '2TkWjGCu8jurholsfdWtG4', 'spotify:track:4iV5W9uYEdYUVa79Axb7Rh, spotify:track:1301WleyT98MSxVHPZCA6M')
704 | .then(function (data) {
705 | console.log('tracks removed from playlist');
706 | });
707 | ```
708 |
709 | #### Reorder a Playlist's Tracks
710 | Reorder a track or a group of tracks in a playlist.
711 | ```js
712 | Spotify.reorderPlaylistTracks('user_id', 'playlist_id', options);
713 | ```
714 | ##### Options Object (Required)
715 | - range_start - integer - Required. The position of the first track to be reordered.
716 | - range_length - integer - Optional. The amount of tracks to be reordered. Defaults to 1 if not set.
717 | - insert_before - integer - Required. The position where the tracks should be inserted.
718 | - snapshot_id - string - Optional. The playlist's snapshot ID against which you want to make the changes.
719 |
720 |
721 | Example:
722 | ```js
723 | Spotify.reorderPlaylistTracks('1176458919', '2TkWjGCu8jurholsfdWtG4', {
724 | range_start: 8,
725 | range_length: 5,
726 | insert_before: 0
727 | }).then(function (data) {
728 | console.log(data);
729 | });
730 | ```
731 |
732 |
733 | #### Replace a Playlist’s Tracks
734 | Replace all the tracks in a playlist, overwriting its existing tracks. This powerful request can be useful for replacing tracks, re-ordering existing tracks, or clearing the playlist. Replacing tracks in a public playlist requires the ```playlist-modify-public``` scope. Replacing tracks in a private playlist requires the ```playlist-modify-private``` scope.
735 | ```js
736 | Spotify.replacePlaylistTracks('user_id', 'playlist_id', 'comma separated string or array of spotify track ids or uris');
737 | ```
738 | Example:
739 | ```js
740 | Spotify
741 | .replacePlaylistTracks('1176458919', '2TkWjGCu8jurholsfdWtG4', 'spotify:track:4iV5W9uYEdYUVa79Axb7Rh, spotify:track:1301WleyT98MSxVHPZCA6M')
742 | .then(function (data) {
743 | console.log('tracks removed from playlist');
744 | });
745 | ```
746 |
747 |
748 | #### Change a Playlist’s Details
749 | Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) Changing a public playlist requires the ```playlist-modify-public``` scope. Changing a private playlist requires the ```playlist-modify-private``` scope.
750 | ```js
751 | Spotify.updatePlaylistDetails('user_id', 'playlist_id', options);
752 | ```
753 | ##### Options Object (Optional)
754 | - name - string - Optional. The new name for the playlist, for example "My New Playlist Title".
755 | - public - Boolean - Optional. If true the playlist will be public, if false it will be private.
756 |
757 |
758 | Example:
759 | ```js
760 | Spotify
761 | .updatePlaylistDetails('1176458919', '2TkWjGCu8jurholsfdWtG4', { name: 'Updated Playlist Title' })
762 | .then(function (data) {
763 | console.log('Updated playlist details');
764 | });
765 | ```
766 |
767 |
768 | ### User Profiles
769 | User needs to be logged in to gain access to user profiles
770 |
771 | #### Get a User’s Profile
772 | Get public profile information about a Spotify user.
773 | ```js
774 | Spotify.getUser('user_id');
775 | ```
776 | Example:
777 | ```js
778 | Spotify.getUser('wizzler').then(function (data) {
779 | console.log(data);
780 | });
781 | ```
782 |
783 |
784 | #### Get Current User’s Profile
785 | Get detailed profile information about the current user (including the current user’s username).
786 | ```js
787 | Spotify.getCurrentUser();
788 | ```
789 | Example:
790 | ```js
791 | Spotify.getCurrentUser().then(function (data) {
792 | console.log(data);
793 | });
794 | ```
795 |
796 |
797 | ### Search
798 | #### Search for an Item
799 | Get Spotify catalog information about artists, albums, or tracks that match a keyword string.
800 | ```js
801 | Spotify.search('Search Query', 'type', options);
802 | ```
803 | - type - Required. A comma-separated list of item types to search across. Valid types are: album, artist, playlist, and track.
804 |
805 | ##### Options Object (Optional)
806 | - limit - Optional. The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50.
807 | - offset - Optional. The index of the first object to return. Default: 0 (i.e., the first object). Use with limit to get the next set of objects.
808 |
809 |
810 | Example:
811 | ```js
812 | Spotify.search('Nirvana', 'artist').then(function (data) {
813 | console.log(data);
814 | });
815 | ```
816 |
817 |
818 | ### Tracks
819 | #### Get a Track
820 | Get Spotify catalog information for a single track identified by its unique Spotify ID or Spotify URI.
821 | ```js
822 | Spotify.getTrack('Track Id or Spotify Track URI');
823 | ```
824 | Example:
825 | ```js
826 | Spotify.getTrack('0eGsygTp906u18L0Oimnem').then(function (data) {
827 | console.log(data);
828 | });
829 | ```
830 |
831 | #### Get Several Tracks
832 | Get Spotify catalog information for multiple tracks based on their Spotify IDs.
833 | ```js
834 | Spotify.getTracks('Comma separated list or array of Track Ids');
835 | ```
836 | Example:
837 | ```js
838 | Spotify.getTracks('0eGsygTp906u18L0Oimnem,1lDWb6b6ieDQ2xT7ewTC3G').then(function (data) {
839 | console.log(data);
840 | });
841 | ```
842 |
843 | #### Get Audio Features for a Track
844 | Get audio feature information for a single track identified by its unique Spotify ID.
845 |
846 | ```js
847 | Spotify.getTrackAudioFeatures('Track Id or Spotify Track URI');
848 | ```
849 | Example:
850 | ```js
851 | Spotify.getTrackAudioFeatures('0eGsygTp906u18L0Oimnem').then(function (data) {
852 | console.log(data);
853 | });
854 | ```
855 |
856 | #### Get Audio Features for Several Tracks
857 | Get audio features for multiple tracks based on their Spotify IDs.
858 |
859 | ```js
860 | Spotify.getTracksAudioFeatures('Comma separated list or array of Track Ids');
861 | ```
862 | Example:
863 | ```js
864 | Spotify.getTracksAudioFeatures('0eGsygTp906u18L0Oimnem,1lDWb6b6ieDQ2xT7ewTC3G').then(function (data) {
865 | console.log(data);
866 | });
867 | ```
868 |
869 | ### Authentication
870 | #### Login
871 | Will open login window. Requires user to initiate as it will open a pop up window.
872 | Requires client id, callback uri and scope to be set in config.
873 | ```js
874 | Spotify.login();
875 | ```
876 |
877 | Example:
878 | ```js
879 | $scope.login = function () {
880 | Spotify.login();
881 | };
882 | ```
883 |
884 | #### Example callback html
885 | ```html
886 |
887 |
888 |
889 |
890 |
891 |
892 |
905 |
906 |
907 |
908 |
909 |
910 | ```
911 |
912 |
913 | [](https://bitdeli.com/free "Bitdeli Badge")
914 |
--------------------------------------------------------------------------------