UNPKG

lyricist

Version:

Fetches song lyrics using the Genius.com API and website.

205 lines (147 loc) 5.67 kB
'use strict'; function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } const fetch = require('node-fetch'); const cheerio = require('cheerio'); module.exports = class Lyricist { constructor(accessToken) { if (!accessToken) throw new Error('No access token provided to lyricist!'); this.accessToken = accessToken; } /* Main request function */ _request(path) { var _this = this; return _asyncToGenerator(function* () { const url = `https://api.genius.com/${path}`; const headers = { Authorization: `Bearer ${_this.accessToken}` }; // Fetch result and parse it as JSON const body = yield fetch(url, { headers }); const result = yield body.json(); // Handle errors if (result.error) throw new Error(`${result.error}: ${result.error_description}`); if (result.meta.status !== 200) throw new Error(`${result.meta.status}: ${result.meta.message}`); return result.response; })(); } /* Get song by ID */ song(id, { fetchLyrics = false, textFormat = 'dom' } = {}) { var _this2 = this; return _asyncToGenerator(function* () { if (!id) throw new Error('No ID was provided to lyricist.song()'); const path = `songs/${id}?text_format=${textFormat}`; var _ref = yield _this2._request(path); const song = _ref.song; const lyrics = fetchLyrics ? yield _this2._scrapeLyrics(song.url) : null; return Object.assign({ lyrics }, song); })(); } /* Get album by ID */ album(id, { fetchTracklist = false, textFormat = 'dom' } = {}) { var _this3 = this; return _asyncToGenerator(function* () { if (!id) throw new Error('No ID was provided to lyricist.album()'); const path = `albums/${id}?text_format=${textFormat}`; var _ref2 = yield _this3._request(path); const album = _ref2.album; const tracklist = fetchTracklist ? yield _this3._scrapeTracklist(album.url) : null; return Object.assign({ tracklist }, album); })(); } /* Get artist by ID */ artist(id, { textFormat = 'dom' } = {}) { var _this4 = this; return _asyncToGenerator(function* () { if (!id) throw new Error('No ID was provided to lyricist.artist()'); const path = `artists/${id}?text_format=${textFormat}`; var _ref3 = yield _this4._request(path); const artist = _ref3.artist; return artist; })(); } /* Get artist by exact name (undocumented, likely to change) Potentially unreliable, use at own risk! ⚠️ */ artistByName(name, opts) { var _this5 = this; return _asyncToGenerator(function* () { const slug = _this5._geniusSlug(name); const id = yield _this5._scrapeArtistPageForArtistID(slug); return _this5.artist(id, opts); })(); } /* Get artist songs */ songsByArtist(id, { page = 1, perPage = 20, sort = 'title' } = {}) { var _this6 = this; return _asyncToGenerator(function* () { if (!id) throw new Error('No ID was provided to lyricist.songsByArtist()'); const path = `artists/${id}/songs?per_page=${perPage}&page=${page}&sort=${sort}`; var _ref4 = yield _this6._request(path); const songs = _ref4.songs; return songs; })(); } /* Search (for songs) */ search(query) { var _this7 = this; return _asyncToGenerator(function* () { if (!query) throw new Error('No query was provided to lyricist.search()'); const path = `search?q=${query}`; const response = yield _this7._request(path); return response.hits.map(function (hit) { return hit.result; }); })(); } /* Scrape tracklist */ _scrapeTracklist(url) { return _asyncToGenerator(function* () { const html = yield fetch(url).then(function (res) { return res.text(); }); const $ = cheerio.load(html); const json = $('meta[itemprop="page_data"]').attr('content'); const parsed = JSON.parse(json); const songs = parsed.album_appearances; return songs.map(function ({ song, track_number }) { return Object.assign({ track_number }, song); }); })(); } /* Scrape song lyrics */ _scrapeLyrics(url) { return _asyncToGenerator(function* () { const response = yield fetch(url); const text = yield response.text(); const $ = cheerio.load(text); return $('.lyrics').text().trim(); })(); } /* Get slug from name/title */ _geniusSlug(string) { // Probably not 100% accurate yet // Currently only used by undocumented artistByName function const slug = string.trim().replace(/\s+/g, '-').replace("'", '').replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); // Uppercase first letter return slug.charAt(0).toUpperCase() + slug.slice(1); } /* Scrape artist page to retrieve artist ID */ _scrapeArtistPageForArtistID(slug) { return _asyncToGenerator(function* () { const url = `https://genius.com/artists/${slug}`; const html = yield fetch(url).then(function (res) { return res.text(); }); const $ = cheerio.load(html); const id = $('meta[name="newrelic-resource-path"]').attr('content').split('/').pop(); return id; })(); } };