Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

lyricist

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lyricist - npm Package Compare versions

Comparing version 2.2.0 to 2.2.2

.prettierrc

102

lib/index.js

@@ -17,15 +17,20 @@ const fetch = require('node-fetch');

const headers = {
'Authorization': `Bearer ${this.accessToken}`,
Authorization: `Bearer ${this.accessToken}`,
};
const { meta, response } = await fetch(url, { headers })
.then(response => response.json());
if (meta.status !== 200) {
throw new Error(`${meta.status}: ${meta.message}`);
}
return response;
// Fetch result and parse it as JSON
const body = await fetch(url, { headers });
const result = await 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;
}
/*
Search song by ID
Get song by ID
*/

@@ -36,3 +41,4 @@

const { song } = await this._request(`songs/${id}?text_format=${textFormat}`);
const path = `songs/${id}?text_format=${textFormat}`;
const { song } = await this._request(path);

@@ -51,5 +57,8 @@ const lyrics = fetchLyrics ? await this._scrapeLyrics(song.url) : null;

const { album } = await this._request(`albums/${id}?text_format=${textFormat}`);
const path = `albums/${id}?text_format=${textFormat}`;
const { album } = await this._request(path);
const tracklist = fetchTracklist ? await this._scrapeTracklist(album.url) : null;
const tracklist = fetchTracklist
? await this._scrapeTracklist(album.url)
: null;

@@ -59,10 +68,23 @@ return Object.assign({ tracklist }, album);

/* Get artist */
/* Get artist by ID */
async artist(id, { textFormat = 'dom' } = {}) {
if (!id) throw new Error('No ID was provided to lyricist.artist()');
const { artist } = await this._request(`artists/${id}?text_format=${textFormat}`);
const path = `artists/${id}?text_format=${textFormat}`;
const { artist } = await this._request(path);
return artist;
}
/*
Get artist by exact name (undocumented, likely to change)
Potentially unreliable, use at own risk! ⚠️
*/
async artistByName(name, opts) {
const slug = this._geniusSlug(name);
const id = await this._scrapeArtistPageForArtistID(slug);
return this.artist(id, opts);
}
/* Get artist songs */

@@ -72,17 +94,21 @@

if (!id) throw new Error('No ID was provided to lyricist.songsByArtist()');
const { songs } = await this._request(
`artists/${id}/songs?per_page=${perPage}&page=${page}&sort=${sort}`
);
const path = `artists/${id}/songs?per_page=${perPage}&page=${page}&sort=${sort}`;
const { songs } = await this._request(path);
return songs;
}
/* Search (for songs) */
async search(query) {
if (!query) throw new Error('No query was provided to lyricist.search()');
const response = await this._request(`search?q=${query}`);
const path = `search?q=${query}`;
const response = await this._request(path);
return response.hits.map(hit => hit.result);
}
/*
Scrape tracklist
*/
/* Scrape tracklist */

@@ -96,3 +122,3 @@ async _scrapeTracklist(url) {

return songs.map(({ song, track_number }) =>
Object.assign({ track_number }, song)
Object.assign({ track_number }, song),
);

@@ -107,4 +133,34 @@ }

const $ = cheerio.load(text);
return $('.lyrics').text().trim();
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 */
async _scrapeArtistPageForArtistID(slug) {
const url = `https://genius.com/artists/${slug}`;
const html = await fetch(url).then(res => res.text());
const $ = cheerio.load(html);
const id = $('meta[name="newrelic-resource-path"]')
.attr('content')
.split('/')
.pop();
return id;
}
};

@@ -13,4 +13,15 @@ const Lyricist = require('./');

test('invalid request should return 403 status and throw error', async () => {
await expect(lyricist._request('abc')).toThrow();
test('invalid request should return 403 status and throw error', () =>
expect(lyricist._request('abc')).rejects.toEqual(
new Error('403: Action forbidden for current scope'),
));
test('request with invalid auth key should throw a helpful error', async done => {
const lyricist = new Lyricist("I'm an invalid auth key");
try {
await lyricist._request('songs/1');
} catch (e) {
expect(e.message).toMatch('invalid_token');
done();
}
});

@@ -25,3 +36,5 @@

test('scrape an album tracklist and return an array of songs', async () => {
const result = await lyricist._scrapeTracklist('http://genius.com/albums/Son-lux/Lanterns');
const result = await lyricist._scrapeTracklist(
'http://genius.com/albums/Son-lux/Lanterns',
);
expect(result).toBeInstanceOf(Array);

@@ -34,3 +47,5 @@ expect(result.length > 0).toBeTruthy();

test('scrape song lyrics and return text', async () => {
const result = await lyricist._scrapeLyrics('https://genius.com/Son-lux-alternate-world-lyrics');
const result = await lyricist._scrapeLyrics(
'https://genius.com/Son-lux-alternate-world-lyrics',
);
expect(result).toMatch(/Alternate world/);

@@ -40,4 +55,25 @@ });

describe('_geniusSlug', () => {
test('converts a name/title to the slug used by genius.com', async () => {
const namesAndExpectedSlugs = {
'Kanye West': 'Kanye-west',
'A$AP Rocky': 'A-ap-rocky',
'Alt J': 'Alt-j',
};
const names = Object.keys(namesAndExpectedSlugs);
const expectedSlugs = names.map(name => namesAndExpectedSlugs[name]);
const slugs = names.map(lyricist._geniusSlug);
expect(slugs).toEqual(expectedSlugs);
});
});
describe('_scrapeArtistPageForArtistID', () => {
test('scrape an artist page and return their genius ID', async () => {
const result = await lyricist._scrapeArtistPageForArtistID('Son-lux');
expect(result).toEqual('94423');
});
});
describe('song()', () => {
test('throw an error if no ID is given', async (done) => {
test('throw an error if no ID is given', async done => {
try {

@@ -63,3 +99,3 @@ await lyricist.song();

describe('album()', () => {
test('throw an error if no ID is given', async (done) => {
test('throw an error if no ID is given', async done => {
try {

@@ -86,3 +122,3 @@ await lyricist.album();

describe('artist()', () => {
test('throw an error if no ID is given', async (done) => {
test('throw an error if no ID is given', async done => {
try {

@@ -100,10 +136,19 @@ await lyricist.artist();

});
})
});
describe('artistByName()', () => {
test('load artist by name', async () => {
const result = await lyricist.artistByName('Son Lux');
expect(result.api_path).toEqual('/artists/94423');
});
});
describe('songsByArtist()', () => {
test('throw an error if no ID is given', async (done) => {
test('throw an error if no ID is given', async done => {
try {
await lyricist.songsByArtist();
} catch (e) {
expect(e.message).toEqual('No ID was provided to lyricist.songsByArtist()');
expect(e.message).toEqual(
'No ID was provided to lyricist.songsByArtist()',
);
done();

@@ -113,3 +158,3 @@ }

test('load artist songs', async() => {
test('load artist songs', async () => {
const result = await lyricist.songsByArtist(2);

@@ -119,3 +164,3 @@ expect(result[0]).toHaveProperty('title');

test('perPage option', async() => {
test('perPage option', async () => {
const perPage = 10;

@@ -126,10 +171,12 @@ const result = await lyricist.songsByArtist(2, { perPage });

test('page option', async() => {
test('page option', async () => {
const page = 2;
const result = await lyricist.songsByArtist(2, { page });
expect(result.find(t => t.title === 'Addicted to the Game').id).toEqual(3129);
expect(result.find(t => t.title === 'Addicted to the Game').id).toEqual(
3129,
);
});
test('sort option', async() => {
const sort = 'popularity'
test('sort option', async () => {
const sort = 'popularity';
const result = await lyricist.songsByArtist(2);

@@ -144,3 +191,3 @@ const resultWithSort = await lyricist.songsByArtist(2, { sort });

describe('search()', () => {
test('throw an error if no search term is given', async (done) => {
test('throw an error if no search term is given', async done => {
try {

@@ -155,7 +202,8 @@ await lyricist.search();

test('return search results', async () => {
const result = await lyricist.search('spirit of my silence I can hear you');
const result = await lyricist.search(
'spirit of my silence I can hear you',
);
expect(result[0].primary_artist.name).toEqual('Sufjan Stevens');
});
});
});

@@ -24,17 +24,14 @@ 'use strict';

const headers = {
'Authorization': `Bearer ${_this.accessToken}`
Authorization: `Bearer ${_this.accessToken}`
};
var _ref = yield fetch(url, { headers }).then(function (response) {
return response.json();
});
// Fetch result and parse it as JSON
const body = yield fetch(url, { headers });
const result = yield body.json();
const meta = _ref.meta,
response = _ref.response;
// 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}`);
if (meta.status !== 200) {
throw new Error(`${meta.status}: ${meta.message}`);
}
return response;
return result.response;
})();

@@ -44,3 +41,3 @@ }

/*
Search song by ID
Get song by ID
*/

@@ -54,7 +51,9 @@

var _ref2 = yield _this2._request(`songs/${id}?text_format=${textFormat}`);
const path = `songs/${id}?text_format=${textFormat}`;
const song = _ref2.song;
var _ref = yield _this2._request(path);
const song = _ref.song;
const lyrics = fetchLyrics ? yield _this2._scrapeLyrics(song.url) : null;

@@ -76,7 +75,9 @@

var _ref3 = yield _this3._request(`albums/${id}?text_format=${textFormat}`);
const path = `albums/${id}?text_format=${textFormat}`;
const album = _ref3.album;
var _ref2 = yield _this3._request(path);
const album = _ref2.album;
const tracklist = fetchTracklist ? yield _this3._scrapeTracklist(album.url) : null;

@@ -88,3 +89,3 @@

/* Get artist */
/* Get artist by ID */

@@ -97,6 +98,8 @@ artist(id, { textFormat = 'dom' } = {}) {

var _ref4 = yield _this4._request(`artists/${id}?text_format=${textFormat}`);
const path = `artists/${id}?text_format=${textFormat}`;
const artist = _ref4.artist;
var _ref3 = yield _this4._request(path);
const artist = _ref3.artist;
return artist;

@@ -106,6 +109,21 @@ })();

/*
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 _this5 = this;
var _this6 = this;

@@ -115,6 +133,9 @@ return _asyncToGenerator(function* () {

var _ref5 = yield _this5._request(`artists/${id}/songs?per_page=${perPage}&page=${page}&sort=${sort}`);
const path = `artists/${id}/songs?per_page=${perPage}&page=${page}&sort=${sort}`;
const songs = _ref5.songs;
var _ref4 = yield _this6._request(path);
const songs = _ref4.songs;
return songs;

@@ -124,8 +145,13 @@ })();

/* Search (for songs) */
search(query) {
var _this6 = this;
var _this7 = this;
return _asyncToGenerator(function* () {
if (!query) throw new Error('No query was provided to lyricist.search()');
const response = yield _this6._request(`search?q=${query}`);
const path = `search?q=${query}`;
const response = yield _this7._request(path);
return response.hits.map(function (hit) {

@@ -137,5 +163,3 @@ return hit.result;

/*
Scrape tracklist
*/
/* Scrape tracklist */

@@ -167,2 +191,26 @@ _scrapeTracklist(url) {

}
/* 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;
})();
}
};
{
"name": "lyricist",
"version": "2.2.0",
"version": "2.2.2",
"description": "Fetches song lyrics using the Genius.com API and website.",

@@ -14,10 +14,9 @@ "main": "lib/index.js",

"test:coverage": "jest --coverage",
"build": "rimraf node6 && babel lib --out-dir node6 --ignore *.test.js"
"build": "rimraf node6 && babel lib --out-dir node6 --ignore *.test.js",
"precommit": "lint-staged"
},
"keywords": [
"lyric",
"lyrics",
"scrape",
"genius"
],
"lint-staged": {
"lib/*.js": ["prettier --write", "git add"]
},
"keywords": ["lyric", "lyrics", "scrape", "genius"],
"author": "scf4 (https://github.com/scf4)",

@@ -31,3 +30,2 @@ "license": "MIT",

"cheerio": "^0.22.0",
"lyricist": "^2.0.0",
"node-fetch": "^1.6.3"

@@ -37,9 +35,12 @@ },

"babel-cli": "^6.24.1",
"babel-jest": "^21.0.2",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.5.2",
"babel-jest": "^19.0.0",
"babel-polyfill": "^6.23.0",
"dotenv": "^4.0.0",
"jest": "^19.0.2",
"husky": "^0.14.3",
"jest": "^21.1.0",
"lint-staged": "^4.1.3",
"prettier": "^1.6.1",
"rimraf": "^2.6.1"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc