diff --git a/angular-dynamic-locale/angular-dynamic-locale.d.ts b/angular-dynamic-locale/angular-dynamic-locale.d.ts index a30df1d7ed..e404e95328 100644 --- a/angular-dynamic-locale/angular-dynamic-locale.d.ts +++ b/angular-dynamic-locale/angular-dynamic-locale.d.ts @@ -5,6 +5,11 @@ /// +declare module "angular-dynamic-locale" { + import ng = angular.dynamicLocale; + export = ng; +} + declare module angular.dynamicLocale { interface tmhDynamicLocaleService { diff --git a/angularjs/angular.d.ts b/angularjs/angular.d.ts index c5ebeaa92f..14ccdbf043 100644 --- a/angularjs/angular.d.ts +++ b/angularjs/angular.d.ts @@ -1632,7 +1632,6 @@ declare module angular { // see http://angularjs.blogspot.com.br/2015/11/angularjs-15-beta2-and-14-releases.html // and http://toddmotto.com/exploring-the-angular-1-5-component-method/ /////////////////////////////////////////////////////////////////////////// - /** * Runtime representation a type that a Component or other object is instances of. * @@ -1728,6 +1727,10 @@ declare module angular { $routeConfig?: RouteDefinition[]; } + interface IComponentTemplateFn { + ( $element?: IAugmentedJQuery, $attrs?: IAttributes ): string; + } + /////////////////////////////////////////////////////////////////////////// // Directive // see http://docs.angularjs.org/api/ng.$compileProvider#directive diff --git a/backbone/backbone-global.d.ts b/backbone/backbone-global.d.ts index 764aa83d75..c16e1a59e3 100644 --- a/backbone/backbone-global.d.ts +++ b/backbone/backbone-global.d.ts @@ -43,6 +43,7 @@ declare module Backbone { interface PersistenceOptions { url?: string; + data?: any; beforeSend?: (jqxhr: JQueryXHR) => void; success?: (modelOrCollection?: any, response?: any, options?: any) => void; error?: (modelOrCollection?: any, jqxhr?: JQueryXHR, options?: any) => void; diff --git a/bcrypt-nodejs/bcrypt-nodejs-tests.ts b/bcrypt-nodejs/bcrypt-nodejs-tests.ts new file mode 100644 index 0000000000..2a151c1c7e --- /dev/null +++ b/bcrypt-nodejs/bcrypt-nodejs-tests.ts @@ -0,0 +1,30 @@ +/// + +import bCrypt = require("bcrypt-nodejs"); + +function test_sync() { + var salt1 = bCrypt.genSaltSync(); + var salt2 = bCrypt.genSaltSync(8); + + var hash1 = bCrypt.hashSync('super secret'); + var hash2 = bCrypt.hashSync('super secret', salt1); + + var compare1 = bCrypt.compareSync('super secret', hash1); + + var rounds1 = bCrypt.getRounds(hash2); +} + +function test_async() { + var cbString = (error: Error, result: string) => {}; + var cbVoid = () => {}; + var cbBoolean = (error: Error, result: boolean) => {}; + + bCrypt.genSalt(8, cbString); + + var salt = bCrypt.genSaltSync(); + bCrypt.hash('super secret', salt, cbString); + bCrypt.hash('super secret', salt, cbVoid, cbString); + + var hash = bCrypt.hashSync('super secret'); + bCrypt.compare('super secret', hash, cbBoolean); +} \ No newline at end of file diff --git a/bcrypt-nodejs/bcrypt-nodejs.d.ts b/bcrypt-nodejs/bcrypt-nodejs.d.ts new file mode 100644 index 0000000000..32b735d68f --- /dev/null +++ b/bcrypt-nodejs/bcrypt-nodejs.d.ts @@ -0,0 +1,68 @@ +// Type definitions for bcrypt-nodejs +// Project: https://github.com/shaneGirish/bcrypt-nodejs +// Definitions by: David Broder-Rodgers +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module "bcrypt-nodejs" { + /** + * Generate a salt synchronously + * @param rounds Number of rounds to process the data for (default - 10) + * @return Generated salt + */ + export function genSaltSync(rounds?: number): string; + + /** + * Generate a salt asynchronously + * @param rounds Number of rounds to process the data for (default - 10) + * @param callback Callback with error and resulting salt, to be fired once the salt has been generated + */ + export function genSalt(rounds: number, callback: (error: Error, result: string) => void): void; + + /** + * Generate a hash synchronously + * @param data Data to be encrypted + * @param salt Salt to be used in encryption (default - new salt generated with 10 rounds) + * @return Generated hash + */ + export function hashSync(data: string, salt?: string): string; + + /** + * Generate a hash asynchronously + * @param data Data to be encrypted + * @param salt Salt to be used in encryption + * @param callback Callback with error and hashed result, to be fired once the data has been encrypted + */ + export function hash(data: string, salt: string, callback: (error: Error, result: string) => void): void; + + /** + * Generate a hash asynchronously + * @param data Data to be encrypted + * @param salt Salt to be used in encryption + * @param progressCallback Callback to be fired multiple times during the hash calculation to signify progress + * @param callback Callback with error and hashed result, to be fired once the data has been encrypted + */ + export function hash(data: string, salt: string, progressCallback: () => void, callback: (error: Error, result: string) => void): void; + + /** + * Compares data with a hash synchronously + * @param data Data to be compared + * @param hash Hash to be compared to + * @return true if matching, false otherwise + */ + export function compareSync(data: string, hash: string): boolean; + + /** + * Compares data with a hash asynchronously + * @param data Data to be compared + * @param hash Hash to be compared to + * @param callback Callback with error and match result, to be fired once the data has been compared + */ + export function compare(data: string, hash: string, callback: (error: Error, result: boolean) => void): void; + + /** + * Get number of rounds used for hash + * @param hash Hash from which the number of rounds used should be extracted + * @return number of rounds used to encrypt a given hash + */ + export function getRounds(hash: string): number; +} diff --git a/bezier-easing/bezier-easing-tests.ts b/bezier-easing/bezier-easing-tests.ts new file mode 100644 index 0000000000..eab1fb4f15 --- /dev/null +++ b/bezier-easing/bezier-easing-tests.ts @@ -0,0 +1,21 @@ +/// + +function test_create_from_array() { + let easing: BezierEasing = BezierEasing([0, 0, 1, 0.5]); +} + +function test_create_from_params() { + let easing: BezierEasing = BezierEasing(0, 0, 1, 0.5); +} + +function test_create_from_builtins() { + let easing: BezierEasing = BezierEasing.css['ease-in']; +} + +function test_methods() { + let easing: BezierEasing = BezierEasing.css['ease-in']; + let easedRatio: number = easing.get(0.5); + let points: Array = easing.getPoints(); + let stringified: string = easing.toString(); + let asCSS: string = easing.toCSS(); +} diff --git a/bezier-easing/bezier-easing.d.ts b/bezier-easing/bezier-easing.d.ts new file mode 100644 index 0000000000..695368e7af --- /dev/null +++ b/bezier-easing/bezier-easing.d.ts @@ -0,0 +1,24 @@ +// Type definitions for bezier-easing +// Project: https://github.com/gre/bezier-easing +// Definitions by: brian ridley +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare interface BezierEasing { + get(ratio: number): number; + getPoints(): Array; + toString(): string; + toCSS(): string; +} + +declare function BezierEasing(points: Array): BezierEasing; +declare function BezierEasing(a: number, b: number, c: number, d: number): BezierEasing; + +declare namespace BezierEasing { + let css: { + 'ease': BezierEasing, + 'linear': BezierEasing, + 'ease-in': BezierEasing, + 'ease-out': BezierEasing, + 'ease-in-out': BezierEasing + }; +} diff --git a/bluebird/bluebird-tests.ts b/bluebird/bluebird-tests.ts index 5f96d28efc..278b1d2297 100644 --- a/bluebird/bluebird-tests.ts +++ b/bluebird/bluebird-tests.ts @@ -85,15 +85,15 @@ var bazProm: Promise; // - - - - - - - - - - - - - - - - - -var numThen: Promise.Thenable; -var strThen: Promise.Thenable; -var anyThen: Promise.Thenable; -var boolThen: Promise.Thenable; -var objThen: Promise.Thenable; -var voidThen: Promise.Thenable; +var numThen: PromiseLike; +var strThen: PromiseLike; +var anyThen: PromiseLike; +var boolThen: PromiseLike; +var objThen: PromiseLike; +var voidThen: PromiseLike; -var fooThen: Promise.Thenable; -var barThen: Promise.Thenable; +var fooThen: PromiseLike; +var barThen: PromiseLike; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -106,12 +106,12 @@ var barArrProm: Promise; // - - - - - - - - - - - - - - - - - -var numArrThen: Promise.Thenable; -var strArrThen: Promise.Thenable; -var anyArrThen: Promise.Thenable; +var numArrThen: PromiseLike; +var strArrThen: PromiseLike; +var anyArrThen: PromiseLike; -var fooArrThen: Promise.Thenable; -var barArrThen: Promise.Thenable; +var fooArrThen: PromiseLike; +var barArrThen: PromiseLike; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -124,18 +124,18 @@ var barPromArr: Promise[]; // - - - - - - - - - - - - - - - - - -var numThenArr: Promise.Thenable[]; -var strThenArr: Promise.Thenable[]; -var anyThenArr: Promise.Thenable[]; +var numThenArr: PromiseLike[]; +var strThenArr: PromiseLike[]; +var anyThenArr: PromiseLike[]; -var fooThenArr: Promise.Thenable[]; -var barThenArr: Promise.Thenable[]; +var fooThenArr: PromiseLike[]; +var barThenArr: PromiseLike[]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // booya! -var fooThenArrThen: Promise.Thenable[]>; -var barThenArrThen: Promise.Thenable[]>; +var fooThenArrThen: PromiseLike[]>; +var barThenArrThen: PromiseLike[]>; var fooResolver: Promise.Resolver; var barResolver: Promise.Resolver; diff --git a/bluebird/bluebird.d.ts b/bluebird/bluebird.d.ts index 3d205f2ed7..ea8bebe0c2 100644 --- a/bluebird/bluebird.d.ts +++ b/bluebird/bluebird.d.ts @@ -1,6 +1,6 @@ // Type definitions for bluebird 2.0.0 // Project: https://github.com/petkaantonov/bluebird -// Definitions by: Bart van der Schoor +// Definitions by: Bart van der Schoor , falsandtru // Definitions: https://github.com/borisyankov/DefinitelyTyped // ES6 model with generics overload was sourced and trans-multiplied from es6-promises.d.ts @@ -16,762 +16,766 @@ // TODO verify support to have no return statement in handlers to get a Promise (more overloads?) -declare class Promise implements Promise.Thenable, Promise.Inspection { - /** - * Create a new promise. The passed in function will receive functions `resolve` and `reject` as its arguments which can be called to seal the fate of the created promise. - */ - constructor(callback: (resolve: (thenableOrResult?: R | Promise.Thenable) => void, reject: (error: any) => void) => void); - - /** - * Promises/A+ `.then()` with progress handler. Returns a new promise chained from this promise. The new promise will be rejected or resolved dedefer on the passed `fulfilledHandler`, `rejectedHandler` and the state of this promise. - */ - then(onFulfill: (value: R) => U|Promise.Thenable, onReject?: (error: any) => U|Promise.Thenable, onProgress?: (note: any) => any): Promise; - then(onFulfill: (value: R) => U|Promise.Thenable, onReject?: (error: any) => void|Promise.Thenable, onProgress?: (note: any) => any): Promise; - - /** - * This is a catch-all exception handler, shortcut for calling `.then(null, handler)` on this promise. Any exception happening in a `.then`-chain will propagate to nearest `.catch` handler. - * - * Alias `.caught();` for compatibility with earlier ECMAScript version. - */ - catch(onReject?: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - caught(onReject?: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - - catch(onReject?: (error: any) => U|Promise.Thenable): Promise; - caught(onReject?: (error: any) => U|Promise.Thenable): Promise; - - /** - * This extends `.catch` to work more like catch-clauses in languages like Java or C#. Instead of manually checking `instanceof` or `.name === "SomeError"`, you may specify a number of error constructors which are eligible for this catch handler. The catch handler that is first met that has eligible constructors specified, is the one that will be called. - * - * This method also supports predicate-based filters. If you pass a predicate function instead of an error constructor, the predicate will receive the error as an argument. The return result of the predicate will be used determine whether the error handler should be called. - * - * Alias `.caught();` for compatibility with earlier ECMAScript version. - */ - catch(predicate: (error: any) => boolean, onReject: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - caught(predicate: (error: any) => boolean, onReject: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - - catch(predicate: (error: any) => boolean, onReject: (error: any) => U|Promise.Thenable): Promise; - caught(predicate: (error: any) => boolean, onReject: (error: any) => U|Promise.Thenable): Promise; - - catch(ErrorClass: Function, onReject: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - caught(ErrorClass: Function, onReject: (error: any) => R|Promise.Thenable|void|Promise.Thenable): Promise; - - catch(ErrorClass: Function, onReject: (error: any) => U|Promise.Thenable): Promise; - caught(ErrorClass: Function, onReject: (error: any) => U|Promise.Thenable): Promise; - - - /** - * Like `.catch` but instead of catching all types of exceptions, it only catches those that don't originate from thrown errors but rather from explicit rejections. - */ - error(onReject: (reason: any) => Promise.Thenable): Promise; - error(onReject: (reason: any) => U): Promise; - - /** - * Pass a handler that will be called regardless of this promise's fate. Returns a new promise chained from this promise. There are special semantics for `.finally()` in that the final value cannot be modified from the handler. - * - * Alias `.lastly();` for compatibility with earlier ECMAScript version. - */ - finally(handler: () => Promise.Thenable): Promise; - finally(handler: () => U): Promise; - - lastly(handler: () => Promise.Thenable): Promise; - lastly(handler: () => U): Promise; - - /** - * Create a promise that follows this promise, but is bound to the given `thisArg` value. A bound promise will call its handlers with the bound value set to `this`. Additionally promises derived from a bound promise will also be bound promises with the same `thisArg` binding as the original promise. - */ - bind(thisArg: any): Promise; - - /** - * Like `.then()`, but any unhandled rejection that ends up here will be thrown as an error. - */ - done(onFulfilled: (value: R) => Promise.Thenable, onRejected: (error: any) => Promise.Thenable, onProgress?: (note: any) => any): void; - done(onFulfilled: (value: R) => Promise.Thenable, onRejected?: (error: any) => U, onProgress?: (note: any) => any): void; - done(onFulfilled: (value: R) => U, onRejected: (error: any) => Promise.Thenable, onProgress?: (note: any) => any): void; - done(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U, onProgress?: (note: any) => any): void; - - /** - * Like `.finally()`, but not called for rejections. - */ - tap(onFulFill: (value: R) => Promise.Thenable): Promise; - tap(onFulfill: (value: R) => U): Promise; - - /** - * Shorthand for `.then(null, null, handler);`. Attach a progress handler that will be called if this promise is progressed. Returns a new promise chained from this promise. - */ - progressed(handler: (note: any) => any): Promise; - - /** - * Same as calling `Promise.delay(this, ms)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - delay(ms: number): Promise; - - /** - * Returns a promise that will be fulfilled with this promise's fulfillment value or rejection reason. However, if this promise is not fulfilled or rejected within `ms` milliseconds, the returned promise is rejected with a `Promise.TimeoutError` instance. - * - * You may specify a custom error message with the `message` parameter. - */ - timeout(ms: number, message?: string): Promise; - - /** - * Register a node-style callback on this promise. When this promise is is either fulfilled or rejected, the node callback will be called back with the node.js convention where error reason is the first argument and success value is the second argument. The error argument will be `null` in case of success. - * Returns back this promise instead of creating a new one. If the `callback` argument is not a function, this method does not do anything. - */ - nodeify(callback: (err: any, value?: R) => void, options?: Promise.SpreadOption): Promise; - nodeify(...sink: any[]): Promise; - - /** - * Marks this promise as cancellable. Promises by default are not cancellable after v0.11 and must be marked as such for `.cancel()` to have any effect. Marking a promise as cancellable is infectious and you don't need to remark any descendant promise. - */ - cancellable(): Promise; - - /** - * Cancel this promise. The cancellation will propagate to farthest cancellable ancestor promise which is still pending. - * - * That ancestor will then be rejected with a `CancellationError` (get a reference from `Promise.CancellationError`) object as the rejection reason. - * - * In a promise rejection handler you may check for a cancellation by seeing if the reason object has `.name === "Cancel"`. - * - * Promises are by default not cancellable. Use `.cancellable()` to mark a promise as cancellable. - */ - // TODO what to do with this? - cancel(reason?: any): Promise; - - /** - * Like `.then()`, but cancellation of the the returned promise or any of its descendant will not propagate cancellation to this promise or this promise's ancestors. - */ - fork(onFulfilled: (value: R) => Promise.Thenable, onRejected: (error: any) => Promise.Thenable, onProgress?: (note: any) => any): Promise; - fork(onFulfilled: (value: R) => Promise.Thenable, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; - fork(onFulfilled: (value: R) => U, onRejected: (error: any) => Promise.Thenable, onProgress?: (note: any) => any): Promise; - fork(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; - - /** - * Create an uncancellable promise based on this promise. - */ - uncancellable(): Promise; - - /** - * See if this promise can be cancelled. - */ - isCancellable(): boolean; - - /** - * See if this `promise` has been fulfilled. - */ - isFulfilled(): boolean; - - /** - * See if this `promise` has been rejected. - */ - isRejected(): boolean; - - /** - * See if this `promise` is still defer. - */ - isPending(): boolean; - - /** - * See if this `promise` is resolved -> either fulfilled or rejected. - */ - isResolved(): boolean; - - /** - * Get the fulfillment value of the underlying promise. Throws if the promise isn't fulfilled yet. - * - * throws `TypeError` - */ - value(): R; - - /** - * Get the rejection reason for the underlying promise. Throws if the promise isn't rejected yet. - * - * throws `TypeError` - */ - reason(): any; - - /** - * Synchronously inspect the state of this `promise`. The `PromiseInspection` will represent the state of the promise as snapshotted at the time of calling `.inspect()`. - */ - inspect(): Promise.Inspection; - - /** - * This is a convenience method for doing: - * - * - * promise.then(function(obj){ - * return obj[propertyName].call(obj, arg...); - * }); - * - */ - call(propertyName: string, ...args: any[]): Promise; - - /** - * This is a convenience method for doing: - * - * - * promise.then(function(obj){ - * return obj[propertyName]; - * }); - * - */ - // TODO find way to fix get() - // get(propertyName: string): Promise; - - /** - * Convenience method for: - * - * - * .then(function() { - * return value; - * }); - * - * - * in the case where `value` doesn't change its value. That means `value` is bound at the time of calling `.return()` - * - * Alias `.thenReturn();` for compatibility with earlier ECMAScript version. - */ - return(): Promise; - thenReturn(): Promise; - return(value: U): Promise; - thenReturn(value: U): Promise; - - /** - * Convenience method for: - * - * - * .then(function() { - * throw reason; - * }); - * - * Same limitations apply as with `.return()`. - * - * Alias `.thenThrow();` for compatibility with earlier ECMAScript version. - */ - throw(reason: Error): Promise; - thenThrow(reason: Error): Promise; - - /** - * Convert to String. - */ - toString(): string; - - /** - * This is implicitly called by `JSON.stringify` when serializing the object. Returns a serialized representation of the `Promise`. - */ - toJSON(): Object; - - /** - * Like calling `.then`, but the fulfillment value or rejection reason is assumed to be an array, which is flattened to the formal parameters of the handlers. - */ - // TODO how to model instance.spread()? like Q? - spread(onFulfill: Function, onReject?: (reason: any) => Promise.Thenable): Promise; - spread(onFulfill: Function, onReject?: (reason: any) => U): Promise; - /* - // TODO or something like this? - spread(onFulfill: (...values: W[]) => Promise.Thenable, onReject?: (reason: any) => Promise.Thenable): Promise; - spread(onFulfill: (...values: W[]) => Promise.Thenable, onReject?: (reason: any) => U): Promise; - spread(onFulfill: (...values: W[]) => U, onReject?: (reason: any) => Promise.Thenable): Promise; - spread(onFulfill: (...values: W[]) => U, onReject?: (reason: any) => U): Promise; - */ - /** - * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - all(): Promise; - - /** - * Same as calling `Promise.props(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO how to model instance.props()? - props(): Promise; - - /** - * Same as calling `Promise.settle(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - settle(): Promise[]>; - - /** - * Same as calling `Promise.any(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - any(): Promise; - - /** - * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - some(count: number): Promise; - - /** - * Same as calling `Promise.race(thisPromise, count)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - race(): Promise; - - /** - * Same as calling `Promise.map(thisPromise, mapper)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - map(mapper: (item: Q, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - map(mapper: (item: Q, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; - - /** - * Same as `Promise.mapSeries(thisPromise, mapper)`. - */ - // TODO type inference from array-resolving promise? - mapSeries(mapper: (item: Q, index: number, arrayLength: number) => U|Promise.Thenable): Promise; - - /** - * Same as calling `Promise.reduce(thisPromise, Function reducer, initialValue)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - reduce(reducer: (memo: U, item: Q, index: number, arrayLength: number) => Promise.Thenable, initialValue?: U): Promise; - reduce(reducer: (memo: U, item: Q, index: number, arrayLength: number) => U, initialValue?: U): Promise; - - /** - * Same as calling ``Promise.filter(thisPromise, filterer)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - // TODO type inference from array-resolving promise? - filter(filterer: (item: U, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - filter(filterer: (item: U, index: number, arrayLength: number) => boolean, options?: Promise.ConcurrencyOption): Promise; - - /** - * Same as calling ``Promise.each(thisPromise, iterator)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. - */ - each(iterator: (item: R, index: number, arrayLength: number) => U | Promise.Thenable): Promise; - - /** - * Start the chain of promises with `Promise.try`. Any synchronous exceptions will be turned into rejections on the returned promise. - * - * Note about second argument: if it's specifically a true array, its values become respective arguments for the function call. Otherwise it is passed as is as the first argument for the function call. - * - * Alias for `attempt();` for compatibility with earlier ECMAScript version. - */ - static try(fn: () => Promise.Thenable, args?: any[], ctx?: any): Promise; - static try(fn: () => R, args?: any[], ctx?: any): Promise; - - static attempt(fn: () => Promise.Thenable, args?: any[], ctx?: any): Promise; - static attempt(fn: () => R, args?: any[], ctx?: any): Promise; - - /** - * Returns a new function that wraps the given function `fn`. The new function will always return a promise that is fulfilled with the original functions return values or rejected with thrown exceptions from the original function. - * This method is convenient when a function can sometimes return synchronously or throw synchronously. - */ - static method(fn: Function): Function; - - /** - * Create a promise that is resolved with the given `value`. If `value` is a thenable or promise, the returned promise will assume its state. - */ - static resolve(): Promise; - static resolve(value: Promise.Thenable): Promise; - static resolve(value: R): Promise; - - /** - * Create a promise that is rejected with the given `reason`. - */ - static reject(reason: any): Promise; - static reject(reason: any): Promise; - - /** - * Create a promise with undecided fate and return a `PromiseResolver` to control it. See resolution?: Promise(#promise-resolution). - */ - static defer(): Promise.Resolver; - - /** - * Cast the given `value` to a trusted promise. If `value` is already a trusted `Promise`, it is returned as is. If `value` is not a thenable, a fulfilled is: Promise returned with `value` as its fulfillment value. If `value` is a thenable (Promise-like object, like those returned by jQuery's `$.ajax`), returns a trusted that: Promise assimilates the state of the thenable. - */ - static cast(value: Promise.Thenable): Promise; - static cast(value: R): Promise; - - /** - * Sugar for `Promise.resolve(undefined).bind(thisArg);`. See `.bind()`. - */ - static bind(thisArg: any): Promise; - - /** - * See if `value` is a trusted Promise. - */ - static is(value: any): boolean; - - /** - * Call this right after the library is loaded to enabled long stack traces. Long stack traces cannot be disabled after being enabled, and cannot be enabled after promises have alread been created. Long stack traces imply a substantial performance penalty, around 4-5x for throughput and 0.5x for latency. - */ - static longStackTraces(): void; - - /** - * Returns a promise that will be fulfilled with `value` (or `undefined`) after given `ms` milliseconds. If `value` is a promise, the delay will start counting down when it is fulfilled and the returned promise will be fulfilled with the fulfillment value of the `value` promise. - */ - // TODO enable more overloads - static delay(value: Promise.Thenable, ms: number): Promise; - static delay(value: R, ms: number): Promise; - static delay(ms: number): Promise; - - /** - * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument. - * - * If the `nodeFunction` calls its callback with multiple success values, the fulfillment value will be an array of them. - * - * If you pass a `receiver`, the `nodeFunction` will be called as a method on the `receiver`. - */ - static promisify(func: (callback: (err:any, result: T) => void) => void, receiver?: any): () => Promise; - static promisify(func: (arg1: A1, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1) => Promise; - static promisify(func: (arg1: A1, arg2: A2, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2) => Promise; - static promisify(func: (arg1: A1, arg2: A2, arg3: A3, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3) => Promise; - static promisify(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4) => Promise; - static promisify(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5) => Promise; - static promisify(nodeFunction: Function, receiver?: any): Function; - - /** - * Promisifies the entire object by going through the object's properties and creating an async equivalent of each function on the object and its prototype chain. The promisified method name will be the original method name postfixed with `Async`. Returns the input object. - * - * Note that the original methods on the object are not overwritten but new methods are created with the `Async`-postfix. For example, if you `promisifyAll()` the node.js `fs` object use `fs.statAsync()` to call the promisified `stat` method. - */ - // TODO how to model promisifyAll? - static promisifyAll(target: Object, options?: Promise.PromisifyAllOptions): any; - - - /** - * Returns a promise that is resolved by a node style callback function. - */ - static fromNode(resolver: (callback: (err: any, result?: any) => void) => void): Promise; - - /** - * Returns a function that can use `yield` to run asynchronous code synchronously. This feature requires the support of generators which are drafted in the next version of the language. Node version greater than `0.11.2` is required and needs to be executed with the `--harmony-generators` (or `--harmony`) command-line switch. - */ - // TODO fix coroutine GeneratorFunction - static coroutine(generatorFunction: Function): Function; - - /** - * Spawn a coroutine which may yield promises to run asynchronous code synchronously. This feature requires the support of generators which are drafted in the next version of the language. Node version greater than `0.11.2` is required and needs to be executed with the `--harmony-generators` (or `--harmony`) command-line switch. - */ - // TODO fix spawn GeneratorFunction - static spawn(generatorFunction: Function): Promise; - - /** - * This is relevant to browser environments with no module loader. - * - * Release control of the `Promise` namespace to whatever it was before this library was loaded. Returns a reference to the library namespace so you can attach it to something else. - */ - static noConflict(): typeof Promise; - - /** - * Add `handler` as the handler to call when there is a possibly unhandled rejection. The default handler logs the error stack to stderr or `console.error` in browsers. - * - * Passing no value or a non-function will have the effect of removing any kind of handling for possibly unhandled rejections. - */ - static onPossiblyUnhandledRejection(handler: (reason: any) => any): void; - - /** - * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled when all the items in the array are fulfilled. The promise's fulfillment value is an array with fulfillment values at respective positions to the original array. If any promise in the array rejects, the returned promise is rejected with the rejection reason. - */ - // TODO enable more overloads - // promise of array with promises of value - static all(values: Promise.Thenable[]>): Promise; - // promise of array with values - static all(values: Promise.Thenable): Promise; - // array with promises of value - static all(values: Promise.Thenable[]): Promise; +declare var Promise: PromiseConstructor; + +interface PromiseConstructor { + /** + * Create a new promise. The passed in function will receive functions `resolve` and `reject` as its arguments which can be called to seal the fate of the created promise. + */ + new (callback: (resolve: (thenableOrResult?: T | PromiseLike) => void, reject: (error: any) => void) => void): Promise; + + // Ideally, we'd define e.g. "export class RangeError extends Error {}", + // but as Error is defined as an interface (not a class), TypeScript doesn't + // allow extending Error, only implementing it. + // However, if we want to catch() only a specific error type, we need to pass + // a constructor function to it. So, as a workaround, we define them here as such. + RangeError(): RangeError; + CancellationError(): Promise.CancellationError; + TimeoutError(): Promise.TimeoutError; + TypeError(): Promise.TypeError; + RejectionError(): Promise.RejectionError; + OperationalError(): Promise.OperationalError; + + /** + * Changes how bluebird schedules calls a-synchronously. + * + * @param scheduler Should be a function that asynchronously schedules + * the calling of the passed in function + */ + setScheduler(scheduler: (callback: (...args: any[]) => void) => void): void; + + /** + * Start the chain of promises with `Promise.try`. Any synchronous exceptions will be turned into rejections on the returned promise. + * + * Note about second argument: if it's specifically a true array, its values become respective arguments for the function call. Otherwise it is passed as is as the first argument for the function call. + * + * Alias for `attempt();` for compatibility with earlier ECMAScript version. + */ + try(fn: () => PromiseLike, args?: any[], ctx?: any): Promise; + try(fn: () => T, args?: any[], ctx?: any): Promise; + + attempt(fn: () => PromiseLike, args?: any[], ctx?: any): Promise; + attempt(fn: () => T, args?: any[], ctx?: any): Promise; + + /** + * Returns a new function that wraps the given function `fn`. The new function will always return a promise that is fulfilled with the original functions return values or rejected with thrown exceptions from the original function. + * This method is convenient when a function can sometimes return synchronously or throw synchronously. + */ + method(fn: Function): Function; + + /** + * Create a promise that is resolved with the given `value`. If `value` is a thenable or promise, the returned promise will assume its state. + */ + resolve(): Promise; + resolve(value: PromiseLike): Promise; + resolve(value: T): Promise; + + /** + * Create a promise that is rejected with the given `reason`. + */ + reject(reason: any): Promise; + reject(reason: any): Promise; + + /** + * Create a promise with undecided fate and return a `PromiseResolver` to control it. See resolution?: Promise(#promise-resolution). + */ + defer(): Promise.Resolver; + + /** + * Cast the given `value` to a trusted promise. If `value` is already a trusted `Promise`, it is returned as is. If `value` is not a thenable, a fulfilled is: Promise returned with `value` as its fulfillment value. If `value` is a thenable (Promise-like object, like those returned by jQuery's `$.ajax`), returns a trusted that: Promise assimilates the state of the thenable. + */ + cast(value: PromiseLike): Promise; + cast(value: T): Promise; + + /** + * Sugar for `Promise.resolve(undefined).bind(thisArg);`. See `.bind()`. + */ + bind(thisArg: any): Promise; + + /** + * See if `value` is a trusted Promise. + */ + is(value: any): boolean; + + /** + * Call this right after the library is loaded to enabled long stack traces. Long stack traces cannot be disabled after being enabled, and cannot be enabled after promises have alread been created. Long stack traces imply a substantial performance penalty, around 4-5x for throughput and 0.5x for latency. + */ + longStackTraces(): void; + + /** + * Returns a promise that will be fulfilled with `value` (or `undefined`) after given `ms` milliseconds. If `value` is a promise, the delay will start counting down when it is fulfilled and the returned promise will be fulfilled with the fulfillment value of the `value` promise. + */ + // TODO enable more overloads + delay(value: PromiseLike, ms: number): Promise; + delay(value: T, ms: number): Promise; + delay(ms: number): Promise; + + /** + * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument. + * + * If the `nodeFunction` calls its callback with multiple success values, the fulfillment value will be an array of them. + * + * If you pass a `receiver`, the `nodeFunction` will be called as a method on the `receiver`. + */ + promisify(func: (callback: (err: any, result: T) => void) => void, receiver?: any): () => Promise; + promisify(func: (arg1: A1, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1) => Promise; + promisify(func: (arg1: A1, arg2: A2, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2) => Promise; + promisify(func: (arg1: A1, arg2: A2, arg3: A3, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3) => Promise; + promisify(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4) => Promise; + promisify(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5) => Promise; + promisify(nodeFunction: Function, receiver?: any): Function; + + /** + * Promisifies the entire object by going through the object's properties and creating an async equivalent of each function on the object and its prototype chain. The promisified method name will be the original method name postfixed with `Async`. Returns the input object. + * + * Note that the original methods on the object are not overwritten but new methods are created with the `Async`-postfix. For example, if you `promisifyAll()` the node.js `fs` object use `fs.statAsync()` to call the promisified `stat` method. + */ + // TODO how to model promisifyAll? + promisifyAll(target: Object, options?: Promise.PromisifyAllOptions): any; + + + /** + * Returns a promise that is resolved by a node style callback function. + */ + fromNode(resolver: (callback: (err: any, result?: any) => void) => void): Promise; + + /** + * Returns a function that can use `yield` to run asynchronous code synchronously. This feature requires the support of generators which are drafted in the next version of the language. Node version greater than `0.11.2` is required and needs to be executed with the `--harmony-generators` (or `--harmony`) command-line switch. + */ + // TODO fix coroutine GeneratorFunction + coroutine(generatorFunction: Function): Function; + + /** + * Spawn a coroutine which may yield promises to run asynchronous code synchronously. This feature requires the support of generators which are drafted in the next version of the language. Node version greater than `0.11.2` is required and needs to be executed with the `--harmony-generators` (or `--harmony`) command-line switch. + */ + // TODO fix spawn GeneratorFunction + spawn(generatorFunction: Function): Promise; + + /** + * This is relevant to browser environments with no module loader. + * + * Release control of the `Promise` namespace to whatever it was before this library was loaded. Returns a reference to the library namespace so you can attach it to something else. + */ + noConflict(): typeof Promise; + + /** + * Add `handler` as the handler to call when there is a possibly unhandled rejection. The default handler logs the error stack to stderr or `console.error` in browsers. + * + * Passing no value or a non-function will have the effect of removing any kind of handling for possibly unhandled rejections. + */ + onPossiblyUnhandledRejection(handler: (reason: any) => any): void; + + /** + * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled when all the items in the array are fulfilled. The promise's fulfillment value is an array with fulfillment values at respective positions to the original array. If any promise in the array rejects, the returned promise is rejected with the rejection reason. + */ + // TODO enable more overloads + // promise of array with promises of value + all(values: PromiseLike[]>): Promise; + // promise of array with values + all(values: PromiseLike): Promise; + // array with promises of value + all(values: PromiseLike[]): Promise; // array with promises of different types - static all(values: [Promise.Thenable, Promise.Thenable]): Promise<[T1, T2]>; - static all(values: [Promise.Thenable, Promise.Thenable, Promise.Thenable]): Promise<[T1, T2, T3]>; - static all(values: [Promise.Thenable, Promise.Thenable, Promise.Thenable, Promise.Thenable]): Promise<[T1, T2, T3, T4]>; - static all(values: [Promise.Thenable, Promise.Thenable, Promise.Thenable, Promise.Thenable, Promise.Thenable]): Promise<[T1, T2, T3, T4, T5]>; - // array with values - static all(values: R[]): Promise; + all(values: [PromiseLike, PromiseLike]): Promise<[T1, T2]>; + all(values: [PromiseLike, PromiseLike, PromiseLike]): Promise<[T1, T2, T3]>; + all(values: [PromiseLike, PromiseLike, PromiseLike, PromiseLike]): Promise<[T1, T2, T3, T4]>; + all(values: [PromiseLike, PromiseLike, PromiseLike, PromiseLike, PromiseLike]): Promise<[T1, T2, T3, T4, T5]>; + // array with values + all(values: T[]): Promise; - /** - * Like ``Promise.all`` but for object properties instead of array items. Returns a promise that is fulfilled when all the properties of the object are fulfilled. The promise's fulfillment value is an object with fulfillment values at respective keys to the original object. If any promise in the object rejects, the returned promise is rejected with the rejection reason. - * - * If `object` is a trusted `Promise`, then it will be treated as a promise for object rather than for its properties. All other objects are treated for their properties as is returned by `Object.keys` - the object's own enumerable properties. - * - * *The original object is not modified.* - */ - // TODO verify this is correct - // trusted promise for object - static props(object: Promise): Promise; - // object - static props(object: Object): Promise; + /** + * Like ``Promise.all`` but for object properties instead of array items. Returns a promise that is fulfilled when all the properties of the object are fulfilled. The promise's fulfillment value is an object with fulfillment values at respective keys to the original object. If any promise in the object rejects, the returned promise is rejected with the rejection reason. + * + * If `object` is a trusted `Promise`, then it will be treated as a promise for object rather than for its properties. All other objects are treated for their properties as is returned by `Object.keys` - the object's own enumerable properties. + * + * *The original object is not modified.* + */ + // TODO verify this is correct + // trusted promise for object + props(object: Promise): Promise; + // object + props(object: Object): Promise; - /** - * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled when all the items in the array are either fulfilled or rejected. The fulfillment value is an array of ``PromiseInspection`` instances at respective positions in relation to the input array. - * - * *original: The array is not modified. The input array sparsity is retained in the resulting array.* - */ - // promise of array with promises of value - static settle(values: Promise.Thenable[]>): Promise[]>; - // promise of array with values - static settle(values: Promise.Thenable): Promise[]>; - // array with promises of value - static settle(values: Promise.Thenable[]): Promise[]>; - // array with values - static settle(values: R[]): Promise[]>; + /** + * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled when all the items in the array are either fulfilled or rejected. The fulfillment value is an array of ``PromiseInspection`` instances at respective positions in relation to the input array. + * + * *original: The array is not modified. The input array sparsity is retained in the resulting array.* + */ + // promise of array with promises of value + settle(values: PromiseLike[]>): Promise[]>; + // promise of array with values + settle(values: PromiseLike): Promise[]>; + // array with promises of value + settle(values: PromiseLike[]): Promise[]>; + // array with values + settle(values: T[]): Promise[]>; - /** - * Like `Promise.some()`, with 1 as `count`. However, if the promise fulfills, the fulfillment value is not an array of 1 but the value directly. - */ - // promise of array with promises of value - static any(values: Promise.Thenable[]>): Promise; - // promise of array with values - static any(values: Promise.Thenable): Promise; - // array with promises of value - static any(values: Promise.Thenable[]): Promise; - // array with values - static any(values: R[]): Promise; + /** + * Like `Promise.some()`, with 1 as `count`. However, if the promise fulfills, the fulfillment value is not an array of 1 but the value directly. + */ + // promise of array with promises of value + any(values: PromiseLike[]>): Promise; + // promise of array with values + any(values: PromiseLike): Promise; + // array with promises of value + any(values: PromiseLike[]): Promise; + // array with values + any(values: T[]): Promise; - /** - * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled or rejected as soon as a promise in the array is fulfilled or rejected with the respective rejection reason or fulfillment value. - * - * **Note** If you pass empty array or a sparse array with no values, or a promise/thenable for such, it will be forever pending. - */ - // promise of array with promises of value - static race(values: Promise.Thenable[]>): Promise; - // promise of array with values - static race(values: Promise.Thenable): Promise; - // array with promises of value - static race(values: Promise.Thenable[]): Promise; - // array with values - static race(values: R[]): Promise; + /** + * Given an array, or a promise of an array, which contains promises (or a mix of promises and values) return a promise that is fulfilled or rejected as soon as a promise in the array is fulfilled or rejected with the respective rejection reason or fulfillment value. + * + * **Note** If you pass empty array or a sparse array with no values, or a promise/thenable for such, it will be forever pending. + */ + // promise of array with promises of value + race(values: PromiseLike[]>): Promise; + // promise of array with values + race(values: PromiseLike): Promise; + // array with promises of value + race(values: PromiseLike[]): Promise; + // array with values + race(values: T[]): Promise; - /** - * Initiate a competetive race between multiple promises or values (values will become immediately fulfilled promises). When `count` amount of promises have been fulfilled, the returned promise is fulfilled with an array that contains the fulfillment values of the winners in order of resolution. - * - * If too many promises are rejected so that the promise can never become fulfilled, it will be immediately rejected with an array of rejection reasons in the order they were thrown in. - * - * *The original array is not modified.* - */ - // promise of array with promises of value - static some(values: Promise.Thenable[]>, count: number): Promise; - // promise of array with values - static some(values: Promise.Thenable, count: number): Promise; - // array with promises of value - static some(values: Promise.Thenable[], count: number): Promise; - // array with values - static some(values: R[], count: number): Promise; + /** + * Initiate a competetive race between multiple promises or values (values will become immediately fulfilled promises). When `count` amount of promises have been fulfilled, the returned promise is fulfilled with an array that contains the fulfillment values of the winners in order of resolution. + * + * If too many promises are rejected so that the promise can never become fulfilled, it will be immediately rejected with an array of rejection reasons in the order they were thrown in. + * + * *The original array is not modified.* + */ + // promise of array with promises of value + some(values: PromiseLike[]>, count: number): Promise; + // promise of array with values + some(values: PromiseLike, count: number): Promise; + // array with promises of value + some(values: PromiseLike[], count: number): Promise; + // array with values + some(values: T[], count: number): Promise; - /** - * Like `Promise.all()` but instead of having to pass an array, the array is generated from the passed variadic arguments. - */ - // variadic array with promises of value - static join(...values: Promise.Thenable[]): Promise; - // variadic array with values - static join(...values: R[]): Promise; + /** + * Like `Promise.all()` but instead of having to pass an array, the array is generated from the passed variadic arguments. + */ + // variadic array with promises of value + join(...values: PromiseLike[]): Promise; + // variadic array with values + join(...values: T[]): Promise; - /** - * Map an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `mapper` function with the signature `(item, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. - * - * If the `mapper` function returns promises or thenables, the returned promise will wait for all the mapped results to be resolved as well. - * - * *The original array is not modified.* - */ - // promise of array with promises of value - static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; + /** + * Map an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `mapper` function with the signature `(item, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. + * + * If the `mapper` function returns promises or thenables, the returned promise will wait for all the mapped results to be resolved as well. + * + * *The original array is not modified.* + */ + // promise of array with promises of value + map(values: PromiseLike[]>, mapper: (item: T, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + map(values: PromiseLike[]>, mapper: (item: T, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; - // promise of array with values - static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; + // promise of array with values + map(values: PromiseLike, mapper: (item: T, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + map(values: PromiseLike, mapper: (item: T, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; - // array with promises of value - static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; + // array with promises of value + map(values: PromiseLike[], mapper: (item: T, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + map(values: PromiseLike[], mapper: (item: T, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; - // array with values - static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; - static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; + // array with values + map(values: T[], mapper: (item: T, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + map(values: T[], mapper: (item: T, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; - /** - * Similar to `map` with concurrency set to 1 but guaranteed to execute in sequential order - * - * If the `mapper` function returns promises or thenables, the returned promise will wait for all the mapped results to be resolved as well. - * - * *The original array is not modified.* - */ - // promise of array with promises of value - static mapSeries(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => U|Promise.Thenable): Promise; + /** + * Similar to `map` with concurrency set to 1 but guaranteed to execute in sequential order + * + * If the `mapper` function returns promises or thenables, the returned promise will wait for all the mapped results to be resolved as well. + * + * *The original array is not modified.* + */ + // promise of array with promises of value + mapSeries(values: PromiseLike[]>, mapper: (item: R, index: number, arrayLength: number) => U | PromiseLike): Promise; - // promise of array with values - static mapSeries(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => U|Promise.Thenable): Promise; + // promise of array with values + mapSeries(values: PromiseLike, mapper: (item: R, index: number, arrayLength: number) => U | PromiseLike): Promise; - // array with promises of value - static mapSeries(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => U|Promise.Thenable): Promise; + // array with promises of value + mapSeries(values: PromiseLike[], mapper: (item: R, index: number, arrayLength: number) => U | PromiseLike): Promise; - // array with values - static mapSeries(values: R[], mapper: (item: R, index: number, arrayLength: number) => U|Promise.Thenable): Promise; - - /** - * Reduce an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `reducer` function with the signature `(total, current, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. - * - * If the reducer function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration. - * - * *The original array is not modified. If no `intialValue` is given and the array doesn't contain at least 2 items, the callback will not be called and `undefined` is returned. If `initialValue` is given and the array doesn't have at least 1 item, `initialValue` is returned.* - */ - // promise of array with promises of value - static reduce(values: Promise.Thenable[]>, reducer: (total: U, current: R, index: number, arrayLength: number) => Promise.Thenable, initialValue?: U): Promise; - static reduce(values: Promise.Thenable[]>, reducer: (total: U, current: R, index: number, arrayLength: number) => U, initialValue?: U): Promise; + // array with values + mapSeries(values: R[], mapper: (item: R, index: number, arrayLength: number) => U | PromiseLike): Promise; + - // promise of array with values - static reduce(values: Promise.Thenable, reducer: (total: U, current: R, index: number, arrayLength: number) => Promise.Thenable, initialValue?: U): Promise; - static reduce(values: Promise.Thenable, reducer: (total: U, current: R, index: number, arrayLength: number) => U, initialValue?: U): Promise; + /** + * Reduce an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `reducer` function with the signature `(total, current, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. + * + * If the reducer function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration. + * + * *The original array is not modified. If no `intialValue` is given and the array doesn't contain at least 2 items, the callback will not be called and `undefined` is returned. If `initialValue` is given and the array doesn't have at least 1 item, `initialValue` is returned.* + */ + // promise of array with promises of value + reduce(values: PromiseLike[]>, reducer: (total: U, current: T, index: number, arrayLength: number) => PromiseLike, initialValue?: U): Promise; + reduce(values: PromiseLike[]>, reducer: (total: U, current: T, index: number, arrayLength: number) => U, initialValue?: U): Promise; - // array with promises of value - static reduce(values: Promise.Thenable[], reducer: (total: U, current: R, index: number, arrayLength: number) => Promise.Thenable, initialValue?: U): Promise; - static reduce(values: Promise.Thenable[], reducer: (total: U, current: R, index: number, arrayLength: number) => U, initialValue?: U): Promise; + // promise of array with values + reduce(values: PromiseLike, reducer: (total: U, current: T, index: number, arrayLength: number) => PromiseLike, initialValue?: U): Promise; + reduce(values: PromiseLike, reducer: (total: U, current: T, index: number, arrayLength: number) => U, initialValue?: U): Promise; - // array with values - static reduce(values: R[], reducer: (total: U, current: R, index: number, arrayLength: number) => Promise.Thenable, initialValue?: U): Promise; - static reduce(values: R[], reducer: (total: U, current: R, index: number, arrayLength: number) => U, initialValue?: U): Promise; + // array with promises of value + reduce(values: PromiseLike[], reducer: (total: U, current: T, index: number, arrayLength: number) => PromiseLike, initialValue?: U): Promise; + reduce(values: PromiseLike[], reducer: (total: U, current: T, index: number, arrayLength: number) => U, initialValue?: U): Promise; - /** - * Filter an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `filterer` function with the signature `(item, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. - * - * The return values from the filtered functions are coerced to booleans, with the exception of promises and thenables which are awaited for their eventual result. - * - * *The original array is not modified. - */ - // promise of array with promises of value - static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; - static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; + // array with values + reduce(values: T[], reducer: (total: U, current: T, index: number, arrayLength: number) => PromiseLike, initialValue?: U): Promise; + reduce(values: T[], reducer: (total: U, current: T, index: number, arrayLength: number) => U, initialValue?: U): Promise; - // promise of array with values - static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; - static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; + /** + * Filter an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `filterer` function with the signature `(item, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. + * + * The return values from the filtered functions are coerced to booleans, with the exception of promises and thenables which are awaited for their eventual result. + * + * *The original array is not modified. + */ + // promise of array with promises of value + filter(values: PromiseLike[]>, filterer: (item: T, index: number, arrayLength: number) => PromiseLike, option?: Promise.ConcurrencyOption): Promise; + filter(values: PromiseLike[]>, filterer: (item: T, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; - // array with promises of value - static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; - static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; + // promise of array with values + filter(values: PromiseLike, filterer: (item: T, index: number, arrayLength: number) => PromiseLike, option?: Promise.ConcurrencyOption): Promise; + filter(values: PromiseLike, filterer: (item: T, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; - // array with values - static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; - static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; + // array with promises of value + filter(values: PromiseLike[], filterer: (item: T, index: number, arrayLength: number) => PromiseLike, option?: Promise.ConcurrencyOption): Promise; + filter(values: PromiseLike[], filterer: (item: T, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; - /** - * Iterate over an array, or a promise of an array, which contains promises (or a mix of promises and values) with the given iterator function with the signature (item, index, value) where item is the resolved value of a respective promise in the input array. Iteration happens serially. If any promise in the input array is rejected the returned promise is rejected as well. - * - * Resolves to the original array unmodified, this method is meant to be used for side effects. If the iterator function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration. - */ - // promise of array with promises of value - static each(values: Promise.Thenable[]>, iterator: (item: R, index: number, arrayLength: number) => U | Promise.Thenable): Promise; - // array with promises of value - static each(values: Promise.Thenable[], iterator: (item: R, index: number, arrayLength: number) => U | Promise.Thenable): Promise; - // array with values OR promise of array with values - static each(values: R[] | Promise.Thenable, iterator: (item: R, index: number, arrayLength: number) => U | Promise.Thenable): Promise; + // array with values + filter(values: T[], filterer: (item: T, index: number, arrayLength: number) => PromiseLike, option?: Promise.ConcurrencyOption): Promise; + filter(values: T[], filterer: (item: T, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; + + /** + * Iterate over an array, or a promise of an array, which contains promises (or a mix of promises and values) with the given iterator function with the signature (item, index, value) where item is the resolved value of a respective promise in the input array. Iteration happens serially. If any promise in the input array is rejected the returned promise is rejected as well. + * + * Resolves to the original array unmodified, this method is meant to be used for side effects. If the iterator function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration. + */ + // promise of array with promises of value + each(values: PromiseLike[]>, iterator: (item: T, index: number, arrayLength: number) => U | PromiseLike): Promise; + // array with promises of value + each(values: PromiseLike[], iterator: (item: T, index: number, arrayLength: number) => U | PromiseLike): Promise; + // array with values OR promise of array with values + each(values: T[] | PromiseLike, iterator: (item: T, index: number, arrayLength: number) => U | PromiseLike): Promise; } -declare module Promise { - export interface RangeError extends Error { - } - export interface CancellationError extends Error { - } - export interface TimeoutError extends Error { - } - export interface TypeError extends Error { - } - export interface RejectionError extends Error { - } - export interface OperationalError extends Error { - } +interface Promise extends PromiseLike, Promise.Inspection { + /** + * Promises/A+ `.then()` with progress handler. Returns a new promise chained from this promise. The new promise will be rejected or resolved dedefer on the passed `fulfilledHandler`, `rejectedHandler` and the state of this promise. + */ + then(onFulfill: (value: T) => U | PromiseLike, onReject?: (error: any) => U | PromiseLike, onProgress?: (note: any) => any): Promise; + then(onFulfill: (value: T) => U | PromiseLike, onReject?: (error: any) => void | PromiseLike, onProgress?: (note: any) => any): Promise; - export interface ConcurrencyOption { - concurrency: number; - } - export interface SpreadOption { - spread: boolean; - } - export interface PromisifyAllOptions { - suffix?: string; - filter?: (name: string, func: Function, target?: any, passesDefaultFilter?: boolean) => boolean; - // The promisifier gets a reference to the original method and should return a function which returns a promise - promisifier?: (originalMethod: Function) => () => Thenable ; - } + /** + * This is a catch-all exception handler, shortcut for calling `.then(null, handler)` on this promise. Any exception happening in a `.then`-chain will propagate to nearest `.catch` handler. + * + * Alias `.caught();` for compatibility with earlier ECMAScript version. + */ + catch(onReject?: (error: any) => T | PromiseLike | void | PromiseLike): Promise; + caught(onReject?: (error: any) => T | PromiseLike | void | PromiseLike): Promise; - // Ideally, we'd define e.g. "export class RangeError extends Error {}", - // but as Error is defined as an interface (not a class), TypeScript doesn't - // allow extending Error, only implementing it. - // However, if we want to catch() only a specific error type, we need to pass - // a constructor function to it. So, as a workaround, we define them here as such. - export function RangeError(): RangeError; - export function CancellationError(): CancellationError; - export function TimeoutError(): TimeoutError; - export function TypeError(): TypeError; - export function RejectionError(): RejectionError; - export function OperationalError(): OperationalError; + catch(onReject?: (error: any) => U | PromiseLike): Promise; + caught(onReject?: (error: any) => U | PromiseLike): Promise; - export interface Thenable { - then(onFulfilled: (value: R) => U|Thenable, onRejected?: (error: any) => U|Thenable): Thenable; - then(onFulfilled: (value: R) => U|Thenable, onRejected?: (error: any) => void|Thenable): Thenable; - } + /** + * This extends `.catch` to work more like catch-clauses in languages like Java or C#. Instead of manually checking `instanceof` or `.name === "SomeError"`, you may specify a number of error constructors which are eligible for this catch handler. The catch handler that is first met that has eligible constructors specified, is the one that will be called. + * + * This method also supports predicate-based filters. If you pass a predicate function instead of an error constructor, the predicate will receive the error as an argument. The return result of the predicate will be used determine whether the error handler should be called. + * + * Alias `.caught();` for compatibility with earlier ECMAScript version. + */ + catch(predicate: (error: any) => boolean, onReject: (error: any) => T | PromiseLike | void | PromiseLike): Promise; + caught(predicate: (error: any) => boolean, onReject: (error: any) => T | PromiseLike | void | PromiseLike): Promise; - export interface Resolver { - /** - * Returns a reference to the controlled promise that can be passed to clients. - */ - promise: Promise; + catch(predicate: (error: any) => boolean, onReject: (error: any) => U | PromiseLike): Promise; + caught(predicate: (error: any) => boolean, onReject: (error: any) => U | PromiseLike): Promise; - /** - * Resolve the underlying promise with `value` as the resolution value. If `value` is a thenable or a promise, the underlying promise will assume its state. - */ - resolve(value: R): void; - resolve(): void; + catch(ErrorClass: Function, onReject: (error: any) => T | PromiseLike | void | PromiseLike): Promise; + caught(ErrorClass: Function, onReject: (error: any) => T | PromiseLike | void | PromiseLike): Promise; - /** - * Reject the underlying promise with `reason` as the rejection reason. - */ - reject(reason: any): void; + catch(ErrorClass: Function, onReject: (error: any) => U | PromiseLike): Promise; + caught(ErrorClass: Function, onReject: (error: any) => U | PromiseLike): Promise; - /** - * Progress the underlying promise with `value` as the progression value. - */ - progress(value: any): void; - /** - * Gives you a callback representation of the `PromiseResolver`. Note that this is not a method but a property. The callback accepts error object in first argument and success values on the 2nd parameter and the rest, I.E. node js conventions. - * - * If the the callback is called with multiple success values, the resolver fullfills its promise with an array of the values. - */ - // TODO specify resolver callback - callback: (err: any, value: R, ...values: R[]) => void; - } + /** + * Like `.catch` but instead of catching all types of exceptions, it only catches those that don't originate from thrown errors but rather from explicit rejections. + */ + error(onReject: (reason: any) => PromiseLike): Promise; + error(onReject: (reason: any) => U): Promise; - export interface Inspection { - /** - * See if the underlying promise was fulfilled at the creation time of this inspection object. - */ - isFulfilled(): boolean; + /** + * Pass a handler that will be called regardless of this promise's fate. Returns a new promise chained from this promise. There are special semantics for `.finally()` in that the final value cannot be modified from the handler. + * + * Alias `.lastly();` for compatibility with earlier ECMAScript version. + */ + finally(handler: () => PromiseLike): Promise; + finally(handler: () => U): Promise; - /** - * See if the underlying promise was rejected at the creation time of this inspection object. - */ - isRejected(): boolean; + lastly(handler: () => PromiseLike): Promise; + lastly(handler: () => U): Promise; - /** - * See if the underlying promise was defer at the creation time of this inspection object. - */ - isPending(): boolean; + /** + * Create a promise that follows this promise, but is bound to the given `thisArg` value. A bound promise will call its handlers with the bound value set to `this`. Additionally promises derived from a bound promise will also be bound promises with the same `thisArg` binding as the original promise. + */ + bind(thisArg: any): Promise; - /** - * Get the fulfillment value of the underlying promise. Throws if the promise wasn't fulfilled at the creation time of this inspection object. - * - * throws `TypeError` - */ - value(): R; + /** + * Like `.then()`, but any unhandled rejection that ends up here will be thrown as an error. + */ + done(onFulfilled: (value: T) => PromiseLike, onRejected: (error: any) => PromiseLike, onProgress?: (note: any) => any): void; + done(onFulfilled: (value: T) => PromiseLike, onRejected?: (error: any) => U, onProgress?: (note: any) => any): void; + done(onFulfilled: (value: T) => U, onRejected: (error: any) => PromiseLike, onProgress?: (note: any) => any): void; + done(onFulfilled?: (value: T) => U, onRejected?: (error: any) => U, onProgress?: (note: any) => any): void; - /** - * Get the rejection reason for the underlying promise. Throws if the promise wasn't rejected at the creation time of this inspection object. - * - * throws `TypeError` - */ - reason(): any; - } + /** + * Like `.finally()`, but not called for rejections. + */ + tap(onFulFill: (value: T) => PromiseLike): Promise; + tap(onFulfill: (value: T) => U): Promise; - /** - * Changes how bluebird schedules calls a-synchronously. - * - * @param scheduler Should be a function that asynchronously schedules - * the calling of the passed in function - */ - export function setScheduler(scheduler: (callback: (...args: any[]) => void) => void): void; + /** + * Shorthand for `.then(null, null, handler);`. Attach a progress handler that will be called if this promise is progressed. Returns a new promise chained from this promise. + */ + progressed(handler: (note: any) => any): Promise; + + /** + * Same as calling `Promise.delay(this, ms)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + delay(ms: number): Promise; + + /** + * Returns a promise that will be fulfilled with this promise's fulfillment value or rejection reason. However, if this promise is not fulfilled or rejected within `ms` milliseconds, the returned promise is rejected with a `Promise.TimeoutError` instance. + * + * You may specify a custom error message with the `message` parameter. + */ + timeout(ms: number, message?: string): Promise; + + /** + * Register a node-style callback on this promise. When this promise is is either fulfilled or rejected, the node callback will be called back with the node.js convention where error reason is the first argument and success value is the second argument. The error argument will be `null` in case of success. + * Returns back this promise instead of creating a new one. If the `callback` argument is not a function, this method does not do anything. + */ + nodeify(callback: (err: any, value?: T) => void, options?: Promise.SpreadOption): Promise; + nodeify(...sink: any[]): Promise; + + /** + * Marks this promise as cancellable. Promises by default are not cancellable after v0.11 and must be marked as such for `.cancel()` to have any effect. Marking a promise as cancellable is infectious and you don't need to remark any descendant promise. + */ + cancellable(): Promise; + + /** + * Cancel this promise. The cancellation will propagate to farthest cancellable ancestor promise which is still pending. + * + * That ancestor will then be rejected with a `CancellationError` (get a reference from `Promise.CancellationError`) object as the rejection reason. + * + * In a promise rejection handler you may check for a cancellation by seeing if the reason object has `.name === "Cancel"`. + * + * Promises are by default not cancellable. Use `.cancellable()` to mark a promise as cancellable. + */ + // TODO what to do with this? + cancel(reason?: any): Promise; + + /** + * Like `.then()`, but cancellation of the the returned promise or any of its descendant will not propagate cancellation to this promise or this promise's ancestors. + */ + fork(onFulfilled: (value: T) => PromiseLike, onRejected: (error: any) => PromiseLike, onProgress?: (note: any) => any): Promise; + fork(onFulfilled: (value: T) => PromiseLike, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; + fork(onFulfilled: (value: T) => U, onRejected: (error: any) => PromiseLike, onProgress?: (note: any) => any): Promise; + fork(onFulfilled?: (value: T) => U, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; + + /** + * Create an uncancellable promise based on this promise. + */ + uncancellable(): Promise; + + /** + * See if this promise can be cancelled. + */ + isCancellable(): boolean; + + /** + * See if this `promise` has been fulfilled. + */ + isFulfilled(): boolean; + + /** + * See if this `promise` has been rejected. + */ + isRejected(): boolean; + + /** + * See if this `promise` is still defer. + */ + isPending(): boolean; + + /** + * See if this `promise` is resolved -> either fulfilled or rejected. + */ + isResolved(): boolean; + + /** + * Get the fulfillment value of the underlying promise. Throws if the promise isn't fulfilled yet. + * + * throws `TypeError` + */ + value(): T; + + /** + * Get the rejection reason for the underlying promise. Throws if the promise isn't rejected yet. + * + * throws `TypeError` + */ + reason(): any; + + /** + * Synchronously inspect the state of this `promise`. The `PromiseInspection` will represent the state of the promise as snapshotted at the time of calling `.inspect()`. + */ + inspect(): Promise.Inspection; + + /** + * This is a convenience method for doing: + * + * + * promise.then(function(obj){ + * return obj[propertyName].call(obj, arg...); + * }); + * + */ + call(propertyName: string, ...args: any[]): Promise; + + /** + * This is a convenience method for doing: + * + * + * promise.then(function(obj){ + * return obj[propertyName]; + * }); + * + */ + // TODO find way to fix get() + // get(propertyName: string): Promise; + + /** + * Convenience method for: + * + * + * .then(function() { + * return value; + * }); + * + * + * in the case where `value` doesn't change its value. That means `value` is bound at the time of calling `.return()` + * + * Alias `.thenReturn();` for compatibility with earlier ECMAScript version. + */ + return(): Promise; + thenReturn(): Promise; + return(value: U): Promise; + thenReturn(value: U): Promise; + + /** + * Convenience method for: + * + * + * .then(function() { + * throw reason; + * }); + * + * Same limitations apply as with `.return()`. + * + * Alias `.thenThrow();` for compatibility with earlier ECMAScript version. + */ + throw(reason: Error): Promise; + thenThrow(reason: Error): Promise; + + /** + * Convert to String. + */ + toString(): string; + + /** + * This is implicitly called by `JSON.stringify` when serializing the object. Returns a serialized representation of the `Promise`. + */ + toJSON(): Object; + + /** + * Like calling `.then`, but the fulfillment value or rejection reason is assumed to be an array, which is flattened to the formal parameters of the handlers. + */ + // TODO how to model instance.spread()? like Q? + spread(onFulfill: Function, onReject?: (reason: any) => PromiseLike): Promise; + spread(onFulfill: Function, onReject?: (reason: any) => U): Promise; + /* + // TODO or something like this? + spread(onFulfill: (...values: W[]) => PromiseLike, onReject?: (reason: any) => PromiseLike): Promise; + spread(onFulfill: (...values: W[]) => PromiseLike, onReject?: (reason: any) => U): Promise; + spread(onFulfill: (...values: W[]) => U, onReject?: (reason: any) => PromiseLike): Promise; + spread(onFulfill: (...values: W[]) => U, onReject?: (reason: any) => U): Promise; + */ + /** + * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + all(): Promise; + + /** + * Same as calling `Promise.props(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO how to model instance.props()? + props(): Promise; + + /** + * Same as calling `Promise.settle(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + settle(): Promise[]>; + + /** + * Same as calling `Promise.any(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + any(): Promise; + + /** + * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + some(count: number): Promise; + + /** + * Same as calling `Promise.race(thisPromise, count)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + race(): Promise; + + /** + * Same as calling `Promise.map(thisPromise, mapper)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + map(mapper: (item: Q, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + map(mapper: (item: Q, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; + + /** + * Same as `Promise.mapSeries(thisPromise, mapper)`. + */ + // TODO type inference from array-resolving promise? + mapSeries(mapper: (item: Q, index: number, arrayLength: number) => U | PromiseLike): Promise; + + /** + * Same as calling `Promise.reduce(thisPromise, Function reducer, initialValue)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + reduce(reducer: (memo: U, item: Q, index: number, arrayLength: number) => PromiseLike, initialValue?: U): Promise; + reduce(reducer: (memo: U, item: Q, index: number, arrayLength: number) => U, initialValue?: U): Promise; + + /** + * Same as calling ``Promise.filter(thisPromise, filterer)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + // TODO type inference from array-resolving promise? + filter(filterer: (item: U, index: number, arrayLength: number) => PromiseLike, options?: Promise.ConcurrencyOption): Promise; + filter(filterer: (item: U, index: number, arrayLength: number) => boolean, options?: Promise.ConcurrencyOption): Promise; + + /** + * Same as calling ``Promise.each(thisPromise, iterator)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + each(iterator: (item: T, index: number, arrayLength: number) => U | PromiseLike): Promise; +} + +/** + * Don't use variable namespace such as variables, functions, and classes. + * If you use this namespace, it will conflict in es6. + */ +declare namespace Promise { + export interface RangeError extends Error { + } + export interface CancellationError extends Error { + } + export interface TimeoutError extends Error { + } + export interface TypeError extends Error { + } + export interface RejectionError extends Error { + } + export interface OperationalError extends Error { + } + + export interface ConcurrencyOption { + concurrency: number; + } + export interface SpreadOption { + spread: boolean; + } + export interface PromisifyAllOptions { + suffix?: string; + filter?: (name: string, func: Function, target?: any, passesDefaultFilter?: boolean) => boolean; + // The promisifier gets a reference to the original method and should return a function which returns a promise + promisifier?: (originalMethod: Function) => () => PromiseLike; + } + + export interface Resolver { + /** + * Returns a reference to the controlled promise that can be passed to clients. + */ + promise: Promise; + + /** + * Resolve the underlying promise with `value` as the resolution value. If `value` is a thenable or a promise, the underlying promise will assume its state. + */ + resolve(value: T): void; + resolve(): void; + + /** + * Reject the underlying promise with `reason` as the rejection reason. + */ + reject(reason: any): void; + + /** + * Progress the underlying promise with `value` as the progression value. + */ + progress(value: any): void; + + /** + * Gives you a callback representation of the `PromiseResolver`. Note that this is not a method but a property. The callback accepts error object in first argument and success values on the 2nd parameter and the rest, I.E. node js conventions. + * + * If the the callback is called with multiple success values, the resolver fullfills its promise with an array of the values. + */ + // TODO specify resolver callback + callback: (err: any, value: T, ...values: T[]) => void; + } + + export interface Inspection { + /** + * See if the underlying promise was fulfilled at the creation time of this inspection object. + */ + isFulfilled(): boolean; + + /** + * See if the underlying promise was rejected at the creation time of this inspection object. + */ + isRejected(): boolean; + + /** + * See if the underlying promise was defer at the creation time of this inspection object. + */ + isPending(): boolean; + + /** + * Get the fulfillment value of the underlying promise. Throws if the promise wasn't fulfilled at the creation time of this inspection object. + * + * throws `TypeError` + */ + value(): T; + + /** + * Get the rejection reason for the underlying promise. Throws if the promise wasn't rejected at the creation time of this inspection object. + * + * throws `TypeError` + */ + reason(): any; + } } declare module 'bluebird' { - export = Promise; + export = Promise; } diff --git a/breeze/breeze.d.ts b/breeze/breeze.d.ts index 2a60df6d84..1cc587c2f2 100644 --- a/breeze/breeze.d.ts +++ b/breeze/breeze.d.ts @@ -392,6 +392,7 @@ declare module breeze { constructor(config?: EntityManagerOptions); constructor(config?: string); + acceptChanges(): void; addEntity(entity: Entity): Entity; attachEntity(entity: Entity, entityState?: EntityStateSymbol, mergeStrategy?: MergeStrategySymbol): Entity; clear(): void; diff --git a/cookies/cookies.d.ts b/cookies/cookies.d.ts index 53de9fe090..5cc5f698a3 100644 --- a/cookies/cookies.d.ts +++ b/cookies/cookies.d.ts @@ -8,91 +8,93 @@ declare module "cookies" { import * as http from "http" - interface ICookies { - /** - * This extracts the cookie with the given name from the - * Cookie header in the request. If such a cookie exists, - * its value is returned. Otherwise, nothing is returned. - */ - get(name: string): string; - /** - * This extracts the cookie with the given name from the - * Cookie header in the request. If such a cookie exists, - * its value is returned. Otherwise, nothing is returned. - */ - get(name: string, opts: IOptions): string; - - /** - * This sets the given cookie in the response and returns - * the current context to allow chaining.If the value is omitted, - * an outbound header with an expired date is used to delete the cookie. - */ - set(name: string, value: string): ICookies; - /** - * This sets the given cookie in the response and returns - * the current context to allow chaining.If the value is omitted, - * an outbound header with an expired date is used to delete the cookie. - */ - set(name: string, value: string, opts: IOptions): ICookies; - } + module cookies { + interface ICookies { + /** + * This extracts the cookie with the given name from the + * Cookie header in the request. If such a cookie exists, + * its value is returned. Otherwise, nothing is returned. + */ + get(name: string): string; + /** + * This extracts the cookie with the given name from the + * Cookie header in the request. If such a cookie exists, + * its value is returned. Otherwise, nothing is returned. + */ + get(name: string, opts: IOptions): string; + + /** + * This sets the given cookie in the response and returns + * the current context to allow chaining.If the value is omitted, + * an outbound header with an expired date is used to delete the cookie. + */ + set(name: string, value: string): ICookies; + /** + * This sets the given cookie in the response and returns + * the current context to allow chaining.If the value is omitted, + * an outbound header with an expired date is used to delete the cookie. + */ + set(name: string, value: string, opts: IOptions): ICookies; + } - interface IOptions { - /** - * a number representing the milliseconds from Date.now() for expiry - */ - maxAge?: number; - /** - * a Date object indicating the cookie's expiration - * date (expires at the end of session by default). - */ - expires?: Date; - /** - * a string indicating the path of the cookie (/ by default). - */ - path?: string; - /** - * a string indicating the domain of the cookie (no default). - */ - domain?: string; - /** - * a boolean indicating whether the cookie is only to be sent - * over HTTPS (false by default for HTTP, true by default for HTTPS). - */ - secure?: boolean; - /** - * a boolean indicating whether the cookie is only to be sent - * over HTTPS (use this if you handle SSL not in your node process). - */ - secureProxy?: boolean; - /** - * a boolean indicating whether the cookie is only to be sent over HTTP(S), - * and not made available to client JavaScript (true by default). - */ - httpOnly?: boolean; - /** - * a boolean indicating whether the cookie is to be signed (false by default). - * If this is true, another cookie of the same name with the .sig suffix - * appended will also be sent, with a 27-byte url-safe base64 SHA1 value - * representing the hash of cookie-name=cookie-value against the first Keygrip key. - * This signature key is used to detect tampering the next time a cookie is received. - */ - signed?: boolean; - /** - * a boolean indicating whether to overwrite previously set - * cookies of the same name (false by default). If this is true, - * all cookies set during the same request with the same - * name (regardless of path or domain) are filtered out of - * the Set-Cookie header when setting this cookie. - */ - overwrite?: boolean; + interface IOptions { + /** + * a number representing the milliseconds from Date.now() for expiry + */ + maxAge?: number; + /** + * a Date object indicating the cookie's expiration + * date (expires at the end of session by default). + */ + expires?: Date; + /** + * a string indicating the path of the cookie (/ by default). + */ + path?: string; + /** + * a string indicating the domain of the cookie (no default). + */ + domain?: string; + /** + * a boolean indicating whether the cookie is only to be sent + * over HTTPS (false by default for HTTP, true by default for HTTPS). + */ + secure?: boolean; + /** + * a boolean indicating whether the cookie is only to be sent + * over HTTPS (use this if you handle SSL not in your node process). + */ + secureProxy?: boolean; + /** + * a boolean indicating whether the cookie is only to be sent over HTTP(S), + * and not made available to client JavaScript (true by default). + */ + httpOnly?: boolean; + /** + * a boolean indicating whether the cookie is to be signed (false by default). + * If this is true, another cookie of the same name with the .sig suffix + * appended will also be sent, with a 27-byte url-safe base64 SHA1 value + * representing the hash of cookie-name=cookie-value against the first Keygrip key. + * This signature key is used to detect tampering the next time a cookie is received. + */ + signed?: boolean; + /** + * a boolean indicating whether to overwrite previously set + * cookies of the same name (false by default). If this is true, + * all cookies set during the same request with the same + * name (regardless of path or domain) are filtered out of + * the Set-Cookie header when setting this cookie. + */ + overwrite?: boolean; + } } interface CookiesStatic { - new (request: http.IncomingMessage, response: http.ServerResponse): ICookies; - new (request: http.IncomingMessage, response: http.ServerResponse, keys?: Array): ICookies; + new (request: http.IncomingMessage, response: http.ServerResponse): cookies.ICookies; + new (request: http.IncomingMessage, response: http.ServerResponse, keys?: Array): cookies.ICookies; } - const _tmp: CookiesStatic; + const cookies: CookiesStatic; - export = _tmp + export = cookies } \ No newline at end of file diff --git a/d3/d3.d.ts b/d3/d3.d.ts index 236b87d55e..1f5ebe7a1e 100644 --- a/d3/d3.d.ts +++ b/d3/d3.d.ts @@ -3032,6 +3032,46 @@ declare module d3 { padding(padding: number): Pack; } + export function partition(): Partition; + export function partition(): Partition; + + module partition { + interface Link { + source: T; + target: T; + } + + interface Node { + parent?: Node; + children?: number; + value?: number; + depth?: number; + x?: number; + y?: number; + dx?: number; + dy?: number; + } + + } + + export interface Partition { + nodes(root: T): T[]; + + links(nodes: T[]): partition.Link[]; + + children(): (node: T, depth: number) => T[]; + children(children: (node: T, depth: number) => T[]): Partition; + + sort(): (a: T, b: T) => number; + sort(comparator: (a: T, b: T) => number): Partition; + + value(): (node: T) => number; + value(value: (node: T) => number): Partition; + + size(): [number, number]; + size(size: [number, number]): Partition; + } + export function pie(): Pie; export function pie(): Pie; diff --git a/debug/debug-tests.ts b/debug/debug-tests.ts index 63a0a3ac4e..a264003409 100644 --- a/debug/debug-tests.ts +++ b/debug/debug-tests.ts @@ -1,4 +1,3 @@ -/// /// import debug = require("debug"); @@ -6,7 +5,7 @@ import debug = require("debug"); debug.disable(); debug.enable("DefinitelyTyped:*"); -var log: debug.Debugger = debug("DefinitelyTyped:log"); +var log:debug.IDebugger = debug("DefinitelyTyped:log"); log("Just text"); log("Formatted test (%d arg)", 1); @@ -15,6 +14,6 @@ log("Formatted %s (%d args)", "test", 2); log("Enabled?: %s", debug.enabled("DefinitelyTyped:log")); log("Namespace: %s", log.namespace); -var error: debug.Debugger = debug("DefinitelyTyped:error"); +var error:debug.IDebugger = debug("DefinitelyTyped:error"); error.log = console.error.bind(console); error("This should be printed to stderr"); diff --git a/debug/debug.d.ts b/debug/debug.d.ts index 1a71725a86..b43cd238c3 100644 --- a/debug/debug.d.ts +++ b/debug/debug.d.ts @@ -1,30 +1,38 @@ // Type definitions for debug // Project: https://github.com/visionmedia/debug -// Definitions by: Seon-Wook Park +// Definitions by: Seon-Wook Park , Gal Talmor // Definitions: https://github.com/borisyankov/DefinitelyTyped -declare module "debug" { - - function d(namespace: string): d.Debugger; - - module d { - export var log: Function; - - function enable(namespaces: string): void; - function disable(): void; - - function enabled(namespace: string): boolean; - - export interface Debugger { - (formatter: any, ...args: any[]): void; - - enabled: boolean; - log: Function; - namespace: string; - } - } - - export = d; +declare var debug: debug.IDebug; +// Support AMD require +declare module 'debug' { + export = debug; } +declare module debug { + export interface IDebug { + (namespace: string): debug.IDebugger, + coerce: (val: any) => any, + disable: () => void, + enable: (namespaces: string) => void, + enabled: (namespaces: string) => boolean, + + names: string[], + skips: string[], + + formatters: IFormatters + } + + export interface IFormatters { + [formatter: string]: Function + } + + export interface IDebugger { + (formatter: any, ...args: any[]): void; + + enabled: boolean; + log: Function; + namespace: string; + } +} diff --git a/dhtmlxscheduler/dhtmlxscheduler.d.ts b/dhtmlxscheduler/dhtmlxscheduler.d.ts index c79ce78c9a..78537e3935 100644 --- a/dhtmlxscheduler/dhtmlxscheduler.d.ts +++ b/dhtmlxscheduler/dhtmlxscheduler.d.ts @@ -1165,11 +1165,22 @@ interface SchedulerStatic{ */ deleteEvent(id: any); + /** + * removes all blocking sets from the scheduler + */ + deleteMarkedTimespan(); + /** * removes marking/blocking set by the addMarkedTimespan() and blockTime() methods * @param id the timespan id */ deleteMarkedTimespan(id: string); + + /** + * removes marking/blocking set by the addMarkedTimespan() and blockTime() methods + * @param configuration for deleting + */ + deleteMarkedTimespan(config: any); /** * deletes a section from the currently active view (if the opened view isn't Timeline in the 'Tree' mode - the method will be ignored) @@ -1212,6 +1223,13 @@ interface SchedulerStatic{ * expands the scheduler to the full screen view */ expand(); + + /** + * filter events that will be displayed on the week view + * @param id event-id + * @param event event-object + */ + filter_week(id: any, event: any); /** * gives access to the objects of lightbox's sections diff --git a/fbemitter/fbemitter-tests.ts b/fbemitter/fbemitter-tests.ts new file mode 100644 index 0000000000..614d579634 --- /dev/null +++ b/fbemitter/fbemitter-tests.ts @@ -0,0 +1,349 @@ +/// +/// +/// +/// +'use strict'; + +/** + * The tests are adapted from ../eventemitter3/eventemitter3-tests.ts + */ + +import { EventEmitter, EventSubscription } from 'fbemitter'; +import * as util from 'util'; +import * as assert from 'assert'; + +describe('EventEmitter', function tests() { + 'use strict'; + + it('inherits when used with require(util).inherits', function () { + class Beast extends EventEmitter { + /* rawr, i'm a beast */ + } + + util.inherits(Beast, EventEmitter); + + var moop = new Beast() + , meap = new Beast(); + + assert.strictEqual(moop instanceof Beast, true); + assert.strictEqual(moop instanceof EventEmitter, true); + + moop.listeners('click'); + meap.listeners('click'); + + moop.addListener('data', function () { + throw new Error('I should not emit'); + }); + + meap.emit('data', 'rawr'); + meap.removeAllListeners(); + }); + + describe('EventEmitter#emit', function () { + it('emits with context', function (done) { + var context = { bar: 'baz' } + , e = new EventEmitter(); + + e.addListener('foo', function (bar: string) { + assert.strictEqual(bar, 'bar'); + assert.strictEqual(this, context); + + done(); + }, context); + + e.emit('foo', 'bar'); + }); + + it('can emit the function with multiple arguments', function () { + var e = new EventEmitter(); + + for(var i = 0; i < 100; i++) { + (function (j: number) { + for (var i = 0, args: number[] = []; i < j; i++) { + args.push(j); + } + + e.once('args', function () { + assert.strictEqual(arguments.length, args.length); + assert.deepStrictEqual(Array.prototype.slice.call(arguments), args); + }); + + e.emit.apply(e, (['args'] as any[]).concat(args)); + })(i); + } + }); + + it('can emit the function with multiple arguments, multiple listeners', function () { + var e = new EventEmitter(); + + for(var i = 0; i < 100; i++) { + (function (j: number) { + for (var i = 0, args: number[] = []; i < j; i++) { + args.push(j); + } + + e.once('args', function () { + assert.strictEqual(arguments.length, args.length); + assert.deepStrictEqual(Array.prototype.slice.call(arguments), args); + }); + + e.once('args', function () { + assert.strictEqual(arguments.length, args.length); + assert.deepStrictEqual(Array.prototype.slice.call(arguments), args); + }); + + e.once('args', function () { + assert.strictEqual(arguments.length, args.length); + assert.deepStrictEqual(Array.prototype.slice.call(arguments), args); + }); + + e.once('args', function () { + assert.strictEqual(arguments.length, args.length); + assert.deepStrictEqual(Array.prototype.slice.call(arguments), args); + }); + + e.emit.apply(e, (['args'] as any[]).concat(args)); + })(i); + } + }); + + it('emits with context, multiple listeners (force loop)', function () { + var e = new EventEmitter(); + + e.addListener('foo', function (bar: string) { + assert.deepStrictEqual(this, { foo: 'bar' }); + assert.strictEqual(bar, 'bar'); + }, { foo: 'bar' }); + + e.addListener('foo', function (bar: string) { + assert.deepStrictEqual(this, { bar: 'baz' }); + assert.strictEqual(bar, 'bar'); + }, { bar: 'baz' }); + + e.emit('foo', 'bar'); + }); + + it('emits with different contexts', function () { + var e = new EventEmitter() + , pattern = ''; + + function writer() { + pattern += this; + } + + e.addListener('write', writer, 'foo'); + e.addListener('write', writer, 'baz'); + e.once('write', writer, 'bar'); + e.once('write', writer, 'banana'); + + e.emit('write'); + assert.strictEqual(pattern, 'foobazbarbanana'); + }); + + it('receives the emitted events', function (done) { + var e = new EventEmitter(); + + e.addListener('data', function (a: string, b: EventEmitter, c: Date, d: void, undef: void) { + assert.strictEqual(a, 'foo'); + assert.strictEqual(b, e); + assert.strictEqual(c instanceof Date, true); + assert.strictEqual(undef, undefined); + assert.strictEqual(arguments.length, 3); + + done(); + }); + + e.emit('data', 'foo', e, new Date()); + }); + + it('emits to all event listeners', function () { + var e = new EventEmitter() + , pattern: string[] = []; + + e.addListener('foo', function () { + pattern.push('foo1'); + }); + + e.addListener('foo', function () { + pattern.push('foo2'); + }); + + e.emit('foo'); + + assert.strictEqual(pattern.join(';'), 'foo1;foo2'); + }); + + }); + + describe('EventEmitter#listeners', function () { + it('returns an empty array if no listeners are specified', function () { + var e = new EventEmitter(); + + assert.strictEqual(e.listeners('foo') instanceof Array, true); + assert.strictEqual(e.listeners('foo').length, 0); + }); + + it('returns an array of function', function () { + var e = new EventEmitter(); + + function foo() {} + + e.addListener('foo', foo); + assert.strictEqual(e.listeners('foo') instanceof Array, true); + assert.strictEqual(e.listeners('foo').length, 1); + console.log(e.listeners('foo')[0]); + assert.strictEqual(e.listeners('foo')[0], foo); + }); + + it('is not vulnerable to modifications', function () { + var e = new EventEmitter(); + + function foo() {} + + e.addListener('foo', foo); + + assert.strictEqual(e.listeners('foo')[0], foo); + + e.listeners('foo').length = 0; + assert.strictEqual(e.listeners('foo')[0], foo); + }); + }); + + describe('EventEmitter#once', function () { + it('only emits it once', function () { + var e = new EventEmitter() + , calls = 0; + + e.once('foo', function () { + calls++; + }); + + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(calls, 1); + }); + + it('only emits once if emits are nested inside the listener', function () { + var e = new EventEmitter() + , calls = 0; + + e.once('foo', function () { + calls++; + e.emit('foo'); + }); + + e.emit('foo'); + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(calls, 1); + }); + + it('only emits once for multiple events', function () { + var e = new EventEmitter() + , multi = 0 + , foo = 0 + , bar = 0; + + e.once('foo', function () { + foo++; + }); + + e.once('foo', function () { + bar++; + }); + + e.addListener('foo', function () { + multi++; + }); + + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + + assert.strictEqual(e.listeners('foo').length, 1); + assert.strictEqual(multi, 5); + assert.strictEqual(foo, 1); + assert.strictEqual(bar, 1); + }); + + it('only emits once with context', function (done) { + var context = { foo: 'bar' } + , e = new EventEmitter(); + + e.once('foo', function (bar: string) { + assert.strictEqual(this, context); + assert.strictEqual(bar, 'bar'); + done(); + }, context); + + e.emit('foo', 'bar'); + }); + }); + + describe('EventSubscription#remove', function () { + it('should only remove the event with the specified function', function () { + var e = new EventEmitter(); + + function bar() {} + var foo = e.addListener('foo', function () {}); + var bar1 = e.addListener('bar', function () {}); + var bar2 = e.addListener('bar', bar); + + assert.strictEqual(e.listeners('foo').length, 1); + assert.strictEqual(e.listeners('bar').length, 2); + + foo.remove(); + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(e.listeners('bar').length, 2); + + bar2.remove(); + assert.strictEqual(e.listeners('bar').length, 1); + + bar1.remove(); + assert.strictEqual(e.listeners('bar').length, 0); + }); + }); + + describe('EventEmitter#removeAllListeners', function () { + it('removes all events for the specified events', function () { + var e = new EventEmitter(); + + e.addListener('foo', function () { throw new Error('oops'); }); + e.addListener('foo', function () { throw new Error('oops'); }); + e.addListener('bar', function () { throw new Error('oops'); }); + e.addListener('aaa', function () { throw new Error('oops'); }); + + e.removeAllListeners('foo'); + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(e.listeners('bar').length, 1); + assert.strictEqual(e.listeners('aaa').length, 1); + + e.removeAllListeners('bar'); + e.removeAllListeners('aaa'); + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(e.listeners('bar').length, 0); + assert.strictEqual(e.listeners('aaa').length, 0); + }); + + it('just nukes the fuck out of everything', function () { + var e = new EventEmitter(); + + e.addListener('foo', function () { throw new Error('oops'); }); + e.addListener('foo', function () { throw new Error('oops'); }); + e.addListener('bar', function () { throw new Error('oops'); }); + e.addListener('aaa', function () { throw new Error('oops'); }); + + e.removeAllListeners(); + assert.strictEqual(e.listeners('foo').length, 0); + assert.strictEqual(e.listeners('bar').length, 0); + assert.strictEqual(e.listeners('aaa').length, 0); + }); + }); + +}); diff --git a/fbemitter/fbemitter.d.ts b/fbemitter/fbemitter.d.ts new file mode 100644 index 0000000000..b26b1a3162 --- /dev/null +++ b/fbemitter/fbemitter.d.ts @@ -0,0 +1,67 @@ +// Type definitions for Facebook's EventEmitter 2.0.0 +// Project: https://github.com/facebook/emitter +// Definitions by: kmxz +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare module 'fbemitter' { + + export class EventSubscription { + + listener: Function; + context: any; + + /** + * Removes this subscription from the subscriber that controls it. + */ + remove(): void; + + } + + export class EventEmitter { + + constructor(); + + /** + * Adds a listener to be invoked when events of the specified type are + * emitted. An optional calling context may be provided. The data arguments + * emitted will be passed to the listener function. + */ + addListener(eventType: string, listener: Function, context?: any): EventSubscription; + + /** + * Similar to addListener, except that the listener is removed after it is + * invoked once. + */ + once(eventType: string, listener: Function, context?: any): EventSubscription; + + /** + * Removes all of the registered listeners, including those registered as + * listener maps. + */ + removeAllListeners(eventType?: string): void; + + /** + * Provides an API that can be called during an eventing cycle to remove the + * last listener that was invoked. This allows a developer to provide an event + * object that can remove the listener (or listener map) during the + * invocation. + * + * If it is called when not inside of an emitting cycle it will throw. + */ + removeCurrentListener(): void; + + /** + * Returns an array of listeners that are currently registered for the given + * event. + */ + listeners(eventType: string): Function[]; + + /** + * Emits an event of the given type with the given data. All handlers of that + * particular type will be notified. + */ + emit(eventType: string, ...data: any[]): void; + + } + +} \ No newline at end of file diff --git a/github-electron/github-electron.d.ts b/github-electron/github-electron.d.ts index 46a8f81a7f..37dd602228 100644 --- a/github-electron/github-electron.d.ts +++ b/github-electron/github-electron.d.ts @@ -1121,7 +1121,7 @@ declare module GitHubElectron { * Note: This API is only available on Mac. */ setMenu(menu: Menu): void; - } + }; } class AutoUpdater implements NodeJS.EventEmitter { @@ -1353,7 +1353,7 @@ declare module GitHubElectron { * Only string properties are send correctly. * Nested objects are not supported. */ - extra?: {} + extra?: {}; } interface CrashReporterPayload extends Object { @@ -1406,7 +1406,7 @@ declare module GitHubElectron { getLastCrashReport(): CrashReporterPayload; } - interface Shell{ + interface Shell { /** * Show the given file in a file manager. If possible, select the file. */ @@ -1464,7 +1464,7 @@ declare module GitHubElectron { sendToHost(channel: string, ...args: any[]): void; } - interface Remote { + interface Remote extends CommonElectron { /** * @returns The object returned by require(module) in the main process. */ @@ -1472,7 +1472,7 @@ declare module GitHubElectron { /** * @returns The BrowserWindow object which this web page belongs to. */ - getCurrentWindow(): BrowserWindow + getCurrentWindow(): BrowserWindow; /** * @returns The global variable of name (e.g. global[name]) in the main process. */ @@ -1481,7 +1481,7 @@ declare module GitHubElectron { * Returns the process object in the main process. This is the same as * remote.getGlobal('process'), but gets cached. */ - process: any; + process: NodeJS.Process; } interface WebFrame { @@ -1523,7 +1523,7 @@ declare module GitHubElectron { // Type definitions for main process - interface ContentTracing { + interface ContentTracing { /** * Get a set of category groups. The category groups can change as new code paths are reached. * @param callback Called once all child processes have acked to the getCategories request. @@ -1710,30 +1710,94 @@ declare module GitHubElectron { RequestBufferJob: typeof RequestBufferJob; } + interface PowerSaveBlocker { + start(type: string): number; + stop(id: number): void; + isStarted(id: number): boolean; + } - interface Electron { + interface ClearStorageDataOptions { + origin?: string; + storages?: string[]; + quotas?: string[]; + } + + interface NetworkEmulationOptions { + offline?: boolean; + latency?: number; + downloadThroughput?: number; + uploadThroughput?: number; + } + + interface CertificateVerifyProc { + (hostname: string, cert: any, callback: (accepted: boolean) => any): any; + } + + class Session { + static fromPartition(partition: string): Session; + static defaultSession: Session; + + cookies: any; + clearCache(callback: Function): void; + clearStorageData(callback: Function): void; + clearStorageData(options: ClearStorageDataOptions, callback: Function): void; + setProxy(config: string, callback: Function): void; + resolveProxy(url: URL, callback: (proxy: any) => any): void; + setDownloadPath(path: string): void; + enableNetworkEmulation(options: NetworkEmulationOptions): void; + disableNetworkEmulation(): void; + setCertificateVerifyProc(proc: CertificateVerifyProc): void; + webRequest: any; + } + + interface CommonElectron { clipboard: GitHubElectron.Clipboard; crashReporter: GitHubElectron.CrashReporter; nativeImage: typeof GitHubElectron.NativeImage; - screen: GitHubElectron.Screen; shell: GitHubElectron.Shell; - remote: GitHubElectron.Remote; - ipcRenderer: GitHubElectron.IpcRenderer; - webFrame: GitHubElectron.WebFrame; + app: GitHubElectron.App; autoUpdater: GitHubElectron.AutoUpdater; BrowserWindow: typeof GitHubElectron.BrowserWindow; contentTracing: GitHubElectron.ContentTracing; dialog: GitHubElectron.Dialog; - globalShortcut: GitHubElectron.GlobalShortcut; ipcMain: NodeJS.EventEmitter; + globalShortcut: GitHubElectron.GlobalShortcut; Menu: typeof GitHubElectron.Menu; MenuItem: typeof GitHubElectron.MenuItem; powerMonitor: NodeJS.EventEmitter; + powerSaveBlocker: GitHubElectron.PowerSaveBlocker; protocol: GitHubElectron.Protocol; + screen: GitHubElectron.Screen; + session: GitHubElectron.Session; Tray: typeof GitHubElectron.Tray; hideInternalModules(): void; } + + interface DesktopCapturerOptions { + types?: string[]; + thumbnailSize?: { + width: number; + height: number; + }; + } + + interface DesktopCapturerSource { + id: string; + name: string; + thumbnail: NativeImage; + } + + interface DesktopCapturer { + getSources(options: any, callback: (error: Error, sources: DesktopCapturerSource[]) => any): void; + } + + interface Electron extends CommonElectron { + desktopCapturer: GitHubElectron.DesktopCapturer; + ipcRenderer: GitHubElectron.IpcRenderer; + remote: GitHubElectron.Remote; + webFrame: GitHubElectron.WebFrame; + } } interface Window { diff --git a/hopscotch/hopscotch.d.ts b/hopscotch/hopscotch.d.ts index 1baac775b5..46fdf17c6d 100644 --- a/hopscotch/hopscotch.d.ts +++ b/hopscotch/hopscotch.d.ts @@ -77,23 +77,84 @@ interface StepDefinition { } interface HopscotchStatic { + /** + * Actually starts the tour. Optional stepNum argument specifies what step to start at. + */ startTour(tour: TourDefinition, stepNum?: number): void; + + /** + * Skips to a given step in the tour + */ showStep(id: number): void; + + /** + * Goes back one step in the tour + */ prevStep(): void; + + /** + * Goes forward one step in the tour + */ nextStep(): void; + + /** + * Ends the current tour. If clearCookie is set to false, the tour state is preserved. + * Otherwise, if clearCookie is set to true or is not provided, the tour state is cleared. + */ endTour(clearCookie: boolean): void; + + /** + * Sets options for running the tour. + */ configure(options: HopscotchConfiguration): void; + + /** + * Returns the currently running tour. + */ getCurrTour(): TourDefinition; + + /** + * Returns the currently running tour. + */ getCurrStepNum(): number; + + /** + * Checks for tour state saved in sessionStorage/cookies and returns the state if + * it exists. Use this method to determine whether or not you should resume a tour. + */ getState(): string; + /** + * Adds a callback for one of the event types. Valid event types are: + * *start*, *end*, *next*, *prev*, *show*, *close*, *error* + */ listen(eventName: string, callback: () => void): void; + + /** + * Removes a callback for one of the event types. + */ unlisten(eventName: string, callback: () => void): void; + + /** + * Remove callbacks for hopscotch events. If tourOnly is set to true, only removes + * callbacks specified by a tour (callbacks set by hopscotch.configure or hopscotch.listen + * will remain). If eventName is null or undefined, callbacks for all events will be removed. + */ removeCallbacks(eventName?: string, tourOnly?: boolean): void; + /** + * Registers a callback helper. See the section about Helpers below. + */ registerHelper(id: string, helper: (...args: any[]) => void): void; + /** + * Resets i18n strings to original default values. + */ resetDefaultI18N(): void; + + /** + * Resets all config options to original values. + */ resetDefaultOptions(): void; } diff --git a/ionic/ionic-tests.ts b/ionic/ionic-tests.ts index bad5f9d9f1..8491fc13f8 100644 --- a/ionic/ionic-tests.ts +++ b/ionic/ionic-tests.ts @@ -200,8 +200,9 @@ class IonicTestController { }; var ionicPopoverController: ionic.popover.IonicPopoverController = this.$ionicPopover.fromTemplate("template", popoverOptions); ionicPopoverController.initialize(popoverOptions); - ionicPopoverController.show(angular.element("body")).then(() => console.log("shown popover")) - ionicPopoverController.hide().then(() => console.log("hid popover")) + ionicPopoverController.show(angular.element("body")).then(() => console.log("shown popover")); + ionicPopoverController.hide().then(() => console.log("hid popover")); + ionicPopoverController.remove().then(() => console.log("removed popover")); var isShown: boolean = ionicPopoverController.isShown(); this.$ionicPopover.fromTemplateUrl("templateUrl", popoverOptions) diff --git a/ionic/ionic.d.ts b/ionic/ionic.d.ts index a3781f26d0..a767b851bf 100644 --- a/ionic/ionic.d.ts +++ b/ionic/ionic.d.ts @@ -238,6 +238,7 @@ declare module ionic { show($event?: any): ng.IPromise; hide(): ng.IPromise; isShown(): boolean; + remove(): ng.IPromise; } interface IonicPopoverOptions { scope?: any; diff --git a/jade/jade-tests.ts b/jade/jade-tests.ts index 8a2b6b48de..6b4774021f 100644 --- a/jade/jade-tests.ts +++ b/jade/jade-tests.ts @@ -1,10 +1,10 @@ /// -import jade from 'jade'; +import * as jade from 'jade'; jade.compile("b")(); jade.compileFile("foo.jade", {})(); jade.compileClient("a")({ a: 1 }); jade.compileClientWithDependenciesTracked("test").body(); jade.render("h1",{}); -jade.renderFile("foo.jade"); \ No newline at end of file +jade.renderFile("foo.jade"); diff --git a/jade/jade.d.ts b/jade/jade.d.ts index 9615fa8c87..0764006e56 100644 --- a/jade/jade.d.ts +++ b/jade/jade.d.ts @@ -4,16 +4,13 @@ // Definitions: https://github.com/borisyankov/DefinitelyTyped declare module 'jade' { - module jade { - function compile(template: string, options?: any): (locals?: any) => string; - function compileFile(path: string, options?: any): (locals?: any) => string; - function compileClient(template: string, options?: any): (locals?: any) => string; - function compileClientWithDependenciesTracked(template: string, options?: any): { - body: (locals?: any) => string; - dependencies: string[]; - }; - function render(template: string, options?: any): string; - function renderFile(path: string, options?: any): string; - } - export default jade; + export function compile(template: string, options?: any): (locals?: any) => string; + export function compileFile(path: string, options?: any): (locals?: any) => string; + export function compileClient(template: string, options?: any): (locals?: any) => string; + export function compileClientWithDependenciesTracked(template: string, options?: any): { + body: (locals?: any) => string; + dependencies: string[]; + }; + export function render(template: string, options?: any): string; + export function renderFile(path: string, options?: any): string; } diff --git a/joi/joi-tests.ts b/joi/joi-tests.ts index 9e631e3e37..c8c05bf872 100644 --- a/joi/joi-tests.ts +++ b/joi/joi-tests.ts @@ -579,7 +579,9 @@ objSchema = objSchema.without(str, strArr); objSchema = objSchema.rename(str, str); objSchema = objSchema.rename(str, str, renOpts); +objSchema = objSchema.assert(str, schema); objSchema = objSchema.assert(str, schema, str); +objSchema = objSchema.assert(ref, schema); objSchema = objSchema.assert(ref, schema, str); objSchema = objSchema.unknown(); diff --git a/joi/joi.d.ts b/joi/joi.d.ts index 2e230dcb86..c774b36ab4 100644 --- a/joi/joi.d.ts +++ b/joi/joi.d.ts @@ -1,6 +1,6 @@ // Type definitions for joi v4.6.0 // Project: https://github.com/spumko/joi -// Definitions by: Bart van der Schoor , Laurence Dougal Myers , Christopher Glantschnig +// Definitions by: Bart van der Schoor , Laurence Dougal Myers , Christopher Glantschnig , David Broder-Rodgers // Definitions: https://github.com/borisyankov/DefinitelyTyped // TODO express type of Schema in a type-parameter (.default, .valid, .example etc) @@ -584,8 +584,8 @@ declare module 'joi' { /** * Verifies an assertion where. */ - assert(ref: string, schema: Schema, message: string): ObjectSchema; - assert(ref: Reference, schema: Schema, message: string): ObjectSchema; + assert(ref: string, schema: Schema, message?: string): ObjectSchema; + assert(ref: Reference, schema: Schema, message?: string): ObjectSchema; /** * Overrides the handling of unknown keys for the scope of the current object only (does not apply to children). diff --git a/lodash/lodash-tests.ts b/lodash/lodash-tests.ts index 3f7a26556d..77a20e2e2b 100644 --- a/lodash/lodash-tests.ts +++ b/lodash/lodash-tests.ts @@ -5920,10 +5920,24 @@ result = _({}).isError(); } // _.isFinite -result = _.isFinite(any); -result = _(1).isFinite(); -result = _([]).isFinite(); -result = _({}).isFinite(); +module TestIsFinite { + { + let result: boolean; + + result = _.isFinite(any); + result = _(1).isFinite(); + result = _([]).isFinite(); + result = _({}).isFinite(); + } + + { + let result: _.LoDashExplicitWrapper; + + result = _(1).chain().isFinite(); + result = _([]).chain().isFinite(); + result = _({}).chain().isFinite(); + } +} // _.isFunction module TestIsFunction { @@ -5987,7 +6001,7 @@ module TestIsNaN { } // _.isNative -module TestIsNull { +module TestIsNative { { let value: number|Function; @@ -6040,17 +6054,35 @@ module TestIsNull { } // _.isNumber -result = _.isNumber(any); -result = _(1).isNumber(); -result = _([]).isNumber(); -result = _({}).isNumber(); -{ - let value: number|string = "foo"; - if (_.isNumber(value)) { - let result: number = value * 42; - } else { - let result: string = value; - } +module TestIsNumber { + { + let value: string|number; + + if (_.isNumber(value)) { + let result: number = value; + } + else { + let result: string = value; + } + } + + { + let result: boolean; + + result = _.isNumber(any); + + result = _(1).isNumber(); + result = _([]).isNumber(); + result = _({}).isNumber(); + } + + { + let result: _.LoDashExplicitWrapper; + + result = _(1).chain().isNumber(); + result = _([]).chain().isNumber(); + result = _({}).chain().isNumber(); + } } // _.isObject @@ -6111,17 +6143,34 @@ module TestIsRegExp { } // _.isString -result = _.isString(any); -result = _(1).isString(); -result = _([]).isString(); -result = _({}).isString(); -{ - let value: string|number = "foo"; - if (_.isString(value)) { - let result: string = value; - } else { - let result: number = value * 42; - } +module TestIsString { + { + let value: number|string; + + if (_.isString(value)) { + let result: string = value; + } + else { + let result: number = value; + } + } + + { + let result: boolean; + + result = _.isString(any); + result = _(1).isString(); + result = _([]).isString(); + result = _({}).isString(); + } + + { + let result: _.LoDashExplicitWrapper; + + result = _(1).chain().isString(); + result = _([]).chain().isString(); + result = _({}).chain().isString(); + } } // _.isTypedArray diff --git a/lodash/lodash.d.ts b/lodash/lodash.d.ts index 584500c101..c45ec90eea 100644 --- a/lodash/lodash.d.ts +++ b/lodash/lodash.d.ts @@ -9928,11 +9928,13 @@ declare module _ { interface LoDashStatic { /** * Checks if value is a finite primitive number. + * * Note: This method is based on Number.isFinite. + * * @param value The value to check. * @return Returns true if value is a finite number, else false. - **/ - isFinite(value?: any): value is number; + */ + isFinite(value?: any): boolean; } interface LoDashImplicitWrapperBase { @@ -9942,6 +9944,13 @@ declare module _ { isFinite(): boolean; } + interface LoDashExplicitWrapperBase { + /** + * @see _.isFinite + */ + isFinite(): LoDashExplicitWrapper; + } + //_.isFunction interface LoDashStatic { /** @@ -10075,7 +10084,9 @@ declare module _ { interface LoDashStatic { /** * Checks if value is classified as a Number primitive or object. + * * Note: To exclude Infinity, -Infinity, and NaN, which are classified as numbers, use the _.isFinite method. + * * @param value The value to check. * @return Returns true if value is correctly classified, else false. */ @@ -10089,6 +10100,13 @@ declare module _ { isNumber(): boolean; } + interface LoDashExplicitWrapperBase { + /** + * see _.isNumber + */ + isNumber(): LoDashExplicitWrapper; + } + //_.isObject interface LoDashStatic { /** @@ -10165,9 +10183,10 @@ declare module _ { interface LoDashStatic { /** * Checks if value is classified as a String primitive or object. + * * @param value The value to check. * @return Returns true if value is correctly classified, else false. - **/ + */ isString(value?: any): value is string; } @@ -10178,6 +10197,13 @@ declare module _ { isString(): boolean; } + interface LoDashExplicitWrapperBase { + /** + * see _.isString + */ + isString(): LoDashExplicitWrapper; + } + //_.isTypedArray interface LoDashStatic { /** diff --git a/moment/moment-node.d.ts b/moment/moment-node.d.ts index babde41c92..3471a8fc30 100644 --- a/moment/moment-node.d.ts +++ b/moment/moment-node.d.ts @@ -1,10 +1,22 @@ -// Type definitions for Moment.js 2.8.0 +// Type definitions for Moment.js 2.10.5 // Project: https://github.com/timrwood/moment // Definitions by: Michael Lakerveld , Aaron King , Hiroki Horiuchi , Dick van den Brink , Adi Dahiya , Matt Brooks // Definitions: https://github.com/borisyankov/DefinitelyTyped declare module moment { + interface MomentDateObject { + years?: number; + /* One digit */ + months?: number; + /* Day of the month */ + date?: number; + hours?: number; + minutes?: number; + seconds?: number; + milliseconds?: number; + } + interface MomentInput { /** Year */ years?: number; @@ -247,8 +259,8 @@ declare module moment { dayOfYear(): number; dayOfYear(d: number): Moment; - from(f: Moment|string|number|Date|number[], suffix?: boolean): string; - to(f: Moment|string|number|Date|number[], suffix?: boolean): string; + from(f: Moment | string | number | Date | number[], suffix?: boolean): string; + to(f: Moment | string | number | Date | number[], suffix?: boolean): string; toNow(withoutPrefix?: boolean): string; diff(b: Moment): number; @@ -272,13 +284,13 @@ declare module moment { isDST(): boolean; isBefore(): boolean; - isBefore(b: Moment|string|number|Date|number[], granularity?: string): boolean; + isBefore(b: Moment | string | number | Date | number[], granularity?: string): boolean; isAfter(): boolean; - isAfter(b: Moment|string|number|Date|number[], granularity?: string): boolean; + isAfter(b: Moment | string | number | Date | number[], granularity?: string): boolean; - isSame(b: Moment|string|number|Date|number[], granularity?: string): boolean; - isBetween(a: Moment|string|number|Date|number[], b: Moment|string|number|Date|number[], granularity?: string): boolean; + isSame(b: Moment | string | number | Date | number[], granularity?: string): boolean; + isBetween(a: Moment | string | number | Date | number[], b: Moment | string | number | Date | number[], granularity?: string): boolean; // Deprecated as of 2.8.0. lang(language: string): Moment; @@ -294,43 +306,47 @@ declare module moment { localeData(): MomentLanguage; // Deprecated as of 2.7.0. - max(date: Moment|string|number|Date|any[]): Moment; + max(date: Moment | string | number | Date | any[]): Moment; max(date: string, format: string): Moment; // Deprecated as of 2.7.0. - min(date: Moment|string|number|Date|any[]): Moment; + min(date: Moment | string | number | Date | any[]): Moment; min(date: string, format: string): Moment; get(unit: string): number; set(unit: string, value: number): Moment; set(objectLiteral: MomentInput): Moment; + + /*This returns an object containing year, month, day-of-month, hour, minute, seconds, milliseconds.*/ + //Works with version 2.10.5+ + toObject(): MomentDateObject; } type formatFunction = () => string; interface MomentCalendar { - lastDay?: string | formatFunction; - sameDay?: string | formatFunction; - nextDay?: string | formatFunction; - lastWeek?: string | formatFunction; - nextWeek?: string | formatFunction; - sameElse?: string | formatFunction; + lastDay?: string | formatFunction; + sameDay?: string | formatFunction; + nextDay?: string | formatFunction; + lastWeek?: string | formatFunction; + nextWeek?: string | formatFunction; + sameElse?: string | formatFunction; } interface BaseMomentLanguage { - months ?: any; - monthsShort ?: any; - weekdays ?: any; - weekdaysShort ?: any; - weekdaysMin ?: any; - relativeTime ?: MomentRelativeTime; - meridiem ?: (hour: number, minute: number, isLowercase: boolean) => string; - calendar ?: MomentCalendar; - ordinal ?: (num: number) => string; + months?: any; + monthsShort?: any; + weekdays?: any; + weekdaysShort?: any; + weekdaysMin?: any; + relativeTime?: MomentRelativeTime; + meridiem?: (hour: number, minute: number, isLowercase: boolean) => string; + calendar?: MomentCalendar; + ordinal?: (num: number) => string; } interface MomentLanguage extends BaseMomentLanguage { - longDateFormat?: MomentLongDateFormat; + longDateFormat?: MomentLongDateFormat; } interface MomentLanguageData extends BaseMomentLanguage { @@ -341,34 +357,34 @@ declare module moment { } interface MomentLongDateFormat { - L: string; - LL: string; - LLL: string; - LLLL: string; - LT: string; - LTS: string; - l?: string; - ll?: string; - lll?: string; - llll?: string; - lt?: string; - lts?: string; + L: string; + LL: string; + LLL: string; + LLLL: string; + LT: string; + LTS: string; + l?: string; + ll?: string; + lll?: string; + llll?: string; + lt?: string; + lts?: string; } interface MomentRelativeTime { - future: any; - past: any; - s: any; - m: any; - mm: any; - h: any; - hh: any; - d: any; - dd: any; - M: any; - MM: any; - y: any; - yy: any; + future: any; + past: any; + s: any; + m: any; + mm: any; + h: any; + hh: any; + d: any; + dd: any; + M: any; + MM: any; + y: any; + yy: any; } interface MomentStatic { @@ -460,8 +476,8 @@ declare module moment { max(...moments: Moment[]): Moment; normalizeUnits(unit: string): string; - relativeTimeThreshold(threshold: string): number|boolean; - relativeTimeThreshold(threshold: string, limit:number): boolean; + relativeTimeThreshold(threshold: string): number | boolean; + relativeTimeThreshold(threshold: string, limit: number): boolean; /** * Constant used to enable explicit ISO_8601 format parsing. diff --git a/mssql/mssql-tests.ts b/mssql/mssql-tests.ts index e508ec3547..f1f1a20b2c 100644 --- a/mssql/mssql-tests.ts +++ b/mssql/mssql-tests.ts @@ -3,6 +3,10 @@ import sql = require('mssql'); +interface Entity{ + value: number; +} + var config: sql.config = { user: 'user', password: 'password', @@ -33,6 +37,18 @@ var connection: sql.Connection = new sql.Connection(config, function (err: any) } }); + getArticlesQuery = "SELECT 1 as value FROM TABLE"; + + requestQuery.query(getArticlesQuery, function (err, recordSet) { + if (err) { + console.error('Error happened calling Query: ' + err.name + " " + err.message); + + } + // checking to see if the articles returned as at least one. + else if (recordSet.length > 0 && recordSet[0].value) { + } + }); + var requestStoredProcedure = new sql.Request(connection); var testId: number = 0; var testString: string = 'test'; @@ -50,6 +66,15 @@ var connection: sql.Connection = new sql.Connection(config, function (err: any) } }); + requestStoredProcedure.execute('StoredProcedureName', function (err, recordsets, returnValue) { + if (err != null) { + console.error('Error happened calling Query: ' + err.name + " " + err.message); + } + else { + console.info(returnValue); + } + }); + var requestStoredProcedureWithOutput = new sql.Request(connection); var testId: number = 0; var testString: string = 'test'; @@ -74,6 +99,15 @@ var connection: sql.Connection = new sql.Connection(config, function (err: any) console.info(requestStoredProcedureWithOutput.parameters['output'].value); } }); + + requestStoredProcedure.execute('StoredProcedureName', function (err, recordsets, returnValue) { + if (err != null) { + console.error('Error happened calling Query: ' + err.name + " " + err.message); + } + else { + console.info(requestStoredProcedureWithOutput.parameters['output'].value); + } + }); } }); @@ -109,8 +143,10 @@ function test_promise_returns() { var request = new sql.Request(); request.batch('create procedure #temporary as select * from table').then((recordset) => { }); + request.batch('create procedure #temporary as select * from table;select 1 as value').then((recordset) => { }); request.bulk(new sql.Table("table_name")).then(() => { }); request.query('SELECT 1').then((recordset) => { }); + request.query('SELECT 1 as value').then(res => { }); request.execute('procedure_name').then((recordset) => { }); } @@ -120,7 +156,7 @@ function test_request_constructor() { var connection: sql.Connection = new sql.Connection(config); var preparedStatment = new sql.PreparedStatement(connection); var transaction = new sql.Transaction(connection); - + var request1 = new sql.Request(connection); var request2 = new sql.Request(preparedStatment); var request3 = new sql.Request(transaction); @@ -141,4 +177,4 @@ function test_classes_extend_eventemitter() { request.on('error', () => { }); preparedStatment.on('error', () => { }) -} \ No newline at end of file +} diff --git a/mssql/mssql.d.ts b/mssql/mssql.d.ts index c434444d3f..2b3db48075 100644 --- a/mssql/mssql.d.ts +++ b/mssql/mssql.d.ts @@ -7,7 +7,7 @@ /// declare module "mssql" { - import events = require('events'); + import events = require('events'); type sqlTypeWithNoParams = { type: sqlTypeFactoryWithNoParams } type sqlTypeWithLength = { type: sqlTypeFactoryWithLength, length: number } @@ -200,15 +200,19 @@ declare module "mssql" { public constructor(transaction: Transaction); public constructor(preparedStatement: PreparedStatement); public execute(procedure: string): Promise; - public execute(procedure: string, callback: (err?: any, recordsets?: any, returnValue?: any) => void): void; + public execute(procedure: string, callback: (err?: any, recordsets?: Entity[], returnValue?: any) => void): void; public input(name: string, value: any): void; public input(name: string, type: any, value: any): void; public output(name: string, type: any, value?: any): void; public pipe(stream: NodeJS.WritableStream): void; public query(command: string): Promise; + public query(command: string): Promise; public query(command: string, callback: (err?: any, recordset?: any) => void): void; + public query(command: string, callback: (err?: any, recordset?: Entity[]) => void): void; public batch(batch: string): Promise; + public batch(batch: string): Promise; public batch(batch: string, callback: (err?: any, recordset?: any) => void): void; + public batch(batch: string, callback: (err?: any, recordset?: Entity[]) => void): void; public bulk(table: Table): Promise; public bulk(table: Table, callback: (err: any, rowCount: any) => void): void; public cancel(): void; @@ -254,7 +258,9 @@ declare module "mssql" { public prepare(statement?: string): Promise; public prepare(statement?: string, callback?: (err?: any) => void): void; public execute(values: Object): Promise; + public execute(values: Object): Promise; public execute(values: Object, callback: (err: any, recordSet: recordSet) => void): void; + public execute(values: Object, callback: (err: any, recordSet: Entity[]) => void): void; public unprepare(): Promise; public unprepare(callback: (err?: any) => void): void; } diff --git a/multer/multer-tests.ts b/multer/multer-tests.ts index 8131293f5d..009ec4fbd0 100644 --- a/multer/multer-tests.ts +++ b/multer/multer-tests.ts @@ -4,5 +4,30 @@ import express = require('express'); import multer = require('multer'); -var app: express.Express = express(); -app.use(multer()); \ No newline at end of file +var upload = multer({ dest: 'uploads/' }); + +var app = express(); + +app.post('/profile', upload.single('avatar'), (req, res, next) => { +}); + +app.post('/photos/upload', upload.array('photos', 12), (req, res, next) => { +}); + +var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) +app.post('/cool-profile', cpUpload, (req, res, next) => { +}); + +var diskStorage = multer.diskStorage({ + destination(req, file, cb) { + cb(null, '/tmp/my-uploads'); + }, + filename(req, file, cb) { + cb(null, file.fieldname + '-' + Date.now()); + } +}) + +var diskUpload = multer({ storage: diskStorage }); + +var memoryStorage = multer.memoryStorage(); +var memoryUpload = multer({ storage: memoryStorage }); diff --git a/multer/multer.d.ts b/multer/multer.d.ts index 06a9d4f7af..facd3da535 100644 --- a/multer/multer.d.ts +++ b/multer/multer.d.ts @@ -1,16 +1,16 @@ // Type definitions for multer // Project: https://github.com/expressjs/multer -// Definitions by: jt000 , vilicvane +// Definitions by: jt000 , vilicvane , David Broder-Rodgers // Definitions: https://github.com/borisyankov/DefinitelyTyped /// - declare module Express { export interface Request { + file: Multer.File; files: { [fieldname: string]: Multer.File - } + }; } module Multer { @@ -40,13 +40,19 @@ declare module Express { declare module "multer" { import express = require('express'); - function multer(options?: multer.Options): express.RequestHandler; - module multer { + interface Field { + /** The field name. */ + name: string; + /** Optional maximum number of files per field to accept. */ + maxCount?: number; + } - type Options = { + interface Options { /** The destination directory for the uploaded files. */ dest?: string; + /** The storage engine to use for uploaded files. */ + storage?: StorageEngine; /** An object specifying the size limits of the following optional properties. This object is passed to busboy directly, and the details of properties can be found on https://github.com/mscdex/busboy#busboy-methods */ limits?: { /** Max field name size (Default: 100 bytes) */ @@ -64,36 +70,45 @@ declare module "multer" { /** For multipart forms, the max number of header key=> value pairs to parse Default: 2000(same as node's http). */ headerPairs?: number; }; - /** A Boolean value to specify whether empty submitted values should be processed and applied to req.body; defaults to false; */ - includeEmptyFields?: boolean; - /** If this Boolean value is true, the file.buffer property holds the data in-memory that Multer would have written to disk. The dest option is still populated and the path property contains the proposed path to save the file. Defaults to false. */ - inMemory?: boolean; - /** Function to rename the uploaded files. Whatever the function returns will become the new name of the uploaded file (extension is not included). The fieldname and filename of the file will be available in this function, use them if you need to. */ - rename?: (fieldname: string, filename: string, req: Express.Request, res: Express.Response) => string; - /** Function to rename the directory in which to place uploaded files. The dest parameter is the default value originally assigned or passed into multer. The req and res parameters are also passed into the function because they may contain information (eg session data) needed to create the path (eg get userid from the session). */ - changeDest?: (dest: string, req: Express.Request, res: Express.Response) => string; - /** Event handler triggered when a file starts to be uploaded. A file object, with the following properties, is available to this function: fieldname, originalname, name, encoding, mimetype, path, and extension. */ - onFileUploadStart?: (file: Express.Multer.File, req: Express.Request, res: Express.Response) => void; - /** Event handler triggered when a chunk of buffer is received. A buffer object along with a file object is available to the function. */ - onFileUploadData?: (file: Express.Multer.File, data: Buffer, req: Express.Request, res: Express.Response) => void; - /** Event handler trigger when a file is completely uploaded. A file object is available to the function. */ - onFileUploadComplete?: (file: Express.Multer.File, req: Express.Request, res: Express.Response) => void; - /** Event handler triggered when the form parsing starts. */ - onParseStart?: () => void; - /** Event handler triggered when the form parsing completes. The request object and the next objects are are passed to the function. */ - onParseEnd?: (req: Express.Request, next: () => void) => void; - /** Event handler for any errors encountering while processing the form. The error object and the next object is available to the function. If you are handling errors yourself, make sure to terminate the request or call the next() function, else the request will be left hanging. */ - onError?: () => void; - /** Event handler triggered when a file size exceeds the specification in the limit object. No more files will be parsed after the limit is reached. */ - onFileSizeLimit?: (file: Express.Multer.File) => void; - /** Event handler triggered when the number of files exceed the specification in the limit object. No more files will be parsed after the limit is reached. */ - onFilesLimit?: () => void; - /** Event handler triggered when the number of fields exceed the specification in the limit object. No more fields will be parsed after the limit is reached. */ - onFieldsLimit?: () => void; - /** Event handler triggered when the number of parts exceed the specification in the limit object. No more files or fields will be parsed after the limit is reached. */ - onPartsLimit?: () => void; - }; + /** A function to control which files to upload and which to skip. */ + fileFilter?: (req: Express.Request, file: Express.Multer.File, callback: (error: Error, acceptFile: boolean) => void) => void; + } + + interface StorageEngine { + _handleFile(req: express.Request, file: Express.Multer.File, callback: (error?: any, info?: Express.Multer.File) => void): void; + _removeFile(req: express.Request, file: Express.Multer.File, callback: (error: Error) => void): void; + } + + interface DiskStorageOptions { + /** A function used to determine within which folder the uploaded files should be stored. Defaults to the system's default temporary directory. */ + destination?: (req: Express.Request, file: Express.Multer.File, callback: (error: Error, destination: string) => void) => void; + /** A function used to determine what the file should be named inside the folder. Defaults to a random name with no file extension. */ + filename?: (req: Express.Request, file: Express.Multer.File, callback: (error: Error, filename: string) => void) => void; + } + + interface Instance { + /** Accept a single file with the name fieldname. The single file will be stored in req.file. */ + single(fieldame: string): express.RequestHandler; + /** Accept an array of files, all with the name fieldname. Optionally error out if more than maxCount files are uploaded. The array of files will be stored in req.files. */ + array(fieldame: string, maxCount?: number): express.RequestHandler; + /** Accept a mix of files, specified by fields. An object with arrays of files will be stored in req.files. */ + fields(fields: Field[]): express.RequestHandler; + /** Accepts all files that comes over the wire. An array of files will be stored in req.files. */ + any(): express.RequestHandler; + } } + interface Multer { + + (options?: multer.Options): multer.Instance; + + /* The disk storage engine gives you full control on storing files to disk. */ + diskStorage(options: multer.DiskStorageOptions): multer.StorageEngine; + /* The memory storage engine stores the files in memory as Buffer objects. */ + memoryStorage(): multer.StorageEngine; + } + + var multer: Multer; + export = multer; } diff --git a/node/node.d.ts b/node/node.d.ts index 14b577986a..450facb4a5 100644 --- a/node/node.d.ts +++ b/node/node.d.ts @@ -490,6 +490,7 @@ declare module "http" { writeHead(statusCode: number, headers?: any): void; statusCode: number; statusMessage: string; + headersSent: boolean; setHeader(name: string, value: string): void; sendDate: boolean; getHeader(name: string): string; diff --git a/raty/raty-tests.ts b/raty/raty-tests.ts new file mode 100644 index 0000000000..89efb79c3d --- /dev/null +++ b/raty/raty-tests.ts @@ -0,0 +1,54 @@ +/// +/// + + +var $element: JQuery = $('
'); + +$element.raty(); + +$element.raty({ + cancel: false, + cancelClass: 'raty-cancel', + cancelHint: 'Cancel this rating!', + cancelOff: 'cancel-off.png', + cancelOn: 'cancel-on.png', + cancelPlace: 'left', + click: undefined, + half: false, + halfShow: true, + hints: ['bad', 'poor', 'regular', 'good', 'gorgeous'], + iconRange: undefined, + mouseout: undefined, + mouseover: undefined, + noRatedMsg: 'Not rated yet!', + number: 5, + numberMax: 20, + path: undefined, + precision: false, + readOnly: false, + round: { down: .25, full: .6, up: .76 }, + score: undefined, + scoreName: 'score', + single: false, + space: true, + starHalf: 'star-half.png', + starOff: 'star-off.png', + starOn: 'star-on.png', + target: undefined, + targetFormat: '{score}', + targetKeep: false, + targetScore: undefined, + targetText: '', + targetType: 'hint', + starType: 'img', +}); + +var score: number = $element.raty('score'); +$element.raty('score', 4); +$element.raty('click', 2); +$element.raty('readOnly', true); +$element.raty('cancel', true); +$element.raty('reload'); +$element.raty('set', { space: false }); +$element.raty('destroy'); +$element.raty('move', 3); diff --git a/raty/raty.d.ts b/raty/raty.d.ts new file mode 100644 index 0000000000..bb02d94752 --- /dev/null +++ b/raty/raty.d.ts @@ -0,0 +1,64 @@ +// Type definitions for jQuery.raty 2.7.0 +// Project: https://github.com/wbotelhos/raty +// Definitions by: Matt Wheatley +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +interface JQuery { + raty(): JQuery; + raty(options: JQueryRatyOptions): JQuery; + raty(method: string, parameter: any): any; + raty(method: 'score'): number; + raty(method: 'score', score: number): void; + raty(method: 'click', star: number): void; + raty(method: 'readonly', on: boolean): void; + raty(method: 'cancel', on: boolean): void; + raty(method: 'reload'): void; + raty(method: 'set', options: JQueryRatyOptions): void; + raty(method: 'destroy'): JQuery; + raty(method: 'move', number: number): void; +} + +interface JQueryRatyOptions { + cancel?: boolean, + cancelClass?: string, + cancelHint?: string, + cancelOff?: string, + cancelOn?: string, + cancelPlace?: string, + click?: (score: number, event: JQueryEventObject) => void, + half?: boolean, + halfShow?: boolean, + hints?: string[], + iconRange?: any[][], + mouseout?: (score: number, event: JQueryEventObject) => void, + mouseover?: (score: number, event: JQueryEventObject) => void, + noRatedMsg?: string, + number?: number, + numberMax?: number, + path?: string, + precision?: boolean, + readOnly?: boolean, + round?: JQueryRatyRoundingOptions, + score?: number, + scoreName?: string, + single?: boolean, + space?: boolean, + starHalf?: string, + starOff?: string, + starOn?: string, + target?: string, + targetFormat?: string, + targetKeep?: boolean, + targetScore?: string, + targetText?: string, + targetType?: string, + starType?: string, +} + +interface JQueryRatyRoundingOptions { + down: number, + full: number, + up: number, +} diff --git a/rcloader/rcloader-tests.ts b/rcloader/rcloader-tests.ts new file mode 100644 index 0000000000..16ade8c555 --- /dev/null +++ b/rcloader/rcloader-tests.ts @@ -0,0 +1,11 @@ +/// + +import RcLoader = require("rcloader"); + +const rcLoader = new RcLoader(".configfilename", { + lookup: true +}); + +rcLoader.for("foo.json", (err, fileOpts) => { + // send the file along +}); diff --git a/rcloader/rcloader.d.ts b/rcloader/rcloader.d.ts new file mode 100644 index 0000000000..e06ac5905d --- /dev/null +++ b/rcloader/rcloader.d.ts @@ -0,0 +1,18 @@ +// Type definitions for rcloader +// Project: https://github.com/spalger/rcloader +// Definitions by: Panu Horsmalahti +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module "rcloader" { + interface Options { + [property: string]: any; + lookup?: boolean; + } + + class RcLoader { + constructor(configfilename: string, options: string | Options); + for(path: string, callback?: (error: any, fileOpts: any) => void): void; + } + + export = RcLoader; +} diff --git a/react/react.d.ts b/react/react.d.ts index bd35811119..15146eb9b5 100644 --- a/react/react.d.ts +++ b/react/react.d.ts @@ -1145,6 +1145,11 @@ declare namespace __React { */ maxWidth?: any; + /** + * Sets the minimum height for an element. It prevents the height of the element to be smaller than the specified value. The value of min-height overrides both max-height and height. + */ + minHeight?: any; + /** * Sets the minimum width of an element. It limits the width property to be not smaller than the value specified in min-width. */ @@ -1817,7 +1822,7 @@ declare namespace __React { vocab?: string; // Non-standard Attributes - autoCapitalize?: boolean; + autoCapitalize?: string; autoCorrect?: string; autoSave?: string; color?: string; diff --git a/rss/rss-tests.ts b/rss/rss-tests.ts new file mode 100644 index 0000000000..38ce28a977 --- /dev/null +++ b/rss/rss-tests.ts @@ -0,0 +1,71 @@ +/// + +// this test is copied from https://github.com/dylang/node-rss +// it basically: +// +// * creates an RSS feed with some attributes, +// * add an item to it +// * then generates XML string + +import * as RSS from 'rss'; + +var feed = new RSS({ + title: 'title', + description: 'description', + feed_url: 'http://example.com/rss.xml', + site_url: 'http://example.com', + image_url: 'http://example.com/icon.png', + docs: 'http://example.com/rss/docs.html', + managingEditor: 'Dylan Greene', + webMaster: 'Dylan Greene', + copyright: '2013 Dylan Greene', + language: 'en', + categories: ['Category 1','Category 2','Category 3'], + pubDate: 'May 20, 2012 04:00:00 GMT', + ttl: 60, + custom_namespaces: { + 'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd' + }, + custom_elements: [ + { 'itunes:subtitle': 'A show about everything' }, + { 'itunes:author': 'John Doe' }, + { 'itunes:summary': 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store'}, + { 'itunes:owner': [ + { 'itunes:name': 'John Doe' }, + { 'itunes:email': 'john.doe@example.com' } + ] + }, + { 'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything.jpg' + } + } + } + ] +}); + +feed.item({ + title: 'item title', + description: 'use this for the content. It can include html.', + url: 'http://example.com/article4?this&that', + guid: '1123', + categories: ['Category 1','Category 2','Category 3','Category 4'], + author: 'Guest Author', + date: 'May 27, 2012', + lat: 33.417974, + long: -111.933231, + enclosure: { url:'...', file:'path-to-file' }, + custom_elements: [ + { 'itunes:author': 'John Doe' }, + { 'itunes:subtitle': 'A short primer on table spices' }, + { 'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg' + } + } + }, + { 'itunes:duration': '7:04' } + ] +}); + +var xml = feed.xml(); diff --git a/rss/rss.d.ts b/rss/rss.d.ts new file mode 100644 index 0000000000..eab2fc70da --- /dev/null +++ b/rss/rss.d.ts @@ -0,0 +1,209 @@ +// Type definitions for rss +// Project: https://github.com/dylang/node-rss +// Definitions by: Second Datke +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module NodeRSS { + interface FeedOptions { + /** + * Title of your site or feed. + */ + title: string; + /** + * A short description of the feed. + */ + description?: string; + /** + * Feed generator. + */ + generator?: string; + /** + * URL to the rss feed. + */ + feed_url: string; + /** + * URL to the site that the feed is for. + */ + site_url: string; + /** + * Small image for feed readers to use. + */ + image_url?: string; + /** + * URL to documentation on this feed. + */ + docs?: string; + /** + * Who manages content in this feed. + */ + managingEditor?: string; + /** + * Who manages feed availability and technical support. + */ + webMaster?: string; + /** + * Copyright information for this feed. + */ + copyright?: string; + /** + * The language of the content of this feed. + */ + language?: string; + /** + * One or more categories this feed belongs to. + */ + categories?: string[]; + /** + * The publication date for content in the feed. + * Accepts Date object or string with any format + * JS Date can parse. + */ + pubDate?: Date | string; + /** + * Number of minutes feed can be cached before refreshing + * from source. + */ + ttl?: number; + /** + * Where is the PubSubHub hub located. + */ + hub?: string; + /** + * Put additional namespaces in element + * (without 'xmlns:' prefix). + */ + custom_namespaces?: Object; + /** + * Put additional elements in the feed (node-xml syntax). + */ + custom_elements?: any[]; + } + + interface EnclosureObject { + /** + * URL to file object (or file). + */ + url: string; + /** + * Path to binary file (or URL). + */ + file: string; + /** + * Size of the file. + */ + size?: number; + /** + * If not provided, the MIME Type will be guessed based + * on the extension of the file or URL, passing type to + * the enclosure will override the guessed type. + */ + type?: string; + } + + interface ItemOptions { + /** + * Title of this particular item. + */ + title: string; + /** + * Content for the item. Can contain HTML but link and image + * URLs must be absolute path including hostname. + */ + description: string; + /** + * URL to the item. This could be a blog entry. + */ + url: string; + /** + * A unique string feed readers use to know if an item is + * new or has already been seen. If you use a guid never + * change it. If you don't provide a guid then your item + * urls must be unique. + * Defaults to url. + */ + guid?: string; + /** + * If provided, each array item will be added as a category + * element. + */ + categories?: string[]; + /** + * If included it is the name of the item's creator. If not + * provided the item author will be the same as the feed author. + * This is typical except on multi-author blogs. + */ + author?: string; + /** + * The date and time of when the item was created. Feed + * readers use this to determine the sort order. Some readers + * will also use it to determine if the content should be + * presented as unread. + * Accepts Date object or string with any format + * JS Date can parse. + */ + date: Date | string; + /** + * The latitude coordinate of the item for GeoRSS. + */ + lat?: number; + /** + * The longitude coordinate of the item for GeoRSS. + */ + long?: number; + /** + * Put additional elements in the item (node-xml syntax). + */ + custom_elements?: any[]; + /** + * An enclosure object. + */ + enclosure?: EnclosureObject; + } + + interface XmlOptions { + /** + * What to use as a tab. Defaults to no tabs (compressed). + * For example you can use '\t' for tab character, or ' ' + * for two-space tabs. If you set it to true it will use + * four spaces. + */ + indent?: boolean | string; + } + + interface RSS { + /** + * Add an item to a feed. An item can be used for a blog + * entry, project update, log entry, etc. + * @param {ItemOptions} itemOptions + * @returns {RSS} + */ + item(itemOptions: ItemOptions): RSS; + /** + * Generate XML and return as a string for this feed. + * @returns {string} + */ + xml(): string; + /** + * Generate XML and return as a string for this feed. + * + * @param {XmlOptions} xmlOptions - You can use indent + * option to specify the tab character to use. + * @returns {string} + */ + xml(xmlOptions: XmlOptions): string; + } + + interface RSSFactory { + /** + * Create an RSS feed with options. + * @param {FeedOptions} feedOptions - Options for the RSS feed. + * @returns {RSS} + */ + new(feedOptions: FeedOptions): RSS; + } +} + +declare module 'rss' { + var factory: NodeRSS.RSSFactory; + export = factory; +} diff --git a/s3rver/s3rver-tests.ts b/s3rver/s3rver-tests.ts new file mode 100644 index 0000000000..afa7e92273 --- /dev/null +++ b/s3rver/s3rver-tests.ts @@ -0,0 +1,14 @@ +/// + +import S3rver = require('s3rver'); + +var s3rver = new S3rver({ + port: 5694, + hostname: 'localhost', + silent: true, + indexDocument: 'index.html', + errorDocument: '', + directory: '/tmp/s3rver_test_directory' +}).run((err, hostname, port, directory) => {}); + +s3rver.close(); diff --git a/s3rver/s3rver.d.ts b/s3rver/s3rver.d.ts new file mode 100644 index 0000000000..e34650986e --- /dev/null +++ b/s3rver/s3rver.d.ts @@ -0,0 +1,32 @@ +// Type definitions for S3rver +// Project: https://github.com/jamhall/s3rver +// Definitions by: David Broder-Rodgers +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "s3rver" { + import * as http from "http"; + + class S3rver { + constructor(options: S3rverOptions) + setPort(port: number): S3rver; + setHostname(hostname: string): S3rver; + setDirectory(directory: string): S3rver; + setSilent(silent: boolean): S3rver; + setIndexDocument(indexDocument: string): S3rver; + setErrorDocument(errorDocument: string): S3rver; + run(callback: (error: Error, hostname: string, port: number, directory: string) => void): http.Server; + } + + interface S3rverOptions { + port?: number; + hostname?: string; + silent?: boolean; + indexDocument?: string; + errorDocument?: string; + directory: string; + } + + export = S3rver; +} diff --git a/spotify-api/spotify-api-tests.ts b/spotify-api/spotify-api-tests.ts new file mode 100644 index 0000000000..db90150162 --- /dev/null +++ b/spotify-api/spotify-api-tests.ts @@ -0,0 +1,6273 @@ +/* + * This test file contains the sample output from The Spotify Web Api obtained from [The Web API Console](https://developer.spotify.com/web-api/console/) + * The standard suggested values for input were used. + * + * Combined with the typings it should compile without errors. + * + * The order of tests is the same as on [The Spotify Web Api](https://developer.spotify.com/web-api/endpoint-reference/) + * To find tests, search for "* Tests" instead of scrolling to keep sane. + */ + +/// + + + + +/** + * Tests the response of https://developer.spotify.com/web-api/get-album/ + */ +var getSingleAlbum : SpotifyApi.SingleAlbumResponse = { + "album_type" : "album", + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "copyrights" : [ { + "text" : "(P) 2000 Sony Music Entertainment Inc.", + "type" : "P" + } ], + "external_ids" : { + "upc" : "5099749994324" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0sNOF9WDwhWunNAHPD3Baj" + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/albums/0sNOF9WDwhWunNAHPD3Baj", + "id" : "0sNOF9WDwhWunNAHPD3Baj", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/07c323340e03e25a8e5dd5b9a8ec72b69c50089d", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8b662d81966a0ec40dc10563807696a8479cd48b", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/54b3222c8aaa77890d1ac37b3aaaa1fc9ba630ae", + "width" : 64 + } ], + "name" : "She's So Unusual", + "popularity" : 0, + "release_date" : "1983", + "release_date_precision" : "year", + "tracks" : { + "href" : "https://api.spotify.com/v1/albums/0sNOF9WDwhWunNAHPD3Baj/tracks?offset=0&limit=50", + "items" : [ { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 305560, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3f9zqUnrnIq0LANhmnaF0V" + }, + "href" : "https://api.spotify.com/v1/tracks/3f9zqUnrnIq0LANhmnaF0V", + "id" : "3f9zqUnrnIq0LANhmnaF0V", + "name" : "Money Changes Everything", + "preview_url" : null, + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:3f9zqUnrnIq0LANhmnaF0V" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 238266, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2joHDtKFVDDyWDHnOxZMAX" + }, + "href" : "https://api.spotify.com/v1/tracks/2joHDtKFVDDyWDHnOxZMAX", + "id" : "2joHDtKFVDDyWDHnOxZMAX", + "name" : "Girls Just Want to Have Fun", + "preview_url" : null, + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:2joHDtKFVDDyWDHnOxZMAX" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 306706, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6ClztHzretmPHCeiNqR5wD" + }, + "href" : "https://api.spotify.com/v1/tracks/6ClztHzretmPHCeiNqR5wD", + "id" : "6ClztHzretmPHCeiNqR5wD", + "name" : "When You Were Mine", + "preview_url" : null, + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:6ClztHzretmPHCeiNqR5wD" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 241333, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2tVHvZK4YYzTloSCBPm2tg" + }, + "href" : "https://api.spotify.com/v1/tracks/2tVHvZK4YYzTloSCBPm2tg", + "id" : "2tVHvZK4YYzTloSCBPm2tg", + "name" : "Time After Time", + "preview_url" : null, + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:2tVHvZK4YYzTloSCBPm2tg" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 229266, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6iLhMDtOr52OVXaZdha5M6" + }, + "href" : "https://api.spotify.com/v1/tracks/6iLhMDtOr52OVXaZdha5M6", + "id" : "6iLhMDtOr52OVXaZdha5M6", + "name" : "She Bop", + "preview_url" : null, + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:6iLhMDtOr52OVXaZdha5M6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 272840, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3csiLr2B2wRj4lsExn6jLf" + }, + "href" : "https://api.spotify.com/v1/tracks/3csiLr2B2wRj4lsExn6jLf", + "id" : "3csiLr2B2wRj4lsExn6jLf", + "name" : "All Through the Night", + "preview_url" : null, + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:3csiLr2B2wRj4lsExn6jLf" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 220333, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4mRAnuBGYsW4WGbpW0QUkp" + }, + "href" : "https://api.spotify.com/v1/tracks/4mRAnuBGYsW4WGbpW0QUkp", + "id" : "4mRAnuBGYsW4WGbpW0QUkp", + "name" : "Witness", + "preview_url" : null, + "track_number" : 7, + "type" : "track", + "uri" : "spotify:track:4mRAnuBGYsW4WGbpW0QUkp" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 252626, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3AIeUnffkLQaUaX1pkHyeD" + }, + "href" : "https://api.spotify.com/v1/tracks/3AIeUnffkLQaUaX1pkHyeD", + "id" : "3AIeUnffkLQaUaX1pkHyeD", + "name" : "I'll Kiss You", + "preview_url" : null, + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:3AIeUnffkLQaUaX1pkHyeD" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 45933, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/53eCpAFNbA9MQNfLilN3CH" + }, + "href" : "https://api.spotify.com/v1/tracks/53eCpAFNbA9MQNfLilN3CH", + "id" : "53eCpAFNbA9MQNfLilN3CH", + "name" : "He's so Unusual", + "preview_url" : null, + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:53eCpAFNbA9MQNfLilN3CH" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 196373, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/51JS0KXziu9U1T8EBdRTUF" + }, + "href" : "https://api.spotify.com/v1/tracks/51JS0KXziu9U1T8EBdRTUF", + "id" : "51JS0KXziu9U1T8EBdRTUF", + "name" : "Yeah Yeah", + "preview_url" : null, + "track_number" : 10, + "type" : "track", + "uri" : "spotify:track:51JS0KXziu9U1T8EBdRTUF" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 275560, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2BGJvRarwOa2kiIGpLjIXT" + }, + "href" : "https://api.spotify.com/v1/tracks/2BGJvRarwOa2kiIGpLjIXT", + "id" : "2BGJvRarwOa2kiIGpLjIXT", + "name" : "Money Changes Everything", + "preview_url" : null, + "track_number" : 11, + "type" : "track", + "uri" : "spotify:track:2BGJvRarwOa2kiIGpLjIXT" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY" + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 320400, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5ggatiDTbCIJsUAa7IUP65" + }, + "href" : "https://api.spotify.com/v1/tracks/5ggatiDTbCIJsUAa7IUP65", + "id" : "5ggatiDTbCIJsUAa7IUP65", + "name" : "She Bop - Live", + "preview_url" : null, + "track_number" : 12, + "type" : "track", + "uri" : "spotify:track:5ggatiDTbCIJsUAa7IUP65" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2BTZIqw0ntH9MvilQ3ewNY" + }, + "href" : "https://api.spotify.com/v1/artists/2BTZIqw0ntH9MvilQ3ewNY", + "id" : "2BTZIqw0ntH9MvilQ3ewNY", + "name" : "Cyndi Lauper", + "type" : "artist", + "uri" : "spotify:artist:2BTZIqw0ntH9MvilQ3ewNY", + } ], + "available_markets" : [ ], + "disc_number" : 1, + "duration_ms" : 288240, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5ZBxoa2kBrBah3qNIV4rm7" + }, + "href" : "https://api.spotify.com/v1/tracks/5ZBxoa2kBrBah3qNIV4rm7", + "id" : "5ZBxoa2kBrBah3qNIV4rm7", + "name" : "All Through The Night - Live", + "preview_url" : null, + "track_number" : 13, + "type" : "track", + "uri" : "spotify:track:5ZBxoa2kBrBah3qNIV4rm7" + } ], + "limit" : 50, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 13 + }, + "type" : "album", + "uri" : "spotify:album:0sNOF9WDwhWunNAHPD3Baj" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-several-albums/ + */ +var getMultipleAlbumsResponse : SpotifyApi.MultipleAlbumsResponse = { + "albums" : [ { + "album_type" : "album", + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "copyrights" : [ { + "text" : "(C) 2013 Universal Island Records, a division of Universal Music Operations Limited", + "type" : "C" + }, { + "text" : "(P) 2013 Universal Island Records, a division of Universal Music Operations Limited", + "type" : "P" + } ], + "external_ids" : { + "upc" : "00602537518357" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/album/41MnTivkwTO3UUJ8DrqEJJ" + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/albums/41MnTivkwTO3UUJ8DrqEJJ", + "id" : "41MnTivkwTO3UUJ8DrqEJJ", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/89b92c6b59131776c0cd8e5df46301ffcf36ed69", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/eb6f0b2594d81f8d9dced193f3e9a3bc4318aedc", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/21e1ebcd7ebd3b679d9d5084bba1e163638b103a", + "width" : 64 + } ], + "name" : "The Best Of Keane (Deluxe Edition)", + "popularity" : 56, + "release_date" : "2013-01-01", + "release_date_precision" : "day", + "tracks" : { + "href" : "https://api.spotify.com/v1/albums/41MnTivkwTO3UUJ8DrqEJJ/tracks?offset=0&limit=50", + "items" : [ { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 215986, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4r9PmSmbAOOWqaGWLf6M9Q" + }, + "href" : "https://api.spotify.com/v1/tracks/4r9PmSmbAOOWqaGWLf6M9Q", + "id" : "4r9PmSmbAOOWqaGWLf6M9Q", + "name" : "Everybody's Changing", + "preview_url" : "https://p.scdn.co/mp3-preview/fe9d90cd8a51ea672789c13856d886901125bc05", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:4r9PmSmbAOOWqaGWLf6M9Q" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 235880, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0HJQD8uqX2Bq5HVdLnd3ep" + }, + "href" : "https://api.spotify.com/v1/tracks/0HJQD8uqX2Bq5HVdLnd3ep", + "id" : "0HJQD8uqX2Bq5HVdLnd3ep", + "name" : "Somewhere Only We Know", + "preview_url" : "https://p.scdn.co/mp3-preview/af246a57475c5491157fa21c069b130baaaacccd", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:0HJQD8uqX2Bq5HVdLnd3ep" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 218426, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/087AcwkqBIuIebZWpwbOI4" + }, + "href" : "https://api.spotify.com/v1/tracks/087AcwkqBIuIebZWpwbOI4", + "id" : "087AcwkqBIuIebZWpwbOI4", + "name" : "Bend & Break", + "preview_url" : "https://p.scdn.co/mp3-preview/e3bdc5a44b62df8135f893730ce1124526b9c5c1", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:087AcwkqBIuIebZWpwbOI4" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 275093, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5s2TY4v3WTECwelIqqqtuS" + }, + "href" : "https://api.spotify.com/v1/tracks/5s2TY4v3WTECwelIqqqtuS", + "id" : "5s2TY4v3WTECwelIqqqtuS", + "name" : "Bedshaped", + "preview_url" : "https://p.scdn.co/mp3-preview/11bcd8e1e5817414e09da5ffdca88ea97925767c", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:5s2TY4v3WTECwelIqqqtuS" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 207653, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5Q9h1xA3xqUJyx1dDlq6MI" + }, + "href" : "https://api.spotify.com/v1/tracks/5Q9h1xA3xqUJyx1dDlq6MI", + "id" : "5Q9h1xA3xqUJyx1dDlq6MI", + "name" : "This Is The Last Time", + "preview_url" : "https://p.scdn.co/mp3-preview/4fcf428b407ca80ca4d40ebcde15642ecfda17c8", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:5Q9h1xA3xqUJyx1dDlq6MI" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 250786, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0BIpP7vmh35JEpT1zkv7Sl" + }, + "href" : "https://api.spotify.com/v1/tracks/0BIpP7vmh35JEpT1zkv7Sl", + "id" : "0BIpP7vmh35JEpT1zkv7Sl", + "name" : "Atlantic", + "preview_url" : "https://p.scdn.co/mp3-preview/7c1ba58788479e16da1ed98b73523bfd731683b4", + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:0BIpP7vmh35JEpT1zkv7Sl" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 185813, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/64rOSkztPrTECtWTB0F2OD" + }, + "href" : "https://api.spotify.com/v1/tracks/64rOSkztPrTECtWTB0F2OD", + "id" : "64rOSkztPrTECtWTB0F2OD", + "name" : "Is It Any Wonder?", + "preview_url" : "https://p.scdn.co/mp3-preview/aeb8fcb164cf337f5233edc62bd74d78441ea096", + "track_number" : 7, + "type" : "track", + "uri" : "spotify:track:64rOSkztPrTECtWTB0F2OD" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 239986, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5XulFHMk0X9foui8If85qV" + }, + "href" : "https://api.spotify.com/v1/tracks/5XulFHMk0X9foui8If85qV", + "id" : "5XulFHMk0X9foui8If85qV", + "name" : "Nothing In My Way", + "preview_url" : "https://p.scdn.co/mp3-preview/f10421f201ba60bcf470da0347ae0fa1eccd2195", + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:5XulFHMk0X9foui8If85qV" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 277360, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7EbeyS7knwgd3TtJepU1On" + }, + "href" : "https://api.spotify.com/v1/tracks/7EbeyS7knwgd3TtJepU1On", + "id" : "7EbeyS7knwgd3TtJepU1On", + "name" : "Hamburg Song", + "preview_url" : "https://p.scdn.co/mp3-preview/39f70e54618d6cca3f240edcb552ed39d4fc5202", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:7EbeyS7knwgd3TtJepU1On" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 233520, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5faIME3g9Lxo4Myf8ArY9l" + }, + "href" : "https://api.spotify.com/v1/tracks/5faIME3g9Lxo4Myf8ArY9l", + "id" : "5faIME3g9Lxo4Myf8ArY9l", + "name" : "Crystal Ball", + "preview_url" : "https://p.scdn.co/mp3-preview/8eb1a3df454cb9137771b60f26df71034fc80f47", + "track_number" : 10, + "type" : "track", + "uri" : "spotify:track:5faIME3g9Lxo4Myf8ArY9l" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 302813, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3dkTbaMEfF8mqCNSSZKB5S" + }, + "href" : "https://api.spotify.com/v1/tracks/3dkTbaMEfF8mqCNSSZKB5S", + "id" : "3dkTbaMEfF8mqCNSSZKB5S", + "name" : "A Bad Dream", + "preview_url" : "https://p.scdn.co/mp3-preview/264f4474ff324def0e3d454d769be615ab105f94", + "track_number" : 11, + "type" : "track", + "uri" : "spotify:track:3dkTbaMEfF8mqCNSSZKB5S" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 267320, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/38zl5v3L94wzbl3iQHAxNM" + }, + "href" : "https://api.spotify.com/v1/tracks/38zl5v3L94wzbl3iQHAxNM", + "id" : "38zl5v3L94wzbl3iQHAxNM", + "name" : "Try Again", + "preview_url" : "https://p.scdn.co/mp3-preview/5620e5b33fe3f2d2dcbb559029a1370aac341411", + "track_number" : 12, + "type" : "track", + "uri" : "spotify:track:38zl5v3L94wzbl3iQHAxNM" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 204013, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1K4SP6flGBk73cgshPqDCp" + }, + "href" : "https://api.spotify.com/v1/tracks/1K4SP6flGBk73cgshPqDCp", + "id" : "1K4SP6flGBk73cgshPqDCp", + "name" : "Spiralling", + "preview_url" : "https://p.scdn.co/mp3-preview/3dc0aaa8015d0fbb2377b970d9048381831953fd", + "track_number" : 13, + "type" : "track", + "uri" : "spotify:track:1K4SP6flGBk73cgshPqDCp" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 311533, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7DNKgwHgPgbGhqdXJGkxf6" + }, + "href" : "https://api.spotify.com/v1/tracks/7DNKgwHgPgbGhqdXJGkxf6", + "id" : "7DNKgwHgPgbGhqdXJGkxf6", + "name" : "Perfect Symmetry", + "preview_url" : "https://p.scdn.co/mp3-preview/3475936f1b54849a64ea70eb6467a8a3a3800bad", + "track_number" : 14, + "type" : "track", + "uri" : "spotify:track:7DNKgwHgPgbGhqdXJGkxf6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 289386, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3CFNKsHlpAleVotCDI78ca" + }, + "href" : "https://api.spotify.com/v1/tracks/3CFNKsHlpAleVotCDI78ca", + "id" : "3CFNKsHlpAleVotCDI78ca", + "name" : "My Shadow", + "preview_url" : "https://p.scdn.co/mp3-preview/bf11da166dc76f5f4392a57146467e36e7173cc9", + "track_number" : 15, + "type" : "track", + "uri" : "spotify:track:3CFNKsHlpAleVotCDI78ca" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 196333, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5OVyLOs64kq6zL12QrQD6o" + }, + "href" : "https://api.spotify.com/v1/tracks/5OVyLOs64kq6zL12QrQD6o", + "id" : "5OVyLOs64kq6zL12QrQD6o", + "name" : "Silenced By The Night", + "preview_url" : "https://p.scdn.co/mp3-preview/ab222c63169f5b847c24ebfe21875d9313ec8bc8", + "track_number" : 16, + "type" : "track", + "uri" : "spotify:track:5OVyLOs64kq6zL12QrQD6o" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 236973, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5AHNNMMn7dApuo4OuqZcPb" + }, + "href" : "https://api.spotify.com/v1/tracks/5AHNNMMn7dApuo4OuqZcPb", + "id" : "5AHNNMMn7dApuo4OuqZcPb", + "name" : "Disconnected", + "preview_url" : "https://p.scdn.co/mp3-preview/8a5201b1a061c5bfca5db879d22c580d7a9eb99a", + "track_number" : 17, + "type" : "track", + "uri" : "spotify:track:5AHNNMMn7dApuo4OuqZcPb" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 208133, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5wPQMzWTFxKI0Aw3I3OJG6" + }, + "href" : "https://api.spotify.com/v1/tracks/5wPQMzWTFxKI0Aw3I3OJG6", + "id" : "5wPQMzWTFxKI0Aw3I3OJG6", + "name" : "Sovereign Light Café", + "preview_url" : "https://p.scdn.co/mp3-preview/5df8fdaa9938b599b9bbc7fbd2cfea2c2bd3a734", + "track_number" : 18, + "type" : "track", + "uri" : "spotify:track:5wPQMzWTFxKI0Aw3I3OJG6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 201653, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1Vz9mv3ITvzSxm9sH2pAdn" + }, + "href" : "https://api.spotify.com/v1/tracks/1Vz9mv3ITvzSxm9sH2pAdn", + "id" : "1Vz9mv3ITvzSxm9sH2pAdn", + "name" : "Higher Than The Sun", + "preview_url" : "https://p.scdn.co/mp3-preview/75ea8651daefb9da6cbca3e6d4e970e7b8b84693", + "track_number" : 19, + "type" : "track", + "uri" : "spotify:track:1Vz9mv3ITvzSxm9sH2pAdn" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 222426, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3FYyMnHLaImyLctEoXZolK" + }, + "href" : "https://api.spotify.com/v1/tracks/3FYyMnHLaImyLctEoXZolK", + "id" : "3FYyMnHLaImyLctEoXZolK", + "name" : "Won't Be Broken", + "preview_url" : "https://p.scdn.co/mp3-preview/2c8dfeb19ead5b96dcf34858b43b96a9e6d70117", + "track_number" : 20, + "type" : "track", + "uri" : "spotify:track:3FYyMnHLaImyLctEoXZolK" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 229533, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0wnewiCeFaZQKejFECOzS2" + }, + "href" : "https://api.spotify.com/v1/tracks/0wnewiCeFaZQKejFECOzS2", + "id" : "0wnewiCeFaZQKejFECOzS2", + "name" : "Snowed Under", + "preview_url" : "https://p.scdn.co/mp3-preview/5a04228466a49f12e839bf3001d6c15eef015953", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:0wnewiCeFaZQKejFECOzS2" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 217440, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5sqAs4udmaaTWn6xXTpmGL" + }, + "href" : "https://api.spotify.com/v1/tracks/5sqAs4udmaaTWn6xXTpmGL", + "id" : "5sqAs4udmaaTWn6xXTpmGL", + "name" : "Walnut Tree", + "preview_url" : "https://p.scdn.co/mp3-preview/834c91889c0d86d4e3f724150976919844c5baa7", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:5sqAs4udmaaTWn6xXTpmGL" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 332973, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1WvLaBfQpk3dv3ciU0we8f" + }, + "href" : "https://api.spotify.com/v1/tracks/1WvLaBfQpk3dv3ciU0we8f", + "id" : "1WvLaBfQpk3dv3ciU0we8f", + "name" : "Fly To Me", + "preview_url" : "https://p.scdn.co/mp3-preview/06bc6f513cb7406660182e0a9a24b19238be019c", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:1WvLaBfQpk3dv3ciU0we8f" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 182733, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1UBiGrtXAKjc0C7GG937pD" + }, + "href" : "https://api.spotify.com/v1/tracks/1UBiGrtXAKjc0C7GG937pD", + "id" : "1UBiGrtXAKjc0C7GG937pD", + "name" : "To The End Of The Earth", + "preview_url" : "https://p.scdn.co/mp3-preview/b347bf5ce7c9fc4fc823ab1bc98f119194d06a66", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:1UBiGrtXAKjc0C7GG937pD" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ ], + "disc_number" : 2, + "duration_ms" : 196826, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7eNyrwrLzbO8URXaaSU9g1" + }, + "href" : "https://api.spotify.com/v1/tracks/7eNyrwrLzbO8URXaaSU9g1", + "id" : "7eNyrwrLzbO8URXaaSU9g1", + "name" : "The Way You Want It", + "preview_url" : null, + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:7eNyrwrLzbO8URXaaSU9g1" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 286200, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5JLkkHYBZHUpQKnrIIVhpV" + }, + "href" : "https://api.spotify.com/v1/tracks/5JLkkHYBZHUpQKnrIIVhpV", + "id" : "5JLkkHYBZHUpQKnrIIVhpV", + "name" : "Something In Me Was Dying", + "preview_url" : "https://p.scdn.co/mp3-preview/79aa74fde8a0da6bb6ebdbbac6fd3b081ececace", + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:5JLkkHYBZHUpQKnrIIVhpV" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ ], + "disc_number" : 2, + "duration_ms" : 263200, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6aTi9DrnoLLvVdFSfzUuKP" + }, + "href" : "https://api.spotify.com/v1/tracks/6aTi9DrnoLLvVdFSfzUuKP", + "id" : "6aTi9DrnoLLvVdFSfzUuKP", + "name" : "Allemande", + "preview_url" : null, + "track_number" : 7, + "type" : "track", + "uri" : "spotify:track:6aTi9DrnoLLvVdFSfzUuKP" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 249426, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1igaBkvf5KZFTsu1fMfDfb" + }, + "href" : "https://api.spotify.com/v1/tracks/1igaBkvf5KZFTsu1fMfDfb", + "id" : "1igaBkvf5KZFTsu1fMfDfb", + "name" : "Let It Slide", + "preview_url" : "https://p.scdn.co/mp3-preview/a4905211b213f0443c6302585e241071a25055df", + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:1igaBkvf5KZFTsu1fMfDfb" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 216200, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4rCgYClAhCLuf9xD2Y8sI6" + }, + "href" : "https://api.spotify.com/v1/tracks/4rCgYClAhCLuf9xD2Y8sI6", + "id" : "4rCgYClAhCLuf9xD2Y8sI6", + "name" : "He Used To Be A Lovely Boy", + "preview_url" : "https://p.scdn.co/mp3-preview/d238b8f92367915eb08c389a55b35c4353aa4cc5", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:4rCgYClAhCLuf9xD2Y8sI6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 236986, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2RsfSyrYHjUtGeCVBf6ib2" + }, + "href" : "https://api.spotify.com/v1/tracks/2RsfSyrYHjUtGeCVBf6ib2", + "id" : "2RsfSyrYHjUtGeCVBf6ib2", + "name" : "Thin Air", + "preview_url" : "https://p.scdn.co/mp3-preview/95f2501973e2571c16c85efa1fc8ab92bf187739", + "track_number" : 10, + "type" : "track", + "uri" : "spotify:track:2RsfSyrYHjUtGeCVBf6ib2" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 269880, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2UwM9vm7I4wx3RxGx8DR17" + }, + "href" : "https://api.spotify.com/v1/tracks/2UwM9vm7I4wx3RxGx8DR17", + "id" : "2UwM9vm7I4wx3RxGx8DR17", + "name" : "The Iron Sea", + "preview_url" : "https://p.scdn.co/mp3-preview/e75172d8becfd594645de8e070e4473edebbedf0", + "track_number" : 11, + "type" : "track", + "uri" : "spotify:track:2UwM9vm7I4wx3RxGx8DR17" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 235440, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2WMpag1ouW7zIySG8PcrIW" + }, + "href" : "https://api.spotify.com/v1/tracks/2WMpag1ouW7zIySG8PcrIW", + "id" : "2WMpag1ouW7zIySG8PcrIW", + "name" : "Maybe I Can Change", + "preview_url" : "https://p.scdn.co/mp3-preview/e84716f556f8d770605f78c2ddacb5a879bb49a2", + "track_number" : 12, + "type" : "track", + "uri" : "spotify:track:2WMpag1ouW7zIySG8PcrIW" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 229586, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7ngI6zHe2AA4YncwFytNR1" + }, + "href" : "https://api.spotify.com/v1/tracks/7ngI6zHe2AA4YncwFytNR1", + "id" : "7ngI6zHe2AA4YncwFytNR1", + "name" : "Time To Go", + "preview_url" : "https://p.scdn.co/mp3-preview/5413cb1452a1c5a0a6aaa49d5ec289d8e9f28dc1", + "track_number" : 13, + "type" : "track", + "uri" : "spotify:track:7ngI6zHe2AA4YncwFytNR1" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 230880, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2BUKGneA8BFCelJhoCIZ7u" + }, + "href" : "https://api.spotify.com/v1/tracks/2BUKGneA8BFCelJhoCIZ7u", + "id" : "2BUKGneA8BFCelJhoCIZ7u", + "name" : "Staring At The Ceiling", + "preview_url" : "https://p.scdn.co/mp3-preview/744949b7bf0d516eac9a7a231ead9b623d073574", + "track_number" : 14, + "type" : "track", + "uri" : "spotify:track:2BUKGneA8BFCelJhoCIZ7u" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 294693, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7rY5n8rnQnNwAtnNfCUQ0O" + }, + "href" : "https://api.spotify.com/v1/tracks/7rY5n8rnQnNwAtnNfCUQ0O", + "id" : "7rY5n8rnQnNwAtnNfCUQ0O", + "name" : "Myth", + "preview_url" : "https://p.scdn.co/mp3-preview/a69a1fc94953c480bde888dcb82eab9a1cac91fc", + "track_number" : 15, + "type" : "track", + "uri" : "spotify:track:7rY5n8rnQnNwAtnNfCUQ0O" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 224986, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0SY7oTzyTMpiXgP4ufO7VW" + }, + "href" : "https://api.spotify.com/v1/tracks/0SY7oTzyTMpiXgP4ufO7VW", + "id" : "0SY7oTzyTMpiXgP4ufO7VW", + "name" : "Difficult Child", + "preview_url" : "https://p.scdn.co/mp3-preview/e48a7b0b0fa708312b4850c97d28337c215a2c95", + "track_number" : 16, + "type" : "track", + "uri" : "spotify:track:0SY7oTzyTMpiXgP4ufO7VW" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 221200, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7dDuGGxttttGh0h9CJ4cUu" + }, + "href" : "https://api.spotify.com/v1/tracks/7dDuGGxttttGh0h9CJ4cUu", + "id" : "7dDuGGxttttGh0h9CJ4cUu", + "name" : "Sea Fog - Live At Arena Ciudad De Mexico, Mexico City / 2012", + "preview_url" : "https://p.scdn.co/mp3-preview/a940bc357a2cd29cae8e5dfe337c874baf334b82", + "track_number" : 17, + "type" : "track", + "uri" : "spotify:track:7dDuGGxttttGh0h9CJ4cUu" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 2, + "duration_ms" : 394786, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0bxCO9Bbm1SkK9BU2DbsYg" + }, + "href" : "https://api.spotify.com/v1/tracks/0bxCO9Bbm1SkK9BU2DbsYg", + "id" : "0bxCO9Bbm1SkK9BU2DbsYg", + "name" : "Russian Farmer's Song", + "preview_url" : "https://p.scdn.co/mp3-preview/59264a05ed0ce01ba5b78f3b9507fe80b3aea94e", + "track_number" : 18, + "type" : "track", + "uri" : "spotify:track:0bxCO9Bbm1SkK9BU2DbsYg" + } ], + "limit" : 50, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 38 + }, + "type" : "album", + "uri" : "spotify:album:41MnTivkwTO3UUJ8DrqEJJ" + }, { + "album_type" : "album", + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "copyrights" : [ { + "text" : "(C) 2012 Universal Island Records, a division of Universal Music Operations Limited", + "type" : "C" + }, { + "text" : "(P) 2012 Universal Island Records, a division of Universal Music Operations Limited", + "type" : "P" + } ], + "external_ids" : { + "upc" : "00602537055425" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6JWc4iAiJ9FjyK0B59ABb4" + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/albums/6JWc4iAiJ9FjyK0B59ABb4", + "id" : "6JWc4iAiJ9FjyK0B59ABb4", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/be368b4f8b3dbcb7bcb39c0707fd33447c1ec398", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/24f4e188d0bedc8e1d2a8e3f242aa9c3ec4b6729", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/b31365a528a6a8e1e8b4c8a2d5d1d4b48b672122", + "width" : 64 + } ], + "name" : "Strangeland", + "popularity" : 53, + "release_date" : "2012-01-01", + "release_date_precision" : "day", + "tracks" : { + "href" : "https://api.spotify.com/v1/albums/6JWc4iAiJ9FjyK0B59ABb4/tracks?offset=0&limit=50", + "items" : [ { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 214666, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/07h75cQlaZBLwwyeWTeIZX" + }, + "href" : "https://api.spotify.com/v1/tracks/07h75cQlaZBLwwyeWTeIZX", + "id" : "07h75cQlaZBLwwyeWTeIZX", + "name" : "You Are Young", + "preview_url" : "https://p.scdn.co/mp3-preview/77459b8644db7f0b14d1a04f9732619bca75d3c9", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:07h75cQlaZBLwwyeWTeIZX" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 196466, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0BhGZmaQ1SET53qGkGvwxD" + }, + "href" : "https://api.spotify.com/v1/tracks/0BhGZmaQ1SET53qGkGvwxD", + "id" : "0BhGZmaQ1SET53qGkGvwxD", + "name" : "Silenced By The Night", + "preview_url" : "https://p.scdn.co/mp3-preview/801c7eecca00b1880c75a15cff92043dbc0d6878", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:0BhGZmaQ1SET53qGkGvwxD" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 237893, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1wL2u2BP9T3cpskdffyfn5" + }, + "href" : "https://api.spotify.com/v1/tracks/1wL2u2BP9T3cpskdffyfn5", + "id" : "1wL2u2BP9T3cpskdffyfn5", + "name" : "Disconnected", + "preview_url" : "https://p.scdn.co/mp3-preview/210fed3f055f5c275bfac85894acd076f84c8d65", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:1wL2u2BP9T3cpskdffyfn5" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 220386, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3Wxu8QRCZdTvwFvwtWOMst" + }, + "href" : "https://api.spotify.com/v1/tracks/3Wxu8QRCZdTvwFvwtWOMst", + "id" : "3Wxu8QRCZdTvwFvwtWOMst", + "name" : "Watch How You Go", + "preview_url" : "https://p.scdn.co/mp3-preview/155dd49cb3c54702b139d6de388ace09041d3a16", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:3Wxu8QRCZdTvwFvwtWOMst" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 218840, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4QRkCwqwHFaZ7xeoR9CHL6" + }, + "href" : "https://api.spotify.com/v1/tracks/4QRkCwqwHFaZ7xeoR9CHL6", + "id" : "4QRkCwqwHFaZ7xeoR9CHL6", + "name" : "Sovereign Light Café", + "preview_url" : "https://p.scdn.co/mp3-preview/3f44115c51b854605f707a9d24903cad7b27e6b8", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:4QRkCwqwHFaZ7xeoR9CHL6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 236733, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4IGKv5K4HbAfufzf2OUEg0" + }, + "href" : "https://api.spotify.com/v1/tracks/4IGKv5K4HbAfufzf2OUEg0", + "id" : "4IGKv5K4HbAfufzf2OUEg0", + "name" : "On The Road", + "preview_url" : "https://p.scdn.co/mp3-preview/0fd8c40ab8fb97a4a9e69b3b5c4669cbcfcef330", + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:4IGKv5K4HbAfufzf2OUEg0" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 252333, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3jQg3xqVv1H6Y3jp6FzR3M" + }, + "href" : "https://api.spotify.com/v1/tracks/3jQg3xqVv1H6Y3jp6FzR3M", + "id" : "3jQg3xqVv1H6Y3jp6FzR3M", + "name" : "The Starting Line", + "preview_url" : "https://p.scdn.co/mp3-preview/693b6baa37c37ee1a90e12b24e92c3145663c007", + "track_number" : 7, + "type" : "track", + "uri" : "spotify:track:3jQg3xqVv1H6Y3jp6FzR3M" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 226560, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3NT6rwZk7igASQR4HJFP0x" + }, + "href" : "https://api.spotify.com/v1/tracks/3NT6rwZk7igASQR4HJFP0x", + "id" : "3NT6rwZk7igASQR4HJFP0x", + "name" : "Black Rain", + "preview_url" : "https://p.scdn.co/mp3-preview/68932717dfc96a006b3d2f30f0899bc7b5b6e83c", + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:3NT6rwZk7igASQR4HJFP0x" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 292946, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1QKQ8eP3aEsW4LEd42umP6" + }, + "href" : "https://api.spotify.com/v1/tracks/1QKQ8eP3aEsW4LEd42umP6", + "id" : "1QKQ8eP3aEsW4LEd42umP6", + "name" : "Neon River", + "preview_url" : "https://p.scdn.co/mp3-preview/da1d919d5b2b59392577e3a55335fcd93e4d40bd", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:1QKQ8eP3aEsW4LEd42umP6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 191906, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7uuSUJdpPRoXeR37IAV1a0" + }, + "href" : "https://api.spotify.com/v1/tracks/7uuSUJdpPRoXeR37IAV1a0", + "id" : "7uuSUJdpPRoXeR37IAV1a0", + "name" : "Day Will Come", + "preview_url" : "https://p.scdn.co/mp3-preview/b2ba652d57410f72e1d4d34f96f72277701aa6d6", + "track_number" : 10, + "type" : "track", + "uri" : "spotify:track:7uuSUJdpPRoXeR37IAV1a0" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 223800, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6dksuIyuNHcFVcx9ixCMbq" + }, + "href" : "https://api.spotify.com/v1/tracks/6dksuIyuNHcFVcx9ixCMbq", + "id" : "6dksuIyuNHcFVcx9ixCMbq", + "name" : "In Your Own Time", + "preview_url" : "https://p.scdn.co/mp3-preview/a9950ccfb4db1596840e9696a3b7db6cebab200d", + "track_number" : 11, + "type" : "track", + "uri" : "spotify:track:6dksuIyuNHcFVcx9ixCMbq" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 203386, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7F4jALhmdEQv49Dy6tNYLq" + }, + "href" : "https://api.spotify.com/v1/tracks/7F4jALhmdEQv49Dy6tNYLq", + "id" : "7F4jALhmdEQv49Dy6tNYLq", + "name" : "Sea Fog", + "preview_url" : "https://p.scdn.co/mp3-preview/7e31e76de98d697f17610af2a0e0d7a823b48e71", + "track_number" : 12, + "type" : "track", + "uri" : "spotify:track:7F4jALhmdEQv49Dy6tNYLq" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 276440, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1VI5LFMf7SFbcT3dz8XYHJ" + }, + "href" : "https://api.spotify.com/v1/tracks/1VI5LFMf7SFbcT3dz8XYHJ", + "id" : "1VI5LFMf7SFbcT3dz8XYHJ", + "name" : "Strangeland - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/873eeb6117633d8d66540ffcfc106fb57564acd2", + "track_number" : 13, + "type" : "track", + "uri" : "spotify:track:1VI5LFMf7SFbcT3dz8XYHJ" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 210986, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/75Zc9ZHq8PY7NMtkIpbwM0" + }, + "href" : "https://api.spotify.com/v1/tracks/75Zc9ZHq8PY7NMtkIpbwM0", + "id" : "75Zc9ZHq8PY7NMtkIpbwM0", + "name" : "Run With Me - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/068afaf6676c7edd937222f5f916e638481ddaba", + "track_number" : 14, + "type" : "track", + "uri" : "spotify:track:75Zc9ZHq8PY7NMtkIpbwM0" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 212560, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4dsiRFi3mmpI0pklauyoQx" + }, + "href" : "https://api.spotify.com/v1/tracks/4dsiRFi3mmpI0pklauyoQx", + "id" : "4dsiRFi3mmpI0pklauyoQx", + "name" : "The Boys - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/f6dc960a09c8e10b7a5525914170101140f8e333", + "track_number" : 15, + "type" : "track", + "uri" : "spotify:track:4dsiRFi3mmpI0pklauyoQx" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 229200, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3GmNkKokMo8RgUxMdgRbiR" + }, + "href" : "https://api.spotify.com/v1/tracks/3GmNkKokMo8RgUxMdgRbiR", + "id" : "3GmNkKokMo8RgUxMdgRbiR", + "name" : "It's Not True - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/806f8f7110acdf970db90840f0d3d3f95353379f", + "track_number" : 16, + "type" : "track", + "uri" : "spotify:track:3GmNkKokMo8RgUxMdgRbiR" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 210120, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2BLnrhqfHx6G3ZAnHzIYxI" + }, + "href" : "https://api.spotify.com/v1/tracks/2BLnrhqfHx6G3ZAnHzIYxI", + "id" : "2BLnrhqfHx6G3ZAnHzIYxI", + "name" : "Silenced By The Night - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/0fb339bdcd390f43c8fd00114fb7b1dac11617a9", + "track_number" : 17, + "type" : "track", + "uri" : "spotify:track:2BLnrhqfHx6G3ZAnHzIYxI" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 272671, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5uwUXAth3No4DVv6x4lXQ9" + }, + "href" : "https://api.spotify.com/v1/tracks/5uwUXAth3No4DVv6x4lXQ9", + "id" : "5uwUXAth3No4DVv6x4lXQ9", + "name" : "The Starting Line - Bonus Track", + "preview_url" : "https://p.scdn.co/mp3-preview/5350d96164b2bb17d5711334b30eefd5dac0043c", + "track_number" : 18, + "type" : "track", + "uri" : "spotify:track:5uwUXAth3No4DVv6x4lXQ9" + } ], + "limit" : 50, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 18 + }, + "type" : "album", + "uri" : "spotify:album:6JWc4iAiJ9FjyK0B59ABb4" + }, { + "album_type" : "album", + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "copyrights" : [ { + "text" : "(C) 2010 Universal Island Records Ltd. A Universal Music Company.", + "type" : "C" + }, { + "text" : "(P) 2010 Universal Island Records Ltd. A Universal Music Company.", + "type" : "P" + } ], + "external_ids" : { + "upc" : "00602527420608" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6UXCm6bOO4gFlDQZV5yL37" + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/albums/6UXCm6bOO4gFlDQZV5yL37", + "id" : "6UXCm6bOO4gFlDQZV5yL37", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/a969ab6750172e5284b1f3a3dd985e3a3839f5c5", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/5a0e940ee6e5d8dc4d7a77df70277709050d10be", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/1e21ac3f484c184c0b168bfed2b4fbff1d03c4ab", + "width" : 64 + } ], + "name" : "Night Train", + "popularity" : 39, + "release_date" : "2010-01-01", + "release_date_precision" : "day", + "tracks" : { + "href" : "https://api.spotify.com/v1/albums/6UXCm6bOO4gFlDQZV5yL37/tracks?offset=0&limit=50", + "items" : [ { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 83546, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3ugblcbYKHrhIvRL4IVY20" + }, + "href" : "https://api.spotify.com/v1/tracks/3ugblcbYKHrhIvRL4IVY20", + "id" : "3ugblcbYKHrhIvRL4IVY20", + "name" : "House Lights", + "preview_url" : "https://p.scdn.co/mp3-preview/36b8ecff155ad6e9d7682f753c642fe48900d19a", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:3ugblcbYKHrhIvRL4IVY20" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 232320, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/06qEl8bMI8qCJiB68M0Ab6" + }, + "href" : "https://api.spotify.com/v1/tracks/06qEl8bMI8qCJiB68M0Ab6", + "id" : "06qEl8bMI8qCJiB68M0Ab6", + "name" : "Back In Time", + "preview_url" : "https://p.scdn.co/mp3-preview/bac9cec3411411bdceed91cf18061b3e0bf1646d", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:06qEl8bMI8qCJiB68M0Ab6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/7pGyQZx9thVa8GxMBeXscB" + }, + "href" : "https://api.spotify.com/v1/artists/7pGyQZx9thVa8GxMBeXscB", + "id" : "7pGyQZx9thVa8GxMBeXscB", + "name" : "K'NAAN", + "type" : "artist", + "uri" : "spotify:artist:7pGyQZx9thVa8GxMBeXscB" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 246800, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3R1MKirozQBVYaBErWy8LB" + }, + "href" : "https://api.spotify.com/v1/tracks/3R1MKirozQBVYaBErWy8LB", + "id" : "3R1MKirozQBVYaBErWy8LB", + "name" : "Stop For A Minute", + "preview_url" : "https://p.scdn.co/mp3-preview/e2d22f632e556a8d68d41290f4d64cb11c0fa3ec", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:3R1MKirozQBVYaBErWy8LB" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 293106, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5TWT6yV2KdJAMH9lblIRi6" + }, + "href" : "https://api.spotify.com/v1/tracks/5TWT6yV2KdJAMH9lblIRi6", + "id" : "5TWT6yV2KdJAMH9lblIRi6", + "name" : "Clear Skies", + "preview_url" : "https://p.scdn.co/mp3-preview/ec4f00fba6b0ec2ba4ec2b8cc7faac79cbe9bd0a", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:5TWT6yV2KdJAMH9lblIRi6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0I8EcYNKMh0Pj6CGJovHOT" + }, + "href" : "https://api.spotify.com/v1/artists/0I8EcYNKMh0Pj6CGJovHOT", + "id" : "0I8EcYNKMh0Pj6CGJovHOT", + "name" : "Tigarah", + "type" : "artist", + "uri" : "spotify:artist:0I8EcYNKMh0Pj6CGJovHOT" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 236706, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1IEVCAISZpS9GiAdZkHTR6" + }, + "href" : "https://api.spotify.com/v1/tracks/1IEVCAISZpS9GiAdZkHTR6", + "id" : "1IEVCAISZpS9GiAdZkHTR6", + "name" : "Ishin Denshin (You've Got To Help Yourself)", + "preview_url" : "https://p.scdn.co/mp3-preview/b1217e00e762770534aed53e4109f514f049766f", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:1IEVCAISZpS9GiAdZkHTR6" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 276720, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1EAoq7c9LRsJIo2bAt4Lxr" + }, + "href" : "https://api.spotify.com/v1/tracks/1EAoq7c9LRsJIo2bAt4Lxr", + "id" : "1EAoq7c9LRsJIo2bAt4Lxr", + "name" : "Your Love", + "preview_url" : "https://p.scdn.co/mp3-preview/8db14d0124403200fd14c33d7d2b234fa627ff74", + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:1EAoq7c9LRsJIo2bAt4Lxr" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/7pGyQZx9thVa8GxMBeXscB" + }, + "href" : "https://api.spotify.com/v1/artists/7pGyQZx9thVa8GxMBeXscB", + "id" : "7pGyQZx9thVa8GxMBeXscB", + "name" : "K'NAAN", + "type" : "artist", + "uri" : "spotify:artist:7pGyQZx9thVa8GxMBeXscB" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 226480, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2ctReR81XVD8JPlJqJqF1C" + }, + "href" : "https://api.spotify.com/v1/tracks/2ctReR81XVD8JPlJqJqF1C", + "id" : "2ctReR81XVD8JPlJqJqF1C", + "name" : "Looking Back", + "preview_url" : "https://p.scdn.co/mp3-preview/a379bcd0dfb21162d2337f51b5d89e67a94ae755", + "track_number" : 7, + "type" : "track", + "uri" : "spotify:track:2ctReR81XVD8JPlJqJqF1C" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 289360, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1lqTqfWG6dOUR1DHav23JH" + }, + "href" : "https://api.spotify.com/v1/tracks/1lqTqfWG6dOUR1DHav23JH", + "id" : "1lqTqfWG6dOUR1DHav23JH", + "name" : "My Shadow", + "preview_url" : "https://p.scdn.co/mp3-preview/63f4dbf7c5e792d19eb773f1dfc351e20fd0f139", + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:1lqTqfWG6dOUR1DHav23JH" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/53A0W3U0s8diEn9RhXQhVz" + }, + "href" : "https://api.spotify.com/v1/artists/53A0W3U0s8diEn9RhXQhVz", + "id" : "53A0W3U0s8diEn9RhXQhVz", + "name" : "Keane", + "type" : "artist", + "uri" : "spotify:artist:53A0W3U0s8diEn9RhXQhVz" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 619079, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1OiJZvD8pQmgLwA0HU3YLs" + }, + "href" : "https://api.spotify.com/v1/tracks/1OiJZvD8pQmgLwA0HU3YLs", + "id" : "1OiJZvD8pQmgLwA0HU3YLs", + "name" : "Night Train Track By Track Commentary", + "preview_url" : "https://p.scdn.co/mp3-preview/387cd4efd9b9c16425cf8e0e77aa7cf174878572", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:1OiJZvD8pQmgLwA0HU3YLs" + } ], + "limit" : 50, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 9 + }, + "type" : "album", + "uri" : "spotify:album:6UXCm6bOO4gFlDQZV5yL37" + } ] +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-albums-tracks/ + */ +var getAlbumTracks : SpotifyApi.AlbumTracksResponse = { + "href" : "https://api.spotify.com/v1/albums/6akEvsycLGftJxYudPjmqK/tracks?offset=0&limit=2", + "items" : [ { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q" + }, + "href" : "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q", + "id" : "08td7MxkoHQkXnWAYD8d6Q", + "name" : "Tania Bowra", + "type" : "artist", + "uri" : "spotify:artist:08td7MxkoHQkXnWAYD8d6Q" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 276773, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2TpxZ7JUBn3uw46aR7qd6V" + }, + "href" : "https://api.spotify.com/v1/tracks/2TpxZ7JUBn3uw46aR7qd6V", + "id" : "2TpxZ7JUBn3uw46aR7qd6V", + "name" : "All I Want", + "preview_url" : "https://p.scdn.co/mp3-preview/12b8cee72118f995f5494e1b34251e4ac997445e", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:2TpxZ7JUBn3uw46aR7qd6V" + }, { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q" + }, + "href" : "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q", + "id" : "08td7MxkoHQkXnWAYD8d6Q", + "name" : "Tania Bowra", + "type" : "artist", + "uri" : "spotify:artist:08td7MxkoHQkXnWAYD8d6Q" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 247680, + "explicit" : false, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4PjcfyZZVE10TFd9EKA72r" + }, + "href" : "https://api.spotify.com/v1/tracks/4PjcfyZZVE10TFd9EKA72r", + "id" : "4PjcfyZZVE10TFd9EKA72r", + "name" : "Someday", + "preview_url" : "https://p.scdn.co/mp3-preview/4a54d83c195d0bc17b1b23fc931d37fb363224d8", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:4PjcfyZZVE10TFd9EKA72r" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/albums/6akEvsycLGftJxYudPjmqK/tracks?offset=2&limit=2", + "offset" : 0, + "previous" : null, + "total" : 11 +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-artist/ + */ +var getAnArtist : SpotifyApi.SingleArtistResponse = { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF" + }, + "followers" : { + "href" : null, + "total" : 416433 + }, + "genres" : [ "indie folk", "indie pop" ], + "href" : "https://api.spotify.com/v1/artists/0OdUWJ0sBjDrqHygGUXeCF", + "id" : "0OdUWJ0sBjDrqHygGUXeCF", + "images" : [ { + "height" : 816, + "url" : "https://i.scdn.co/image/eb266625dab075341e8c4378a177a27370f91903", + "width" : 1000 + }, { + "height" : 522, + "url" : "https://i.scdn.co/image/2f91c3cace3c5a6a48f3d0e2fd21364d4911b332", + "width" : 640 + }, { + "height" : 163, + "url" : "https://i.scdn.co/image/2efc93d7ee88435116093274980f04ebceb7b527", + "width" : 200 + }, { + "height" : 52, + "url" : "https://i.scdn.co/image/4f25297750dfa4051195c36809a9049f6b841a23", + "width" : 64 + } ], + "name" : "Band of Horses", + "popularity" : 66, + "type" : "artist", + "uri" : "spotify:artist:0OdUWJ0sBjDrqHygGUXeCF" +}; + + + +/** + * Tests https://developer.spotify.com/web-api/get-several-artists/ + */ +var getSeveralArtists : SpotifyApi.MultipleArtistsResponse = { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0oSGxfWSnnOXhD2fKuz2Gy" + }, + "followers" : { + "href" : null, + "total" : 910485 + }, + "genres" : [ "art rock", "glam rock", "permanent wave" ], + "href" : "https://api.spotify.com/v1/artists/0oSGxfWSnnOXhD2fKuz2Gy", + "id" : "0oSGxfWSnnOXhD2fKuz2Gy", + "images" : [ { + "height" : 1000, + "url" : "https://i.scdn.co/image/32bd9707b42a2c081482ec9cd3ffa8879f659f95", + "width" : 1000 + }, { + "height" : 640, + "url" : "https://i.scdn.co/image/865f24753e5e4f40a383bf24a9cdda598a4559a8", + "width" : 640 + }, { + "height" : 200, + "url" : "https://i.scdn.co/image/7ddd6fa5cf78aee2f2e8b347616151393022b7d9", + "width" : 200 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c8dc28c191432862afce298216458a6f00bbfbd8", + "width" : 64 + } ], + "name" : "David Bowie", + "popularity" : 72, + "type" : "artist", + "uri" : "spotify:artist:0oSGxfWSnnOXhD2fKuz2Gy" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3dBVyJ7JuOMt4GE9607Qin" + }, + "followers" : { + "href" : null, + "total" : 83707 + }, + "genres" : [ "glam rock", "protopunk" ], + "href" : "https://api.spotify.com/v1/artists/3dBVyJ7JuOMt4GE9607Qin", + "id" : "3dBVyJ7JuOMt4GE9607Qin", + "images" : [ { + "height" : 1300, + "url" : "https://i.scdn.co/image/5515a710c94ccd4edd8b9a0587778ed5e3f997da", + "width" : 1000 + }, { + "height" : 832, + "url" : "https://i.scdn.co/image/c990e667b4ca8240c73b0db06e6d76a3b27ce929", + "width" : 640 + }, { + "height" : 260, + "url" : "https://i.scdn.co/image/de2fa1d11c59e63143117d44ec9990b9e40451a2", + "width" : 200 + }, { + "height" : 83, + "url" : "https://i.scdn.co/image/b39638735adb4a4a54621293b99ab65c546f605e", + "width" : 64 + } ], + "name" : "T. Rex", + "popularity" : 55, + "type" : "artist", + "uri" : "spotify:artist:3dBVyJ7JuOMt4GE9607Qin" + } ] +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-artists-albums/ + */ +var getArtistsAlbums : SpotifyApi.ArtistsAlbumsResponse = { + "href" : "https://api.spotify.com/v1/artists/1vCWHaC5f2uS3yhpwWbIA6/albums?offset=0&limit=2&album_type=single", + "items" : [ { + "album_type" : "single", + "available_markets" : [ "CA", "MX", "US" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3qmjJVxvSp5k7seea8z0PU" + }, + "href" : "https://api.spotify.com/v1/albums/3qmjJVxvSp5k7seea8z0PU", + "id" : "3qmjJVxvSp5k7seea8z0PU", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/47827fbf1492983ba2eae4d109ca44467126d4c4", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/eec169cb9c70bde4998c437d37cb849b47572f7a", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/df36cadc3eeb0fb6b8da7c6490e53a2f1229775b", + "width" : 64 + } ], + "name" : "Broken Arrows (Remixes)", + "type" : "album", + "uri" : "spotify:album:3qmjJVxvSp5k7seea8z0PU" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/4nCNj68SZym6hNxXDkRtjN" + }, + "href" : "https://api.spotify.com/v1/albums/4nCNj68SZym6hNxXDkRtjN", + "id" : "4nCNj68SZym6hNxXDkRtjN", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c735be011394f4e7cdf1ebbf95d112cb69fd3414", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/7f4221fda86e4daa539fd29233fadad039cc46d9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/e1930bf1293d89799a0e382b40ebad5455b11857", + "width" : 64 + } ], + "name" : "Broken Arrows (Remixes)", + "type" : "album", + "uri" : "spotify:album:4nCNj68SZym6hNxXDkRtjN" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/artists/1vCWHaC5f2uS3yhpwWbIA6/albums?offset=2&limit=2&album_type=single", + "offset" : 0, + "previous" : null, + "total" : 168 +}; + + + +var getArtistsTopTracks : SpotifyApi.ArtistsTopTracksResponse = { + "tracks" : [ { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "href" : "https://api.spotify.com/v1/albums/6zk4RKl6JFlgLCV4Z7DQ7N", + "id" : "6zk4RKl6JFlgLCV4Z7DQ7N", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/1b4845d0abd116eab69a3059ec0a0374030e0261", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/2a12ad8c66ce0ed90bd127fcc5701251e169688c", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/73cf829fee9a9ac481e60b1bf919bc9fb20753e6", + "width" : 64 + } ], + "name" : "Elvis' Christmas Album", + "type" : "album", + "uri" : "spotify:album:6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 129173, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15701155" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3QiAAp20rPC3dcAtKtMaqQ" + }, + "href" : "https://api.spotify.com/v1/tracks/3QiAAp20rPC3dcAtKtMaqQ", + "id" : "3QiAAp20rPC3dcAtKtMaqQ", + "name" : "Blue Christmas", + "popularity" : 80, + "preview_url" : "https://p.scdn.co/mp3-preview/ddcfe1df4783b2e41f494dec4b13917fb8e1465d", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:3QiAAp20rPC3dcAtKtMaqQ" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "href" : "https://api.spotify.com/v1/albums/6zk4RKl6JFlgLCV4Z7DQ7N", + "id" : "6zk4RKl6JFlgLCV4Z7DQ7N", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/1b4845d0abd116eab69a3059ec0a0374030e0261", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/2a12ad8c66ce0ed90bd127fcc5701251e169688c", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/73cf829fee9a9ac481e60b1bf919bc9fb20753e6", + "width" : 64 + } ], + "name" : "Elvis' Christmas Album", + "type" : "album", + "uri" : "spotify:album:6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 115826, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15701156" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7n7VsX3sv66znBwA8b5uhp" + }, + "href" : "https://api.spotify.com/v1/tracks/7n7VsX3sv66znBwA8b5uhp", + "id" : "7n7VsX3sv66znBwA8b5uhp", + "name" : "Here Comes Santa Claus (Right Down Santa Claus Lane)", + "popularity" : 72, + "preview_url" : "https://p.scdn.co/mp3-preview/6a21a6141687ff9b2f0bede600ff1f6c85bcd8d1", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:7n7VsX3sv66znBwA8b5uhp" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/7xe8VI48TxUpU1IIo0RfGi" + }, + "href" : "https://api.spotify.com/v1/albums/7xe8VI48TxUpU1IIo0RfGi", + "id" : "7xe8VI48TxUpU1IIo0RfGi", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/479ec1fcd836348926b576260b5be92503f8b0a4", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/255a1b0e1cb4edda647854db0f438e3af78e3018", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/49e1648ce6f47aa0ccb6cc50929c898528557cf3", + "width" : 64 + } ], + "name" : "Blue Hawaii", + "type" : "album", + "uri" : "spotify:album:7xe8VI48TxUpU1IIo0RfGi" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 179773, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC16101350" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/44AyOl4qVkzS48vBsbNXaC" + }, + "href" : "https://api.spotify.com/v1/tracks/44AyOl4qVkzS48vBsbNXaC", + "id" : "44AyOl4qVkzS48vBsbNXaC", + "name" : "Can't Help Falling in Love", + "popularity" : 70, + "preview_url" : "https://p.scdn.co/mp3-preview/26e409b39a2da6dc18fab61020c90be2938dc0e9", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:44AyOl4qVkzS48vBsbNXaC" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/270qabVGN0kCo2SJQn5a72" + }, + "href" : "https://api.spotify.com/v1/albums/270qabVGN0kCo2SJQn5a72", + "id" : "270qabVGN0kCo2SJQn5a72", + "images" : [ { + "height" : 636, + "url" : "https://i.scdn.co/image/258782c56c531d9dff4b7e5f2192764d98e6b99b", + "width" : 640 + }, { + "height" : 298, + "url" : "https://i.scdn.co/image/3a59000a810f7e4ac234b1c4a6acb84f19a43d4e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/cce7105a3e441834b892a6d5e57893e55ec3ec09", + "width" : 64 + } ], + "name" : "The Classic Christmas Album", + "type" : "album", + "uri" : "spotify:album:270qabVGN0kCo2SJQn5a72" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3P33qFNGBVXl86yQYWspFj" + }, + "href" : "https://api.spotify.com/v1/artists/3P33qFNGBVXl86yQYWspFj", + "id" : "3P33qFNGBVXl86yQYWspFj", + "name" : "Martina McBride", + "type" : "artist", + "uri" : "spotify:artist:3P33qFNGBVXl86yQYWspFj" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 148546, + "explicit" : false, + "external_ids" : { + "isrc" : "USRN10800437" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/7upOqYZUQvA0nyVroaHeSg" + }, + "href" : "https://api.spotify.com/v1/tracks/7upOqYZUQvA0nyVroaHeSg", + "id" : "7upOqYZUQvA0nyVroaHeSg", + "name" : "Blue Christmas", + "popularity" : 48, + "preview_url" : "https://p.scdn.co/mp3-preview/64edbec4b760d1c2bc0606f6d7c11c9a244c0155", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:7upOqYZUQvA0nyVroaHeSg" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0C3t1htEDTFKcg7F2rNbek" + }, + "href" : "https://api.spotify.com/v1/albums/0C3t1htEDTFKcg7F2rNbek", + "id" : "0C3t1htEDTFKcg7F2rNbek", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/97f150dc58d9900133e895f8e61e2087621dccdc", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/0b45ca0a9e6c03137e7f733a9bd8856f63143702", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/185d20742c42d78ff0f58f3c970565ddc9217c94", + "width" : 64 + } ], + "name" : "Elvis' Golden Records", + "type" : "album", + "uri" : "spotify:album:0C3t1htEDTFKcg7F2rNbek" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 146480, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15705223" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4gphxUgq0JSFv2BCLhNDiE" + }, + "href" : "https://api.spotify.com/v1/tracks/4gphxUgq0JSFv2BCLhNDiE", + "id" : "4gphxUgq0JSFv2BCLhNDiE", + "name" : "Jailhouse Rock", + "popularity" : 66, + "preview_url" : "https://p.scdn.co/mp3-preview/29990f669b5328b6c40320596a2b14d8660cdb54", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:4gphxUgq0JSFv2BCLhNDiE" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "href" : "https://api.spotify.com/v1/albums/6zk4RKl6JFlgLCV4Z7DQ7N", + "id" : "6zk4RKl6JFlgLCV4Z7DQ7N", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/1b4845d0abd116eab69a3059ec0a0374030e0261", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/2a12ad8c66ce0ed90bd127fcc5701251e169688c", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/73cf829fee9a9ac481e60b1bf919bc9fb20753e6", + "width" : 64 + } ], + "name" : "Elvis' Christmas Album", + "type" : "album", + "uri" : "spotify:album:6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 113333, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15701158" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2hON3z0PTxwx9u4zzEyFRo" + }, + "href" : "https://api.spotify.com/v1/tracks/2hON3z0PTxwx9u4zzEyFRo", + "id" : "2hON3z0PTxwx9u4zzEyFRo", + "name" : "Santa Bring My Baby Back (To Me)", + "popularity" : 66, + "preview_url" : "https://p.scdn.co/mp3-preview/2c83cc06efce130b5dfb855657b308b946689ce2", + "track_number" : 6, + "type" : "track", + "uri" : "spotify:track:2hON3z0PTxwx9u4zzEyFRo" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/38lhaWsw8PImY1pIIlKyDJ" + }, + "href" : "https://api.spotify.com/v1/albums/38lhaWsw8PImY1pIIlKyDJ", + "id" : "38lhaWsw8PImY1pIIlKyDJ", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/5f52605ad70e4ee4d79fce461d94b6f6142e24ef", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/781849a6b88350d11ffb9c5b095eb1b4fae23b25", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/53dcb2071ce2b77d633eee3a7ae6768dcdc6d60a", + "width" : 64 + } ], + "name" : "Back In Memphis", + "type" : "album", + "uri" : "spotify:album:38lhaWsw8PImY1pIIlKyDJ" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 263973, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC16901355" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1OtWwtGFPXVhdAVKZHwrNF" + }, + "href" : "https://api.spotify.com/v1/tracks/1OtWwtGFPXVhdAVKZHwrNF", + "id" : "1OtWwtGFPXVhdAVKZHwrNF", + "name" : "Suspicious Minds", + "popularity" : 66, + "preview_url" : "https://p.scdn.co/mp3-preview/1577e9e4e6f90ef513ff274024db9c7cb56703d7", + "track_number" : 14, + "type" : "track", + "uri" : "spotify:track:1OtWwtGFPXVhdAVKZHwrNF" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "href" : "https://api.spotify.com/v1/albums/6zk4RKl6JFlgLCV4Z7DQ7N", + "id" : "6zk4RKl6JFlgLCV4Z7DQ7N", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/1b4845d0abd116eab69a3059ec0a0374030e0261", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/2a12ad8c66ce0ed90bd127fcc5701251e169688c", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/73cf829fee9a9ac481e60b1bf919bc9fb20753e6", + "width" : 64 + } ], + "name" : "Elvis' Christmas Album", + "type" : "album", + "uri" : "spotify:album:6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 145000, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15706998" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6cw1OgKsuEWQbmQb5Z4a3T" + }, + "href" : "https://api.spotify.com/v1/tracks/6cw1OgKsuEWQbmQb5Z4a3T", + "id" : "6cw1OgKsuEWQbmQb5Z4a3T", + "name" : "Silent Night", + "popularity" : 66, + "preview_url" : "https://p.scdn.co/mp3-preview/b4d48860e3e19f0449920f5b1e08cd36739e107d", + "track_number" : 8, + "type" : "track", + "uri" : "spotify:track:6cw1OgKsuEWQbmQb5Z4a3T" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "href" : "https://api.spotify.com/v1/albums/6zk4RKl6JFlgLCV4Z7DQ7N", + "id" : "6zk4RKl6JFlgLCV4Z7DQ7N", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/1b4845d0abd116eab69a3059ec0a0374030e0261", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/2a12ad8c66ce0ed90bd127fcc5701251e169688c", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/73cf829fee9a9ac481e60b1bf919bc9fb20753e6", + "width" : 64 + } ], + "name" : "Elvis' Christmas Album", + "type" : "album", + "uri" : "spotify:album:6zk4RKl6JFlgLCV4Z7DQ7N" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 142600, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC15701161" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5b1jXYUOgAX5QAHXPVHdld" + }, + "href" : "https://api.spotify.com/v1/tracks/5b1jXYUOgAX5QAHXPVHdld", + "id" : "5b1jXYUOgAX5QAHXPVHdld", + "name" : "Santa Claus Is Back In Town", + "popularity" : 65, + "preview_url" : "https://p.scdn.co/mp3-preview/88e57383420e295ea5ca4c626d2a042d6ac64c1e", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:5b1jXYUOgAX5QAHXPVHdld" + }, { + "album" : { + "album_type" : "compilation", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/34EYk8vvJHCUlNrpGxepea" + }, + "href" : "https://api.spotify.com/v1/albums/34EYk8vvJHCUlNrpGxepea", + "id" : "34EYk8vvJHCUlNrpGxepea", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/6324fe377dcedf110025527873dafc9b7ee0bb34", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/d2e2148023e8a87b7a2f8d2abdfa936154e470b8", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/af45f7b48d8a4c7252e1b1ad9240ed8b08c06b31", + "width" : 64 + } ], + "name" : "Elvis 75 - Good Rockin' Tonight", + "type" : "album", + "uri" : "spotify:album:34EYk8vvJHCUlNrpGxepea" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/43ZHCT0cAZBISjO8DG9PnE" + }, + "href" : "https://api.spotify.com/v1/artists/43ZHCT0cAZBISjO8DG9PnE", + "id" : "43ZHCT0cAZBISjO8DG9PnE", + "name" : "Elvis Presley", + "type" : "artist", + "uri" : "spotify:artist:43ZHCT0cAZBISjO8DG9PnE" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/6EkPaTMpQmLwR7CgYiKHha" + }, + "href" : "https://api.spotify.com/v1/artists/6EkPaTMpQmLwR7CgYiKHha", + "id" : "6EkPaTMpQmLwR7CgYiKHha", + "name" : "JXL", + "type" : "artist", + "uri" : "spotify:artist:6EkPaTMpQmLwR7CgYiKHha" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 4, + "duration_ms" : 211173, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC10200288" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/4l2hnfUx0esSbITQa7iJt0" + }, + "href" : "https://api.spotify.com/v1/tracks/4l2hnfUx0esSbITQa7iJt0", + "id" : "4l2hnfUx0esSbITQa7iJt0", + "name" : "A Little Less Conversation - JXL Radio Edit Remix", + "popularity" : 63, + "preview_url" : "https://p.scdn.co/mp3-preview/d257e518f4a17cf3f46475e6759b76b4c934f2ad", + "track_number" : 19, + "type" : "track", + "uri" : "spotify:track:4l2hnfUx0esSbITQa7iJt0" + } ] +}; + + + + +var getArtistRelatedArtists : SpotifyApi.ArtistsRelatedArtistsResponse = { + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0JDkhL4rjiPNEp92jAgJnS" + }, + "followers" : { + "href" : null, + "total" : 127811 + }, + "genres" : [ "brill building pop", "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/0JDkhL4rjiPNEp92jAgJnS", + "id" : "0JDkhL4rjiPNEp92jAgJnS", + "images" : [ { + "height" : 1373, + "url" : "https://i.scdn.co/image/7f1b3c37612225eb475418cce5fad6c4b899028d", + "width" : 1000 + }, { + "height" : 879, + "url" : "https://i.scdn.co/image/b5137cd3489bd841acc464f0f381ae2c9adc0a40", + "width" : 640 + }, { + "height" : 275, + "url" : "https://i.scdn.co/image/664df3c8d77780e9871a1e80ee0389e84fa82ddc", + "width" : 200 + }, { + "height" : 88, + "url" : "https://i.scdn.co/image/6479926a4a97dd7ddddc70b7fb87c6b7de0d705d", + "width" : 64 + } ], + "name" : "Roy Orbison", + "popularity" : 60, + "type" : "artist", + "uri" : "spotify:artist:0JDkhL4rjiPNEp92jAgJnS" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2zyz0VJqrDXeFDIyrfVXSo" + }, + "followers" : { + "href" : null, + "total" : 65322 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/2zyz0VJqrDXeFDIyrfVXSo", + "id" : "2zyz0VJqrDXeFDIyrfVXSo", + "images" : [ { + "height" : 1278, + "url" : "https://i.scdn.co/image/9ff799b50db2f8f5fe8eaec5daac36e1792f3cb3", + "width" : 1000 + }, { + "height" : 818, + "url" : "https://i.scdn.co/image/198a68c93e80bd7384678d62100bddca884ffff7", + "width" : 640 + }, { + "height" : 256, + "url" : "https://i.scdn.co/image/ce87f34433255b9cd3889ee7e6af10f168cee9b4", + "width" : 200 + }, { + "height" : 82, + "url" : "https://i.scdn.co/image/d050407ffb44438e02830d6125b1bd2b955d5731", + "width" : 64 + } ], + "name" : "Jerry Lee Lewis", + "popularity" : 53, + "type" : "artist", + "uri" : "spotify:artist:2zyz0VJqrDXeFDIyrfVXSo" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3wYyutjgII8LJVVOLrGI0D" + }, + "followers" : { + "href" : null, + "total" : 95371 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/3wYyutjgII8LJVVOLrGI0D", + "id" : "3wYyutjgII8LJVVOLrGI0D", + "images" : [ { + "height" : 1266, + "url" : "https://i.scdn.co/image/e8246f90d11c6d4985069cc4b29c0a1e41e75241", + "width" : 1000 + }, { + "height" : 810, + "url" : "https://i.scdn.co/image/9a6b7bce7b052c7c12412bbdfd50cf85eb05b81e", + "width" : 640 + }, { + "height" : 253, + "url" : "https://i.scdn.co/image/2c2b311b63e4e91739b419b1e8382d6421e680b3", + "width" : 200 + }, { + "height" : 81, + "url" : "https://i.scdn.co/image/5cef984df6a60c96520c952ef85923de0907a512", + "width" : 64 + } ], + "name" : "Buddy Holly", + "popularity" : 55, + "type" : "artist", + "uri" : "spotify:artist:3wYyutjgII8LJVVOLrGI0D" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/73sSFVlM6pkweLXE8qw1OS" + }, + "followers" : { + "href" : null, + "total" : 26194 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/73sSFVlM6pkweLXE8qw1OS", + "id" : "73sSFVlM6pkweLXE8qw1OS", + "images" : [ { + "height" : 1129, + "url" : "https://i.scdn.co/image/53b1e360f7e4978410529ee7a971c3f8a4118622", + "width" : 1000 + }, { + "height" : 723, + "url" : "https://i.scdn.co/image/e4eb935b9af1f78735e9e25e8e75e3685b81fdd8", + "width" : 640 + }, { + "height" : 226, + "url" : "https://i.scdn.co/image/d6f709471d825cb9cf991acb77b7fb87667c0de1", + "width" : 200 + }, { + "height" : 72, + "url" : "https://i.scdn.co/image/6ced7f8bcb6a04e22dd357c4110fa0e4349933cd", + "width" : 64 + } ], + "name" : "Ricky Nelson", + "popularity" : 46, + "type" : "artist", + "uri" : "spotify:artist:73sSFVlM6pkweLXE8qw1OS" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/5hIClg6noTaCzMu2s5wp4f" + }, + "followers" : { + "href" : null, + "total" : 15528 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/5hIClg6noTaCzMu2s5wp4f", + "id" : "5hIClg6noTaCzMu2s5wp4f", + "images" : [ { + "height" : 737, + "url" : "https://i.scdn.co/image/02b340629ddcc41fe48932fba641312f27de49a7", + "width" : 999 + }, { + "height" : 472, + "url" : "https://i.scdn.co/image/c99b5bc0bd9bfd566c6f64eccf9ae6426aaeff20", + "width" : 640 + }, { + "height" : 147, + "url" : "https://i.scdn.co/image/a2240effbf0c00539348d81e90380a14a51651cc", + "width" : 199 + }, { + "height" : 47, + "url" : "https://i.scdn.co/image/9af48c6576925720e3d43aacdd7797c52e1a639b", + "width" : 64 + } ], + "name" : "Carl Perkins", + "popularity" : 44, + "type" : "artist", + "uri" : "spotify:artist:5hIClg6noTaCzMu2s5wp4f" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/4ACplpEqD6JIVgKrafauzs" + }, + "followers" : { + "href" : null, + "total" : 44959 + }, + "genres" : [ "brill building pop", "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/4ACplpEqD6JIVgKrafauzs", + "id" : "4ACplpEqD6JIVgKrafauzs", + "images" : [ { + "height" : 1035, + "url" : "https://i.scdn.co/image/bf582c9e540c2f12771cfd032f592d31697cfae9", + "width" : 1000 + }, { + "height" : 662, + "url" : "https://i.scdn.co/image/da7c23421146985b7e1583d3bc09ecba9f7ac5c6", + "width" : 640 + }, { + "height" : 207, + "url" : "https://i.scdn.co/image/b430dbc0ed1d6926b9088440683d15270e5154cc", + "width" : 200 + }, { + "height" : 66, + "url" : "https://i.scdn.co/image/985afca7544c6933b7e7ada2018c4ed0b4bba7a0", + "width" : 64 + } ], + "name" : "The Everly Brothers", + "popularity" : 53, + "type" : "artist", + "uri" : "spotify:artist:4ACplpEqD6JIVgKrafauzs" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/4xls23Ye9WR9yy3yYMpAMm" + }, + "followers" : { + "href" : null, + "total" : 62897 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/4xls23Ye9WR9yy3yYMpAMm", + "id" : "4xls23Ye9WR9yy3yYMpAMm", + "images" : [ { + "height" : 1181, + "url" : "https://i.scdn.co/image/b4db13fb1d2e2872d7b7eac4b17d67870482f16f", + "width" : 1000 + }, { + "height" : 756, + "url" : "https://i.scdn.co/image/217387b531599ffb81751ab8629c4baf78d85c4e", + "width" : 640 + }, { + "height" : 236, + "url" : "https://i.scdn.co/image/82fe8f7a2d139b7c746b5ff6985f6b186113dd75", + "width" : 200 + }, { + "height" : 76, + "url" : "https://i.scdn.co/image/de0d8715aa69bdbbd1236c6c88528ff93804e86d", + "width" : 64 + } ], + "name" : "Little Richard", + "popularity" : 55, + "type" : "artist", + "uri" : "spotify:artist:4xls23Ye9WR9yy3yYMpAMm" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1p0t3JtUTayV2wb1RGN9mO" + }, + "followers" : { + "href" : null, + "total" : 26019 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/1p0t3JtUTayV2wb1RGN9mO", + "id" : "1p0t3JtUTayV2wb1RGN9mO", + "images" : [ { + "height" : 752, + "url" : "https://i.scdn.co/image/6c3d2f6c26991828bf2d776fc468b929ca31304a", + "width" : 648 + }, { + "height" : 743, + "url" : "https://i.scdn.co/image/21c81243f2df0b3ce5cdcd7af629beef7e8af76e", + "width" : 640 + }, { + "height" : 232, + "url" : "https://i.scdn.co/image/9a800b3323b9edcdb0267aad068aedd594cc1fd1", + "width" : 200 + }, { + "height" : 74, + "url" : "https://i.scdn.co/image/5b01110b8def5978979b9bd946612e353028828d", + "width" : 64 + } ], + "name" : "Eddie Cochran", + "popularity" : 48, + "type" : "artist", + "uri" : "spotify:artist:1p0t3JtUTayV2wb1RGN9mO" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/293zczrfYafIItmnmM3coR" + }, + "followers" : { + "href" : null, + "total" : 155572 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/293zczrfYafIItmnmM3coR", + "id" : "293zczrfYafIItmnmM3coR", + "images" : [ { + "height" : 1198, + "url" : "https://i.scdn.co/image/806ae8389df74bb2f8df1adf64c67c0e6dc76048", + "width" : 1000 + }, { + "height" : 766, + "url" : "https://i.scdn.co/image/f07a0dc93bde1aa294355c26b2a75edaa274c8f8", + "width" : 640 + }, { + "height" : 240, + "url" : "https://i.scdn.co/image/c5d23d159328aa908baaeeff6fa4855cf8519999", + "width" : 200 + }, { + "height" : 77, + "url" : "https://i.scdn.co/image/98006c221cbcc29bc9746757e69fa896fd0a5640", + "width" : 64 + } ], + "name" : "Chuck Berry", + "popularity" : 65, + "type" : "artist", + "uri" : "spotify:artist:293zczrfYafIItmnmM3coR" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/5Y9xEAGW4GwGJgbiI6W85P" + }, + "followers" : { + "href" : null, + "total" : 29285 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/5Y9xEAGW4GwGJgbiI6W85P", + "id" : "5Y9xEAGW4GwGJgbiI6W85P", + "images" : [ { + "height" : 719, + "url" : "https://i.scdn.co/image/02da1b78ba9cad76b662cff4d0fdf41f20bbc67d", + "width" : 1000 + }, { + "height" : 460, + "url" : "https://i.scdn.co/image/be6d7f39b75ff62aadc113d4c2142291821bdc0d", + "width" : 640 + }, { + "height" : 144, + "url" : "https://i.scdn.co/image/1f234198e2d01e415acdc058956993c89f842b32", + "width" : 200 + }, { + "height" : 46, + "url" : "https://i.scdn.co/image/f1a5f9fc9ad095d419313308b38f805e42c05dcf", + "width" : 64 + } ], + "name" : "Ritchie Valens", + "popularity" : 50, + "type" : "artist", + "uri" : "spotify:artist:5Y9xEAGW4GwGJgbiI6W85P" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/4cPHsZM98sKzmV26wlwD2W" + }, + "followers" : { + "href" : null, + "total" : 25168 + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/artists/4cPHsZM98sKzmV26wlwD2W", + "id" : "4cPHsZM98sKzmV26wlwD2W", + "images" : [ { + "height" : 1469, + "url" : "https://i.scdn.co/image/b2d04f712c91bcf98a28ce1a8c2f674ddb724ec6", + "width" : 1000 + }, { + "height" : 940, + "url" : "https://i.scdn.co/image/4ca270764861f2e13851b8e5110bb96ba7f39359", + "width" : 640 + }, { + "height" : 294, + "url" : "https://i.scdn.co/image/89ecdb230bcc12e980ce58fd88d20cc6dbc5b388", + "width" : 200 + }, { + "height" : 94, + "url" : "https://i.scdn.co/image/2e615b79eb4c945b7a57e241448e681d7f2da8bd", + "width" : 64 + } ], + "name" : "Brenda Lee", + "popularity" : 68, + "type" : "artist", + "uri" : "spotify:artist:4cPHsZM98sKzmV26wlwD2W" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2XBzvyw3fwtZu4iUz12x0G" + }, + "followers" : { + "href" : null, + "total" : 12228 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/2XBzvyw3fwtZu4iUz12x0G", + "id" : "2XBzvyw3fwtZu4iUz12x0G", + "images" : [ { + "height" : 809, + "url" : "https://i.scdn.co/image/8e9c925577ff4d563f9f12324453be1b5d026494", + "width" : 1000 + }, { + "height" : 518, + "url" : "https://i.scdn.co/image/37b77aa15c67c4d8763a73301360d405715a7145", + "width" : 640 + }, { + "height" : 162, + "url" : "https://i.scdn.co/image/3b2ae8fdc389ee165b7f5787fd91ae6604ff4fca", + "width" : 200 + }, { + "height" : 52, + "url" : "https://i.scdn.co/image/fb39aac889247b6528b3bbc85c1e2ef773ad2b47", + "width" : 64 + } ], + "name" : "Bill Haley", + "popularity" : 37, + "type" : "artist", + "uri" : "spotify:artist:2XBzvyw3fwtZu4iUz12x0G" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/6KWcxMWVNVIYbdOQyJtsSy" + }, + "followers" : { + "href" : null, + "total" : 46850 + }, + "genres" : [ "brill building pop" ], + "href" : "https://api.spotify.com/v1/artists/6KWcxMWVNVIYbdOQyJtsSy", + "id" : "6KWcxMWVNVIYbdOQyJtsSy", + "images" : [ { + "height" : 857, + "url" : "https://i.scdn.co/image/10557069b43b1059e6490d062a5d21154a78d69d", + "width" : 689 + }, { + "height" : 796, + "url" : "https://i.scdn.co/image/f6fa63eb8267c9381557adbb37119900c49c3734", + "width" : 640 + }, { + "height" : 249, + "url" : "https://i.scdn.co/image/634e2cd425103bfd8766a7f31adcaa0bdfedb3ac", + "width" : 200 + }, { + "height" : 80, + "url" : "https://i.scdn.co/image/864692e8803ffa885e34cbcde41acb218019c17e", + "width" : 64 + } ], + "name" : "The Platters", + "popularity" : 56, + "type" : "artist", + "uri" : "spotify:artist:6KWcxMWVNVIYbdOQyJtsSy" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/5ZKMPRDHc7qElVJFh3uRqB" + }, + "followers" : { + "href" : null, + "total" : 24305 + }, + "genres" : [ "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/5ZKMPRDHc7qElVJFh3uRqB", + "id" : "5ZKMPRDHc7qElVJFh3uRqB", + "images" : [ { + "height" : 997, + "url" : "https://i.scdn.co/image/beff5827580bcc4d129cbc0872768095eeba8c14", + "width" : 1000 + }, { + "height" : 638, + "url" : "https://i.scdn.co/image/dbabf703779789917c4dd1c0e54da62c7a45ce92", + "width" : 640 + }, { + "height" : 199, + "url" : "https://i.scdn.co/image/74761c343bec27c814b8e44e4bc095cbf1b674bb", + "width" : 200 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/0c30af5647c74fee14fb97981c23b336abbc9f21", + "width" : 64 + } ], + "name" : "Wanda Jackson", + "popularity" : 46, + "type" : "artist", + "uri" : "spotify:artist:5ZKMPRDHc7qElVJFh3uRqB" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/5VAHm7V5mnsxvQrWw3KHmx" + }, + "followers" : { + "href" : null, + "total" : 11286 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/5VAHm7V5mnsxvQrWw3KHmx", + "id" : "5VAHm7V5mnsxvQrWw3KHmx", + "images" : [ { + "height" : 1224, + "url" : "https://i.scdn.co/image/f3f3a6df9ee1854a32a8a4e635820002c6ef32be", + "width" : 1000 + }, { + "height" : 784, + "url" : "https://i.scdn.co/image/4ebffb55a443fb401fe0233fd6c8bb42f381f235", + "width" : 640 + }, { + "height" : 245, + "url" : "https://i.scdn.co/image/12876b206cc3e3d1133a674c8e02caee88ca5285", + "width" : 200 + }, { + "height" : 78, + "url" : "https://i.scdn.co/image/4d3bf8fc93e3e0c7314c38142d38c74959c9f52d", + "width" : 64 + } ], + "name" : "Gene Vincent", + "popularity" : 40, + "type" : "artist", + "uri" : "spotify:artist:5VAHm7V5mnsxvQrWw3KHmx" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/09C0xjtosNAIXP36wTnWxd" + }, + "followers" : { + "href" : null, + "total" : 40209 + }, + "genres" : [ "new orleans blues", "rock-and-roll", "swamp pop" ], + "href" : "https://api.spotify.com/v1/artists/09C0xjtosNAIXP36wTnWxd", + "id" : "09C0xjtosNAIXP36wTnWxd", + "images" : [ { + "height" : 1170, + "url" : "https://i.scdn.co/image/1e7e3ddbe8c3862d32d35aef5e4a763718f1e370", + "width" : 1000 + }, { + "height" : 749, + "url" : "https://i.scdn.co/image/172221e04fef2e038871248b3abdecbcf8f5c131", + "width" : 640 + }, { + "height" : 234, + "url" : "https://i.scdn.co/image/5ee1c7e5f1a45125ee8315d90ca62e6afb04cc25", + "width" : 200 + }, { + "height" : 75, + "url" : "https://i.scdn.co/image/afe5d30d0286526a60aa0d37c02d5864eb24f67b", + "width" : 64 + } ], + "name" : "Fats Domino", + "popularity" : 52, + "type" : "artist", + "uri" : "spotify:artist:09C0xjtosNAIXP36wTnWxd" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3MFp4cYuYtTZe3d3xkLLbr" + }, + "followers" : { + "href" : null, + "total" : 9304 + }, + "genres" : [ "rock-and-roll", "rockabilly" ], + "href" : "https://api.spotify.com/v1/artists/3MFp4cYuYtTZe3d3xkLLbr", + "id" : "3MFp4cYuYtTZe3d3xkLLbr", + "images" : [ { + "height" : 587, + "url" : "https://i.scdn.co/image/5ff43c4d5c1131fd5adcc4c3cab712a7ef044148", + "width" : 640 + }, { + "height" : 275, + "url" : "https://i.scdn.co/image/18b454401b7bf1ae7fe7e713ee0406f9d3246727", + "width" : 300 + }, { + "height" : 59, + "url" : "https://i.scdn.co/image/a7b0b3eeae2cfbf7419c2c3fa704992c39cf1c62", + "width" : 64 + } ], + "name" : "Bill Haley & His Comets", + "popularity" : 44, + "type" : "artist", + "uri" : "spotify:artist:3MFp4cYuYtTZe3d3xkLLbr" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/7ceUfdWq2t5nbatS6ollHh" + }, + "followers" : { + "href" : null, + "total" : 34766 + }, + "genres" : [ "adult standards", "brill building pop", "christmas", "lounge" ], + "href" : "https://api.spotify.com/v1/artists/7ceUfdWq2t5nbatS6ollHh", + "id" : "7ceUfdWq2t5nbatS6ollHh", + "images" : [ { + "height" : 1100, + "url" : "https://i.scdn.co/image/2cf68a5624e8a646d51760740d83be8a3361cb71", + "width" : 1000 + }, { + "height" : 704, + "url" : "https://i.scdn.co/image/5a571c35e1840766e3f15dabb42d86adda26da90", + "width" : 640 + }, { + "height" : 220, + "url" : "https://i.scdn.co/image/d9f7f5448bfe1492337d78c1791ab442f9b8b56a", + "width" : 200 + }, { + "height" : 70, + "url" : "https://i.scdn.co/image/5b3f6e1161dff6d711d8d1b0c9a802096aa5b87b", + "width" : 64 + } ], + "name" : "Paul Anka", + "popularity" : 55, + "type" : "artist", + "uri" : "spotify:artist:7ceUfdWq2t5nbatS6ollHh" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/7qQJQ3YtcGlqaLg5tcypN2" + }, + "followers" : { + "href" : null, + "total" : 19394 + }, + "genres" : [ "rock-and-roll" ], + "href" : "https://api.spotify.com/v1/artists/7qQJQ3YtcGlqaLg5tcypN2", + "id" : "7qQJQ3YtcGlqaLg5tcypN2", + "images" : [ { + "height" : 1250, + "url" : "https://i.scdn.co/image/10d80af483070c9a1d4636a36ca2d1f89289c933", + "width" : 1000 + }, { + "height" : 800, + "url" : "https://i.scdn.co/image/0b5b079ad92eac89fad895f309499ff772ce08c1", + "width" : 640 + }, { + "height" : 250, + "url" : "https://i.scdn.co/image/d0a244ebffff84aa94682338ca70b5d0e18790fa", + "width" : 200 + }, { + "height" : 80, + "url" : "https://i.scdn.co/image/0fdfd8a3beef84b7bc9cf9191519f6192a54764e", + "width" : 64 + } ], + "name" : "Chubby Checker", + "popularity" : 47, + "type" : "artist", + "uri" : "spotify:artist:7qQJQ3YtcGlqaLg5tcypN2" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1T0wRBO0CK0vK8ouUMqEl5" + }, + "followers" : { + "href" : null, + "total" : 119129 + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/artists/1T0wRBO0CK0vK8ouUMqEl5", + "id" : "1T0wRBO0CK0vK8ouUMqEl5", + "images" : [ { + "height" : 1376, + "url" : "https://i.scdn.co/image/b50aca00cc09b9f036171ea1c2a47a6db8aac968", + "width" : 1000 + }, { + "height" : 880, + "url" : "https://i.scdn.co/image/da6f2d822801f0af81bde165540f8d6891404a3e", + "width" : 640 + }, { + "height" : 275, + "url" : "https://i.scdn.co/image/37985e105605e760eb7a86866cc8eeb94b513e23", + "width" : 200 + }, { + "height" : 88, + "url" : "https://i.scdn.co/image/7931338574dcf8c2ae09dded11f1668b0110c0b0", + "width" : 64 + } ], + "name" : "Tom Jones", + "popularity" : 59, + "type" : "artist", + "uri" : "spotify:artist:1T0wRBO0CK0vK8ouUMqEl5" + } ] +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-list-featured-playlists/ + */ +var featuredPlaylists : SpotifyApi.ListOfFeaturedPlaylistsResponse = { + "message" : "Enjoy a mellow afternoon.", + "playlists" : { + "href" : "https://api.spotify.com/v1/browse/featured-playlists?country=SE×tamp=2015-12-25T15:10:15&offset=0&limit=2", + "items" : [ { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify/playlist/16BpjqQV1Ey0HeDueNDSYz" + }, + "href" : "https://api.spotify.com/v1/users/spotify/playlists/16BpjqQV1Ey0HeDueNDSYz", + "id" : "16BpjqQV1Ey0HeDueNDSYz", + "images" : [ { + "height" : 300, + "url" : "https://i.scdn.co/image/6b282f0ad7f5de8c8f04a20268376be638e8241a", + "width" : 300 + } ], + "name" : "Afternoon Acoustic", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify" + }, + "href" : "https://api.spotify.com/v1/users/spotify", + "id" : "spotify", + "type" : "user", + "uri" : "spotify:user:spotify" + }, + "public" : null, + "snapshot_id" : "ymcdjXlXzZPZClmP0Pm4iuHaWk4r5OejEOoCOIstJdfxgYNljKWePUZm2v2PzHJT", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/spotify/playlists/16BpjqQV1Ey0HeDueNDSYz/tracks", + "total" : 111 + }, + "type" : "playlist", + "uri" : "spotify:user:spotify:playlist:16BpjqQV1Ey0HeDueNDSYz" + }, { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify/playlist/7nUikuZL4MgIXS43cMpQZE" + }, + "href" : "https://api.spotify.com/v1/users/spotify/playlists/7nUikuZL4MgIXS43cMpQZE", + "id" : "7nUikuZL4MgIXS43cMpQZE", + "images" : [ { + "height" : 300, + "url" : "https://i.scdn.co/image/7fbae403e487e03098c1050902e3fb83f9e4a606", + "width" : 300 + } ], + "name" : "Jazzy Christmas", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify" + }, + "href" : "https://api.spotify.com/v1/users/spotify", + "id" : "spotify", + "type" : "user", + "uri" : "spotify:user:spotify" + }, + "public" : null, + "snapshot_id" : "v2Y0q77RziNFIIFIdUrHIw6om2Wqx/kBny4u5REQYj3mcf8EFVVigOdzg8kRTJxU", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/spotify/playlists/7nUikuZL4MgIXS43cMpQZE/tracks", + "total" : 22 + }, + "type" : "playlist", + "uri" : "spotify:user:spotify:playlist:7nUikuZL4MgIXS43cMpQZE" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/browse/featured-playlists?country=SE×tamp=2015-12-25T15:10:15&offset=2&limit=2", + "offset" : 0, + "previous" : null, + "total" : 13 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-list-new-releases/ + */ +var newReleases : SpotifyApi.ListOfNewReleasesResponse = { + "albums" : { + "href" : "https://api.spotify.com/v1/browse/new-releases?country=SE&offset=0&limit=20", + "items" : [ { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/1PULmKbHeOqlkIwcDMNwD4" + }, + "href" : "https://api.spotify.com/v1/albums/1PULmKbHeOqlkIwcDMNwD4", + "id" : "1PULmKbHeOqlkIwcDMNwD4", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/377d0c66cae914111f5ee721853dc68d2cc53556", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/54ec202ec205ea6430aefce2b644d934ff0a7036", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/5897d86139c6aa6d579e85c7a49b876c70a59334", + "width" : 64 + } ], + "name" : "Sgt. Pepper's Lonely Hearts Club Band (Remastered)", + "type" : "album", + "uri" : "spotify:album:1PULmKbHeOqlkIwcDMNwD4" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/03Qh833fEdVT30Pfs93ea6" + }, + "href" : "https://api.spotify.com/v1/albums/03Qh833fEdVT30Pfs93ea6", + "id" : "03Qh833fEdVT30Pfs93ea6", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/d6028aea974c75961cb9cdc2263f5d8a8a6582bd", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/adebae7bf6a4a441bc6a5a17ca840f77df6ed3b9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/3b0ddfadf13b9f3e74da93fcb21e4183a4d9fcc8", + "width" : 64 + } ], + "name" : "The Beatles (Remastered)", + "type" : "album", + "uri" : "spotify:album:03Qh833fEdVT30Pfs93ea6" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/2Pqkn9Dq2DFtdfkKAeqgMd" + }, + "href" : "https://api.spotify.com/v1/albums/2Pqkn9Dq2DFtdfkKAeqgMd", + "id" : "2Pqkn9Dq2DFtdfkKAeqgMd", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/9cab76ad73ce2adbacbd118ebc632255ce7c1841", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/a650b9dadd2b2d66ab9d7788abdcbfab45b2997d", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/b00a9daeee0a66bd3723d723cce6134cf3c38303", + "width" : 64 + } ], + "name" : "Abbey Road (Remastered)", + "type" : "album", + "uri" : "spotify:album:2Pqkn9Dq2DFtdfkKAeqgMd" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3OdI6e43crvyAHhaqpxSyz" + }, + "href" : "https://api.spotify.com/v1/albums/3OdI6e43crvyAHhaqpxSyz", + "id" : "3OdI6e43crvyAHhaqpxSyz", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/a7f271263055adb87353c76b2e5ebbdec07e92a9", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8bc940347ba801f90614d9cda11f995b096cca52", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/f945ab4ae2c9e9d85dcd6c81cfe012860db9c2bc", + "width" : 64 + } ], + "name" : "Rubber Soul (Remastered)", + "type" : "album", + "uri" : "spotify:album:3OdI6e43crvyAHhaqpxSyz" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0PYyrqs9NXtxPhf0CZkq2L" + }, + "href" : "https://api.spotify.com/v1/albums/0PYyrqs9NXtxPhf0CZkq2L", + "id" : "0PYyrqs9NXtxPhf0CZkq2L", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/6ed84deed3993bbdfb644f91cb9db2a85b25da38", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/b868b08257b96def9260e1a7e547be11bd8c26b0", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/1760ab1210d0ebbda3094e6945db559b7483a1dd", + "width" : 64 + } ], + "name" : "Revolver (Remastered)", + "type" : "album", + "uri" : "spotify:album:0PYyrqs9NXtxPhf0CZkq2L" + }, { + "album_type" : "single", + "available_markets" : [ "AU", "HK", "MY", "NZ", "PH", "SG", "TW", "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "TR", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3qm3S8gkGPCdeCwaGUj4WE" + }, + "href" : "https://api.spotify.com/v1/albums/3qm3S8gkGPCdeCwaGUj4WE", + "id" : "3qm3S8gkGPCdeCwaGUj4WE", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/bf891e3702739cb350352dcac45e4243d809ca92", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/4930f0ace2e239840f173487b74a16eb2d266eb5", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/d3ece8847b11a0f45a307f60c74006aa01018728", + "width" : 64 + } ], + "name" : "Stevie Knows (7th Heaven Remix)", + "type" : "album", + "uri" : "spotify:album:3qm3S8gkGPCdeCwaGUj4WE" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0HkanXbi3f3Riv9ISsO11s" + }, + "href" : "https://api.spotify.com/v1/albums/0HkanXbi3f3Riv9ISsO11s", + "id" : "0HkanXbi3f3Riv9ISsO11s", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4f408ce56d89e4ed6cb350e3f93b76d1e4a55cc3", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/29823623b87bff215519b9d744f55f47984cab18", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/1e987283293d4a50e52e668649f9e79c4b236790", + "width" : 64 + } ], + "name" : "I'm From Long Beach - Single", + "type" : "album", + "uri" : "spotify:album:0HkanXbi3f3Riv9ISsO11s" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3bgOyqPJTjGJyyhcPZTwjQ" + }, + "href" : "https://api.spotify.com/v1/albums/3bgOyqPJTjGJyyhcPZTwjQ", + "id" : "3bgOyqPJTjGJyyhcPZTwjQ", + "images" : [ { + "height" : 600, + "url" : "https://i.scdn.co/image/2dacef968af7cd9bc10ad43c10a5866fdaa431fe", + "width" : 600 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/860edb16f98ad8c422d65714c999c23c56bdb18a", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/1302a1823a425d24f3f6effa9c149a445cf4e20d", + "width" : 64 + } ], + "name" : "Två vägar", + "type" : "album", + "uri" : "spotify:album:3bgOyqPJTjGJyyhcPZTwjQ" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/1qqwJHUhez843oBaz5et2S" + }, + "href" : "https://api.spotify.com/v1/albums/1qqwJHUhez843oBaz5et2S", + "id" : "1qqwJHUhez843oBaz5et2S", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/8c02adb97fe766ed2c7cc0e13e445bf987d1edf1", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/c66a7ab5c04e88a6c7ad5ce9ec21dab15bbcd5e6", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/e9274182ce9999095da6118d83aec90834803ac3", + "width" : 64 + } ], + "name" : "Might Not", + "type" : "album", + "uri" : "spotify:album:1qqwJHUhez843oBaz5et2S" + }, { + "album_type" : "single", + "available_markets" : [ "AT", "AU", "CH", "DE", "DK", "FI", "GB", "IE", "IS", "NO", "NZ", "SE" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0Ux8McYvQSzNFbub73OFqk" + }, + "href" : "https://api.spotify.com/v1/albums/0Ux8McYvQSzNFbub73OFqk", + "id" : "0Ux8McYvQSzNFbub73OFqk", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/892bef68ecad8b6a07181c19ed565b1a7be12009", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/0c3e2c96a9973a82e6ff78ba270421e2db65b4b0", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/7fb9c038d2628fd2b7bef39610aced6f91d49cff", + "width" : 64 + } ], + "name" : "Merry Xmas (feat. Monty)", + "type" : "album", + "uri" : "spotify:album:0Ux8McYvQSzNFbub73OFqk" + }, { + "album_type" : "album", + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6uG9BscYmPnAbtl6Cy9u91" + }, + "href" : "https://api.spotify.com/v1/albums/6uG9BscYmPnAbtl6Cy9u91", + "id" : "6uG9BscYmPnAbtl6Cy9u91", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4d26ef97cbfe370350770332fdd45e1152425b4e", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/e43b111ee4ed30b17ae40b1c73326a54df53ffc9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/96c8941a9ead45c01e65fc615ed5a95f13af869f", + "width" : 64 + } ], + "name" : "Summer In The Winter", + "type" : "album", + "uri" : "spotify:album:6uG9BscYmPnAbtl6Cy9u91" + }, { + "album_type" : "single", + "available_markets" : [ "AU", "HK", "MY", "NZ", "PH", "SG", "TW", "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "TR", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CO", "EC", "PA", "PE", "CR", "GT", "HN", "MX", "NI", "SV" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6U4UXePoZz8jI0WAgOY0QK" + }, + "href" : "https://api.spotify.com/v1/albums/6U4UXePoZz8jI0WAgOY0QK", + "id" : "6U4UXePoZz8jI0WAgOY0QK", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/aedf44f75f661d3b15ccef4afe42d4460e9c1df3", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/b541b9adf17d67f0e5dc88b7b4a91c8f05271c79", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/7e4bdb5457d31d12a0fe191500e1b75b370166f7", + "width" : 64 + } ], + "name" : "Lay It All On Me (feat. Big Sean, Vic Mensa & Ed Sheeran) [Rudi VIP Mix]", + "type" : "album", + "uri" : "spotify:album:6U4UXePoZz8jI0WAgOY0QK" + }, { + "album_type" : "single", + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "TR", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3skXXEPIZHApEfglcwIlvR" + }, + "href" : "https://api.spotify.com/v1/albums/3skXXEPIZHApEfglcwIlvR", + "id" : "3skXXEPIZHApEfglcwIlvR", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/96a4ed623f6c79b305e06080a976244baefa36eb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/14f3afa15d40d00db46baa6429fd79bed40a5cdd", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/16875c5e3377ae90ea2f6ea9932977961b2ed1d5", + "width" : 64 + } ], + "name" : "Christmas Will Break Your Heart", + "type" : "album", + "uri" : "spotify:album:3skXXEPIZHApEfglcwIlvR" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0rd1TF9fOXVHoSuHJ9Sckm" + }, + "href" : "https://api.spotify.com/v1/albums/0rd1TF9fOXVHoSuHJ9Sckm", + "id" : "0rd1TF9fOXVHoSuHJ9Sckm", + "images" : [ { + "height" : 600, + "url" : "https://i.scdn.co/image/03e10634c4c654cedf1129ddce00f90f35367bb4", + "width" : 600 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/aed4e0d36ed4f1b9622c7842b6208008a29f5c85", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/af2ad8bd173eac67935201982d357fc865f1ff7a", + "width" : 64 + } ], + "name" : "Snökristaller - EP", + "type" : "album", + "uri" : "spotify:album:0rd1TF9fOXVHoSuHJ9Sckm" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/7FideSlOCa2PVAjvK1Ytw4" + }, + "href" : "https://api.spotify.com/v1/albums/7FideSlOCa2PVAjvK1Ytw4", + "id" : "7FideSlOCa2PVAjvK1Ytw4", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c08c07f4cee62d88f02c8e3cc9c2f3e3b05451c8", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/9e1757f3f64c632bcab34d7ca586bd46a16999b5", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/105fba4aa1f327324cf0fbdebe52ca6a394188d9", + "width" : 64 + } ], + "name" : "Kalla Mig (Black Knight Remix)", + "type" : "album", + "uri" : "spotify:album:7FideSlOCa2PVAjvK1Ytw4" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/4Ek2i3GBY8sQGIooFX3mTL" + }, + "href" : "https://api.spotify.com/v1/albums/4Ek2i3GBY8sQGIooFX3mTL", + "id" : "4Ek2i3GBY8sQGIooFX3mTL", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/220fe52d445a678b92cacb418fecf9580ab41761", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/ea4823e62f173366037eacd6cd5ee1406c5f05db", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/ef351095477677c88ee784939dffff5cf87cce7f", + "width" : 64 + } ], + "name" : "Born To Be Loved (Faråker Remix)", + "type" : "album", + "uri" : "spotify:album:4Ek2i3GBY8sQGIooFX3mTL" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6YBCE5NFQQTVuZVhBCMnSe" + }, + "href" : "https://api.spotify.com/v1/albums/6YBCE5NFQQTVuZVhBCMnSe", + "id" : "6YBCE5NFQQTVuZVhBCMnSe", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/bc0d0ff74393abbb232eb04f0a4bb91439b1cbe1", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/e071dc624ca44264a8ace9a7bfb8bd1407428862", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/efd6dadf26d8a9a692478cdd19152e5cc833546e", + "width" : 64 + } ], + "name" : "Quentin Tarantino's The Hateful Eight (Original Motion Picture Soundtrack)", + "type" : "album", + "uri" : "spotify:album:6YBCE5NFQQTVuZVhBCMnSe" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AT", "AU", "BE", "BG", "CH", "CY", "DE", "DK", "DO", "EE", "FI", "GB", "HK", "IE", "IS", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NL", "NO", "NZ", "PH", "RO", "SE", "SG", "SI", "SK", "TW" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/4RndEmppoOEWuTGSFQOqJs" + }, + "href" : "https://api.spotify.com/v1/albums/4RndEmppoOEWuTGSFQOqJs", + "id" : "4RndEmppoOEWuTGSFQOqJs", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/8f20aeb3ce6c9d7714bd76fc474220857ad9cfc3", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/1fba47df83950df286cf9cb607b6cf7ada2b0003", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/e7d622fd9257e62c267d0343db34840a7835b521", + "width" : 64 + } ], + "name" : "Star Wars: The Force Awakens (Original Motion Picture Soundtrack)", + "type" : "album", + "uri" : "spotify:album:4RndEmppoOEWuTGSFQOqJs" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AU", "BE", "BG", "BO", "BR", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/4qgWyE8Pp9AZ94src2XEi7" + }, + "href" : "https://api.spotify.com/v1/albums/4qgWyE8Pp9AZ94src2XEi7", + "id" : "4qgWyE8Pp9AZ94src2XEi7", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/7bbb0eb112150c76c27d6ed1fead3c53a02ca303", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/690157ca7a732698f46c815e295d2bafe6492d83", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/1297f1ffa9875ed7e18f9a44d86768f75589bea2", + "width" : 64 + } ], + "name" : "One Call Away (feat. Tyga) [Remix]", + "type" : "album", + "uri" : "spotify:album:4qgWyE8Pp9AZ94src2XEi7" + }, { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5BFg8l4NYyZ90DWqcBjbt6" + }, + "href" : "https://api.spotify.com/v1/albums/5BFg8l4NYyZ90DWqcBjbt6", + "id" : "5BFg8l4NYyZ90DWqcBjbt6", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c82b30ae6e4a240bd705e5c1111778d5425df98a", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/5f746a9db4250f544e24d0094a46422d521c6c90", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/19cd283556d61505b8066c0735916395c252c57a", + "width" : 64 + } ], + "name" : "Christmas & Chill", + "type" : "album", + "uri" : "spotify:album:5BFg8l4NYyZ90DWqcBjbt6" + } ], + "limit" : 20, + "next" : "https://api.spotify.com/v1/browse/new-releases?country=SE&offset=20&limit=20", + "offset" : 0, + "previous" : null, + "total" : 500 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-list-categories/ + */ +var listOfCategories : SpotifyApi.MultipleCategoriesResponse = { + "categories" : { + "href" : "https://api.spotify.com/v1/browse/categories?offset=0&limit=20", + "items" : [ { + "href" : "https://api.spotify.com/v1/browse/categories/toplists", + "icons" : [ { + "height" : 275, + "url" : "https://t.scdn.co/media/derived/toplists_11160599e6a04ac5d6f2757f5511778f_0_0_275_275.jpg", + "width" : 275 + } ], + "id" : "toplists", + "name" : "Top Lists" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/holidays", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/links/holidays2015_274x274.jpg", + "width" : 274 + } ], + "id" : "holidays", + "name" : "Happy Holidays" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/yearinmusic", + "icons" : [ { + "height" : null, + "url" : "https://t.scdn.co/media/categories/yearinmusic2015_274x274.png", + "width" : null + } ], + "id" : "yearinmusic", + "name" : "Year in Music" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/mood", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/original/mood-274x274_976986a31ac8c49794cbdc7246fd5ad7_274x274.jpg", + "width" : 274 + } ], + "id" : "mood", + "name" : "Mood" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/party", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/links/partyicon_274x274.jpg", + "width" : 274 + } ], + "id" : "party", + "name" : "Party" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/pop", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/pop-274x274_447148649685019f5e2a03a39e78ba52_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "pop", + "name" : "Pop" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/popculture", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/trending-274x274_7b238f7217985e79d3664f2734347b98_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "popculture", + "name" : "Trending" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/focus", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/original/genre-images-square-274x274_5e50d72b846a198fcd2ca9b3aef5f0c8_274x274.jpg", + "width" : 274 + } ], + "id" : "focus", + "name" : "Focus" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/rock", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/rock_9ce79e0a4ef901bbd10494f5b855d3cc_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "rock", + "name" : "Rock" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/indie_alt", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/indie-274x274_add35b2b767ff7f3897262ad86809bdb_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "indie_alt", + "name" : "Indie/Alternative" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/edm_dance", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/edm-274x274_0ef612604200a9c14995432994455a6d_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "edm_dance", + "name" : "EDM/Dance" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/chill", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/chill-274x274_4c46374f007813dd10b37e8d8fd35b4b_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "chill", + "name" : "Chill" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/dinner", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/original/dinner_1b6506abba0ba52c54e6d695c8571078_274x274.jpg", + "width" : 274 + } ], + "id" : "dinner", + "name" : "Dinner" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/sleep", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/sleep-274x274_0d4f836af8fab7bf31526968073e671c_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "sleep", + "name" : "Sleep" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/hiphop", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/original/hip-274_0a661854d61e29eace5fe63f73495e68_274x274.jpg", + "width" : 274 + } ], + "id" : "hiphop", + "name" : "Hip Hop" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/latin", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/latin-274x274_befbbd1fbb8e045491576e317cb16cdf_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "latin", + "name" : "Latino" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/workout", + "icons" : [ { + "height" : null, + "url" : "https://t.scdn.co/media/links/workout-274x274.jpg", + "width" : null + } ], + "id" : "workout", + "name" : "Workout" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/rnb", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/r-b-274x274_fd56efa72f4f63764b011b68121581d8_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "rnb", + "name" : "RnB" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/country", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/icon-274x274_6a35972b380f65dc348e0c798fe626a4_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "country", + "name" : "Country" + }, { + "href" : "https://api.spotify.com/v1/browse/categories/folk_americana", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/folk-274x274_ced3f75528ac61faf505863f7d7fae64_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "folk_americana", + "name" : "Folk & Americana" + } ], + "limit" : 20, + "next" : "https://api.spotify.com/v1/browse/categories?offset=20&limit=20", + "offset" : 0, + "previous" : null, + "total" : 33 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-category/ + */ +var category : SpotifyApi.SingleCategoryResponse = { + "href" : "https://api.spotify.com/v1/browse/categories/rock", + "icons" : [ { + "height" : 274, + "url" : "https://t.scdn.co/media/derived/rock_9ce79e0a4ef901bbd10494f5b855d3cc_0_0_274_274.jpg", + "width" : 274 + } ], + "id" : "rock", + "name" : "Rock" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-categorys-playlists/ + */ +var categoryPlaylists : SpotifyApi.CategoryPlaylistsReponse = { + "playlists" : { + "href" : "https://api.spotify.com/v1/browse/categories/party/playlists?country=BR&offset=0&limit=2", + "items" : [ { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotifybrazilian/playlist/6U9RHRz1G477YpMNeLy9uI" + }, + "href" : "https://api.spotify.com/v1/users/spotifybrazilian/playlists/6U9RHRz1G477YpMNeLy9uI", + "id" : "6U9RHRz1G477YpMNeLy9uI", + "images" : [ { + "height" : 300, + "url" : "https://i.scdn.co/image/510c519ae934ea4bb26219277f8c1a859e8cb01a", + "width" : 300 + } ], + "name" : "Esquenta Sertanejo", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotifybrazilian" + }, + "href" : "https://api.spotify.com/v1/users/spotifybrazilian", + "id" : "spotifybrazilian", + "type" : "user", + "uri" : "spotify:user:spotifybrazilian" + }, + "public" : null, + "snapshot_id" : "+jMowNjnBWpQqnkgYk47IRKrEsXLxUXR348Mtg/+kZWjLkpS4HTADpzyV6X/iIJm", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/spotifybrazilian/playlists/6U9RHRz1G477YpMNeLy9uI/tracks", + "total" : 100 + }, + "type" : "playlist", + "uri" : "spotify:user:spotifybrazilian:playlist:6U9RHRz1G477YpMNeLy9uI" + }, { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotifybrazilian/playlist/4k7EZPI3uKMz4aRRrLVfen" + }, + "href" : "https://api.spotify.com/v1/users/spotifybrazilian/playlists/4k7EZPI3uKMz4aRRrLVfen", + "id" : "4k7EZPI3uKMz4aRRrLVfen", + "images" : [ { + "height" : 300, + "url" : "https://i.scdn.co/image/1ec2655266c18dc62a39a270cd89a875705733a2", + "width" : 300 + } ], + "name" : "Noite Eletrônica", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotifybrazilian" + }, + "href" : "https://api.spotify.com/v1/users/spotifybrazilian", + "id" : "spotifybrazilian", + "type" : "user", + "uri" : "spotify:user:spotifybrazilian" + }, + "public" : null, + "snapshot_id" : "JWtQF9AcG8yXA/xIihTpZNxJuVdcJ0UwPZQrkRi8kP2om0nZJNg/WvwAz1TMBdlX", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/spotifybrazilian/playlists/4k7EZPI3uKMz4aRRrLVfen/tracks", + "total" : 100 + }, + "type" : "playlist", + "uri" : "spotify:user:spotifybrazilian:playlist:4k7EZPI3uKMz4aRRrLVfen" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/browse/categories/party/playlists?country=BR&offset=2&limit=2", + "offset" : 0, + "previous" : null, + "total" : 79 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-current-users-profile/ + */ +var userProfilePrivate : SpotifyApi.CurrentUsersProfileResponse = { + "birthdate" : "1982-06-29", + "country" : "DK", + "display_name" : null, + "email" : "niels@physicalcode.com", + "external_urls" : { + "spotify" : "https://open.spotify.com/user/physicaltunes" + }, + "followers" : { + "href" : null, + "total" : 2 + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "images" : [ ], + "product" : "premium", + "type" : "user", + "uri" : "spotify:user:physicaltunes" +} + + + + +/** + * Tests https://developer.spotify.com/web-api/get-followed-artists/ + */ +var followedArtists : SpotifyApi.UsersFollowedArtistsResponse = { + "artists" : { + "items" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1F102kNzMqsmOpF7AfFmm5" + }, + "followers" : { + "href" : null, + "total" : 21835 + }, + "genres" : [ "psychill" ], + "href" : "https://api.spotify.com/v1/artists/1F102kNzMqsmOpF7AfFmm5", + "id" : "1F102kNzMqsmOpF7AfFmm5", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/81716e1e7397e8213f943f6bc34df32025abbbf2", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/4415b0213e0b4fa4c2ee54cb5fb8d547558c7c05", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/47d4847098235891b983de21ea2629015632cc89", + "width" : 64 + } ], + "name" : "Ott", + "popularity" : 44, + "type" : "artist", + "uri" : "spotify:artist:1F102kNzMqsmOpF7AfFmm5" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1oM1vgebNTCZmVYwC3YYl8" + }, + "followers" : { + "href" : null, + "total" : 12777 + }, + "genres" : [ "funk metal" ], + "href" : "https://api.spotify.com/v1/artists/1oM1vgebNTCZmVYwC3YYl8", + "id" : "1oM1vgebNTCZmVYwC3YYl8", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/ce6f6717f07c969ec41f0c45bf29b9c1f312f9d4", + "width" : 960 + }, { + "height" : 427, + "url" : "https://i.scdn.co/image/bf35aa3fd5bbfdcefac0b1120bc950cc1903dab7", + "width" : 640 + }, { + "height" : 133, + "url" : "https://i.scdn.co/image/2ad4e34ef6341ac8c57c5d4a48507b70234d5bda", + "width" : 200 + }, { + "height" : 43, + "url" : "https://i.scdn.co/image/b0a8ffe5baa974df1cf4f4abbf0ad4037eb14472", + "width" : 64 + } ], + "name" : "Les Claypool", + "popularity" : 32, + "type" : "artist", + "uri" : "spotify:artist:1oM1vgebNTCZmVYwC3YYl8" + } ], + "next" : "https://api.spotify.com/v1/me/following?type=artist&after=1oM1vgebNTCZmVYwC3YYl8&limit=2", + "total" : 10, + "cursors" : { + "after" : "1oM1vgebNTCZmVYwC3YYl8" + }, + "limit" : 2, + "href" : "https://api.spotify.com/v1/me/following?type=artist&limit=2" + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/follow-artists-users/ + */ +var followArtistsOrUsers : SpotifyApi.FollowArtistsOrUsersResponse = {} + + + + +/** + * Tests https://developer.spotify.com/web-api/unfollow-artists-users/ + */ +var unfollowArtistsOrUsers : SpotifyApi.UnfollowArtistsOrUsersResponse = {} + + + + +/** + * Tests https://developer.spotify.com/web-api/check-current-user-follows/ + */ +var checkCurrentUserFollows : SpotifyApi.UserFollowsUsersOrArtistsResponse = [ true, true, false ]; + + + + +/** + * Tests https://developer.spotify.com/web-api/follow-playlist/ + */ +var followPlaylist : SpotifyApi.FollowPlaylistReponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/unfollow-playlist/ + */ +var unfollowPlaylist : SpotifyApi.UnfollowPlaylistReponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/save-tracks-user/ + */ +var saveTracksForUser : SpotifyApi.SaveTracksForUserResponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/console/get-current-user-saved-tracks + */ +var getSavedTracks : SpotifyApi.UsersSavedTracksResponse = { + "href" : "https://api.spotify.com/v1/me/tracks?offset=0&limit=5&market=DK", + "items" : [ { + "added_at" : "2015-12-24T08:02:23Z", + "track" : { + "album" : { + "album_type" : "compilation", + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5UtlwR5GMEM3XrF8GdzMmB" + }, + "href" : "https://api.spotify.com/v1/albums/5UtlwR5GMEM3XrF8GdzMmB", + "id" : "5UtlwR5GMEM3XrF8GdzMmB", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c0fb10c0253dbd63dc063afb2dedc17922da72bb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/3bb609bb7cb6b63d90ac8cc9f30164cd1dba421e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c18d91c939997d3a33251fc7a85cbf552795ecb1", + "width" : 64 + } ], + "name" : "The Beatles 1967 - 1970 (Remastered)", + "type" : "album", + "uri" : "spotify:album:5UtlwR5GMEM3XrF8GdzMmB" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2" + }, + "href" : "https://api.spotify.com/v1/artists/3WrFJ7ztbogyGnTHbHJFl2", + "id" : "3WrFJ7ztbogyGnTHbHJFl2", + "name" : "The Beatles", + "type" : "artist", + "uri" : "spotify:artist:3WrFJ7ztbogyGnTHbHJFl2" + } ], + "disc_number" : 1, + "duration_ms" : 248933, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAYE0601640" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0m0lCaz6HZyNx1oOrrzxWE" + }, + "href" : "https://api.spotify.com/v1/tracks/0m0lCaz6HZyNx1oOrrzxWE", + "id" : "0m0lCaz6HZyNx1oOrrzxWE", + "is_playable" : true, + "name" : "Strawberry Fields Forever - Remastered 2009", + "popularity" : 21, + "preview_url" : "https://p.scdn.co/mp3-preview/c6b38e29e03b8308c0f2f6e623fe298d24ff274e", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:0m0lCaz6HZyNx1oOrrzxWE" + } + }, { + "added_at" : "2015-12-24T08:02:23Z", + "track" : { + "album" : { + "album_type" : "compilation", + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5UtlwR5GMEM3XrF8GdzMmB" + }, + "href" : "https://api.spotify.com/v1/albums/5UtlwR5GMEM3XrF8GdzMmB", + "id" : "5UtlwR5GMEM3XrF8GdzMmB", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c0fb10c0253dbd63dc063afb2dedc17922da72bb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/3bb609bb7cb6b63d90ac8cc9f30164cd1dba421e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c18d91c939997d3a33251fc7a85cbf552795ecb1", + "width" : 64 + } ], + "name" : "The Beatles 1967 - 1970 (Remastered)", + "type" : "album", + "uri" : "spotify:album:5UtlwR5GMEM3XrF8GdzMmB" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2" + }, + "href" : "https://api.spotify.com/v1/artists/3WrFJ7ztbogyGnTHbHJFl2", + "id" : "3WrFJ7ztbogyGnTHbHJFl2", + "name" : "The Beatles", + "type" : "artist", + "uri" : "spotify:artist:3WrFJ7ztbogyGnTHbHJFl2" + } ], + "disc_number" : 1, + "duration_ms" : 181600, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAYE0601641" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/72IGjRtsOv6kde11MBDALW" + }, + "href" : "https://api.spotify.com/v1/tracks/72IGjRtsOv6kde11MBDALW", + "id" : "72IGjRtsOv6kde11MBDALW", + "is_playable" : true, + "name" : "Penny Lane - Remastered 2009", + "popularity" : 18, + "preview_url" : "https://p.scdn.co/mp3-preview/aa92e277779518b8bd12d7332a11c212f45d1da5", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:72IGjRtsOv6kde11MBDALW" + } + }, { + "added_at" : "2015-12-24T08:02:23Z", + "track" : { + "album" : { + "album_type" : "compilation", + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5UtlwR5GMEM3XrF8GdzMmB" + }, + "href" : "https://api.spotify.com/v1/albums/5UtlwR5GMEM3XrF8GdzMmB", + "id" : "5UtlwR5GMEM3XrF8GdzMmB", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c0fb10c0253dbd63dc063afb2dedc17922da72bb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/3bb609bb7cb6b63d90ac8cc9f30164cd1dba421e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c18d91c939997d3a33251fc7a85cbf552795ecb1", + "width" : 64 + } ], + "name" : "The Beatles 1967 - 1970 (Remastered)", + "type" : "album", + "uri" : "spotify:album:5UtlwR5GMEM3XrF8GdzMmB" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2" + }, + "href" : "https://api.spotify.com/v1/artists/3WrFJ7ztbogyGnTHbHJFl2", + "id" : "3WrFJ7ztbogyGnTHbHJFl2", + "name" : "The Beatles", + "type" : "artist", + "uri" : "spotify:artist:3WrFJ7ztbogyGnTHbHJFl2" + } ], + "disc_number" : 1, + "duration_ms" : 122133, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAYE0601507" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/51UQJuxkNLgtX8UsfoDqRR" + }, + "href" : "https://api.spotify.com/v1/tracks/51UQJuxkNLgtX8UsfoDqRR", + "id" : "51UQJuxkNLgtX8UsfoDqRR", + "is_playable" : true, + "name" : "Sgt. Pepper's Lonely Hearts Club Band - Remastered 2009", + "popularity" : 17, + "preview_url" : "https://p.scdn.co/mp3-preview/b6a5c9b4b23918c11f8e9e93b9d522ab5cb1e881", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:51UQJuxkNLgtX8UsfoDqRR" + } + }, { + "added_at" : "2015-12-24T08:02:23Z", + "track" : { + "album" : { + "album_type" : "compilation", + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5UtlwR5GMEM3XrF8GdzMmB" + }, + "href" : "https://api.spotify.com/v1/albums/5UtlwR5GMEM3XrF8GdzMmB", + "id" : "5UtlwR5GMEM3XrF8GdzMmB", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c0fb10c0253dbd63dc063afb2dedc17922da72bb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/3bb609bb7cb6b63d90ac8cc9f30164cd1dba421e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c18d91c939997d3a33251fc7a85cbf552795ecb1", + "width" : 64 + } ], + "name" : "The Beatles 1967 - 1970 (Remastered)", + "type" : "album", + "uri" : "spotify:album:5UtlwR5GMEM3XrF8GdzMmB" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2" + }, + "href" : "https://api.spotify.com/v1/artists/3WrFJ7ztbogyGnTHbHJFl2", + "id" : "3WrFJ7ztbogyGnTHbHJFl2", + "name" : "The Beatles", + "type" : "artist", + "uri" : "spotify:artist:3WrFJ7ztbogyGnTHbHJFl2" + } ], + "disc_number" : 1, + "duration_ms" : 164186, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAYE0601508" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2G5HiV1RpXDTb17jV4WUgU" + }, + "href" : "https://api.spotify.com/v1/tracks/2G5HiV1RpXDTb17jV4WUgU", + "id" : "2G5HiV1RpXDTb17jV4WUgU", + "is_playable" : true, + "name" : "With A Little Help From My Friends - Remastered 2009", + "popularity" : 17, + "preview_url" : "https://p.scdn.co/mp3-preview/e9eda0a7e66d6ee0ccd3b124774e81b1f80bde08", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:2G5HiV1RpXDTb17jV4WUgU" + } + }, { + "added_at" : "2015-12-24T08:02:23Z", + "track" : { + "album" : { + "album_type" : "compilation", + "external_urls" : { + "spotify" : "https://open.spotify.com/album/5UtlwR5GMEM3XrF8GdzMmB" + }, + "href" : "https://api.spotify.com/v1/albums/5UtlwR5GMEM3XrF8GdzMmB", + "id" : "5UtlwR5GMEM3XrF8GdzMmB", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/c0fb10c0253dbd63dc063afb2dedc17922da72bb", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/3bb609bb7cb6b63d90ac8cc9f30164cd1dba421e", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/c18d91c939997d3a33251fc7a85cbf552795ecb1", + "width" : 64 + } ], + "name" : "The Beatles 1967 - 1970 (Remastered)", + "type" : "album", + "uri" : "spotify:album:5UtlwR5GMEM3XrF8GdzMmB" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2" + }, + "href" : "https://api.spotify.com/v1/artists/3WrFJ7ztbogyGnTHbHJFl2", + "id" : "3WrFJ7ztbogyGnTHbHJFl2", + "name" : "The Beatles", + "type" : "artist", + "uri" : "spotify:artist:3WrFJ7ztbogyGnTHbHJFl2" + } ], + "disc_number" : 1, + "duration_ms" : 209666, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAYE0601509" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/5VDZsW2ka4oKuiOkj8xC9a" + }, + "href" : "https://api.spotify.com/v1/tracks/5VDZsW2ka4oKuiOkj8xC9a", + "id" : "5VDZsW2ka4oKuiOkj8xC9a", + "is_playable" : true, + "name" : "Lucy In The Sky With Diamonds - Remastered 2009", + "popularity" : 17, + "preview_url" : "https://p.scdn.co/mp3-preview/0609bc1b13ea40ddfa6a23c09aef08e23848f73f", + "track_number" : 5, + "type" : "track", + "uri" : "spotify:track:5VDZsW2ka4oKuiOkj8xC9a" + } + } ], + "limit" : 5, + "next" : "https://api.spotify.com/v1/me/tracks?offset=5&limit=5&market=DK", + "offset" : 0, + "previous" : null, + "total" : 2884 +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/remove-tracks-user/ + */ +var removeUsersTracks : SpotifyApi.RemoveUsersSavedTracksResponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/check-users-saved-tracks/ + */ +var checkUsersTracks : SpotifyApi.CheckUserSavedAlbumsResponse = [ false, false, true ]; + + + + +/** + * Tests https://developer.spotify.com/web-api/save-albums-user/ + */ +var saveAlbumForUser : SpotifyApi.SaveAlbumsForUserResponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/remove-albums-user/ + */ +var saveAlbumForUser : SpotifyApi.RemoveAlbumsForUserResponse = {}; + + + + + +/** + * Tests https://developer.spotify.com/web-api/check-users-saved-albums/ + */ +var checkUsersSavedAlbums : SpotifyApi.CheckUserSavedAlbumsResponse = [ true, false, false, true ]; + + + + +/** + * Tests https://developer.spotify.com/web-api/search-item/?type=album + */ +var searchAlbums : SpotifyApi.AlbumSearchResponse = { + "albums" : { + "href" : "https://api.spotify.com/v1/search?query=Californication&offset=20&limit=2&type=album", + "items" : [ { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/0ceQvLxLMxAo2VLtphFXnq" + }, + "href" : "https://api.spotify.com/v1/albums/0ceQvLxLMxAo2VLtphFXnq", + "id" : "0ceQvLxLMxAo2VLtphFXnq", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/7a048f1f93f967d3458361970a079648b231767f", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8cab5da41d6446e5878d92a25a04c4283a512647", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/4f4c4de0b215d8ae5d3d239fe4b4fc26e8fd9d8e", + "width" : 64 + } ], + "name" : "Californication (Karaoke Version) (Karaoke Hits of The Red Hot Chili Peppers)", + "type" : "album", + "uri" : "spotify:album:0ceQvLxLMxAo2VLtphFXnq" + }, { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/65b1E2nNuRD2o0PVr8fFv1" + }, + "href" : "https://api.spotify.com/v1/albums/65b1E2nNuRD2o0PVr8fFv1", + "id" : "65b1E2nNuRD2o0PVr8fFv1", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/6d5dd24845ed51b795cb6d10898076989a0bdb87", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/e81dff6c380773f6fc1b5997ca5c2b5506b145e9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/b5e832623b8fa8d4e4c91b4aa1cdc82a35e4c471", + "width" : 64 + } ], + "name" : "Californication (Karaoke Version) (In the Style of Red Hot Chili Peppers)", + "type" : "album", + "uri" : "spotify:album:65b1E2nNuRD2o0PVr8fFv1" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/search?query=Californication&offset=22&limit=2&type=album", + "offset" : 20, + "previous" : "https://api.spotify.com/v1/search?query=Californication&offset=18&limit=2&type=album", + "total" : 27 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/search-item/?type=artist + */ +var searchArtists : SpotifyApi.ArtistSearchResponse = { + "artists" : { + "href" : "https://api.spotify.com/v1/search?query=tania+bowra&offset=0&limit=20&type=artist", + "items" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q" + }, + "followers" : { + "href" : null, + "total" : 26 + }, + "genres" : [ ], + "href" : "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q", + "id" : "08td7MxkoHQkXnWAYD8d6Q", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/f2798ddab0c7b76dc2d270b65c4f67ddef7f6718", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/b414091165ea0f4172089c2fc67bb35aa37cfc55", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/8522fc78be4bf4e83fea8e67bb742e7d3dfe21b4", + "width" : 64 + } ], + "name" : "Tania Bowra", + "popularity" : 2, + "type" : "artist", + "uri" : "spotify:artist:08td7MxkoHQkXnWAYD8d6Q" + } ], + "limit" : 20, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 1 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/search-item/?type=playlist + */ +var searchPlaylists : SpotifyApi.PlaylistSearchResponse = { + "playlists" : { + "href" : "https://api.spotify.com/v1/search?query=Summer&offset=20&limit=2&type=playlist", + "items" : [ { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/twistoffame/playlist/4atqr0nDMUxQFLd09yhk9w" + }, + "href" : "https://api.spotify.com/v1/users/twistoffame/playlists/4atqr0nDMUxQFLd09yhk9w", + "id" : "4atqr0nDMUxQFLd09yhk9w", + "images" : [ { + "height" : 640, + "url" : "https://mosaic.scdn.co/640/4e1d108995a6947bfc6b1d728f0fcd5b4c5ec64444e09ba9156ae93324850b27f17fe7523178d05dfd3cac76a8f1f3cab516f06873eeec16977efdf0c3c226ca1b710078b9f2d9b01c9fdd0c7823c80d", + "width" : 640 + }, { + "height" : 300, + "url" : "https://mosaic.scdn.co/300/4e1d108995a6947bfc6b1d728f0fcd5b4c5ec64444e09ba9156ae93324850b27f17fe7523178d05dfd3cac76a8f1f3cab516f06873eeec16977efdf0c3c226ca1b710078b9f2d9b01c9fdd0c7823c80d", + "width" : 300 + }, { + "height" : 60, + "url" : "https://mosaic.scdn.co/60/4e1d108995a6947bfc6b1d728f0fcd5b4c5ec64444e09ba9156ae93324850b27f17fe7523178d05dfd3cac76a8f1f3cab516f06873eeec16977efdf0c3c226ca1b710078b9f2d9b01c9fdd0c7823c80d", + "width" : 60 + } ], + "name" : "Summer", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/twistoffame" + }, + "href" : "https://api.spotify.com/v1/users/twistoffame", + "id" : "twistoffame", + "type" : "user", + "uri" : "spotify:user:twistoffame" + }, + "public" : null, + "snapshot_id" : "4Hfz5J478TU3Iljnxc5qXAJt/mCS8Q92XNvbRJjd1CPDjiDAP4Aj+3PZKYT5VxZ6", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/twistoffame/playlists/4atqr0nDMUxQFLd09yhk9w/tracks", + "total" : 116 + }, + "type" : "playlist", + "uri" : "spotify:user:twistoffame:playlist:4atqr0nDMUxQFLd09yhk9w" + }, { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/1174077483/playlist/3fAKyVYIkAiinuipRUGJHj" + }, + "href" : "https://api.spotify.com/v1/users/1174077483/playlists/3fAKyVYIkAiinuipRUGJHj", + "id" : "3fAKyVYIkAiinuipRUGJHj", + "images" : [ { + "height" : 640, + "url" : "https://mosaic.scdn.co/640/5112bb05919320d47d5011d2479515392e995a208a46ad36789d2eba454e16caffca4fb994f5f64cf3cf87bfde0748d389702a69e0ba01f6091e2403f844302197c69972032ba43f3cc73e25f2f562e0", + "width" : 640 + }, { + "height" : 300, + "url" : "https://mosaic.scdn.co/300/5112bb05919320d47d5011d2479515392e995a208a46ad36789d2eba454e16caffca4fb994f5f64cf3cf87bfde0748d389702a69e0ba01f6091e2403f844302197c69972032ba43f3cc73e25f2f562e0", + "width" : 300 + }, { + "height" : 60, + "url" : "https://mosaic.scdn.co/60/5112bb05919320d47d5011d2479515392e995a208a46ad36789d2eba454e16caffca4fb994f5f64cf3cf87bfde0748d389702a69e0ba01f6091e2403f844302197c69972032ba43f3cc73e25f2f562e0", + "width" : 60 + } ], + "name" : "Summer Bash 2015", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/1174077483" + }, + "href" : "https://api.spotify.com/v1/users/1174077483", + "id" : "1174077483", + "type" : "user", + "uri" : "spotify:user:1174077483" + }, + "public" : null, + "snapshot_id" : "4hO+Np6z7Pvla+BDmNGTP8cOuBjPcnY0YhpQdH9Kj2AvuvhyokjcIXLhw59Ufsof", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/1174077483/playlists/3fAKyVYIkAiinuipRUGJHj/tracks", + "total" : 162 + }, + "type" : "playlist", + "uri" : "spotify:user:1174077483:playlist:3fAKyVYIkAiinuipRUGJHj" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/search?query=Summer&offset=22&limit=2&type=playlist", + "offset" : 20, + "previous" : "https://api.spotify.com/v1/search?query=Summer&offset=18&limit=2&type=playlist", + "total" : 9721 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/search-item/?type=track + */ +var searchTracks : SpotifyApi.TrackSearchResponse = { + "tracks" : { + "href" : "https://api.spotify.com/v1/search?query=Summer&offset=20&limit=2&type=track", + "items" : [ { + "album" : { + "album_type" : "album", + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "AD", "BE", "CZ", "DK", "ES", "FR", "HU", "IT", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU", "HK", "MY", "PH", "SG", "TW" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/049UASMZj7hfeDWWY8BzoE" + }, + "href" : "https://api.spotify.com/v1/albums/049UASMZj7hfeDWWY8BzoE", + "id" : "049UASMZj7hfeDWWY8BzoE", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4d26ef97cbfe370350770332fdd45e1152425b4e", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/e43b111ee4ed30b17ae40b1c73326a54df53ffc9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/96c8941a9ead45c01e65fc615ed5a95f13af869f", + "width" : 64 + } ], + "name" : "Summer In The Winter", + "type" : "album", + "uri" : "spotify:album:049UASMZj7hfeDWWY8BzoE" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/6KZDXtSj0SzGOV705nNeh3" + }, + "href" : "https://api.spotify.com/v1/artists/6KZDXtSj0SzGOV705nNeh3", + "id" : "6KZDXtSj0SzGOV705nNeh3", + "name" : "Kid Ink", + "type" : "artist", + "uri" : "spotify:artist:6KZDXtSj0SzGOV705nNeh3" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0z4gvV4rjIZ9wHck67ucSV" + }, + "href" : "https://api.spotify.com/v1/artists/0z4gvV4rjIZ9wHck67ucSV", + "id" : "0z4gvV4rjIZ9wHck67ucSV", + "name" : "Akon", + "type" : "artist", + "uri" : "spotify:artist:0z4gvV4rjIZ9wHck67ucSV" + } ], + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "AD", "BE", "CZ", "DK", "ES", "FR", "HU", "IT", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU", "HK", "MY", "PH", "SG", "TW" ], + "disc_number" : 1, + "duration_ms" : 240013, + "explicit" : false, + "external_ids" : { + "isrc" : "USRC11503201" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/42BptFJWPANaOHUxDBo7Gf" + }, + "href" : "https://api.spotify.com/v1/tracks/42BptFJWPANaOHUxDBo7Gf", + "id" : "42BptFJWPANaOHUxDBo7Gf", + "name" : "Rewind", + "popularity" : 0, + "preview_url" : "https://p.scdn.co/mp3-preview/257b7e9cf68642f3d96b57a4bcf5824d9ccaab21", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:42BptFJWPANaOHUxDBo7Gf" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU", "HK", "MY", "PH", "SG", "TW" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6uG9BscYmPnAbtl6Cy9u91" + }, + "href" : "https://api.spotify.com/v1/albums/6uG9BscYmPnAbtl6Cy9u91", + "id" : "6uG9BscYmPnAbtl6Cy9u91", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4d26ef97cbfe370350770332fdd45e1152425b4e", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/e43b111ee4ed30b17ae40b1c73326a54df53ffc9", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/96c8941a9ead45c01e65fc615ed5a95f13af869f", + "width" : 64 + } ], + "name" : "Summer In The Winter", + "type" : "album", + "uri" : "spotify:album:6uG9BscYmPnAbtl6Cy9u91" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/6KZDXtSj0SzGOV705nNeh3" + }, + "href" : "https://api.spotify.com/v1/artists/6KZDXtSj0SzGOV705nNeh3", + "id" : "6KZDXtSj0SzGOV705nNeh3", + "name" : "Kid Ink", + "type" : "artist", + "uri" : "spotify:artist:6KZDXtSj0SzGOV705nNeh3" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/5wd2VuNxYv2rZ3z6qY0Wvx" + }, + "href" : "https://api.spotify.com/v1/artists/5wd2VuNxYv2rZ3z6qY0Wvx", + "id" : "5wd2VuNxYv2rZ3z6qY0Wvx", + "name" : "Bïa", + "type" : "artist", + "uri" : "spotify:artist:5wd2VuNxYv2rZ3z6qY0Wvx" + } ], + "available_markets" : [ "BG", "CY", "EE", "FI", "GR", "LT", "LV", "RO", "AD", "AT", "BE", "CH", "CZ", "DE", "DK", "ES", "FR", "HU", "IT", "LI", "LU", "MC", "MT", "NL", "NO", "PL", "SE", "SI", "SK", "GB", "IE", "IS", "PT", "BR", "UY", "AR", "CL", "PY", "BO", "DO", "CA", "CO", "EC", "PA", "PE", "US", "CR", "GT", "HN", "MX", "NI", "SV", "NZ", "AU", "HK", "MY", "PH", "SG", "TW" ], + "disc_number" : 1, + "duration_ms" : 196146, + "explicit" : true, + "external_ids" : { + "isrc" : "USRC11503196" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3sXcUMhBQLCyr6Cl6z7RP4" + }, + "href" : "https://api.spotify.com/v1/tracks/3sXcUMhBQLCyr6Cl6z7RP4", + "id" : "3sXcUMhBQLCyr6Cl6z7RP4", + "name" : "Good Idea", + "popularity" : 0, + "preview_url" : "https://p.scdn.co/mp3-preview/0f2dae3a28d6cb952576adbf6c613d62ce25af49", + "track_number" : 9, + "type" : "track", + "uri" : "spotify:track:3sXcUMhBQLCyr6Cl6z7RP4" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/search?query=Summer&offset=22&limit=2&type=track", + "offset" : 20, + "previous" : "https://api.spotify.com/v1/search?query=Summer&offset=18&limit=2&type=track", + "total" : 334363 + } +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-track/ + */ +var track : SpotifyApi.SingleTrackResponse = { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6TJmQnO44YE5BtTxH8pop1" + }, + "href" : "https://api.spotify.com/v1/albums/6TJmQnO44YE5BtTxH8pop1", + "id" : "6TJmQnO44YE5BtTxH8pop1", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/8e13218039f81b000553e25522a7f0d7a0600f2e", + "width" : 629 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8c1e066b5d1045038437d92815d49987f519e44f", + "width" : 295 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/d49268a8fc0768084f4750cf1647709e89a27172", + "width" : 63 + } ], + "name" : "Hot Fuss", + "type" : "album", + "uri" : "spotify:album:6TJmQnO44YE5BtTxH8pop1" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu" + }, + "href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu", + "id" : "0C0XlULifJtAgn6ZNCW2eu", + "name" : "The Killers", + "type" : "artist", + "uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 222075, + "explicit" : false, + "external_ids" : { + "isrc" : "USIR20400274" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0eGsygTp906u18L0Oimnem" + }, + "href" : "https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem", + "id" : "0eGsygTp906u18L0Oimnem", + "name" : "Mr. Brightside", + "popularity" : 74, + "preview_url" : "https://p.scdn.co/mp3-preview/934da7155ec15deb326635d69d050543ecbee2b4", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:0eGsygTp906u18L0Oimnem" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-several-tracks/ + */ +var tracks : SpotifyApi.MultipleTracksResponse = { + "tracks" : [ { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6TJmQnO44YE5BtTxH8pop1" + }, + "href" : "https://api.spotify.com/v1/albums/6TJmQnO44YE5BtTxH8pop1", + "id" : "6TJmQnO44YE5BtTxH8pop1", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/8e13218039f81b000553e25522a7f0d7a0600f2e", + "width" : 629 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8c1e066b5d1045038437d92815d49987f519e44f", + "width" : 295 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/d49268a8fc0768084f4750cf1647709e89a27172", + "width" : 63 + } ], + "name" : "Hot Fuss", + "type" : "album", + "uri" : "spotify:album:6TJmQnO44YE5BtTxH8pop1" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu" + }, + "href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu", + "id" : "0C0XlULifJtAgn6ZNCW2eu", + "name" : "The Killers", + "type" : "artist", + "uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 222075, + "explicit" : false, + "external_ids" : { + "isrc" : "USIR20400274" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/0eGsygTp906u18L0Oimnem" + }, + "href" : "https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem", + "id" : "0eGsygTp906u18L0Oimnem", + "name" : "Mr. Brightside", + "popularity" : 74, + "preview_url" : "https://p.scdn.co/mp3-preview/934da7155ec15deb326635d69d050543ecbee2b4", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:0eGsygTp906u18L0Oimnem" + }, { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6TJmQnO44YE5BtTxH8pop1" + }, + "href" : "https://api.spotify.com/v1/albums/6TJmQnO44YE5BtTxH8pop1", + "id" : "6TJmQnO44YE5BtTxH8pop1", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/8e13218039f81b000553e25522a7f0d7a0600f2e", + "width" : 629 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/8c1e066b5d1045038437d92815d49987f519e44f", + "width" : 295 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/d49268a8fc0768084f4750cf1647709e89a27172", + "width" : 63 + } ], + "name" : "Hot Fuss", + "type" : "album", + "uri" : "spotify:album:6TJmQnO44YE5BtTxH8pop1" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu" + }, + "href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu", + "id" : "0C0XlULifJtAgn6ZNCW2eu", + "name" : "The Killers", + "type" : "artist", + "uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ], + "disc_number" : 1, + "duration_ms" : 197160, + "explicit" : false, + "external_ids" : { + "isrc" : "USIR20400195" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1lDWb6b6ieDQ2xT7ewTC3G" + }, + "href" : "https://api.spotify.com/v1/tracks/1lDWb6b6ieDQ2xT7ewTC3G", + "id" : "1lDWb6b6ieDQ2xT7ewTC3G", + "name" : "Somebody Told Me", + "popularity" : 68, + "preview_url" : "https://p.scdn.co/mp3-preview/0d07673cfb46218a49c96eed639933f19b45cf9c", + "track_number" : 4, + "type" : "track", + "uri" : "spotify:track:1lDWb6b6ieDQ2xT7ewTC3G" + } ] +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-users-profile/ + */ +var userProfile : SpotifyApi.UserProfileResponse = { + "display_name" : "Ronald Pompa", + "external_urls" : { + "spotify" : "https://open.spotify.com/user/wizzler" + }, + "followers" : { + "href" : null, + "total" : 4259 + }, + "href" : "https://api.spotify.com/v1/users/wizzler", + "id" : "wizzler", + "images" : [ { + "height" : null, + "url" : "http://profile-images.scdn.co/images/userprofile/default/3d8a0ed1317df75d99d152a60494a78bfd30c37f", + "width" : null + } ], + "type" : "user", + "uri" : "spotify:user:wizzler" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-list-users-playlists/ + */ +var usersPlaylists : SpotifyApi.ListOfUsersPlaylistsResponse = { + "href" : "https://api.spotify.com/v1/users/wizzler/playlists?offset=0&limit=2", + "items" : [ { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/wizzler/playlist/6yRf9SJ1YiAhNAu7UCwgXQ" + }, + "href" : "https://api.spotify.com/v1/users/wizzler/playlists/6yRf9SJ1YiAhNAu7UCwgXQ", + "id" : "6yRf9SJ1YiAhNAu7UCwgXQ", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/5c383056e25a3e3ec858151afb70afe763c00f9b", + "width" : 640 + } ], + "name" : "My Shazam Tracks", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/wizzler" + }, + "href" : "https://api.spotify.com/v1/users/wizzler", + "id" : "wizzler", + "type" : "user", + "uri" : "spotify:user:wizzler" + }, + "public" : true, + "snapshot_id" : "WlQppvajE5kH/Xt5cHfHxJ6mSsFckwYixA06q7y1asdUz+m5v7pq6xb1f0FiFa7I", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/wizzler/playlists/6yRf9SJ1YiAhNAu7UCwgXQ/tracks", + "total" : 1 + }, + "type" : "playlist", + "uri" : "spotify:user:wizzler:playlist:6yRf9SJ1YiAhNAu7UCwgXQ" + }, { + "collaborative" : false, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/wizzler/playlist/3FJd21jWvCjGCLx7eKrext" + }, + "href" : "https://api.spotify.com/v1/users/wizzler/playlists/3FJd21jWvCjGCLx7eKrext", + "id" : "3FJd21jWvCjGCLx7eKrext", + "images" : [ { + "height" : 300, + "url" : "https://i.scdn.co/image/15858d38fdac4af890dcc634f4946c5bf83c0915", + "width" : 300 + } ], + "name" : "Video Game Masterpieces", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/wizzler" + }, + "href" : "https://api.spotify.com/v1/users/wizzler", + "id" : "wizzler", + "type" : "user", + "uri" : "spotify:user:wizzler" + }, + "public" : true, + "snapshot_id" : "LO0O/RGsDLEgeDC3xVR4HisMNsDqoPLE8QBRqllyvevTJ09tFWIUbjrYoEJbUhCa", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/wizzler/playlists/3FJd21jWvCjGCLx7eKrext/tracks", + "total" : 33 + }, + "type" : "playlist", + "uri" : "spotify:user:wizzler:playlist:3FJd21jWvCjGCLx7eKrext" + } ], + "limit" : 2, + "next" : "https://api.spotify.com/v1/users/wizzler/playlists?offset=2&limit=2", + "offset" : 0, + "previous" : null, + "total" : 7 +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/get-playlist/ + */ +var playlist : SpotifyApi.SinglePlaylistResponse = { + "collaborative" : false, + "description" : null, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes/playlist/0r6srTg2RFfBWba9WZ6Dlq" + }, + "followers" : { + "href" : null, + "total" : 0 + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes/playlists/0r6srTg2RFfBWba9WZ6Dlq", + "id" : "0r6srTg2RFfBWba9WZ6Dlq", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4adbb659aac44f3eb198e0d7adb85dcf3faf2578", + "width" : 640 + } ], + "name" : "Grundtræning 2svxw", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes" + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "type" : "user", + "uri" : "spotify:user:physicaltunes" + }, + "public" : true, + "snapshot_id" : "Cy9RoIj+cxQzYP1IYy/QX3DT07he1nKjjk/R1LoR0FwVO9NErLfzJofaJzQYb2kq", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/physicaltunes/playlists/0r6srTg2RFfBWba9WZ6Dlq/tracks?offset=0&limit=100", + "items" : [ { + "added_at" : "2015-10-05T06:04:05Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes" + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "type" : "user", + "uri" : "spotify:user:physicaltunes" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/063f8Ej8rLVTz9KkjQKEMa" + }, + "href" : "https://api.spotify.com/v1/albums/063f8Ej8rLVTz9KkjQKEMa", + "id" : "063f8Ej8rLVTz9KkjQKEMa", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/4adbb659aac44f3eb198e0d7adb85dcf3faf2578", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/42cda2065e164df3f923737f3f40b0a26c6b6bd5", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/6fdee9084e91faaa23bbf5880ad3cf5988aea438", + "width" : 64 + } ], + "name" : "Ambient 1/Music For Airports", + "type" : "album", + "uri" : "spotify:album:063f8Ej8rLVTz9KkjQKEMa" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/7MSUfLeTdDEoZiJPDSBXgi" + }, + "href" : "https://api.spotify.com/v1/artists/7MSUfLeTdDEoZiJPDSBXgi", + "id" : "7MSUfLeTdDEoZiJPDSBXgi", + "name" : "Brian Eno", + "type" : "artist", + "uri" : "spotify:artist:7MSUfLeTdDEoZiJPDSBXgi" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 1041520, + "explicit" : false, + "external_ids" : { + "isrc" : "GBAAA0400426" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3bCmDqflFBHijgJfvtqev5" + }, + "href" : "https://api.spotify.com/v1/tracks/3bCmDqflFBHijgJfvtqev5", + "id" : "3bCmDqflFBHijgJfvtqev5", + "name" : "1/1 - 2004 Digital Remaster", + "popularity" : 58, + "preview_url" : "https://p.scdn.co/mp3-preview/b7cd7208aa6c68607b492c5298234cbe8b86c39d", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:3bCmDqflFBHijgJfvtqev5" + } + }, { + "added_at" : "2015-10-05T06:05:23Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes" + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "type" : "user", + "uri" : "spotify:user:physicaltunes" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IT", "LI", "LU", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/3LXNSUpx48PQxUn2StRqfu" + }, + "href" : "https://api.spotify.com/v1/albums/3LXNSUpx48PQxUn2StRqfu", + "id" : "3LXNSUpx48PQxUn2StRqfu", + "images" : [ { + "height" : 575, + "url" : "https://i.scdn.co/image/b455d0dba3b95e1a2550d293e6e6443dc68c7a76", + "width" : 640 + }, { + "height" : 270, + "url" : "https://i.scdn.co/image/5da3b3f3d5ac24aaaf2e4c9d7042d5091f6fef2e", + "width" : 300 + }, { + "height" : 58, + "url" : "https://i.scdn.co/image/ee18c4134b0979437f042ee7b3b4d4a78719bedc", + "width" : 64 + } ], + "name" : "The Very Best Of Little Richard", + "type" : "album", + "uri" : "spotify:album:3LXNSUpx48PQxUn2StRqfu" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/4xls23Ye9WR9yy3yYMpAMm" + }, + "href" : "https://api.spotify.com/v1/artists/4xls23Ye9WR9yy3yYMpAMm", + "id" : "4xls23Ye9WR9yy3yYMpAMm", + "name" : "Little Richard", + "type" : "artist", + "uri" : "spotify:artist:4xls23Ye9WR9yy3yYMpAMm" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IT", "LI", "LU", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW" ], + "disc_number" : 1, + "duration_ms" : 127386, + "explicit" : false, + "external_ids" : { + "isrc" : "USC4R0817279" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/1fMMRoalpb7E8m5FsAta2y" + }, + "href" : "https://api.spotify.com/v1/tracks/1fMMRoalpb7E8m5FsAta2y", + "id" : "1fMMRoalpb7E8m5FsAta2y", + "name" : "Good Golly Miss Molly", + "popularity" : 53, + "preview_url" : "https://p.scdn.co/mp3-preview/e3dbf57f76595ec38b11a947fa770af3e63d9da9", + "track_number" : 3, + "type" : "track", + "uri" : "spotify:track:1fMMRoalpb7E8m5FsAta2y" + } + }, { + "added_at" : "2015-10-05T06:03:49Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes" + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "type" : "user", + "uri" : "spotify:user:physicaltunes" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/2Uc0HAF0Cj0LAgyzYZX5e3" + }, + "href" : "https://api.spotify.com/v1/albums/2Uc0HAF0Cj0LAgyzYZX5e3", + "id" : "2Uc0HAF0Cj0LAgyzYZX5e3", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/43660a1f9fd70e3463a782e5f7948a54f4e4cc99", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/517be4be20d34be9a9b27e1ff72d974a3ad86238", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/427ac24b200fb7c6ae2a9d62ea499309702d8675", + "width" : 64 + } ], + "name" : "The Miseducation of Lauryn Hill", + "type" : "album", + "uri" : "spotify:album:2Uc0HAF0Cj0LAgyzYZX5e3" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/2Mu5NfyYm8n5iTomuKAEHl" + }, + "href" : "https://api.spotify.com/v1/artists/2Mu5NfyYm8n5iTomuKAEHl", + "id" : "2Mu5NfyYm8n5iTomuKAEHl", + "name" : "Ms. Lauryn Hill", + "type" : "artist", + "uri" : "spotify:artist:2Mu5NfyYm8n5iTomuKAEHl" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/336vr2M3Va0FjyvB55lJEd" + }, + "href" : "https://api.spotify.com/v1/artists/336vr2M3Va0FjyvB55lJEd", + "id" : "336vr2M3Va0FjyvB55lJEd", + "name" : "D'Angelo", + "type" : "artist", + "uri" : "spotify:artist:336vr2M3Va0FjyvB55lJEd" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 350533, + "explicit" : false, + "external_ids" : { + "isrc" : "USSM19803112" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3xhXKRGahWzcXF8rD5gUvd" + }, + "href" : "https://api.spotify.com/v1/tracks/3xhXKRGahWzcXF8rD5gUvd", + "id" : "3xhXKRGahWzcXF8rD5gUvd", + "name" : "Nothing Even Matters", + "popularity" : 62, + "preview_url" : "https://p.scdn.co/mp3-preview/1911854c887c31b05e3167ca18182da1838ce1ed", + "track_number" : 12, + "type" : "track", + "uri" : "spotify:track:3xhXKRGahWzcXF8rD5gUvd" + } + } ], + "limit" : 100, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 3 + }, + "type" : "playlist", + "uri" : "spotify:user:physicaltunes:playlist:0r6srTg2RFfBWba9WZ6Dlq" +}; + + + + +/** + * Tests + */ +var playlistTracks : SpotifyApi.PlaylistTrackResponse = { + "href" : "https://api.spotify.com/v1/users/spotify_espa%C3%B1a/playlists/21THa8j9TaSGuXYNBU5tsC/tracks?offset=0&limit=3", + "items" : [ { + "added_at" : "2015-12-09T23:12:56Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify_espa%C3%B1a" + }, + "href" : "https://api.spotify.com/v1/users/spotify_espa%C3%B1a", + "id" : "spotify_españa", + "type" : "user", + "uri" : "spotify:user:spotify_espa%C3%B1a" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "single", + "available_markets" : [ "AD", "AR", "AT", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/26vwjM6FkX2nEx9I0FKmih" + }, + "href" : "https://api.spotify.com/v1/albums/26vwjM6FkX2nEx9I0FKmih", + "id" : "26vwjM6FkX2nEx9I0FKmih", + "images" : [ { + "height" : 543, + "url" : "https://i.scdn.co/image/e7fda36ee273b819e4aa12dd1d362c04fe1ec087", + "width" : 640 + }, { + "height" : 255, + "url" : "https://i.scdn.co/image/d7347a32de62dcb1bcac5fa4d0ad9d1d5c7e688e", + "width" : 300 + }, { + "height" : 54, + "url" : "https://i.scdn.co/image/bfb8f8395b8983013dea49d1f18563d4f22476ce", + "width" : 64 + } ], + "name" : "Beautiful Liar", + "type" : "album", + "uri" : "spotify:album:26vwjM6FkX2nEx9I0FKmih" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/6vWDO969PvNqNYHIOW5v0m" + }, + "href" : "https://api.spotify.com/v1/artists/6vWDO969PvNqNYHIOW5v0m", + "id" : "6vWDO969PvNqNYHIOW5v0m", + "name" : "Beyoncé", + "type" : "artist", + "uri" : "spotify:artist:6vWDO969PvNqNYHIOW5v0m" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0EmeFodog0BfCgMzAIvKQp" + }, + "href" : "https://api.spotify.com/v1/artists/0EmeFodog0BfCgMzAIvKQp", + "id" : "0EmeFodog0BfCgMzAIvKQp", + "name" : "Shakira", + "type" : "artist", + "uri" : "spotify:artist:0EmeFodog0BfCgMzAIvKQp" + } ], + "available_markets" : [ "AD", "AR", "AT", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 201520, + "explicit" : false, + "external_ids" : { + "isrc" : "USSM10700448" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/2P5cIXejqLpHDQeCHAbbBG" + }, + "href" : "https://api.spotify.com/v1/tracks/2P5cIXejqLpHDQeCHAbbBG", + "id" : "2P5cIXejqLpHDQeCHAbbBG", + "name" : "Beautiful Liar - Main Version / Album Version", + "popularity" : 58, + "preview_url" : "https://p.scdn.co/mp3-preview/fe55d5e4879a799186e29d24a3c9ffb0c1f9d9ab", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:2P5cIXejqLpHDQeCHAbbBG" + } + }, { + "added_at" : "2015-12-09T23:12:56Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify_espa%C3%B1a" + }, + "href" : "https://api.spotify.com/v1/users/spotify_espa%C3%B1a", + "id" : "spotify_españa", + "type" : "user", + "uri" : "spotify:user:spotify_espa%C3%B1a" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "album", + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/33va5yaUhlioHypFUHhsck" + }, + "href" : "https://api.spotify.com/v1/albums/33va5yaUhlioHypFUHhsck", + "id" : "33va5yaUhlioHypFUHhsck", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/f104b4e08885330e5747047635127a965b748d4d", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/738aeecd73221be81a6277b9925b36ee078aa66d", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/f47c9a5a7eb92d86c9f1ad4bf599648cd3b76e8d", + "width" : 64 + } ], + "name" : "El Taxi Compilation - 16 Urban Latin Hits", + "type" : "album", + "uri" : "spotify:album:33va5yaUhlioHypFUHhsck" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1noWnd8QFQD9VLxWEeo4Zf" + }, + "href" : "https://api.spotify.com/v1/artists/1noWnd8QFQD9VLxWEeo4Zf", + "id" : "1noWnd8QFQD9VLxWEeo4Zf", + "name" : "Don Miguelo", + "type" : "artist", + "uri" : "spotify:artist:1noWnd8QFQD9VLxWEeo4Zf" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/0TnOYISbd1XYRBk9myaseg" + }, + "href" : "https://api.spotify.com/v1/artists/0TnOYISbd1XYRBk9myaseg", + "id" : "0TnOYISbd1XYRBk9myaseg", + "name" : "Pitbull", + "type" : "artist", + "uri" : "spotify:artist:0TnOYISbd1XYRBk9myaseg" + } ], + "available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "US", "UY" ], + "disc_number" : 1, + "duration_ms" : 262253, + "explicit" : false, + "external_ids" : { + "isrc" : "ITF251400144" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/6toFnL1smMF8zxBpp8GHYE" + }, + "href" : "https://api.spotify.com/v1/tracks/6toFnL1smMF8zxBpp8GHYE", + "id" : "6toFnL1smMF8zxBpp8GHYE", + "name" : "Como Yo Le Doy", + "popularity" : 53, + "preview_url" : "https://p.scdn.co/mp3-preview/6482bab5aa82742ad0e374c3660230c15a35e397", + "track_number" : 2, + "type" : "track", + "uri" : "spotify:track:6toFnL1smMF8zxBpp8GHYE" + } + }, { + "added_at" : "2015-12-09T23:12:56Z", + "added_by" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/spotify_espa%C3%B1a" + }, + "href" : "https://api.spotify.com/v1/users/spotify_espa%C3%B1a", + "id" : "spotify_españa", + "type" : "user", + "uri" : "spotify:user:spotify_espa%C3%B1a" + }, + "is_local" : false, + "track" : { + "album" : { + "album_type" : "single", + "available_markets" : [ "CA", "MX", "US" ], + "external_urls" : { + "spotify" : "https://open.spotify.com/album/6GY8rrxuEzSJI08F0rfigi" + }, + "href" : "https://api.spotify.com/v1/albums/6GY8rrxuEzSJI08F0rfigi", + "id" : "6GY8rrxuEzSJI08F0rfigi", + "images" : [ { + "height" : 640, + "url" : "https://i.scdn.co/image/6538912b146e0dd3a4d981801cc89216f1480648", + "width" : 640 + }, { + "height" : 300, + "url" : "https://i.scdn.co/image/01d1c656b0af77059ca0450c30380c80f761cc15", + "width" : 300 + }, { + "height" : 64, + "url" : "https://i.scdn.co/image/2774d8f8aab91ea59688c5461e7c6cc8fe38af22", + "width" : 64 + } ], + "name" : "Sorry (Latino Remix)", + "type" : "album", + "uri" : "spotify:album:6GY8rrxuEzSJI08F0rfigi" + }, + "artists" : [ { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1uNFoZAHBGtllmzznpCI3s" + }, + "href" : "https://api.spotify.com/v1/artists/1uNFoZAHBGtllmzznpCI3s", + "id" : "1uNFoZAHBGtllmzznpCI3s", + "name" : "Justin Bieber", + "type" : "artist", + "uri" : "spotify:artist:1uNFoZAHBGtllmzznpCI3s" + }, { + "external_urls" : { + "spotify" : "https://open.spotify.com/artist/1vyhD5VmyZ7KMfW5gqLgo5" + }, + "href" : "https://api.spotify.com/v1/artists/1vyhD5VmyZ7KMfW5gqLgo5", + "id" : "1vyhD5VmyZ7KMfW5gqLgo5", + "name" : "J Balvin", + "type" : "artist", + "uri" : "spotify:artist:1vyhD5VmyZ7KMfW5gqLgo5" + } ], + "available_markets" : [ "CA", "MX", "US" ], + "disc_number" : 1, + "duration_ms" : 219986, + "explicit" : false, + "external_ids" : { + "isrc" : "USUM71517619" + }, + "external_urls" : { + "spotify" : "https://open.spotify.com/track/3grxgV6Ot8KqtysApjYLs1" + }, + "href" : "https://api.spotify.com/v1/tracks/3grxgV6Ot8KqtysApjYLs1", + "id" : "3grxgV6Ot8KqtysApjYLs1", + "name" : "Sorry - Latino Remix", + "popularity" : 80, + "preview_url" : "https://p.scdn.co/mp3-preview/7ddedcc0486b4ba86bd8931f73f6cc67dabdf577", + "track_number" : 1, + "type" : "track", + "uri" : "spotify:track:3grxgV6Ot8KqtysApjYLs1" + } + } ], + "limit" : 3, + "next" : "https://api.spotify.com/v1/users/spotify_espa%C3%B1a/playlists/21THa8j9TaSGuXYNBU5tsC/tracks?offset=3&limit=3", + "offset" : 0, + "previous" : null, + "total" : 69 +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/create-playlist/ + */ +var newPlaylist : SpotifyApi.CreatePlaylistResponse = { + "collaborative" : false, + "description" : null, + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes/playlist/7tlEEvpdUKuXsS1EAHYKnD" + }, + "followers" : { + "href" : null, + "total" : 0 + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes/playlists/7tlEEvpdUKuXsS1EAHYKnD", + "id" : "7tlEEvpdUKuXsS1EAHYKnD", + "images" : [ ], + "name" : "New Cool Playlist", + "owner" : { + "external_urls" : { + "spotify" : "http://open.spotify.com/user/physicaltunes" + }, + "href" : "https://api.spotify.com/v1/users/physicaltunes", + "id" : "physicaltunes", + "type" : "user", + "uri" : "spotify:user:physicaltunes" + }, + "public" : false, + "snapshot_id" : "6ZasQLSA1dudU/rJlMKbTESXYRont3Bh8XwhSCGfUI3+bDjCXG8CWycbzWo4mxGu", + "tracks" : { + "href" : "https://api.spotify.com/v1/users/physicaltunes/playlists/7tlEEvpdUKuXsS1EAHYKnD/tracks", + "items" : [ ], + "limit" : 100, + "next" : null, + "offset" : 0, + "previous" : null, + "total" : 0 + }, + "type" : "playlist", + "uri" : "spotify:user:physicaltunes:playlist:7tlEEvpdUKuXsS1EAHYKnD" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/change-playlist-details/ + */ +var changePlaylistDetails : SpotifyApi.ChangePlaylistDetailsReponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/add-tracks-to-playlist/ + */ +var addTracksToPlaylist : SpotifyApi.AddTracksToPlaylistResponse = { + "snapshot_id" : "4qQeMTnHV5LCL9w/lI9Mlu5shi2pk+iiIm6VEpmKdMPCE6adhRNTG9SXflxh8DTt" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/remove-tracks-playlist/ + */ +var removeTracksFromPlaylist : SpotifyApi.RemoveTracksFromPlaylistResponse = { + "snapshot_id" : "t3+4ZWOqedj+bmcHHu1HKNqYfIyYAfXKlSHHykvS4KAm7hoVhDoCpn+KIuFZebZp" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/reorder-playlists-tracks/ + */ +var reorderTracksInPlaylist : SpotifyApi.ReorderPlaylistTracksResponse = { + "snapshot_id" : "t3+4ZWOqedj+bmcHHu1HKNqYfIyYAfXKlSHHykvS4KAm7hoVhDoCpn+KIuFZebZp" +}; + + + + +/** + * Tests https://developer.spotify.com/web-api/replace-playlists-tracks/ + */ +var replacePlaylistTracks : SpotifyApi.ReplacePlaylistTracksResponse = {}; + + + + +/** + * Tests https://developer.spotify.com/web-api/check-user-following-playlist/ + */ +var checkUserFollowsPlaylist : SpotifyApi.UsersFollowPlaylistReponse = [true, false, true]; \ No newline at end of file diff --git a/spotify-api/spotify-api.d.ts b/spotify-api/spotify-api.d.ts new file mode 100644 index 0000000000..ffc4597459 --- /dev/null +++ b/spotify-api/spotify-api.d.ts @@ -0,0 +1,686 @@ +// Type definitions for The Spotify Web API v1.0 +// Project: https://developer.spotify.com/web-api/ +// Definitions by: Niels Kristian Hansen Skovmand +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +// Release comments: +// ----------------- +// TrackObjects and AlbumObjects is specified in the docs as always having the available_markets property, +// but when it is sent in https://developer.spotify.com/web-api/console/get-current-user-saved-tracks +// the available_markets are missing. Therefore it is marked as optional in this source code. + + +declare module SpotifyApi { + + // + // Parameter Objects for searching + // + + /** + * Object for search parameters for searching for tracks, playlists, artists or albums. + * See: [Search for an item](https://developer.spotify.com/web-api/search-item/) + * + * q and type are not optional in the API, however they are marked as optional here, since various libraries + * implement them as function call parameters instead. This could be changed. + * + * @param q Required. The search query's keywords (and optional field filters and operators). + * @param type Required. A comma-separated list of item types to search across. Valid types are: album, artist, playlist, and track. + * @param market Optional. An ISO 3166-1 alpha-2 country code or the string from_token + * @param limit Optional. The maximum number of results to return. Default: 20. Minimum: 1. Maximum: 50. + * @param offset Optional. The index of the first result to return. Default: 0 (i.e., the first result). Maximum offset: 100.000. Use with limit to get the next page of search results. + */ + interface SearchForItemParameterObject { + q?: string; + type?: string; + market?: string; + limit?: number; + offset?: number; + } + + + // + // Responses from the Spotify Web API in the same order as in the API endpoint docs seen here: + // [API Endpoint Reference](https://developer.spotify.com/web-api/endpoint-reference/) + // + + // Generic interfaces for re-use: + + /** + * Void Response + */ + interface VoidResponse {} + + /** + * Response with Playlist Snapshot + */ + interface PlaylistSnapshotResponse { + snapshot_id: string + } + + + // Spotify API Endpoints: + + /** + * Get an Album + * GET /v1/albums/{id} + */ + interface SingleAlbumResponse extends AlbumObjectFull {} + + /** + * Get Several Albums + * GET /v1/albums + */ + interface MultipleAlbumsResponse { + albums: AlbumObjectFull[] + } + + /** + * Get an Album’s Tracks + * GET /v1/albums/{id}/tracks + */ + interface AlbumTracksResponse extends PagingObject {} + + /** + * Get an Artist + * GET /v1/artists/{id} + */ + interface SingleArtistResponse extends ArtistObjectFull {} + + /** + * Get Several Artists + * GET /v1/artists + */ + interface MultipleArtistsResponse { + artists: ArtistObjectFull[] + } + + /** + * Get an Artist’s Albums + * GET /v1/artists/{id}/albums + */ + interface ArtistsAlbumsResponse extends PagingObject {} + + /** + * Get an Artist’s Top Tracks + * GET /v1/artists/{id}/top-tracks + */ + interface ArtistsTopTracksResponse { + tracks: TrackObjectFull[] + } + + /** + * Get an Artist’s Related Artists + * GET /v1/artists/{id}/related-artists + */ + interface ArtistsRelatedArtistsResponse { + artists: ArtistObjectFull[] + } + + /** + * Get a list of featured playlists + * GET /v1/browse/featured-playlists + */ + interface ListOfFeaturedPlaylistsResponse { + message?: string, + playlists: PagingObject + } + + /** + * Get a list of new releases + * GET /v1/browse/new-releases + */ + interface ListOfNewReleasesResponse { + message?: string, + albums: PagingObject + } + + /** + * Get a list of categories + * GET /v1/browse/categories + */ + interface MultipleCategoriesResponse { + categories: PagingObject + } + + /** + * Get a category + * GET /v1/browse/categories/{category_id} + */ + interface SingleCategoryResponse extends CategoryObject {} + + /** + * Get a categorys playlists + * GET /v1/browse/categories/{id}/playlists + */ + interface CategoryPlaylistsReponse { + playlists: PagingObject + } + + /** + * Get Current User’s Profile + * GET /v1/me + */ + interface CurrentUsersProfileResponse extends UserObjectPrivate {} + + /** + * Get User’s Followed Artists + * GET /v1/me/following?type=artist + */ + interface UsersFollowedArtistsResponse { + artists: CursorBasedPagingObject + } + + /** + * Follow artists or users + * PUT /v1/me/following + */ + interface FollowArtistsOrUsersResponse extends VoidResponse {} + + /** + * Unfollow artists or users + * DELETE /v1/me/following + */ + interface UnfollowArtistsOrUsersResponse extends VoidResponse {} + + /** + * Check if User Follows Users or Artists + * GET /v1/me/following/contains + */ + interface UserFollowsUsersOrArtistsResponse extends Array {} + + /** + * Follow a Playlist + * PUT /v1/users/{owner_id}/playlists/{playlist_id}/followers + */ + interface FollowPlaylistReponse extends VoidResponse {} + + /** + * Unfollow a Playlist + * DELETE /v1/users/{owner_id}/playlists/{playlist_id}/followers + */ + interface UnfollowPlaylistReponse extends VoidResponse {} + + /** + * Save tracks for user + * PUT /v1/me/tracks?ids={ids} + */ + interface SaveTracksForUserResponse extends VoidResponse {} + + /** + * Get user's saved tracks + * GET /v1/me/tracks + */ + interface UsersSavedTracksResponse extends PagingObject {} + + /** + * Remove User’s Saved Tracks + * DELETE /v1/me/tracks?ids={ids} + */ + interface RemoveUsersSavedTracksResponse extends VoidResponse {} + + /** + * Check User’s Saved Tracks + * GET /v1/me/tracks/contains + */ + interface CheckUsersSavedTracksResponse extends Array {} + + /** + * Save albums for user + * PUT /v1/me/albums?ids={ids} + */ + interface SaveAlbumsForUserResponse extends VoidResponse {} + + /** + * Get user's saved albums + * GET /v1/me/albums + */ + interface UsersSavedAlbumsResponse extends PagingObject {} + + /** + * Remove Albums for Current User + * DELETE /v1/me/albums?ids={ids} + */ + interface RemoveAlbumsForUserResponse extends VoidResponse {} + + /** + * Check user's saved albums + * DELETE /v1/me/albums/contains?ids={ids} + */ + interface CheckUserSavedAlbumsResponse extends Array {} + + /** + * Search for an album + * GET /v1/search?type=album + */ + interface AlbumSearchResponse { + albums: PagingObject + } + + /** + * Search for an artist + * GET /v1/search?type=artist + */ + interface ArtistSearchResponse { + artists: PagingObject + } + + /** + * Search for a playlist + * GET /v1/search?type=playlist + */ + interface PlaylistSearchResponse { + playlists: PagingObject + } + + /** + * Search for a track + * GET /v1/search?type=track + */ + interface TrackSearchResponse { + tracks: PagingObject + } + + /** + * Get a track + * GET /v1/tracks/{id} + */ + interface SingleTrackResponse extends TrackObjectFull {} + + /** + * Get multiple tracks + * GET /v1/tracks?ids={ids} + */ + interface MultipleTracksResponse { + tracks: TrackObjectFull[] + } + + /** + * Get user profile + * GET /v1/users/{user_id} + */ + interface UserProfileResponse extends UserObjectPublic {} + + /** + * Get a list of a user's playlists + * GET /v1/users/{user_id}/playlists + */ + interface ListOfUsersPlaylistsResponse extends PagingObject {} + + /** + * Get a list of the current user's playlists + * GET /v1/me/playlists + */ + interface ListOfCurrentUsersPlaylistsResponse extends PagingObject {} + + /** + * Get a playlist + * GET /v1/users/{user_id}/playlists/{playlist_id} + */ + interface SinglePlaylistResponse extends PlaylistObjectFull {} + + /** + * Get a playlist's tracks + * GET /v1/users/{user_id}/playlists/{playlist_id}/tracks + */ + interface PlaylistTrackResponse extends PagingObject {} + + /** + * Create a Playlist + * POST /v1/users/{user_id}/playlists + */ + interface CreatePlaylistResponse extends PlaylistObjectFull {} + + /** + * Change a Playlist’s Details + * PUT /v1/users/{user_id}/playlists/{playlist_id} + */ + interface ChangePlaylistDetailsReponse extends VoidResponse {} + + /** + * Add Tracks to a Playlist + * POST /v1/users/{user_id}/playlists/{playlist_id}/tracks + */ + interface AddTracksToPlaylistResponse extends PlaylistSnapshotResponse {} + + /** + * Remove Tracks from a Playlist + * DELETE /v1/users/{user_id}/playlists/{playlist_id}/tracks + */ + interface RemoveTracksFromPlaylistResponse extends PlaylistSnapshotResponse {} + + /** + * Reorder a Playlist’s Tracks + * PUT /v1/users/{user_id}/playlists/{playlist_id}/tracks + */ + interface ReorderPlaylistTracksResponse extends PlaylistSnapshotResponse {} + + /** + * Replace a Playlist’s Tracks + * PUT /v1/users/{user_id}/playlists/{playlist_id}/tracks + */ + interface ReplacePlaylistTracksResponse extends VoidResponse {} + + /** + * Check if Users Follow a Playlist + * GET /v1/users/{user_id}/playlists/{playlist_id}/followers/contains + */ + interface UsersFollowPlaylistReponse extends Array {} + + + + // + // Objects from the Object Models of the Spotify Web Api + // [Object Model](https://developer.spotify.com/web-api/object-model) + // + + // + // The Paging Object wrappers used for retrieving collections from the Spotify API. + // + + /** + * BasePagingObject which the IPagingObject and ICursorBasedPagingObject extend from. + * Doesn't exist in itself in the spotify API. + */ + interface BasePagingObject { + href: string, + items: T[], + limit: number, + next: string, + total: number + } + + /** + * Paging Object wrapper used for retrieving collections from the Spotify API. + * [](https://developer.spotify.com/web-api/object-model/#paging-object) + */ + interface PagingObject extends BasePagingObject { + previous: string, + offset: number + } + + /** + * Cursor Based Paging Object wrappers used for retrieving collections from the Spotify API. + * [](https://developer.spotify.com/web-api/object-model/#cursor-based-paging-object) + */ + interface CursorBasedPagingObject extends BasePagingObject { + cursors: CursorObject + } + + + + // + // All other objects of the Object Models from the Spotify Web Api, ordered alphabetically. + // + + /** + * Full Album Object + * [album object (full)](https://developer.spotify.com/web-api/object-model/#album-object-simplified) + */ + interface AlbumObjectFull extends AlbumObjectSimplified { + artists: ArtistObjectSimplified[], + copyrights: CopyrightObject[], + external_ids: ExternalIdObject, + genres: string[], + popularity: number, + release_date: string, + release_date_precision: string, + tracks: PagingObject, + } + + /** + * Simplified Album Object + * [album object (simplified)](https://developer.spotify.com/web-api/object-model/#album-object-simplified) + */ + interface AlbumObjectSimplified { + album_type: string, + available_markets?: string[], + external_urls: ExternalUrlObject, + href: string, + id: string, + images: ImageObject[], + name: string, + type: string, + uri: string + } + + /** + * Full Artist Object + * [artist object (full)](https://developer.spotify.com/web-api/object-model/) + */ + interface ArtistObjectFull extends ArtistObjectSimplified { + followers: FollowersObject, + genres: string[], + images: ImageObject[], + popularity: number, + } + + /** + * Simplified Artist Object + * [artist object (simplified)](https://developer.spotify.com/web-api/object-model/) + */ + interface ArtistObjectSimplified { + external_urls: ExternalUrlObject, + href: string, + id: string, + name: string, + type: string, + uri: string + } + + /** + * Category Object + * [category object](https://developer.spotify.com/web-api/object-model/) + */ + interface CategoryObject { + href: string, + icons: ImageObject[], + id: string, + name: string + } + + /** + * Copyright object + * [copyright object](https://developer.spotify.com/web-api/object-model/) + */ + interface CopyrightObject { + text: string, + type: string + } + + /** + * Cursor object + * [cursor object](https://developer.spotify.com/web-api/object-model/) + */ + interface CursorObject { + after: string + } + + /** + * Error object + * [error object](https://developer.spotify.com/web-api/object-model/) + */ + interface ErrorObject { + status: number, + message: string + } + + /** + * External Id object + * [](https://developer.spotify.com/web-api/object-model/) + * + * Note that there might be other types available, it couldn't be found in the docs. + */ + interface ExternalIdObject { + isrc?: string, + ean?: string, + upc?: string + } + + /** + * External Url Object + * [](https://developer.spotify.com/web-api/object-model/) + * + * Note that there might be other types available, it couldn't be found in the docs. + */ + interface ExternalUrlObject { + spotify: string + } + + /** + * Followers Object + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface FollowersObject { + href: string, + total: number + } + + /** + * Image Object + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface ImageObject { + height?: number, + url: string, + width?: number + } + + /** + * Base Playlist Object. Does not in itself exist in Spotify Web Api, + * but needs to be made since the tracks types vary in the Full and Simplified versions. + */ + interface PlaylistBaseObject { + collaborative: boolean, + external_urls: ExternalUrlObject, + href: string, + id: string, + images: ImageObject[], + name: string, + owner: UserObjectPublic, + public: boolean, + snapshot_id: string, + type: string, + uri: string + } + + /** + * Playlist Object Full + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface PlaylistObjectFull extends PlaylistBaseObject { + description: string, + followers: FollowersObject, + tracks: PagingObject + } + + /** + * Playlist Object Simplified + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface PlaylistObjectSimplified extends PlaylistBaseObject { + tracks: { + href: string, + total: number + } + } + + /** + * The Track Object in Playlists + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface PlaylistTrackObject { + added_at: string, + added_by: UserObjectPublic, + is_local: boolean, + track: TrackObjectFull + } + + /** + * Saved Track Object in Playlists + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface SavedTrackObject { + added_at: string, + track: TrackObjectFull + } + + /** + * Saved Track Object in Playlists + * [](https://developer.spotify.com/web-api/object-model/) + */ + interface SavedAlbumObject { + added_at: string, + album: AlbumObjectFull + } + + /** + * Full Track Object + * [track object (full)](https://developer.spotify.com/web-api/object-model/#track-object-full) + */ + interface TrackObjectFull extends TrackObjectSimplified { + album: AlbumObjectSimplified, + external_ids: ExternalIdObject, + popularity: number + } + + /** + * Simplified Track Object + * [track object (simplified)](https://developer.spotify.com/web-api/object-model/#track-object-simplified) + */ + interface TrackObjectSimplified { + artists: ArtistObjectSimplified[], + available_markets?: string[], + disc_number: number, + duration_ms: number, + explicit: boolean, + external_urls: ExternalUrlObject, + href: string, + id: string, + is_playable?: boolean, + linked_from?: TrackLinkObject, + name: string, + preview_url: string, + track_number: number, + type: string, + uri: string + } + + /** + * Track Link Object + * [](https://developer.spotify.com/web-api/object-model/#track-object-simplified) + */ + interface TrackLinkObject { + external_urls: ExternalUrlObject, + href: string, + id: string, + type: string, + uri: string + } + + /** + * User Object (Private) + * [](https://developer.spotify.com/web-api/object-model/#track-object-simplified) + */ + interface UserObjectPrivate extends UserObjectPublic { + birthdate: string, + country: string, + email: string, + product: string + } + + /** + * User Object (Public) + * [](https://developer.spotify.com/web-api/object-model/#track-object-simplified) + */ + interface UserObjectPublic { + display_name?: string, + external_urls: ExternalUrlObject, + followers?: FollowersObject, + href: string, + id: string, + images?: ImageObject[], + type: string, + uri: string + } + +} \ No newline at end of file diff --git a/stripe/stripe.d.ts b/stripe/stripe.d.ts index 96d8758bc7..27d60d961a 100644 --- a/stripe/stripe.d.ts +++ b/stripe/stripe.d.ts @@ -1,6 +1,6 @@ // Type definitions for stripe // Project: https://stripe.com/ -// Definitions by: Andy Hawkins , Eric J. Smith +// Definitions by: Andy Hawkins , Eric J. Smith , Amrit Kahlon // Definitions: https://github.com/borisyankov/DefinitelyTyped interface StripeStatic { @@ -11,7 +11,8 @@ interface StripeStatic { cardType(cardNumber: string): string; getToken(token: string, responseHandler: (status: number, response: StripeTokenResponse) => void): void; card: StripeCardData; - createToken(data: StripeTokenData, responseHandler: (status: number, response: StripeTokenResponse) => void): void; + createToken(data: StripeTokenData, responseHandler: (status: number, response: StripeTokenResponse) => void): void; + bankAccount: StripeBankAccount; } interface StripeTokenData { @@ -40,7 +41,10 @@ interface StripeTokenResponse { } interface StripeError { + type: string; + code: string; message: string; + param?: string; } interface StripeCardData { @@ -60,7 +64,41 @@ interface StripeCardData { address_country?: string; } +interface StripeBankAccount +{ + createToken(params: StripeBankTokenParams, stripeResponseHandler: (status:number, response: StripeBankTokenResponse) => void): void; + validateRoutingNumber(routingNumber: number | string, countryCode: string): boolean; + validateAccountNumber(accountNumber: number | string, countryCode: string): boolean; +} + +interface StripeBankTokenParams +{ + country: string; + currency: string; + account_number: number | string; + routing_number?: number | string; +} + +interface StripeBankTokenResponse +{ + id: string; + bank_account: { + id: string; + country: string; + bank_name: string; + last4: number; + validated: boolean; + object: string; + }; + created: number; + livemode: boolean; + type: string; + object: string; + used: boolean; + error: StripeError; +} + declare var Stripe: StripeStatic; declare module "Stripe" { - export = StripeStatic; + export = StripeStatic; } diff --git a/through/through.d.ts b/through/through.d.ts index 6e13e4d623..70a7d989c8 100644 --- a/through/through.d.ts +++ b/through/through.d.ts @@ -6,19 +6,19 @@ /// declare module "through" { - import stream = require("stream"); + import stream = require("stream"); - function through(write?: (data: any) => void, - end?: () => void, - opts?: { - autoDestroy: boolean; - }): through.ThroughStream; + function through(write?: (data: any) => void, + end?: () => void, + opts?: { + autoDestroy: boolean; + }): through.ThroughStream; - module through { - export interface ThroughStream extends stream.Transform { - autoDestroy: boolean; - } - } + module through { + export interface ThroughStream extends stream.Transform { + autoDestroy: boolean; + } + } - export = through; + export = through; } diff --git a/tracking/tracking-tests.ts b/tracking/tracking-tests.ts new file mode 100644 index 0000000000..e1fdd85607 --- /dev/null +++ b/tracking/tracking-tests.ts @@ -0,0 +1,55 @@ +/// + +// All tracking tests below are code taken verbatim (or, as close as possible) from the tracking docs: https://trackingjs.com/docs.html + +var colors = new tracking.ColorTracker(['magenta', 'cyan', 'yellow']); + +colors.on('track', function(event) { + if (event.data.length === 0) { + // No colors were detected in this frame. + } else { + event.data.forEach(function(rect) { + console.log(rect.x, rect.y, rect.height, rect.width, rect.color); + }); + } +}); + +tracking.track('#myVideo', colors); + +var myTracker = new tracking.Tracker('target'); + +myTracker.on('track', function(event) { + if (event.data.length === 0) { + // No targets were detected in this frame. + } else { + event.data.forEach(function(data) { + // Plots the detected targets here. + }); + } +}); + +var trackerTask = tracking.track('#myVideo', myTracker); + +trackerTask.stop(); // Stops the tracking +trackerTask.run(); // Runs it again anytime + +tracking.ColorTracker.registerColor('green', function(r, g, b) { + if (r < 50 && g > 200 && b < 50) { + return true; + } + return false; +}); + +var objects = new tracking.ObjectTracker(['face', 'eye', 'mouth']); + +objects.on('track', function(event) { + if (event.data.length === 0) { + // No objects were detected in this frame. + } else { + event.data.forEach(function(rect) { + // rect.x, rect.y, rect.height, rect.width + }); + } +}); + +tracking.track('#myVideo', objects); diff --git a/tracking/tracking.d.ts b/tracking/tracking.d.ts new file mode 100644 index 0000000000..cf8b228e3c --- /dev/null +++ b/tracking/tracking.d.ts @@ -0,0 +1,40 @@ +// Type definitions for Tracking.js v1.1.2 +// Project: https://github.com/eduardolundgren/tracking.js +// Definitions by: Tim Perry +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module tracking { + export class ColorTracker extends Tracker { + constructor(colours: string[]); + + static registerColor(name: string, predicate: (r: number, g: number, b: number) => boolean): void; + } + + export class ObjectTracker extends Tracker { + constructor(objects: string[]); + } + + class Tracker { + constructor(target: string); + on(eventName: string, callback: (event: TrackEvent) => void): void; + } + + interface TrackEvent { + data: TrackRect[]; + } + + interface TrackRect { + x: number; + y: number; + height: number; + width: number; + color: string; + } + + interface TrackerTask { + stop(): void; + run(): void; + } + + export function track(selector: string, tracker: tracking.Tracker): TrackerTask; +} diff --git a/vue-router/vue-router-tests.ts b/vue-router/vue-router-tests.ts new file mode 100644 index 0000000000..b0fc1b511d --- /dev/null +++ b/vue-router/vue-router-tests.ts @@ -0,0 +1,117 @@ +/// + +Vue.use(VueRouter); + +namespace TestBasic { + "use strict"; + + var Foo = Vue.extend({ + template: "

This is foo!

", + route: { + canActivate(transition: vuerouter.Transition) { + return true; + } + } + }); + + var Bar = Vue.extend({ + template: "

This is bar!

" + }); + + var App = Vue.extend({}); + var app = new App(); + app.$on("some event", function() { + var name: string = app.$route.name; + }); + + var router = new VueRouter(); + + router.map({ + "/foo": { + component: Foo + }, + "/bar": { + component: Bar + } + }); + + router.start(App, "#app"); +} + +namespace TestAdvanced { + "use strict"; + + namespace App { + + export class App { + authenticating: boolean; + + data() { + return { + authenticating: false + }; + } + } + } + + namespace Inbox { + export class Index { + static route: vuerouter.TransitionHook = { + canActivate: function(transition) { + var n: number = transition.to.params.id; + transition.next(); + }, + activate: function() { + return new Promise((resolve) => { + resolve(); + }); + }, + deactivate: function({next}) { + next(); + } + }; + } + } + + namespace RouteConfig { + export function configRouter(router: vuerouter.Router) { + router.map({ + "/about": { + component: {}, + auth: false + }, + "*": { + component: {} + } + }); + + router.redirect({ + "/info": "/about", + "/hello/:userId": "/user/:userId" + }); + + router.beforeEach((transition) => { + if (transition.to.path === "/forbidden") { + router.app.authenticating = true; + setTimeout(() => { + router.app.authenticating = false; + alert(""); + transition.abort(); + }, 3000); + } else { + transition.next(); + } + }); + } + } + + import configRouter = RouteConfig.configRouter; + + const router = new VueRouter({ + history: true, + saveScrollPosition: true + }); + + configRouter(router); + router.start(App, "#app"); +} diff --git a/vue-router/vue-router.d.ts b/vue-router/vue-router.d.ts new file mode 100644 index 0000000000..97f31c922d --- /dev/null +++ b/vue-router/vue-router.d.ts @@ -0,0 +1,91 @@ +// Type definitions for vue-router 0.7.7 +// Project: https://github.com/vuejs/vue-router +// Definitions by: kaorun343 +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// +/// + +declare namespace vuerouter { + + interface Transition { + from: $route; + to: $route; + next(data?: any): void; + abort(reason?: any): void; + redirect(path: string): void; + } + + interface RouterOption { + hashbang?: boolean; + history?: boolean; + abstract?: boolean; + root?: string; + linkActiveClass?: string; + saveScrollPosition?: boolean; + transitionOnLoad?: boolean; + suppressTransitionError?: boolean; + } + + interface RouterStatic { + new (option?: RouterOption): Router; + } + + interface RouteMapObject { + component: any; + subRoutes?: { [key: string]: RouteMapObject }; + [key: string]: any; + } + + interface Router { + + app: RootVueApp; + mode: string; + + start(App: any, el: string | Element): void; + stop(): void; + map(routeMap: { [path: string]: RouteMapObject }): void; + on(path: string, config: Object): void; + go(path: string | Object): void; + replace(path: string): void; + redirect(redirectMap: Object): void; + alias(aliasMap: Object): void; + beforeEach(hook: (transition: Transition) => any): void; + afterEach(hook: (transition: Transition) => any): void; + } + + interface $route { + path: string; + params: Params; + query: Query; + router: Router; + matched: string[]; + name: string; + [key: string]: any; + } + + interface TransitionHook { + data?(transition?: Transition): Thenable | void; + activate?(transition?: Transition): Thenable | void; + deactivate?(transition?: Transition): Thenable | void; + canActivate?(transition?: Transition): Thenable | boolean | void; + canDeactivate?(transition?: Transition): Thenable | boolean | void; + canReuse?: boolean | ((transition: Transition) => boolean); + } +} + +declare namespace vuejs { + interface Vue { + $route: vuerouter.$route; + } + + interface ComponentOption { + route?: vuerouter.TransitionHook; + } +} + +declare var VueRouter: vuerouter.RouterStatic; + +declare module "vue-router" { + export = VueRouter; +}