152 lines
3.9 KiB
JavaScript
152 lines
3.9 KiB
JavaScript
import { parse } from 'url';
|
|
import SpotifyWebApi from 'spotify-web-api-node';
|
|
import urlMatch from './url.js';
|
|
|
|
const spotify = new SpotifyWebApi({
|
|
clientId: process.env.SPOTIFY_CLIENT_ID,
|
|
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
|
|
redirectUri: 'https://combine.fm',
|
|
});
|
|
|
|
|
|
function exactMatch(needle, haystack, type) {
|
|
// try to find exact match
|
|
return haystack.find((entry) => {
|
|
if (entry.type !== type) {
|
|
return false;
|
|
}
|
|
|
|
if (entry.name === needle) {
|
|
return entry;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function looseMatch(needle, haystack, type) {
|
|
// try to find exact match
|
|
return haystack.find((entry) => {
|
|
if (entry.type !== type) {
|
|
return false;
|
|
}
|
|
|
|
if (entry.name.indexOf(needle) >= 0) {
|
|
return entry;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
export async function lookupId(id, type) {
|
|
const token = await spotify.clientCredentialsGrant();
|
|
spotify.setAccessToken(token.body.access_token);
|
|
let data = await spotify[`get${type.charAt(0).toUpperCase()}${type.slice(1)}s`]([id]);
|
|
|
|
data = data.body[`${type}s`][0];
|
|
|
|
if(!data) {
|
|
const error = new Error('Not Found');
|
|
error.status = 404;
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
const artist = data.artists[0];
|
|
|
|
if (type === 'album') {
|
|
return {
|
|
service: 'spotify',
|
|
type,
|
|
id: data.id,
|
|
name: data.name,
|
|
streamUrl: `https://play.spotify.com/${type}/${data.id}`,
|
|
purchaseUrl: null,
|
|
artwork: {
|
|
small: data.images[1].url.replace('http:', 'https:'),
|
|
large: data.images[0].url.replace('http:', 'https:'),
|
|
},
|
|
artist: {
|
|
name: artist.name,
|
|
},
|
|
};
|
|
} else if (type === 'track') {
|
|
return {
|
|
service: 'spotify',
|
|
type,
|
|
id: data.id,
|
|
name: data.name,
|
|
streamUrl: `https://play.spotify.com/${type}/${data.id}`,
|
|
purchaseUrl: null,
|
|
artwork: {
|
|
small: data.album.images[1].url.replace('http:', 'https:'),
|
|
large: data.album.images[0].url.replace('http:', 'https:'),
|
|
},
|
|
artist: {
|
|
name: artist.name,
|
|
},
|
|
album: {
|
|
name: data.album.name,
|
|
},
|
|
};
|
|
}
|
|
const error = new Error('Not Found');
|
|
error.status = 404;
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
export async function search(data, original = {}) {
|
|
const token = await spotify.clientCredentialsGrant();
|
|
spotify.setAccessToken(token.body.access_token);
|
|
|
|
const markets = ['US', 'GB', 'JP', 'BR', 'DE', 'ES'];
|
|
function cleanParam(str) {
|
|
const chopChars = ['&', '[', '('];
|
|
chopChars.forEach((chr) => {
|
|
if (data.artist.name.indexOf('&') > 0) {
|
|
str = str.substring(0, data.artist.name.indexOf(chr)); // eslint-disable-line no-param-reassign,max-len
|
|
}
|
|
});
|
|
return str.replace(/[:?]+/, '');
|
|
}
|
|
let query;
|
|
const type = data.type;
|
|
|
|
if (type === 'album') {
|
|
query = `artist:${cleanParam(data.artist.name)} album:${cleanParam(data.name)}`;
|
|
} else if (type === 'track') {
|
|
query = `artist:${cleanParam(data.artist.name)} track:${cleanParam(data.name)}${cleanParam(data.albumName).length > 0 ? ` album:${cleanParam(data.albumName)}` : ''}`;
|
|
}
|
|
|
|
for (const market of markets) { // eslint-disable-line
|
|
const response = await spotify[`search${type.charAt(0).toUpperCase()}${type.slice(1)}s`](query, { market });
|
|
|
|
const items = response.body[`${type}s`].items;
|
|
|
|
const name = original.name || data.name;
|
|
|
|
let match = exactMatch(name, items, type);
|
|
if (!match) {
|
|
match = looseMatch(name, items, type);
|
|
}
|
|
|
|
if (match) {
|
|
if (type === 'album') {
|
|
return await lookupId(match.id, type);
|
|
} else if (type === 'track') {
|
|
return await lookupId(match.id, type);
|
|
}
|
|
}
|
|
}
|
|
return { service: 'spotify' };
|
|
}
|
|
|
|
export async function parseUrl(url) {
|
|
const matches = parse(url).path.match(/\/(album|track)[/]+([A-Za-z0-9]+)/);
|
|
|
|
if (matches && matches[2]) {
|
|
return await lookupId(matches[2], matches[1]);
|
|
}
|
|
throw new Error();
|
|
}
|
|
|
|
export const id = 'spotify';
|
|
export const match = urlMatch;
|