UNPKG

spotify-dl

Version:

Spotify Songs, Playlist & Album Downloader

103 lines (97 loc) 3.14 kB
import { promisify } from 'util'; import YoutubeSearch from 'yt-search'; import StringSimilarity from 'string-similarity'; import Constants from './constants.js'; import { logInfo } from './log-helper.js'; const { YOUTUBE_SEARCH: { MAX_MINUTES, VALID_CONTEXTS }, INPUT_TYPES: { SONG }, } = Constants; const search = promisify(YoutubeSearch); /** * This function does the actual api calls to youtube * * @param {String} searchTerms string to search on youtube with * @param {String} type the type of item being searched * @param {String[]} exclusionFilters exclusion texts for description, title * @returns {String[]} youtube links */ const findLinks = async (searchTerms, type, exclusionFilters) => { logInfo(`searching youtube with keywords "${searchTerms}"`); const result = await search(searchTerms); const isSong = Object.values(SONG).includes(type); return result.videos .filter(video => !exclusionFilters || !( exclusionFilters.some( exclusionFilter => video.title.includes(exclusionFilter), ) || exclusionFilters.some( exclusionFilter => video.description.includes(exclusionFilter), ) ), ) .filter(video => ( (!isSong || (video.seconds < (MAX_MINUTES * 60))) && (video.seconds > 0) )) .slice(0, 10) .map(video => (video.url.includes('https://youtube.com')) ? video.url : 'https://youtube.com' + video.url); }; /** * This function searches youtube for given songname * and returns the link of topmost result * * @param {String} itemName name of song * @param {String} albumName name of album * @param {String} artistName name of artist * @param {String} extraSearch extra search terms * @param {String} type type of download being requested * @param {String[]} exclusionFilters exclusion texts for description, title * @returns {String[]} youtube links */ const getLinks = async ({ itemName, albumName, artistName, extraSearch, searchFormat, type, exclusionFilters, }) => { let links = []; if (searchFormat.length) { const contexts = searchFormat.match(/(?<=\{).+?(?=\})/g); const invalidContexts = contexts.filter( context => !VALID_CONTEXTS.includes(context), ); if (invalidContexts.length > 0 || !contexts.length) { throw new Error(`Invalid search contexts: ${invalidContexts}`); } contexts.forEach(context => searchFormat = searchFormat.replace(`{${context}}`, eval(context)), ); links = await findLinks(searchFormat, type, exclusionFilters); } if (!links.length) { const similarity = StringSimilarity.compareTwoStrings(itemName, albumName); // to avoid duplicate song downloads extraSearch = extraSearch ? ` ${extraSearch}` : ''; if (similarity < 0.5) { links = await findLinks( `${albumName} - ${itemName}${extraSearch}`, type, exclusionFilters, ); } if (!links.length) { links = await findLinks( `${artistName} - ${itemName}${extraSearch}`, type, exclusionFilters, ); } } return links; }; export default getLinks;