From 2b65c0632aeb5943de1ad4ab15268b86ee07e3b1 Mon Sep 17 00:00:00 2001 From: Jonathan Cremin Date: Thu, 4 Dec 2014 19:17:41 +0000 Subject: [PATCH] Use promises, split tests, make music services modular, add deezer. --- .gitignore | 1 + lib/{ => services}/beats.js | 35 ++++-- lib/services/deezer.js | 86 +++++++++++++ lib/{ => services}/googleplaymusic.js | 33 +++-- lib/{ => services}/rdio.js | 30 +++-- lib/{ => services}/spotify.js | 30 +++-- package.json | 3 +- public/images/deezer.png | Bin 0 -> 7693 bytes routes/index.js | 149 +++++++---------------- test/services/beats.js | 57 +++++++++ test/services/deezer.js | 0 test/services/googleplaymusic.js | 48 ++++++++ test/services/rdio.js | 41 +++++++ test/services/spotify.js | 34 ++++++ test/test.js | 167 -------------------------- 15 files changed, 407 insertions(+), 307 deletions(-) rename lib/{ => services}/beats.js (72%) create mode 100644 lib/services/deezer.js rename lib/{ => services}/googleplaymusic.js (75%) rename lib/{ => services}/rdio.js (80%) rename lib/{ => services}/spotify.js (71%) create mode 100644 public/images/deezer.png create mode 100644 test/services/beats.js create mode 100644 test/services/deezer.js create mode 100644 test/services/googleplaymusic.js create mode 100644 test/services/rdio.js create mode 100644 test/services/spotify.js delete mode 100644 test/test.js diff --git a/.gitignore b/.gitignore index 3c3629e..fd4f2b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.DS_Store diff --git a/lib/beats.js b/lib/services/beats.js similarity index 72% rename from lib/beats.js rename to lib/services/beats.js index a2599a5..e69a976 100644 --- a/lib/beats.js +++ b/lib/services/beats.js @@ -1,9 +1,13 @@ "use strict"; var parse = require('url').parse; var request = require('superagent'); +var Q = require('q'); + +module.exports.id = "beats"; if (!process.env.BEATS_KEY || !process.env.BEATS_SECRET) { - throw new Error("You need to set BEATS_KEY and BEATS_SECRET environment variables"); + console.warn("BEATS_KEY or BEATS_SECRET environment variables not found, deactivating Beats."); + return; } var credentials = { @@ -13,13 +17,19 @@ var credentials = { var apiRoot = "https://partner.api.beatsmusic.com/v1/api"; -module.exports.lookupId = function(id, next) { +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/beatsmusic\.com$/); +}; + +module.exports.lookupId = function(id) { + var deferred = Q.defer(); if (id.substr(0,2) == "al") { request.get(apiRoot + "/albums/" + id + "/images/default?size=medium&client_id=" + credentials.key).redirects(0).end(function(res) { var artwork = res.headers.location; request.get(apiRoot + "/albums/" + id + "?client_id=" + credentials.key, function(res) { var result = res.body.data; - next({ + deferred.resolve({ service: "beats", type: "album", id: result.id, @@ -37,7 +47,7 @@ module.exports.lookupId = function(id, next) { var result = res.body.data; request.get(apiRoot + "/albums/" + result.refs.album.id + "/images/default?size=medium&client_id=" + credentials.key).redirects(0).end(function(res) { var artwork = res.headers.location; - next({ + deferred.resolve({ service: "beats", type: "track", id: result.id, @@ -54,9 +64,11 @@ module.exports.lookupId = function(id, next) { }); }); } + return deferred.promise; }; -module.exports.search = function(data, next) { +module.exports.search = function(data) { + var deferred = Q.defer(); var query; var type = data.type; @@ -69,19 +81,22 @@ module.exports.search = function(data, next) { var path = "/search?q=" + encodeURIComponent(query) + "&type=" + type + "&client_id=" + credentials.key; request.get(apiRoot + path, function(res) { if (!res.body.data[0]) { - next({service: "beats"}); + deferred.resolve({service: "beats"}); } else { - module.exports.lookupId(res.body.data[0].id, next); + module.exports.lookupId(res.body.data[0].id).then(deferred.resolve); } }); + return deferred.promise; }; -module.exports.parseUrl = function(url, next) { +module.exports.parseUrl = function(url) { + var deferred = Q.defer(); var matches = parse(url).path.match(/\/albums[\/]+([^\/]+)(\/tracks\/)?([^\/]+)?/); if (matches && matches[3]) { - module.exports.lookupId(matches[3], next); + module.exports.lookupId(matches[3]).then(deferred.resolve); } else if (matches && matches[1]) { - module.exports.lookupId(matches[1], next); + module.exports.lookupId(matches[1]).then(deferred.resolve); } + return deferred.promise; } diff --git a/lib/services/deezer.js b/lib/services/deezer.js new file mode 100644 index 0000000..955c8f1 --- /dev/null +++ b/lib/services/deezer.js @@ -0,0 +1,86 @@ +"use strict"; +var parse = require('url').parse; +var request = require('superagent'); +var Q = require('q'); + +module.exports.id = "deezer"; + +var apiRoot = "https://api.deezer.com"; + +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/deezer\.com$/); +}; + +module.exports.lookupId = function(id, type) { + var deferred = Q.defer(); + var path = "/" + type + "/" + id; + + request.get(apiRoot + path, function(res) { + var result = res.body; + + if (type == "album") { + deferred.resolve({ + service: "deezer", + type: type, + id: result.id, + name: result.title, + url: result.link, + artwork: result.cover, + artist: { + name: result.artist.name + }, + }); + } else if (type == "track") { + deferred.resolve({ + service: "deezer", + type: type, + id: result.id, + name: result.title, + url: result.link, + artwork: result.album.cover, + artist: { + name: result.artist.name + }, + album: { + name: result.album.title + } + }); + }; + }); + return deferred.promise; +}; + +module.exports.search = function(data, next) { + var deferred = Q.defer(); + var query; + var type = data.type; + + if (type == "album") { + query = data.artist.name + " " + data.name; + } else if (type == "track") { + query = data.artist.name + " " + data.album.name + " " + data.name; + } + + var path = "/search/" + type + "?q=" + encodeURIComponent(query); + request.get(apiRoot + path, function(res) { + if (!res.body.data[0]) { + deferred.resolve({service: "deezer"}); + } else { + module.exports.lookupId(res.body.data[0].id, type).then(deferred.resolve); + } + }); + return deferred.promise; +}; + +module.exports.parseUrl = function(url, next) { + var deferred = Q.defer(); + var matches = parse(url).path.match(/\/albums[\/]+([^\/]+)(\/tracks\/)?([^\/]+)?/); + + if (matches && matches[3]) { + module.exports.lookupId(matches[3]).then(deferred.resolve); + } else if (matches && matches[1]) { + module.exports.lookupId(matches[1]).then(deferred.resolve); + } + return deferred.promise; +} diff --git a/lib/googleplaymusic.js b/lib/services/googleplaymusic.js similarity index 75% rename from lib/googleplaymusic.js rename to lib/services/googleplaymusic.js index 3889b37..e8e6dfe 100644 --- a/lib/googleplaymusic.js +++ b/lib/services/googleplaymusic.js @@ -2,18 +2,28 @@ var parse = require("url").parse; var PlayMusic = require('playmusic'); var pm = new PlayMusic(); +var Q = require('q'); + +module.exports.id = "google"; if (!process.env.GOOGLE_EMAIL || !process.env.GOOGLE_PASSWORD) { - throw new Error("You need to set GOOGLE_EMAIL and GOOGLE_PASSWORD environment variables"); + console.warn("GOOGLE_EMAIL or GOOGLE_PASSWORD environment variables not found, deactivating Rdio."); + return; } // It's probably ok to not wait for this to finish pm.init({email: process.env.GOOGLE_EMAIL, password: process.env.GOOGLE_PASSWORD}, function() {}); +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/play\.google\.com$/); +}; + module.exports.lookupId = function(id, type, next) { + var deferred = Q.defer(); if (type == "album") { pm.getAlbum(id, true, function(album) { - next({ + deferred.resolve({ service: "googleplaymusic", type: "album", id: album.albumId, @@ -27,7 +37,7 @@ module.exports.lookupId = function(id, type, next) { }); } else if (type == "track") { pm.getAllAccessTrack(id, function(track) { - next({ + deferred.resolve({ service: "googleplaymusic", type: "track", id: track.nid, @@ -43,9 +53,11 @@ module.exports.lookupId = function(id, type, next) { }); }); } + return deferred.promise; } -module.exports.search = function(data, next) { +module.exports.search = function(data) { + var deferred = Q.defer(); var query = ""; var type = data.type; @@ -63,7 +75,7 @@ module.exports.search = function(data, next) { }).shift(); if (!result.album && !result.track) { - next({service:"googleplaymusic"}); + deferred.resolve({service:"googleplaymusic"}); } var id; @@ -73,11 +85,13 @@ module.exports.search = function(data, next) { id = result.track.nid; } - module.exports.lookupId(id, type, next); + module.exports.lookupId(id, type).then(deferred.resolve); }); + return deferred.promise; } module.exports.parseUrl = function(url, next) { + var deferred = Q.defer(); var parsed = parse(url.replace(/\+/g, "%20")); var path = parsed.path; var hash = parsed.hash; @@ -89,13 +103,14 @@ module.exports.parseUrl = function(url, next) { var album = decodeURIComponent(parts[4]); if (id.length > 0) { - return next({id: id, type: type}); + deferred.resolve({id: id, type: type}); } else { - module.exports.search({type: type, name:album, artist: {name: artist}}, next); + module.exports.search({type: type, name:album, artist: {name: artist}}).then(deferred.resolve); } } else if(path) { var matches = path.match(/\/music\/m\/([\w]+)/); var type = matches[1][0] == "T" ? "track" : "album"; - module.exports.lookupId(matches[1], type, next); + module.exports.lookupId(matches[1], type).then(deferred.resolve); } + return deferred.promise; } diff --git a/lib/rdio.js b/lib/services/rdio.js similarity index 80% rename from lib/rdio.js rename to lib/services/rdio.js index 6e1724e..ddea295 100644 --- a/lib/rdio.js +++ b/lib/services/rdio.js @@ -1,17 +1,26 @@ "use strict"; var parse = require('url').parse; +var Q = require('q'); + +module.exports.id = "rdio"; if (!process.env.RDIO_API_KEY || !process.env.RDIO_API_SHARED) { - throw new Error("You need to set RDIO_API_KEY and RDIO_API_SHARED environment variables"); + console.warn("RDIO_API_KEY or RDIO_API_SHARED environment variables not found, deactivating Rdio."); + return; } - var rdio = require('rdio')({ rdio_api_key: process.env.RDIO_API_KEY, rdio_api_shared: process.env.RDIO_API_SHARED, }); -module.exports.lookupId = function(id, next) { +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/rd\.io$/) || parsed.host.match(/rdio\.com$/); +}; + +module.exports.lookupId = function(id) { + var deferred = Q.defer(); rdio.api("", "", { method: 'getObjectFromShortCode', short_code: id, @@ -20,7 +29,7 @@ module.exports.lookupId = function(id, next) { var parsed = parse(result.shortUrl) var id = parsed.path.replace("/x/", "").replace("/", ""); var type = result.album ? "track" : "album"; - next({ + deferred.resolve({ service: "rdio", type: type, id: id, @@ -32,9 +41,11 @@ module.exports.lookupId = function(id, next) { } }); }); + return deferred.promise; }; -module.exports.lookupUrl = function(url, next) { +module.exports.parseUrl = function(url) { + var deferred = Q.defer(); var parsed = parse(url); var data; @@ -58,7 +69,7 @@ module.exports.lookupUrl = function(url, next) { var parsed = parse(result.shortUrl) var id = parsed.path.replace("/x/", "").replace("/", ""); var type = result.album ? "track" : "album"; - next({ + deferred.resolve({ service: "rdio", type: type, id: id, @@ -70,9 +81,11 @@ module.exports.lookupUrl = function(url, next) { } }); }); + return deferred.promise; }; -module.exports.search = function(data, next) { +module.exports.search = function(data) { + var deferred = Q.defer(); var query; var type = data.type; @@ -102,7 +115,7 @@ module.exports.search = function(data, next) { } var parsed = parse(result.shortUrl) var id = parsed.path.replace("/x/", "").replace("/", ""); - next({ + deferred.resolve({ service: "rdio", type: type, id: id, @@ -114,4 +127,5 @@ module.exports.search = function(data, next) { } }); }); + return deferred.promise; }; diff --git a/lib/spotify.js b/lib/services/spotify.js similarity index 71% rename from lib/spotify.js rename to lib/services/spotify.js index abb05c1..bea5a63 100644 --- a/lib/spotify.js +++ b/lib/services/spotify.js @@ -1,8 +1,17 @@ "use strict"; var parse = require('url').parse; var spotify = require('spotify'); +var Q = require('q'); -module.exports.lookupId = function(id, type, next) { +module.exports.id = "spotify"; + +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/spotify\.com$/); +}; + +module.exports.lookupId = function(id, type) { + var deferred = Q.defer(); spotify.lookup({id: id, type: type}, function(err, data) { if ( err ) { console.log('Error occurred: ' + err); @@ -12,7 +21,7 @@ module.exports.lookupId = function(id, type, next) { var artist = data.artists[0]; if (type == "album") { - next({ + deferred.resolve({ service: "spotify", type: type, id: data.id, @@ -24,7 +33,7 @@ module.exports.lookupId = function(id, type, next) { } }); } else if (type == "track") { - next({ + deferred.resolve({ service: "spotify", type: type, id: data.id, @@ -40,9 +49,11 @@ module.exports.lookupId = function(id, type, next) { }) } }); + return deferred.promise; } -module.exports.search = function(data, next) { +module.exports.search = function(data) { + var deferred = Q.defer(); var query = ""; var type = data.type; @@ -59,19 +70,22 @@ module.exports.search = function(data, next) { } if (!data[type + "s"].items[0]) { - next({service:"spotify"}); + deferred.resolve({service:"spotify"}); } var item = data[type + "s"].items[0]; - module.exports.lookupId(item.id, type, next); + module.exports.lookupId(item.id, type).then(deferred.resolve); }); + return deferred.promise; } -module.exports.parseUrl = function(url, next) { +module.exports.parseUrl = function(url) { + var deferred = Q.defer(); var matches = parse(url).path.match(/\/(album|track)[\/]+([^\/]+)/); if (matches && matches[2]) { - module.exports.lookupId(matches[2], matches[1], next); + module.exports.lookupId(matches[2], matches[1]).then(deferred.resolve); } + return deferred.promise; } diff --git a/package.json b/package.json index 567dffb..cedcbe1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "start": "node ./bin/www", - "test": "./node_modules/mocha/bin/mocha --timeout=5000" + "test": "./node_modules/mocha/bin/mocha test/**/*.js --timeout=5000" }, "engines": { "node": "0.10.x" @@ -20,6 +20,7 @@ "helmet": "^0.5.2", "morgan": "~1.3.0", "playmusic": "^1.1.0", + "q": "^1.1.2", "rdio": "^1.5.2", "serve-favicon": "~2.1.3", "spotify": "^0.3.0", diff --git a/public/images/deezer.png b/public/images/deezer.png new file mode 100644 index 0000000000000000000000000000000000000000..d752a8b7dd35722fed034a23bcc5e118ac4dc01d GIT binary patch literal 7693 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 R`L7SOO7iM*?`15*{tvwt0QLX? literal 0 HcmV?d00001 diff --git a/routes/index.js b/routes/index.js index 14e12ca..e5b8ab3 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,83 +1,45 @@ "use strict"; var parse = require('url').parse; +var path = require('path'); var express = require('express'); var router = express.Router(); +var Q = require('q'); -var googleplaymusic = require('../lib/googleplaymusic'); -var spotify = require('../lib/spotify'); -var rdio = require('../lib/rdio'); -var beats = require('../lib/beats'); +var services = {}; + +require("fs").readdirSync(path.join(__dirname, "..", "lib", "services")).forEach(function(file) { + var service = require("../lib/services/" + file); + if (service.search) { + services[service.id] = service; + } +}); var cache = {googleplaymusic:{}, spotify:{},rdio:{}}; router.get('/:service/:type/:id', function(req, res) { - var service = req.params.service; + var serviceId = req.params.service; var type = req.params.type; - var id = req.params.id; - var items = []; + var itemId = req.params.id; + var promises = []; - switch(service) { - case "spotify": - spotify.lookupId(id, type, function(result) { - items.push(result); - googleplaymusic.search(result, function(item) { - items.push(item); - rdio.search(result, function(item) { - items.push(item); - beats.search(result, function(item) { - items.push(item); - res.render(result.type, {items: items}); - }); - }); - }); + services[serviceId].lookupId(itemId, type).then(function(item) { + for (var id in services) { + if (id != serviceId) { + promises.push(services[id].search(item)); + } + } + + Q.allSettled(promises).then(function(results) { + var items = results.map(function(result) { + if (result.state == "fulfilled") { + return result.value; + } }); - break; - case "google": - googleplaymusic.lookupId(id, type, function(result) { - items.push(result); - spotify.search(result, function(item) { - items.push(item); - rdio.search(result, function(item) { - items.push(item); - beats.search(result, function(item) { - items.push(item); - res.render(result.type, {items: items}); - }); - }); - }); - }); - break; - case "rdio": - rdio.lookupId(id, function(result) { - items.push(result); - googleplaymusic.search(result, function(item) { - items.push(item); - spotify.search(result, function(item) { - items.push(item); - beats.search(result, function(item) { - items.push(item); - res.render(result.type, {items: items}); - }); - }); - }); - }); - break; - case "beats": - beats.lookupId(id, function(result) { - items.push(result); - googleplaymusic.search(result, function(item) { - items.push(item); - spotify.search(result, function(item) { - items.push(item); - rdio.search(result, function(item) { - items.push(item); - res.render(result.type, {items: items}); - }); - }); - }); - }); - break; - } + items.unshift(item); + + res.render(type, {items: items}); + }); + }); }); router.post('/search', function(req, res) { @@ -89,43 +51,22 @@ router.post('/search', function(req, res) { return; } - if (url.host.match(/rd\.io$/) || url.host.match(/rdio\.com$/)) { - rdio.lookupUrl(url.href, function(result) { - if (!result.id) { - req.flash('search-error', 'No match found for this link'); - res.redirect('/'); - } - res.redirect("/rdio/" + result.type + "/" + result.id); - }); - } else if (url.host.match(/spotify\.com$/)) { - spotify.parseUrl(url.href, function(result) { - if (!result.id) { - req.flash('search-error', 'No match found for this link'); - res.redirect('/'); - } - res.redirect("/spotify/" + result.type + "/" + result.id); - }); - } else if (url.host.match(/play\.google\.com$/)) { - googleplaymusic.parseUrl(url.href, function(result) { - if (!result) { - req.flash('search-error', 'No match found for this link'); - res.redirect('/'); - } else { - res.redirect("/google/" + result.type + "/" + result.id); - } - }); - } else if (url.host.match(/beatsmusic\.com$/)) { - beats.parseUrl(url.href, function(result) { - if (!result.id) { - req.flash('search-error', 'No match found for this link'); - res.redirect('/'); - } - res.redirect("/beats/" + result.type + "/" + result.id); - }); - } else { - req.flash('search-error', 'No match found for this link'); - res.redirect('/'); + for (var id in services) { + var matched = services[id].match(req.body.url); + if (matched) { + services[id].parseUrl(req.body.url).then(function(result) { + if (!result.id) { + req.flash('search-error', 'No match found for this link'); + res.redirect('/'); + } + res.redirect("/" + id + "/" + result.type + "/" + result.id); + }) + return; + } } + + req.flash('search-error', 'No match found for this link'); + res.redirect('/'); }); /* GET home page. */ diff --git a/test/services/beats.js b/test/services/beats.js new file mode 100644 index 0000000..c5776ba --- /dev/null +++ b/test/services/beats.js @@ -0,0 +1,57 @@ +"use strict"; +var assert = require("assert"); +var should = require('should'); + +var beats = require("../../lib/services/beats"); + +describe('Beats Music', function(){ + describe('lookupId', function(){ + it('should find album by ID', function(done){ + beats.lookupId("al920431").then(function(result) { + result.name.should.equal("Deftones"); + done(); + }); + }); + + it('should find track by ID', function(done){ + beats.lookupId("tr6910289").then(function(result) { + result.name.should.equal("Californication"); + done(); + }); + }); + }); + + describe('search', function(){ + it('should find album by search', function(done){ + beats.search({type: "album", artist: {name: "Deftones"}, name: "Deftones"}).then(function(result) { + result.name.should.equal("Deftones"); + done(); + }); + }); + + it('should find track by search', function(done){ + beats.search({type: "track", artist: {name: "Deftones"}, album: {name: "Deftones"}, name: "Hexagram"}).then(function(result) { + result.name.should.equal("Hexagram"); + done(); + }); + }); + }); + + describe('lookupUrl', function(){ + describe('parseUrl', function(){ + it('should parse album url into ID', function(done){ + beats.parseUrl("https://listen.beatsmusic.com/albums/al920431").then(function(result) { + result.id.should.equal("al920431"); + done(); + }); + }); + + it('should parse track url into ID', function(done){ + beats.parseUrl("https://listen.beatsmusic.com/albums/al6910269/tracks/tr6910289").then(function(result) { + result.id.should.equal("tr6910289"); + done(); + }); + }); + }); + }); +}); diff --git a/test/services/deezer.js b/test/services/deezer.js new file mode 100644 index 0000000..e69de29 diff --git a/test/services/googleplaymusic.js b/test/services/googleplaymusic.js new file mode 100644 index 0000000..a16f1fb --- /dev/null +++ b/test/services/googleplaymusic.js @@ -0,0 +1,48 @@ +"use strict"; +var assert = require("assert"); +var should = require('should'); + +var googleplaymusic = require("../../lib/services/googleplaymusic"); + +describe('Google Play Music', function(){ + describe('lookupId', function(){ + it('should find album by ID', function(done){ + googleplaymusic.lookupId("Byp6lvzimyf74wxi5634ul4tgam", "album").then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('search', function(){ + it('should find album by search', function(done){ + googleplaymusic.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}).then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('lookupUrl', function(){ + it('should parse regular url into album ID', function(done){ + googleplaymusic.parseUrl("https://play.google.com/music/listen#/album/Byp6lvzimyf74wxi5634ul4tgam/David+Guetta/Listen+(Deluxe)").then(function(result) { + result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); + done(); + }); + }); + + it('should parse url without ID into album ID', function(done){ + googleplaymusic.parseUrl("https://play.google.com/music/listen#/album//David+Guetta/Listen+(Deluxe)").then(function(result) { + result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); + done(); + }); + }); + + it('should parse share url into album ID', function(done){ + googleplaymusic.parseUrl("https://play.google.com/music/m/Byp6lvzimyf74wxi5634ul4tgam").then(function(result) { + result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); + done(); + }); + }); + }); +}); diff --git a/test/services/rdio.js b/test/services/rdio.js new file mode 100644 index 0000000..81994bd --- /dev/null +++ b/test/services/rdio.js @@ -0,0 +1,41 @@ +"use strict"; +var assert = require("assert"); +var should = require('should'); + +var rdio = require("../../lib/services/rdio"); + +describe('Rdio', function(){ + describe('lookupId', function(){ + it('should find album by ID', function(done){ + rdio.lookupId("Qj4NXr0").then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('search', function(){ + it('should find album by search', function(done){ + rdio.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}).then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('parseUrl', function(){ + it('should parse regular url into album object', function(done){ + rdio.parseUrl("https://www.rdio.com/artist/David_Guetta/album/Listen_(Deluxe)/").then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + + it('should parse short url into album object', function(done){ + rdio.parseUrl("http://rd.io/x/Qj4NXr0/").then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); +}); diff --git a/test/services/spotify.js b/test/services/spotify.js new file mode 100644 index 0000000..8fa6701 --- /dev/null +++ b/test/services/spotify.js @@ -0,0 +1,34 @@ +"use strict"; +var assert = require("assert"); +var should = require('should'); + +var spotify = require("../../lib/services/spotify"); + +describe('Spotify', function(){ + describe('lookupId', function(){ + it('should find album by ID', function(done){ + spotify.lookupId("77UW17CZFyCaRLHdHeofZu", "album").then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('search', function(){ + it('should find album by search', function(done){ + spotify.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}).then(function(result) { + result.name.should.equal("Listen (Deluxe)"); + done(); + }); + }); + }); + + describe('parseUrl', function(){ + it('should parse url into ID', function(done){ + spotify.parseUrl("https://play.spotify.com/album/77UW17CZFyCaRLHdHeofZu").then(function(result) { + result.id.should.equal("77UW17CZFyCaRLHdHeofZu"); + done(); + }); + }); + }); +}); diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 12bcbc9..0000000 --- a/test/test.js +++ /dev/null @@ -1,167 +0,0 @@ -"use strict"; -var assert = require("assert"); -var should = require('should'); -var spotify = require("../lib/spotify"); -var rdio = require("../lib/rdio"); -var googleplaymusic = require("../lib/googleplaymusic"); -var beats = require("../lib/beats"); - -describe('Spotify', function(){ - describe('lookupId', function(){ - it('should find album by ID', function(done){ - spotify.lookupId("77UW17CZFyCaRLHdHeofZu", "album", function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('search', function(){ - it('should find album by search', function(done){ - spotify.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}, function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('parseUrl', function(){ - it('should parse url into ID', function(done){ - spotify.parseUrl("https://play.spotify.com/album/77UW17CZFyCaRLHdHeofZu", function(result) { - result.id.should.equal("77UW17CZFyCaRLHdHeofZu"); - done(); - }); - }); - }); -}); - -describe('Rdio', function(){ - describe('lookupId', function(){ - it('should find album by ID', function(done){ - rdio.lookupId("Qj4NXr0", function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('search', function(){ - it('should find album by search', function(done){ - rdio.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}, function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('lookupUrl', function(){ - it('should parse regular url into album object', function(done){ - rdio.lookupUrl("https://www.rdio.com/artist/David_Guetta/album/Listen_(Deluxe)/", function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - - it('should parse short url into album object', function(done){ - rdio.lookupUrl("http://rd.io/x/Qj4NXr0/", function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); -}); - -describe('Google Play Music', function(){ - describe('lookupId', function(){ - it('should find album by ID', function(done){ - googleplaymusic.lookupId("Byp6lvzimyf74wxi5634ul4tgam", "album", function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('search', function(){ - it('should find album by search', function(done){ - googleplaymusic.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}, function(result) { - result.name.should.equal("Listen (Deluxe)"); - done(); - }); - }); - }); - - describe('lookupUrl', function(){ - it('should parse regular url into album ID', function(done){ - googleplaymusic.parseUrl("https://play.google.com/music/listen#/album/Byp6lvzimyf74wxi5634ul4tgam/David+Guetta/Listen+(Deluxe)", function(result) { - result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); - done(); - }); - }); - - it('should parse url without ID into album ID', function(done){ - googleplaymusic.parseUrl("https://play.google.com/music/listen#/album//David+Guetta/Listen+(Deluxe)", function(result) { - result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); - done(); - }); - }); - - it('should parse share url into album ID', function(done){ - googleplaymusic.parseUrl("https://play.google.com/music/m/Byp6lvzimyf74wxi5634ul4tgam", function(result) { - result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); - done(); - }); - }); - }); -}); - -describe('Beats Music', function(){ - describe('lookupId', function(){ - it('should find album by ID', function(done){ - beats.lookupId("al920431", function(result) { - result.name.should.equal("Deftones"); - done(); - }); - }); - - it('should find track by ID', function(done){ - beats.lookupId("tr6910289", function(result) { - result.name.should.equal("Californication"); - done(); - }); - }); - }); - - describe('search', function(){ - it('should find album by search', function(done){ - beats.search({type: "album", artist: {name: "Deftones"}, name: "Deftones"}, function(result) { - result.name.should.equal("Deftones"); - done(); - }); - }); - - it('should find track by search', function(done){ - beats.search({type: "track", artist: {name: "Deftones"}, album: {name: "Deftones"}, name: "Hexagram"}, function(result) { - result.name.should.equal("Hexagram"); - done(); - }); - }); - }); - - describe('lookupUrl', function(){ - describe('parseUrl', function(){ - it('should parse album url into ID', function(done){ - beats.parseUrl("https://listen.beatsmusic.com/albums/al920431", function(result) { - result.id.should.equal("al920431"); - done(); - }); - }); - - it('should parse track url into ID', function(done){ - beats.parseUrl("https://listen.beatsmusic.com/albums/al6910269/tracks/tr6910289", function(result) { - result.id.should.equal("tr6910289"); - done(); - }); - }); - }); - }); -});