diff --git a/README.md b/README.md index d884662..7e9b188 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ This is in super early development, has no design and only supports albums right On the immediate todo list: -* Add support for tracks, and maybe artists * Use album release year for additional sanity check on matches -* Do some kind of a design, particularly for the share page * Handle expected and unexpected errors better than the current crash-fest +* Use promises for service searches and do them simultaneously diff --git a/lib/beats.js b/lib/beats.js new file mode 100644 index 0000000..a2599a5 --- /dev/null +++ b/lib/beats.js @@ -0,0 +1,87 @@ +"use strict"; +var parse = require('url').parse; +var request = require('superagent'); + +if (!process.env.BEATS_KEY || !process.env.BEATS_SECRET) { + throw new Error("You need to set BEATS_KEY and BEATS_SECRET environment variables"); +} + +var credentials = { + key: process.env.BEATS_KEY, + secret: process.env.BEATS_SECRET +}; + +var apiRoot = "https://partner.api.beatsmusic.com/v1/api"; + +module.exports.lookupId = function(id, next) { + 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({ + service: "beats", + type: "album", + id: result.id, + name: result.title, + url: "https://listen.beatsmusic.com/albums/" + result.id, + artwork: artwork, + artist: { + name: result.artist_display_name + } + }); + }); + }); + } else if (id.substr(0,2) == "tr") { + request.get(apiRoot + "/tracks/" + id + "?client_id=" + credentials.key, function(res) { + 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({ + service: "beats", + type: "track", + id: result.id, + name: result.title, + url: "https://listen.beatsmusic.com/albums/" + result.refs.album.id + "/tracks/" + result.id, + artwork: artwork, + artist: { + name: result.artist_display_name + }, + album: { + name: result.refs.album.display + } + }); + }); + }); + } +}; + +module.exports.search = function(data, next) { + 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?q=" + encodeURIComponent(query) + "&type=" + type + "&client_id=" + credentials.key; + request.get(apiRoot + path, function(res) { + if (!res.body.data[0]) { + next({service: "beats"}); + } else { + module.exports.lookupId(res.body.data[0].id, next); + } + }); +}; + +module.exports.parseUrl = function(url, next) { + var matches = parse(url).path.match(/\/albums[\/]+([^\/]+)(\/tracks\/)?([^\/]+)?/); + + if (matches && matches[3]) { + module.exports.lookupId(matches[3], next); + } else if (matches && matches[1]) { + module.exports.lookupId(matches[1], next); + } +} diff --git a/lib/rdio.js b/lib/rdio.js index 48606ec..6e1724e 100644 --- a/lib/rdio.js +++ b/lib/rdio.js @@ -92,13 +92,13 @@ module.exports.search = function(data, next) { var result = results.filter(function(result) { if (type == "album" && result.name == data.name) { return result; - } else if (type == "track" && result.album.name == data.album) { + } else if (type == "track" && result.album == data.album.name) { return result; } }).shift(); - console.log(result) + if (!result) { - return next({}); + return next({service: "rdio"}); } var parsed = parse(result.shortUrl) var id = parsed.path.replace("/x/", "").replace("/", ""); diff --git a/package.json b/package.json index 0d9252e..60a4643 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "playmusic": "^1.1.0", "rdio": "^1.5.2", "serve-favicon": "~2.1.3", - "spotify": "^0.3.0" + "spotify": "^0.3.0", + "superagent": "^0.21.0" }, "devDependencies": { "should": "^4.3.0", diff --git a/public/images/beats.png b/public/images/beats.png new file mode 100644 index 0000000..e47c634 Binary files /dev/null and b/public/images/beats.png differ diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index 6fabdeb..802489c 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -65,6 +65,9 @@ h2 { .album-artwork { margin-bottom: 10px; } +.not-found { + opacity: 0.3; +} .service-link { text-align: center; } diff --git a/routes/index.js b/routes/index.js index 2f1cd40..14e12ca 100644 --- a/routes/index.js +++ b/routes/index.js @@ -6,6 +6,7 @@ var router = express.Router(); var googleplaymusic = require('../lib/googleplaymusic'); var spotify = require('../lib/spotify'); var rdio = require('../lib/rdio'); +var beats = require('../lib/beats'); var cache = {googleplaymusic:{}, spotify:{},rdio:{}}; @@ -23,7 +24,10 @@ router.get('/:service/:type/:id', function(req, res) { items.push(item); rdio.search(result, function(item) { items.push(item); - res.render(result.type, {items: items}); + beats.search(result, function(item) { + items.push(item); + res.render(result.type, {items: items}); + }); }); }); }); @@ -35,7 +39,10 @@ router.get('/:service/:type/:id', function(req, res) { items.push(item); rdio.search(result, function(item) { items.push(item); - res.render(result.type, {items: items}); + beats.search(result, function(item) { + items.push(item); + res.render(result.type, {items: items}); + }); }); }); }); @@ -47,7 +54,25 @@ router.get('/:service/:type/:id', function(req, res) { items.push(item); spotify.search(result, function(item) { items.push(item); - res.render(result.type, {items: items}); + 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}); + }); }); }); }); @@ -56,7 +81,6 @@ router.get('/:service/:type/:id', function(req, res) { }); router.post('/search', function(req, res) { - // determine spotify or google music var url = parse(req.body.url); if (!url.host) { @@ -90,6 +114,14 @@ router.post('/search', function(req, res) { 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('/'); diff --git a/views/album.ejs b/views/album.ejs index b503a3e..cedc15a 100644 --- a/views/album.ejs +++ b/views/album.ejs @@ -32,10 +32,17 @@