| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 | 
							- import mongoose from "mongoose";
 
- import async from "async";
 
- import config from "config";
 
- import sckey from "soundcloud-key-fetch";
 
- import * as rax from "retry-axios";
 
- import axios from "axios";
 
- import CoreClass from "../core";
 
- let SoundCloudModule;
 
- let DBModule;
 
- let CacheModule;
 
- let MediaModule;
 
- const soundcloudTrackObjectToMusareTrackObject = soundcloudTrackObject => {
 
- 	const {
 
- 		id,
 
- 		title,
 
- 		artwork_url: artworkUrl,
 
- 		created_at: createdAt,
 
- 		duration,
 
- 		genre,
 
- 		kind,
 
- 		license,
 
- 		likes_count: likesCount,
 
- 		playback_count: playbackCount,
 
- 		public: _public,
 
- 		tag_list: tagList,
 
- 		user_id: userId,
 
- 		user,
 
- 		track_format: trackFormat,
 
- 		permalink,
 
- 		monetization_model: monetizationModel,
 
- 		policy,
 
- 		streamable,
 
- 		sharing,
 
- 		state,
 
- 		embeddable_by: embeddableBy
 
- 	} = soundcloudTrackObject;
 
- 	return {
 
- 		trackId: id,
 
- 		title,
 
- 		artworkUrl,
 
- 		soundcloudCreatedAt: new Date(createdAt),
 
- 		duration: duration / 1000,
 
- 		genre,
 
- 		kind,
 
- 		license,
 
- 		likesCount,
 
- 		playbackCount,
 
- 		public: _public,
 
- 		tagList,
 
- 		userId,
 
- 		username: user.username,
 
- 		userPermalink: user.permalink,
 
- 		trackFormat,
 
- 		permalink,
 
- 		monetizationModel,
 
- 		policy,
 
- 		streamable,
 
- 		sharing,
 
- 		state,
 
- 		embeddableBy
 
- 	};
 
- };
 
- class RateLimitter {
 
- 	/**
 
- 	 * Constructor
 
- 	 * @param {number} timeBetween - The time between each allowed YouTube request
 
- 	 */
 
- 	constructor(timeBetween) {
 
- 		this.dateStarted = Date.now();
 
- 		this.timeBetween = timeBetween;
 
- 	}
 
- 	/**
 
- 	 * Returns a promise that resolves whenever the ratelimit of a YouTube request is done
 
- 	 * @returns {Promise} - promise that gets resolved when the rate limit allows it
 
- 	 */
 
- 	continue() {
 
- 		return new Promise(resolve => {
 
- 			if (Date.now() - this.dateStarted >= this.timeBetween) resolve();
 
- 			else setTimeout(resolve, this.dateStarted + this.timeBetween - Date.now());
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Restart the rate limit timer
 
- 	 */
 
- 	restart() {
 
- 		this.dateStarted = Date.now();
 
- 	}
 
- }
 
- class _SoundCloudModule extends CoreClass {
 
- 	// eslint-disable-next-line require-jsdoc
 
- 	constructor() {
 
- 		super("soundcloud");
 
- 		SoundCloudModule = this;
 
- 	}
 
- 	/**
 
- 	 * Initialises the soundcloud module
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	async initialize() {
 
- 		DBModule = this.moduleManager.modules.db;
 
- 		CacheModule = this.moduleManager.modules.cache;
 
- 		MediaModule = this.moduleManager.modules.media;
 
- 		this.soundcloudTrackModel = this.SoundCloudTrackModel = await DBModule.runJob("GET_MODEL", {
 
- 			modelName: "soundcloudTrack"
 
- 		});
 
- 		return new Promise((resolve, reject) => {
 
- 			this.rateLimiter = new RateLimitter(config.get("apis.soundcloud.rateLimit"));
 
- 			this.requestTimeout = config.get("apis.soundcloud.requestTimeout");
 
- 			this.axios = axios.create();
 
- 			this.axios.defaults.raxConfig = {
 
- 				instance: this.axios,
 
- 				retry: config.get("apis.soundcloud.retryAmount"),
 
- 				noResponseRetries: config.get("apis.soundcloud.retryAmount")
 
- 			};
 
- 			rax.attach(this.axios);
 
- 			this.apiKey = null;
 
- 			SoundCloudModule.runJob("TEST_SOUNDCLOUD_API_KEY", {}, null, -1)
 
- 				.then(result => {
 
- 					if (result) {
 
- 						resolve();
 
- 						return;
 
- 					}
 
- 					SoundCloudModule.runJob("GENERATE_SOUNDCLOUD_API_KEY", {}, null, -1)
 
- 						.then(() => {
 
- 							resolve();
 
- 						})
 
- 						.catch(reject);
 
- 				})
 
- 				.catch(reject);
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Generates/fetches a new SoundCloud API key
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	GENERATE_SOUNDCLOUD_API_KEY() {
 
- 		return new Promise((resolve, reject) => {
 
- 			this.log("INFO", "Fetching new SoundCloud API key.");
 
- 			sckey
 
- 				.fetchKey()
 
- 				.then(soundcloudApiKey => {
 
- 					if (!soundcloudApiKey) {
 
- 						this.log("ERROR", "Couldn't fetch new SoundCloud API key.");
 
- 						reject(new Error("Couldn't fetch SoundCloud key."));
 
- 						return;
 
- 					}
 
- 					SoundCloudModule.soundcloudApiKey = soundcloudApiKey;
 
- 					CacheModule.runJob("SET", { key: "soundcloudApiKey", value: soundcloudApiKey }, this)
 
- 						.then(() => {
 
- 							SoundCloudModule.runJob("TEST_SOUNDCLOUD_API_KEY", {}, this).then(result => {
 
- 								if (!result) {
 
- 									this.log("ERROR", "Fetched SoundCloud API key is invalid.");
 
- 									reject(new Error("SoundCloud key isn't valid."));
 
- 								} else {
 
- 									this.log("INFO", "Fetched new valid SoundCloud API key.");
 
- 									resolve();
 
- 								}
 
- 							});
 
- 						})
 
- 						.catch(err => {
 
- 							this.log("ERROR", `Couldn't set new SoundCloud API key in cache. Error: ${err.message}`);
 
- 							reject(err);
 
- 						});
 
- 				})
 
- 				.catch(err => {
 
- 					this.log("ERROR", `Couldn't fetch new SoundCloud API key. Error: ${err.message}`);
 
- 					reject(new Error("Couldn't fetch SoundCloud key."));
 
- 				});
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Tests the stored SoundCloud API key
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	TEST_SOUNDCLOUD_API_KEY() {
 
- 		return new Promise((resolve, reject) => {
 
- 			this.log("INFO", "Testing SoundCloud API key.");
 
- 			CacheModule.runJob("GET", { key: "soundcloudApiKey" }, this).then(soundcloudApiKey => {
 
- 				if (!soundcloudApiKey) {
 
- 					this.log("ERROR", "No SoundCloud API key found in cache.");
 
- 					resolve(false);
 
- 					return;
 
- 				}
 
- 				SoundCloudModule.soundcloudApiKey = soundcloudApiKey;
 
- 				sckey
 
- 					.testKey(soundcloudApiKey)
 
- 					.then(res => {
 
- 						this.log("INFO", `Tested SoundCloud API key. Result: ${res}`);
 
- 						resolve(res);
 
- 					})
 
- 					.catch(err => {
 
- 						this.log("ERROR", `Testing SoundCloud API key error: ${err.message}`);
 
- 						reject(err);
 
- 					});
 
- 			});
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Perform SoundCloud API get track request
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.trackId - the SoundCloud track id to get
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	API_GET_TRACK(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			const { trackId } = payload;
 
- 			SoundCloudModule.runJob(
 
- 				"API_CALL",
 
- 				{
 
- 					url: `https://api-v2.soundcloud.com/tracks/${trackId}`
 
- 				},
 
- 				this
 
- 			)
 
- 				.then(response => {
 
- 					resolve(response);
 
- 				})
 
- 				.catch(err => {
 
- 					reject(err);
 
- 				});
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Perform SoundCloud API call
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.url - request url
 
- 	 * @param {object} payload.params - request parameters
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	API_CALL(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			const { url } = payload;
 
- 			const { soundcloudApiKey } = SoundCloudModule;
 
- 			const params = {
 
- 				client_id: soundcloudApiKey
 
- 			};
 
- 			SoundCloudModule.axios
 
- 				.get(url, {
 
- 					params,
 
- 					timeout: SoundCloudModule.requestTimeout
 
- 				})
 
- 				.then(response => {
 
- 					if (response.data.error) {
 
- 						reject(new Error(response.data.error));
 
- 					} else {
 
- 						resolve({ response });
 
- 					}
 
- 				})
 
- 				.catch(err => {
 
- 					reject(err);
 
- 				});
 
- 			// }
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Create SoundCloud track
 
- 	 * @param {object} payload - an object containing the payload
 
- 	 * @param {object} payload.soundcloudTrack - the soundcloudTrack object
 
- 	 * @returns {Promise} - returns a promise (resolve, reject)
 
- 	 */
 
- 	CREATE_TRACK(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			async.waterfall(
 
- 				[
 
- 					next => {
 
- 						const { soundcloudTrack } = payload;
 
- 						if (typeof soundcloudTrack !== "object") next("Invalid soundcloudTrack type");
 
- 						else {
 
- 							SoundCloudModule.soundcloudTrackModel.insertMany(soundcloudTrack, next);
 
- 						}
 
- 					},
 
- 					(soundcloudTracks, next) => {
 
- 						const mediaSources = soundcloudTracks.map(
 
- 							soundcloudTrack => `soundcloud:${soundcloudTrack.trackId}`
 
- 						);
 
- 						async.eachLimit(
 
- 							mediaSources,
 
- 							2,
 
- 							(mediaSource, next) => {
 
- 								MediaModule.runJob("RECALCULATE_RATINGS", { mediaSource }, this)
 
- 									.then(() => next())
 
- 									.catch(next);
 
- 							},
 
- 							err => {
 
- 								if (err) next(err);
 
- 								else next(null, soundcloudTracks);
 
- 							}
 
- 						);
 
- 					}
 
- 				],
 
- 				(err, soundcloudTracks) => {
 
- 					if (err) reject(new Error(err));
 
- 					else resolve({ soundcloudTracks });
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Get SoundCloud track
 
- 	 * @param {object} payload - an object containing the payload
 
- 	 * @param {string} payload.identifier - the soundcloud track ObjectId or track id
 
- 	 * @param {boolean} payload.createMissing - attempt to fetch and create track if not in db
 
- 	 * @returns {Promise} - returns a promise (resolve, reject)
 
- 	 */
 
- 	GET_TRACK(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			async.waterfall(
 
- 				[
 
- 					next => {
 
- 						const query = mongoose.isObjectIdOrHexString(payload.identifier)
 
- 							? { _id: payload.identifier }
 
- 							: { trackId: payload.identifier };
 
- 						return SoundCloudModule.soundcloudTrackModel.findOne(query, next);
 
- 					},
 
- 					(track, next) => {
 
- 						if (track) return next(null, track, false);
 
- 						if (mongoose.isObjectIdOrHexString(payload.identifier) || !payload.createMissing)
 
- 							return next("SoundCloud track not found.");
 
- 						return SoundCloudModule.runJob("API_GET_TRACK", { trackId: payload.identifier }, this)
 
- 							.then(({ response }) => {
 
- 								const { data } = response;
 
- 								if (!data || !data.id)
 
- 									return next("The specified track does not exist or cannot be publicly accessed.");
 
- 								const soundcloudTrack = soundcloudTrackObjectToMusareTrackObject(data);
 
- 								return next(null, false, soundcloudTrack);
 
- 							})
 
- 							.catch(next);
 
- 					},
 
- 					(track, soundcloudTrack, next) => {
 
- 						if (track) return next(null, track, true);
 
- 						return SoundCloudModule.runJob("CREATE_TRACK", { soundcloudTrack }, this)
 
- 							.then(res => {
 
- 								if (res.soundcloudTracks.length === 1) next(null, res.soundcloudTracks[0], false);
 
- 								else next("SoundCloud track not found.");
 
- 							})
 
- 							.catch(next);
 
- 					}
 
- 				],
 
- 				(err, track, existing) => {
 
- 					if (err) reject(new Error(err));
 
- 					else if (track.policy === "SNIP") reject(new Error("Track is premium-only."));
 
- 					else resolve({ track, existing });
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Tries to get a SoundCloud track from a URL
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.identifier - the SoundCloud track URL
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	GET_TRACK_FROM_URL(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			const scRegex =
 
- 				/soundcloud\.com\/(?<userPermalink>[A-Za-z0-9]+([-_][A-Za-z0-9]+)*)\/(?<permalink>[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*)/;
 
- 			async.waterfall(
 
- 				[
 
- 					next => {
 
- 						const match = scRegex.exec(payload.identifier);
 
- 						if (!match || !match.groups) {
 
- 							next("Invalid SoundCloud URL.");
 
- 							return;
 
- 						}
 
- 						const { userPermalink, permalink } = match.groups;
 
- 						SoundCloudModule.soundcloudTrackModel.findOne({ userPermalink, permalink }, next);
 
- 					},
 
- 					(_dbTrack, next) => {
 
- 						if (_dbTrack) {
 
- 							next(null, _dbTrack, true);
 
- 							return;
 
- 						}
 
- 						SoundCloudModule.runJob("API_RESOLVE", { url: payload.identifier }, this)
 
- 							.then(({ response }) => {
 
- 								const { data } = response;
 
- 								if (!data || !data.id) {
 
- 									next("The provided URL does not exist or cannot be accessed.");
 
- 									return;
 
- 								}
 
- 								if (data.kind !== "track") {
 
- 									next(`Invalid URL provided. Kind got: ${data.kind}.`);
 
- 									return;
 
- 								}
 
- 								// TODO get more data here
 
- 								const { id: trackId } = data;
 
- 								SoundCloudModule.soundcloudTrackModel.findOne({ trackId }, (err, dbTrack) => {
 
- 									if (err) next(err);
 
- 									else if (dbTrack) {
 
- 										next(null, dbTrack, true);
 
- 									} else {
 
- 										const soundcloudTrack = soundcloudTrackObjectToMusareTrackObject(data);
 
- 										SoundCloudModule.runJob("CREATE_TRACK", { soundcloudTrack }, this)
 
- 											.then(res => {
 
- 												if (res.soundcloudTracks.length === 1)
 
- 													next(null, res.soundcloudTracks[0], false);
 
- 												else next("SoundCloud track not found.");
 
- 											})
 
- 											.catch(next);
 
- 									}
 
- 								});
 
- 							})
 
- 							.catch(next);
 
- 					}
 
- 				],
 
- 				(err, track, existing) => {
 
- 					if (err) reject(new Error(err));
 
- 					else if (track.policy === "SNIP") reject(new Error("Track is premium-only."));
 
- 					else resolve({ track, existing });
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Returns an array of songs taken from a SoundCloud playlist
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.url - the url of the SoundCloud playlist
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	GET_PLAYLIST(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			async.waterfall(
 
- 				[
 
- 					next => {
 
- 						SoundCloudModule.runJob("API_RESOLVE", { url: payload.url }, this)
 
- 							.then(async ({ response }) => {
 
- 								const { data } = response;
 
- 								if (!data || !data.id)
 
- 									return next("The provided URL does not exist or cannot be accessed.");
 
- 								let tracks;
 
- 								if (data.kind === "user")
 
- 									tracks = (
 
- 										await SoundCloudModule.runJob(
 
- 											"GET_ARTIST_TRACKS",
 
- 											{
 
- 												artistId: data.id
 
- 											},
 
- 											this
 
- 										)
 
- 									).tracks;
 
- 								else if (data.kind !== "playlist" && data.kind !== "system-playlist")
 
- 									return next(`Invalid URL provided. Kind got: ${data.kind}.`);
 
- 								else tracks = data.tracks;
 
- 								const soundcloudTrackIds = tracks.map(track => track.id);
 
- 								return next(null, soundcloudTrackIds);
 
- 							})
 
- 							.catch(next);
 
- 					}
 
- 				],
 
- 				(err, soundcloudTrackIds) => {
 
- 					if (err && err !== true) {
 
- 						SoundCloudModule.log(
 
- 							"ERROR",
 
- 							"GET_PLAYLIST",
 
- 							"Some error has occurred.",
 
- 							typeof err === "string" ? err : err.message
 
- 						);
 
- 						reject(new Error(typeof err === "string" ? err : err.message));
 
- 					} else {
 
- 						resolve({ songs: soundcloudTrackIds });
 
- 					}
 
- 				}
 
- 			);
 
- 			// kind;
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Returns an array of songs taken from a SoundCloud artist
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.artistId - the id of the SoundCloud artist
 
- 	 * @returns {Promise} - returns promise (reject, resolve)
 
- 	 */
 
- 	GET_ARTIST_TRACKS(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			async.waterfall(
 
- 				[
 
- 					next => {
 
- 						let first = true;
 
- 						let nextHref = null;
 
- 						let tracks = [];
 
- 						async.whilst(
 
- 							next => {
 
- 								if (nextHref || first) next(null, true);
 
- 								else next(null, false);
 
- 							},
 
- 							next => {
 
- 								let job;
 
- 								if (first) {
 
- 									job = SoundCloudModule.runJob(
 
- 										"API_GET_ARTIST_TRACKS",
 
- 										{ artistId: payload.artistId },
 
- 										this
 
- 									);
 
- 									first = false;
 
- 								} else job = SoundCloudModule.runJob("API_GET_ARTIST_TRACKS", { nextHref }, this);
 
- 								job.then(({ response }) => {
 
- 									const { data } = response;
 
- 									const { collection, next_href: _nextHref } = data;
 
- 									nextHref = _nextHref;
 
- 									tracks = tracks.concat(collection);
 
- 									setTimeout(() => {
 
- 										next();
 
- 									}, 500);
 
- 								}).catch(err => {
 
- 									next(err);
 
- 								});
 
- 							},
 
- 							err => {
 
- 								if (err) return next(err);
 
- 								return next(null, tracks);
 
- 							}
 
- 						);
 
- 					}
 
- 				],
 
- 				(err, tracks) => {
 
- 					if (err && err !== true) {
 
- 						SoundCloudModule.log(
 
- 							"ERROR",
 
- 							"GET_ARTIST_TRACKS",
 
- 							"Some error has occurred.",
 
- 							typeof err === "string" ? err : err.message
 
- 						);
 
- 						reject(new Error(typeof err === "string" ? err : err.message));
 
- 					} else {
 
- 						resolve({ tracks });
 
- 					}
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Get Soundcloud artists
 
- 	 * @param {object} payload - an object containing the payload
 
- 	 * @param {Array} payload.userPermalinks - an array of Soundcloud user permalinks
 
- 	 * @returns {Promise} - returns a promise (resolve, reject)
 
- 	 */
 
- 	async GET_ARTISTS_FROM_PERMALINKS(payload) {
 
- 		const getArtists = async userPermalinks => {
 
- 			const jobsToRun = [];
 
- 			userPermalinks.forEach(userPermalink => {
 
- 				const url = `https://soundcloud.com/${userPermalink}`;
 
- 				jobsToRun.push(SoundCloudModule.runJob("API_RESOLVE", { url }, this));
 
- 			});
 
- 			const jobResponses = await Promise.all(jobsToRun);
 
- 			return jobResponses
 
- 				.map(jobResponse => jobResponse.response.data)
 
- 				.map(artist => ({
 
- 					artistId: artist.id,
 
- 					username: artist.username,
 
- 					avatarUrl: artist.avatar_url,
 
- 					permalink: artist.permalink,
 
- 					rawData: artist
 
- 				}));
 
- 		};
 
- 		const { userPermalinks } = payload;
 
- 		const existingArtists = [];
 
- 		const existingUserPermalinks = existingArtists.map(existingArtists => existingArtists.userPermalink);
 
- 		// const existingArtistsObjectIds = existingArtists.map(existingArtists => existingArtists._id.toString());
 
- 		if (userPermalinks.length === existingArtists.length) return { artists: existingArtists };
 
- 		const missingUserPermalinks = userPermalinks.filter(
 
- 			userPermalink => existingUserPermalinks.indexOf(userPermalink) === -1
 
- 		);
 
- 		if (missingUserPermalinks.length === 0) return { videos: existingArtists };
 
- 		const newArtists = await getArtists(missingUserPermalinks);
 
- 		// await SoundcloudModule.soundcloudArtistsModel.insertMany(newArtists);
 
- 		return { artists: existingArtists.concat(newArtists) };
 
- 	}
 
- 	/**
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.url - the url of the SoundCloud resource
 
- 	 * @returns {Promise} - returns a promise (resolve, reject)
 
- 	 */
 
- 	API_RESOLVE(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			const { url } = payload;
 
- 			SoundCloudModule.runJob(
 
- 				"API_CALL",
 
- 				{
 
- 					url: `https://api-v2.soundcloud.com/resolve?url=${encodeURIComponent(url)}`
 
- 				},
 
- 				this
 
- 			)
 
- 				.then(response => {
 
- 					resolve(response);
 
- 				})
 
- 				.catch(err => {
 
- 					reject(err);
 
- 				});
 
- 		});
 
- 	}
 
- 	/**
 
- 	 * Calls the API_CALL with the proper URL to get artist/user tracks
 
- 	 * @param {object} payload - object that contains the payload
 
- 	 * @param {string} payload.artistId - the id of the SoundCloud artist
 
- 	 * @param {string} payload.nextHref - the next url to call
 
- 	 * @returns {Promise} - returns a promise (resolve, reject)
 
- 	 */
 
- 	API_GET_ARTIST_TRACKS(payload) {
 
- 		return new Promise((resolve, reject) => {
 
- 			const { artistId, nextHref } = payload;
 
- 			SoundCloudModule.runJob(
 
- 				"API_CALL",
 
- 				{
 
- 					url: artistId
 
- 						? `https://api-v2.soundcloud.com/users/${artistId}/tracks?access=playable&limit=50`
 
- 						: nextHref
 
- 				},
 
- 				this
 
- 			)
 
- 				.then(response => {
 
- 					resolve(response);
 
- 				})
 
- 				.catch(err => {
 
- 					reject(err);
 
- 				});
 
- 		});
 
- 	}
 
- }
 
- export default new _SoundCloudModule();
 
 
  |