From 00ca82c851e8760dfcb5cc6fd4faf596d9ebb4eb Mon Sep 17 00:00:00 2001
From: Jonathan Cremin <jonathan@crem.in>
Date: Sun, 7 May 2017 20:57:12 +0100
Subject: [PATCH] Improve Deezer matching

---
 lib/services/deezer/index.js | 50 +++++++++++++++++++++++++++++++++---
 test/services/deezer.js      |  5 ++++
 test/services/spotify.js     |  2 +-
 3 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/lib/services/deezer/index.js b/lib/services/deezer/index.js
index 948785a..a2dea0a 100644
--- a/lib/services/deezer/index.js
+++ b/lib/services/deezer/index.js
@@ -75,15 +75,22 @@ export function* lookupId(id, type) {
   }
 };
 
-export function* search(data) {
+export function* search(data, original={}) {
   let cleanParam = function(str) {
     return str.replace(/[\:\?\&]+/, '');
   };
   let query, album;
   let {type} = data;
 
+  const various = data.artist.name === 'Various Artists' || data.artist.name === 'Various';
+
   if (type === 'album') {
-    query = cleanParam(data.artist.name) + ' ' + cleanParam(data.name);
+    // Deezer is shitty about artists with these names, strip them instead
+    if (various) {
+      query = cleanParam(data.name);
+    } else {
+      query = cleanParam(data.artist.name) + ' ' + cleanParam(data.name);
+    }
     album = data.name;
   } else if (type === 'track') {
     query = cleanParam(data.artist.name) + ' ' + cleanParam(data.albumName) + ' ' + cleanParam(data.name);
@@ -91,8 +98,17 @@ export function* search(data) {
   }
 
   var path = '/search/' + type + '?q=' + encodeURIComponent(query);
+
   let response = yield request.get(apiRoot + path);
-  if (response.body.data[0]) {
+
+  const name = original.name || data.name;
+
+  if (response.body.data.length > 0) {
+    let match;
+    if (!(match = exactMatch(name, response.body.data, data.type, various))) {
+      match = looseMatch(name, response.body.data, data.type, various);
+    }
+
     return yield module.exports.lookupId(response.body.data[0].id, type);
   } else {
     var matches = album.match(/^[^\(\[]+/);
@@ -103,9 +119,35 @@ export function* search(data) {
       } else if (type === 'track') {
         cleanedData.albumName = matches[0].trim();
       }
-      return yield module.exports.search(cleanedData);
+      return yield module.exports.search(cleanedData, data);
     } else {
       return Promise.resolve({service: 'deezer'});
     }
   }
 };
+
+function exactMatch(needle, haystack, type, various) {
+    // try to find exact match
+  return haystack.find(function(entry) {
+    if (!entry[type] || (various && (entry.artist.name !== 'Various' || entry.artist.name !== 'Various Artists'))) {
+      return false;
+    }
+    entry = entry[type];
+    if (entry.title === needle) {
+      return entry;
+    }
+  });
+}
+
+function looseMatch(needle, haystack, type, various) {
+    // try to find exact match
+  return haystack.find(function(entry) {
+    if (!entry[type] || (various && (entry.artist.name !== 'Various' || entry.artist.name !== 'Various Artists'))) {
+      return false;
+    }
+    const name = entry[type].title || entry[type].name;
+    if (name.indexOf(needle) >= 0) {
+      return entry[type];
+    }
+  });
+}
diff --git a/test/services/deezer.js b/test/services/deezer.js
index 91d3734..f86d326 100644
--- a/test/services/deezer.js
+++ b/test/services/deezer.js
@@ -20,6 +20,11 @@ describe('Deezer', function(){
       result.name.should.startWith('In Colour');
     });
 
+    it('should find album with various artists by search', function* (){
+      const result = yield deezer.search({type: 'album', artist: {name: 'Various Artists'}, name: 'The Trevor Nelson Collection'});
+      result.name.should.equal('The Trevor Nelson Collection');
+    });
+
     it('should find track by search', function* (){
       const result = yield deezer.search({type: 'track', artist: {name: 'Deftones'}, albumName: 'Deftones', name: 'Hexagram'});
       result.name.should.equal('Hexagram');
diff --git a/test/services/spotify.js b/test/services/spotify.js
index ed229fc..60c7bad 100644
--- a/test/services/spotify.js
+++ b/test/services/spotify.js
@@ -20,7 +20,7 @@ describe('Spotify', function(){
       result.name.should.equal('Listen (Deluxe)');
     });
 
-    it('should find album with colon in name by search', function* (){
+    it('should find album by various artists by search', function* (){
       const result = yield spotify.search({type: 'album', artist: {name: 'Various Artists'}, name: 'The Get Down Part II: Original Soundtrack From The Netflix Original Series'});
       result.name.should.equal('The Get Down Part II: Original Soundtrack From The Netflix Original Series');
     });