From da5daeeffbbca5710e8475c81f3785c6f829c551 Mon Sep 17 00:00:00 2001 From: Jonathan Cremin Date: Thu, 4 Dec 2014 21:11:55 +0000 Subject: [PATCH] Add support for iTunes purchases --- lib/services/beats.js | 6 +- lib/services/deezer.js | 3 +- lib/services/googleplaymusic.js | 6 +- lib/services/itunes.js | 106 ++++++++++++++++++++++++++++++++ lib/services/rdio.js | 9 ++- lib/services/spotify.js | 6 +- public/images/itunes.png | Bin 0 -> 5737 bytes routes/index.js | 4 ++ views/album.ejs | 15 +++-- 9 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 lib/services/itunes.js create mode 100644 public/images/itunes.png diff --git a/lib/services/beats.js b/lib/services/beats.js index e69a976..164575e 100644 --- a/lib/services/beats.js +++ b/lib/services/beats.js @@ -34,7 +34,8 @@ module.exports.lookupId = function(id) { type: "album", id: result.id, name: result.title, - url: "https://listen.beatsmusic.com/albums/" + result.id, + streamUrl: "https://listen.beatsmusic.com/albums/" + result.id, + purchaseUrl: null, artwork: artwork, artist: { name: result.artist_display_name @@ -52,7 +53,8 @@ module.exports.lookupId = function(id) { type: "track", id: result.id, name: result.title, - url: "https://listen.beatsmusic.com/albums/" + result.refs.album.id + "/tracks/" + result.id, + streamUrl: "https://listen.beatsmusic.com/albums/" + result.refs.album.id + "/tracks/" + result.id, + purchaseUrl: null, artwork: artwork, artist: { name: result.artist_display_name diff --git a/lib/services/deezer.js b/lib/services/deezer.js index c3ba5b4..04e2443 100644 --- a/lib/services/deezer.js +++ b/lib/services/deezer.js @@ -27,7 +27,8 @@ module.exports.lookupId = function(id, type) { type: type, id: result.id, name: result.title, - url: result.link, + streamUrl: result.link, + purchaseUrl: null, artwork: artwork, artist: { name: result.artist.name diff --git a/lib/services/googleplaymusic.js b/lib/services/googleplaymusic.js index e8e6dfe..668faf6 100644 --- a/lib/services/googleplaymusic.js +++ b/lib/services/googleplaymusic.js @@ -28,7 +28,8 @@ module.exports.lookupId = function(id, type, next) { type: "album", id: album.albumId, name: album.name, - url: "https://play.google.com/music/listen#/album/" + album.albumId, + streamUrl: "https://play.google.com/music/listen#/album/" + album.albumId, + purchaseUrl: "https://play.google.com/store/music/album?id=" + album.albumId, artwork: album.albumArtRef.replace("http:", ""), artist: { name: album.artist @@ -42,7 +43,8 @@ module.exports.lookupId = function(id, type, next) { type: "track", id: track.nid, name: track.title, - url: "https://play.google.com/music/listen#/track/" + track.nid + "/" + track.albumId, + streamUrl: "https://play.google.com/music/listen#/track/" + track.nid + "/" + track.albumId, + purchaseUrl: "https://play.google.com/store/music/album?id=" + track.albumId, artwork: track.albumArtRef[0].url.replace("http:", ""), album: { name: track.album diff --git a/lib/services/itunes.js b/lib/services/itunes.js new file mode 100644 index 0000000..96f541c --- /dev/null +++ b/lib/services/itunes.js @@ -0,0 +1,106 @@ +"use strict"; +var parse = require('url').parse; +var request = require('superagent'); +var Q = require('q'); + +module.exports.id = "itunes"; + +var apiRoot = "https://itunes.apple.com"; + +module.exports.match = function(url, type) { + var parsed = parse(url); + return parsed.host.match(/itunes.apple\.com$/); +}; + +module.exports.lookupId = function(id, type) { + var deferred = Q.defer(); + if (type == "album") { + 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; + deferred.resolve({ + service: "itunes", + 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 (type == "track") { + 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; + deferred.resolve({ + service: "itunes", + type: "track", + id: result.id, + name: result.title, + purchaseUrl: "https://listen.beatsmusic.com/albums/" + result.refs.album.id + "/tracks/" + result.id, + streamUrl: null, + artwork: artwork, + artist: { + name: result.artist_display_name + }, + album: { + name: result.refs.album.display + } + }); + }); + }); + } + return deferred.promise; +} + +module.exports.search = function(data) { + 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?term=" + encodeURIComponent(query) + "&media=music&entity=album" + request.get(apiRoot + path, function(res) { + var data = JSON.parse(res.text); + if (!data.results[0].collectionId) { + deferred.resolve({service: "itunes"}); + } else { + var result = data.results[0]; + + deferred.resolve({ + service: "itunes", + type: type, + id: result.collectionId, + name: result.collectionName, + streamUrl: null, + purchaseUrl: result.collectionViewUrl, + artwork: result.artworkUrl100.replace("100x100", "200x200"), + artist: { + name: result.artistName + } + }); + } + }); + + 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; +} diff --git a/lib/services/rdio.js b/lib/services/rdio.js index ddea295..fb71f63 100644 --- a/lib/services/rdio.js +++ b/lib/services/rdio.js @@ -34,7 +34,8 @@ module.exports.lookupId = function(id) { type: type, id: id, name: result.name, - url: result.shortUrl, + streamUrl: result.shortUrl, + purchaseUrl: null, artwork: result.icon.replace("http:", "").replace("square-200", "square-250"), artist: { name: result.artist @@ -74,7 +75,8 @@ module.exports.parseUrl = function(url) { type: type, id: id, name: result.name, - url: result.shortUrl, + streamUrl: result.shortUrl, + purchaseUrl: null, artwork: result.icon.replace("http:", "").replace("square-200", "square-250"), artist: { name: result.artist @@ -120,7 +122,8 @@ module.exports.search = function(data) { type: type, id: id, name: result.name, - url: result.shortUrl, + streamUrl: result.shortUrl, + purchaseUrl: null, artwork: result.icon.replace("http:", "").replace("square-200", "square-250"), artist: { name: result.artist diff --git a/lib/services/spotify.js b/lib/services/spotify.js index bea5a63..111a017 100644 --- a/lib/services/spotify.js +++ b/lib/services/spotify.js @@ -26,7 +26,8 @@ module.exports.lookupId = function(id, type) { type: type, id: data.id, name: data.name, - url: "https://play.spotify.com/" + type + "/" + data.id, + streamUrl: "https://play.spotify.com/" + type + "/" + data.id, + purchaseUrl: null, artwork: data.images ? data.images[1].url.replace("http:", "") : data.album.images[1].url.replace("http:", ""), artist: { name: artist.name @@ -38,7 +39,8 @@ module.exports.lookupId = function(id, type) { type: type, id: data.id, name: data.name, - url: "https://play.spotify.com/" + type + "/" + data.id, + streamUrl: "https://play.spotify.com/" + type + "/" + data.id, + purchaseUrl: null, artwork: data.images ? data.images[1].url.replace("http:", "") : data.album.images[1].url.replace("http:", ""), artist: { name: artist.name diff --git a/public/images/itunes.png b/public/images/itunes.png new file mode 100644 index 0000000000000000000000000000000000000000..62605785c32820da7e87bb4dc2d7d653891064f3 GIT binary patch literal 5737 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
">
<%= i==0 ? "Found matches for this link" : "" %>
- <% if (album.url) { %> - + <% if (album.streamUrl) { %> + - <% } else { %> + <% } else if (album.purchaseUrl) { %> + + + <% }else { %> <% } %>
- + <% if((i+1)%4 == 0) { %>
<% } %> <% } %>