Major refactor of service libs, more tests

This commit is contained in:
Jonathan Cremin 2014-12-11 19:53:12 +00:00
parent cda69ea472
commit ce3ff0442c
19 changed files with 288 additions and 118 deletions

View file

@ -17,18 +17,33 @@ var credentials = {
var apiRoot = "https://partner.api.beatsmusic.com/v1/api"; var apiRoot = "https://partner.api.beatsmusic.com/v1/api";
module.exports.match = function(url, type) { module.exports.match = require("./url").match;
var parsed = parse(url);
return parsed.host.match(/beatsmusic\.com$/);
};
module.exports.lookupId = function(id) { 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], "track").then(deferred.resolve);
} else if (matches && matches[1]) {
module.exports.lookupId(matches[1], "album").then(deferred.resolve);
} else {
deferred.reject();
}
return deferred.promise;
}
module.exports.lookupId = function(id, type) {
var deferred = Q.defer(); var deferred = Q.defer();
if (id.substr(0,2) == "al") { if (type == "album") {
request.get(apiRoot + "/albums/" + id + "/images/default?size=medium&client_id=" + credentials.key).redirects(0).end(function(res) { request.get(apiRoot + "/albums/" + id + "/images/default?size=medium&client_id=" + credentials.key).redirects(0).end(function(res) {
var artwork = res.headers.location; var artwork = res.headers.location;
request.get(apiRoot + "/albums/" + id + "?client_id=" + credentials.key, function(res) { request.get(apiRoot + "/albums/" + id + "?client_id=" + credentials.key, function(res) {
if (!res.body.data) {
var error = new Error("Not Found");
error.status = 404;
return deferred.reject(error);
}
var result = res.body.data; var result = res.body.data;
deferred.resolve({ deferred.resolve({
service: "beats", service: "beats",
@ -44,8 +59,13 @@ module.exports.lookupId = function(id) {
}); });
}); });
}); });
} else if (id.substr(0,2) == "tr") { } else if (type == "track") {
request.get(apiRoot + "/tracks/" + id + "?client_id=" + credentials.key, function(res) { request.get(apiRoot + "/tracks/" + id + "?client_id=" + credentials.key, function(res) {
if (!res.body.data) {
var error = new Error("Not Found");
error.status = 404;
return deferred.reject(error);
}
var result = res.body.data; 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) { 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; var artwork = res.headers.location;
@ -103,20 +123,8 @@ module.exports.search = function(data) {
deferred.resolve({service: "beats"}); deferred.resolve({service: "beats"});
} }
} else { } else {
module.exports.lookupId(res.body.data[0].id).then(deferred.resolve); module.exports.lookupId(res.body.data[0].id, type).then(deferred.resolve);
} }
}); });
return deferred.promise; return deferred.promise;
}; };
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]).then(deferred.resolve);
} else if (matches && matches[1]) {
module.exports.lookupId(matches[1]).then(deferred.resolve);
}
return deferred.promise;
}

11
lib/services/beats/url.js Normal file
View file

@ -0,0 +1,11 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url) {
var parsed = parse(url);
if (!parsed.host.match(/beatsmusic\.com$/)) {
return false;
}
var matches = parsed.path.match(/\/albums[\/]+([^\/]+)(\/tracks\/)?([^\/]+)?/);
return matches.length > 1;
};

View file

@ -7,10 +7,19 @@ module.exports.id = "deezer";
var apiRoot = "https://api.deezer.com"; var apiRoot = "https://api.deezer.com";
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
var parsed = parse(url);
return parsed.host.match(/deezer\.com$/); module.exports.parseUrl = function(url, next) {
}; var deferred = Q.defer();
var matches = parse(url).path.match(/\/(album|track)[\/]+([^\/]+)/);
if (matches && matches[2]) {
module.exports.lookupId(matches[2], matches[1]).then(deferred.resolve);
} else {
deferred.reject();
}
return deferred.promise;
}
module.exports.lookupId = function(id, type) { module.exports.lookupId = function(id, type) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -96,13 +105,3 @@ module.exports.search = function(data, next) {
}); });
return deferred.promise; return deferred.promise;
}; };
module.exports.parseUrl = function(url, next) {
var deferred = Q.defer();
var matches = parse(url).path.match(/\/(album|track)[\/]+([^\/]+)/);
if (matches && matches[2]) {
module.exports.lookupId(matches[2], matches[1]).then(deferred.resolve);
}
return deferred.promise;
}

View file

@ -0,0 +1,11 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url) {
var parsed = parse(url);
if (!parsed.host.match(/deezer\.com$/)) {
return false;
}
var matches = parsed.path.match(/\/(album|track)[\/]+([^\/]+)/);
return matches.length > 1;
};

View file

@ -17,10 +17,34 @@ pm.init({email: process.env.GOOGLE_EMAIL, password: process.env.GOOGLE_PASSWORD}
ready.resolve(); ready.resolve();
}); });
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
var parsed = parse(url);
return parsed.host.match(/play\.google\.com$/); module.exports.parseUrl = function(url) {
}; var deferred = Q.defer();
ready.promise.then(function() {
var parsed = parse(url.replace(/\+/g, "%20"));
var path = parsed.path;
var hash = parsed.hash;
if (hash) {
var parts = hash.split("/");
var type = parts[1];
var id = parts[2];
var artist = decodeURIComponent(parts[3]);
var album = decodeURIComponent(parts[4]);
if (id.length > 0) {
deferred.resolve({id: id, type: type});
} else {
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).then(deferred.resolve);
}
});
return deferred.promise;
}
module.exports.lookupId = function(id, type, next) { module.exports.lookupId = function(id, type, next) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -28,7 +52,7 @@ module.exports.lookupId = function(id, type, next) {
if (type == "album") { if (type == "album") {
pm.getAlbum(id, false, function(album) { pm.getAlbum(id, false, function(album) {
deferred.resolve({ deferred.resolve({
service: "googleplaymusic", service: "google",
type: "album", type: "album",
id: album.albumId, id: album.albumId,
name: album.name, name: album.name,
@ -45,7 +69,7 @@ module.exports.lookupId = function(id, type, next) {
} else if (type == "track") { } else if (type == "track") {
pm.getAllAccessTrack(id, function(track) { pm.getAllAccessTrack(id, function(track) {
deferred.resolve({ deferred.resolve({
service: "googleplaymusic", service: "google",
type: "track", type: "track",
id: track.nid, id: track.nid,
name: track.title, name: track.title,
@ -104,7 +128,7 @@ module.exports.search = function(data) {
}).shift(); }).shift();
if (!result) { if (!result) {
deferred.resolve({service: "googleplaymusic"}); deferred.resolve({service: "google"});
} else { } else {
var id; var id;
if (type == "album") { if (type == "album") {
@ -119,30 +143,3 @@ module.exports.search = function(data) {
}); });
return deferred.promise; return deferred.promise;
} }
module.exports.parseUrl = function(url, next) {
var deferred = Q.defer();
ready.promise.then(function() {
var parsed = parse(url.replace(/\+/g, "%20"));
var path = parsed.path;
var hash = parsed.hash;
if (hash) {
var parts = hash.split("/");
var type = parts[1];
var id = parts[2];
var artist = decodeURIComponent(parts[3]);
var album = decodeURIComponent(parts[4]);
if (id.length > 0) {
deferred.resolve({id: id, type: type});
} else {
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).then(deferred.resolve);
}
});
return deferred.promise;
}

View file

@ -0,0 +1,30 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url) {
var parsed = parse(url.replace(/\+/g, "%20"));
if (!parsed.host.match(/play\.google\.com$/)) {
return false;
}
var path = parsed.path;
var hash = parsed.hash;
if (hash) {
var parts = hash.split("/");
var id = parts[2];
var artist = parts[3];
if (id.length > 0) {
return true;
} else if (artist.length > 0) {
return true;
}
} else if(path) {
var matches = path.match(/\/music\/m\/([\w]+)/);
if (matches[1]) {
return true
}
}
return false
};

View file

@ -1,5 +1,6 @@
"use strict"; "use strict";
var parse = require('url').parse; var parse = require('url').parse;
var querystring = require('querystring');
var request = require('superagent'); var request = require('superagent');
var Q = require('q'); var Q = require('q');
@ -7,9 +8,26 @@ module.exports.id = "itunes";
var apiRoot = "https://itunes.apple.com"; var apiRoot = "https://itunes.apple.com";
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
module.exports.parseUrl = function(url) {
var deferred = Q.defer();
var parsed = parse(url); var parsed = parse(url);
return parsed.host.match(/itunes.apple\.com$/); var matches = parsed.path.match(/[\/]?([\/]?[a-z]{2}?)?[\/]+album[\/]+([^\/]+)[\/]+([^\?]+)/);
var query = querystring.parse(parsed.query);
if (matches) {
var type = "album";
var id = matches[3].substr(2);
if (query.i) {
type = "track";
id = query.i;
}
module.exports.lookupId(id, type, matches[1] || "us").then(deferred.resolve, deferred.reject);
} else {
deferred.reject();
}
return deferred.promise;
}; };
module.exports.lookupId = function(id, type, cc) { module.exports.lookupId = function(id, type, cc) {
@ -38,7 +56,7 @@ module.exports.lookupId = function(id, type, cc) {
var item = { var item = {
service: "itunes", service: "itunes",
type: type, type: type,
id: cc + result.collectionId, id: cc + id,
name: result.trackName ? result.trackName : result.collectionName, name: result.trackName ? result.trackName : result.collectionName,
streamUrl: null, streamUrl: null,
purchaseUrl: result.collectionViewUrl, purchaseUrl: result.collectionViewUrl,
@ -58,7 +76,7 @@ module.exports.lookupId = function(id, type, cc) {
} }
}); });
return deferred.promise; return deferred.promise;
} };
module.exports.search = function(data) { module.exports.search = function(data) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -118,16 +136,4 @@ module.exports.search = function(data) {
}); });
return deferred.promise; return deferred.promise;
} };
module.exports.parseUrl = function(url) {
var deferred = Q.defer();
var matches = parse(url).path.match(/[\/]?([\/]?[a-z]{2}?)?\/(album|track)[\/]+([^\/]+)[\/]+([^\?]+)/);
if (matches && matches[4]) {
module.exports.lookupId(matches[4].substr(2), matches[2], matches[1]).then(deferred.resolve, deferred.reject);
} else if (matches[3]) {
module.exports.lookupId(matches[3].substr(2), matches[1], "").then(deferred.resolve, deferred.reject);
}
return deferred.promise;
}

View file

@ -0,0 +1,15 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url, type) {
var parsed = parse(url);
if (!parsed.host.match(/itunes.apple\.com$/)) {
return false;
}
var matches = parsed.path.match(/[\/]?([\/]?[a-z]{2}?)?[\/]+album[\/]+([^\/]+)[\/]+([^\?]+)/);
var query = querystring.parse(parsed.query);
return !!matches[3];
};

View file

@ -14,10 +14,7 @@ var rdio = require('rdio')({
rdio_api_shared: process.env.RDIO_API_SHARED, rdio_api_shared: process.env.RDIO_API_SHARED,
}); });
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
var parsed = parse(url);
return parsed.host.match(/rd\.io$/) || parsed.host.match(/rdio\.com$/);
};
module.exports.lookupId = function(id) { module.exports.lookupId = function(id) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -76,7 +73,7 @@ module.exports.parseUrl = function(url) {
} else { } else {
var error = new Error("Not Found"); var error = new Error("Not Found");
error.status = 404; error.status = 404;
deferred.reject(error); return deferred.reject(error);
} }
rdio.api("", "", data, function(err, results) { rdio.api("", "", data, function(err, results) {
@ -85,7 +82,7 @@ module.exports.parseUrl = function(url) {
if (!result || results.status != "ok") { if (!result || results.status != "ok") {
var error = new Error("Not Found"); var error = new Error("Not Found");
error.status = 404; error.status = 404;
deferred.reject(error); return deferred.reject(error);
} else { } else {
var parsed = parse(result.shortUrl) var parsed = parse(result.shortUrl)
var id = parsed.path.replace("/x/", "").replace("/", ""); var id = parsed.path.replace("/x/", "").replace("/", "");

11
lib/services/rdio/url.js Normal file
View file

@ -0,0 +1,11 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url) {
var parsed = parse(url);
if (!parsed.host.match(/rd\.io$/) && !parsed.host.match(/rdio\.com$/)) {
return false;
}
var matches = parsed.path.match(/[\/]*artist[\/]*([^\/]*)[\/]*album[\/]*([^\/]*)[\/]*([track]*)?[\/]*([^\/]*)/);
return !!matches[2];
};

View file

@ -5,10 +5,17 @@ var Q = require('q');
module.exports.id = "spotify"; module.exports.id = "spotify";
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
var parsed = parse(url);
return parsed.host.match(/spotify\.com$/); 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]).then(deferred.resolve);
}
return deferred.promise;
}
module.exports.lookupId = function(id, type) { module.exports.lookupId = function(id, type) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -95,13 +102,3 @@ module.exports.search = function(data) {
}); });
return deferred.promise; return deferred.promise;
} }
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]).then(deferred.resolve);
}
return deferred.promise;
}

View file

@ -0,0 +1,12 @@
"use strict";
var parse = require('url').parse;
module.exports.match = function(url, type) {
var parsed = parse(url);
if (!parsed.host.match(/spotify\.com$/)) {
return false;
}
var matches = parse(url).path.match(/\/(album|track)[\/]+([^\/]+)/);
return !!matches[2];
};

View file

@ -16,9 +16,7 @@ var credentials = {
var apiRoot = "https://www.googleapis.com/youtube/v3"; var apiRoot = "https://www.googleapis.com/youtube/v3";
module.exports.match = function(url, type) { module.exports.match = require('./url').match;
return false;
};
module.exports.search = function(data) { module.exports.search = function(data) {
var deferred = Q.defer(); var deferred = Q.defer();
@ -33,7 +31,7 @@ module.exports.search = function(data) {
album = data.album.name album = data.album.name
} }
var path = "/search?part=snippet&q=" + encodeURIComponent(query) + "&type=video&videoCaption=any&key=" + credentials.key; var path = "/search?part=snippet&q=" + encodeURIComponent(query) + "&type=video&videoCaption=any&videoCategoryId=10&key=" + credentials.key;
request.get(apiRoot + path, function(res) { request.get(apiRoot + path, function(res) {
var result = res.body.items[0]; var result = res.body.items[0];

View file

@ -0,0 +1,5 @@
"use strict";
module.exports.match = function(url, type) {
return false;
};

View file

@ -36,7 +36,7 @@ module.exports = function(req, res, next) {
error = new Error("Error talking to music service"); error = new Error("Error talking to music service");
error.status = "502"; error.status = "502";
next(error); next(error);
} else if (!error.status) { } else if (!error || !error.status) {
error = new Error("An unexpected error happenend"); error = new Error("An unexpected error happenend");
error.status = 500; error.status = 500;
next(error); next(error);

View file

@ -7,14 +7,14 @@ var beats = require("../../lib/services/beats");
describe('Beats Music', function(){ describe('Beats Music', function(){
describe('lookupId', function(){ describe('lookupId', function(){
it('should find album by ID', function(done){ it('should find album by ID', function(done){
beats.lookupId("al920431").then(function(result) { beats.lookupId("al920431", "album").then(function(result) {
result.name.should.equal("Deftones"); result.name.should.equal("Deftones");
done(); done();
}); });
}); });
it('should find track by ID', function(done){ it('should find track by ID', function(done){
beats.lookupId("tr6910289").then(function(result) { beats.lookupId("tr6910289", "track").then(function(result) {
result.name.should.equal("Californication"); result.name.should.equal("Californication");
done(); done();
}); });

View file

@ -2,12 +2,12 @@
var assert = require("assert"); var assert = require("assert");
var should = require('should'); var should = require('should');
var googleplaymusic = require("../../lib/services/googleplaymusic"); var google = require("../../lib/services/google");
describe('Google Play Music', function(){ describe('Google Play Music', function(){
describe('lookupId', function(){ describe('lookupId', function(){
it('should find album by ID', function(done){ it('should find album by ID', function(done){
googleplaymusic.lookupId("Byp6lvzimyf74wxi5634ul4tgam", "album").then(function(result) { google.lookupId("Byp6lvzimyf74wxi5634ul4tgam", "album").then(function(result) {
result.name.should.equal("Listen (Deluxe)"); result.name.should.equal("Listen (Deluxe)");
done(); done();
}); });
@ -16,7 +16,7 @@ describe('Google Play Music', function(){
describe('search', function(){ describe('search', function(){
it('should find album by search', function(done){ it('should find album by search', function(done){
googleplaymusic.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}).then(function(result) { google.search({type: "album", artist: {name: "David Guetta"}, name: "Listen (Deluxe)"}).then(function(result) {
result.name.should.equal("Listen (Deluxe)"); result.name.should.equal("Listen (Deluxe)");
done(); done();
}); });
@ -25,21 +25,21 @@ describe('Google Play Music', function(){
describe('lookupUrl', function(){ describe('lookupUrl', function(){
it('should parse regular url into album ID', function(done){ 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) { google.parseUrl("https://play.google.com/music/listen#/album/Byp6lvzimyf74wxi5634ul4tgam/David+Guetta/Listen+(Deluxe)").then(function(result) {
result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam");
done(); done();
}); });
}); });
it('should parse url without ID into album ID', function(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) { google.parseUrl("https://play.google.com/music/listen#/album//David+Guetta/Listen+(Deluxe)").then(function(result) {
result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam");
done(); done();
}); });
}); });
it('should parse share url into album ID', function(done){ it('should parse share url into album ID', function(done){
googleplaymusic.parseUrl("https://play.google.com/music/m/Byp6lvzimyf74wxi5634ul4tgam").then(function(result) { google.parseUrl("https://play.google.com/music/m/Byp6lvzimyf74wxi5634ul4tgam").then(function(result) {
result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam"); result.id.should.equal("Byp6lvzimyf74wxi5634ul4tgam");
done(); done();
}); });

57
test/services/itunes.js Normal file
View file

@ -0,0 +1,57 @@
"use strict";
var assert = require("assert");
var should = require('should');
var itunes = require("../../lib/services/itunes");
describe('iTunes Music', function(){
describe('lookupId', function(){
it('should find album by ID', function(done){
itunes.lookupId("id215206912").then(function(result) {
result.name.should.equal("Peace Orchestra");
done();
});
});
it('should find track by ID', function(done){
itunes.lookupId("id215206958").then(function(result) {
result.name.should.equal("Double Drums");
done();
});
});
});
describe('search', function(){
it('should find album by search', function(done){
itunes.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){
itunes.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){
itunes.parseUrl("https://itunes.apple.com/us/album/double-drums/id215206912").then(function(result) {
result.id.should.equal("us215206912");
done();
});
});
it('should parse track url into ID', function(done){
itunes.parseUrl("https://itunes.apple.com/us/album/double-drums/id215206912?i=215206958&uo=4").then(function(result) {
result.id.should.equal("us215206958");
done();
});
});
});
});
});

16
test/services/youtube.js Normal file
View file

@ -0,0 +1,16 @@
"use strict";
var assert = require("assert");
var should = require('should');
var youtube = require("../../lib/services/youtube");
describe('Youtube', function(){
describe('search', function(){
it('should find album by search', function(done){
youtube.search({type: "track", artist: {name: "Aesop Rock"}, album: {name: "Skelethon"}, name: "Zero Dark Thirty"}).then(function(result) {
result.name.should.equal("Aesop Rock - Zero Dark Thirty");
done();
});
});
});
});