From 1a7896716f4bdf6ad891821d595b214cf51e1dc4 Mon Sep 17 00:00:00 2001 From: Jonathan Cremin Date: Thu, 4 Dec 2014 15:45:52 +0000 Subject: [PATCH] Add Beats music support --- README.md | 3 +- lib/beats.js | 87 +++++++++++++++++++++++++++++++++++ lib/rdio.js | 6 +-- package.json | 3 +- public/images/beats.png | Bin 0 -> 10800 bytes public/stylesheets/style.css | 3 ++ routes/index.js | 40 ++++++++++++++-- views/album.ejs | 15 ++++-- views/track.ejs | 15 ++++-- 9 files changed, 154 insertions(+), 18 deletions(-) create mode 100644 lib/beats.js create mode 100644 public/images/beats.png 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 0000000000000000000000000000000000000000..e47c634a0c1f96cc1fce9b118ee6b30fecaad607 GIT binary patch literal 10800 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
">
<%= i==0 ? "Found matches for this link" : "" %>
- - + <% if (album.url) { %> + + + <% } else { %> + + + <% } %>
<% } %> diff --git a/views/track.ejs b/views/track.ejs index 5ec2271..e2e24a1 100644 --- a/views/track.ejs +++ b/views/track.ejs @@ -32,10 +32,17 @@
">
<%= i==0 ? "Found matches for this link" : "" %>
- - + <% if (track.url) { %> + + + <% } else { %> + + + <% } %>
<% } %>