From 2734f9ee1115267dd6bd3209046c602bff56aa70 Mon Sep 17 00:00:00 2001 From: trekiteasy Date: Tue, 5 Feb 2019 09:09:10 +0100 Subject: [PATCH] Initial commit feature lyrics --- app/actions/lyrics.js | 19 ++++ app/plugins/Lyrics/LyricsSearch.js | 159 +++++++++++++++++++++++++++++ app/plugins/Lyrics/index.js | 154 ++++++++++++++++++++++++++++ app/plugins/temp_lyrics.js | 19 ++++ package.json | 3 + 5 files changed, 354 insertions(+) create mode 100644 app/actions/lyrics.js create mode 100644 app/plugins/Lyrics/LyricsSearch.js create mode 100644 app/plugins/Lyrics/index.js create mode 100644 app/plugins/temp_lyrics.js diff --git a/app/actions/lyrics.js b/app/actions/lyrics.js new file mode 100644 index 0000000000..9040f0cad3 --- /dev/null +++ b/app/actions/lyrics.js @@ -0,0 +1,19 @@ +export const LYRIC_SEARCH_START = 'LYRIC_SEARCH_START'; +export const LYRIC_SEARCH_SUCCESS = 'LYRIC_SEARCH_SUCCESS'; + +export function lyricSearchStart (query) { + return { + type: LYRIC_SEARCH_START, + payload: query + }; +} + +export function unifiedSearchSuccess (query, result) { + return { + type: LYRIC_SEARCH_SUCCESS, + payload: { + query: query, + info: result + } + }; +} diff --git a/app/plugins/Lyrics/LyricsSearch.js b/app/plugins/Lyrics/LyricsSearch.js new file mode 100644 index 0000000000..49aeaa3e51 --- /dev/null +++ b/app/plugins/Lyrics/LyricsSearch.js @@ -0,0 +1,159 @@ +import LyricsPlugin from '../temp_lyrics'; +const cheerio = require('cheerio'); +const _ = require('lodash'); +const request = require('request-promise'); +const levenshtein = require('fast-levenshtein'); +import LyricsPlugin from '../temp_lyrics'; + +class LyricsSearch extends LyricsPlugin { + constructor() { + super(); + this.name = 'Lyrics Plugin'; + this.description = 'Allows Nuclear to find lyrics'; + } + + search (terms) { + console.log(terms); + } + + + findLyrics (title, artistName) { + + let promises = []; + + const textln = (html) => { + html.find('br').replaceWith('\n'); + html.find('script').replaceWith(''); + html.find('#video-musictory').replaceWith(''); + html.find('strong').replaceWith(''); + html = _.trim(html.text()); + html = html.replace(/\r\n\n/g, '\n'); + html = html.replace(/\t/g, ''); + html = html.replace(/\n\r\n/g, '\n'); + html = html.replace(/ +/g, ' '); + html = html.replace(/\n /g, '\n'); + return html; + }; + + const lyricsUrl = (title) => { + return _.kebabCase(_.trim(_.toLower(_.deburr(title)))); + }; + const lyricsManiaUrl = (title) => { + return _.snakeCase(_.trim(_.toLower(_.deburr(title)))); + }; + const lyricsManiaUrlAlt = (title) => { + title = _.trim(_.toLower(title)); + title = title.replace('\'', ''); + title = title.replace(' ', '_'); + title = title.replace(/_+/g, '_'); + return title; + }; + + const reqWikia = request({ + uri: 'http://lyrics.wikia.com/wiki/' + encodeURIComponent(artistName) + ':' + encodeURIComponent(title), + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + return textln($('.lyricbox')); + }); + + const reqParolesNet = request({ + uri: 'http://www.paroles.net/' + lyricsUrl(artistName) + '/paroles-' + lyricsUrl(title), + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.song-text').length === 0) { + return Promise.reject(); + } + return textln($('.song-text')); + }); + + const reqLyricsMania1 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrl(title) + '_lyrics_' + lyricsManiaUrl(artistName) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + return Promise.reject(); + } + return textln($('.lyrics-body')); + }); + + const reqLyricsMania2 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrl(title) + '_' + lyricsManiaUrl(artistName) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + return Promise.reject(); + } + return textln($('.lyrics-body')); + }); + + const reqLyricsMania3 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrlAlt(title) + '_lyrics_' + encodeURIComponent(lyricsManiaUrlAlt(artistName)) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + return Promise.reject(); + } + return textln($('.lyrics-body')); + }); + + const reqSweetLyrics = request({ + method: 'POST', + uri: 'http://www.sweetslyrics.com/search.php', + form: { + search: 'title', + searchtext: title + }, + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + let closestLink, closestScore = -1; + _.forEach($('.search_results_row_color'), (e) => { + let artist = $(e).text().replace(/ - .+$/, ''); + let currentScore = levenshtein.get(artistName, artist); + if (closestScore === -1 || currentScore < closestScore) { + closestScore = currentScore; + closestLink = $(e).find('a').last().attr('href'); + } + }); + if (!closestLink) { + return Promise.reject(); + } + return request({ + uri: 'http://www.sweetslyrics.com/' + closestLink, + transform: (body) => { + return cheerio.load(body); + } + }); + }).then(($) => { + return textln($('.lyric_full_text')); + }); + + if (/\(.*\)/.test(title) || /\[.*\]/.test(title)) { + promises.push(this.findLyrics(title.replace(/\(.*\)/g, '').replace(/\[.*\]/g, ''), artistName)); + } + + promises.push(reqWikia); + promises.push(reqParolesNet); + promises.push(reqLyricsMania1); + promises.push(reqLyricsMania2); + promises.push(reqLyricsMania3); + promises.push(reqSweetLyrics); + + return Promise.any(promises).then((lyrics) => { + return lyrics; + }); + } +} + +export default LyricsSearch; diff --git a/app/plugins/Lyrics/index.js b/app/plugins/Lyrics/index.js new file mode 100644 index 0000000000..148d11b589 --- /dev/null +++ b/app/plugins/Lyrics/index.js @@ -0,0 +1,154 @@ +import { createHttpError } from 'builder-util-runtime'; + +const cheerio = require('cheerio'); +const _ = require('lodash'); +const request = require('request-promise'); +const levenshtein = require('fast-levenshtein'); + +// export { default as LyricsSearch } from './LyricsSearch'; + +const textln = (html) => { + // html.find('br').replaceWith('\n'); + html.find('h2').replaceWith(''); + html.find('script').replaceWith(''); + html.find('#video-musictory').replaceWith(''); + html.find('strong').replaceWith(''); + html = _.trim(html.text()); + html = html.replace(/\r\n\n/g, '\n'); + html = html.replace(/\t/g, ''); + html = html.replace(/\n\r\n/g, '\n'); + html = html.replace(/ +/g, ' '); + html = html.replace(/\n /g, '\n'); + html = html.replace(/\n/g, '
'); + return html; +}; + +const lyricsUrl = (title) => { + return _.kebabCase(_.trim(_.toLower(_.deburr(title)))); +}; +const lyricsManiaUrl = (title) => { + return _.snakeCase(_.trim(_.toLower(_.deburr(title)))); +}; +const lyricsManiaUrlAlt = (title) => { + title = _.trim(_.toLower(title)); + title = title.replace('\'', ''); + title = title.replace(' ', '_'); + title = title.replace(/_+/g, '_'); + return title; +}; + +export function search (artistName, trackName) { + let promises = []; + + /* + const reqWikia = request({ + uri: 'http://lyrics.wikia.com/wiki/' + encodeURIComponent(artistName) + ':' + encodeURIComponent(trackName), + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + return textln($('.lyricbox')); + });*/ + + const reqParolesNet = request({ + uri: 'http://www.paroles.net/' + lyricsUrl(artistName) + '/paroles-' + lyricsUrl(trackName), + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.song-text').length === 0) { + // return Promise.reject(); + return Promise.resolve(''); + } + return textln($('.song-text')); + }); + + + /* const reqLyricsMania1 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrl(trackName) + '_lyrics_' + lyricsManiaUrl(artistName) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + // return Promise.reject(); + return Promise.resolve(''); + } + return textln($('.lyrics-body')); + }); + + const reqLyricsMania2 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrl(trackName) + '_' + lyricsManiaUrl(artistName) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + // return Promise.reject(); + return Promise.resolve(''); + } + return textln($('.lyrics-body')); + }); + + const reqLyricsMania3 = request({ + uri: 'http://www.lyricsmania.com/' + lyricsManiaUrlAlt(trackName) + '_lyrics_' + encodeURIComponent(lyricsManiaUrlAlt(artistName)) + '.html', + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + if ($('.lyrics-body').length === 0) { + // return Promise.reject(); + return Promise.resolve(''); + } + return textln($('.lyrics-body')); + });*/ + + /* const reqSweetLyrics = request({ + method: 'POST', + uri: 'http://www.sweetslyrics.com/search.php', + form: { + search: 'trackName', + searchtext: trackName + }, + transform: (body) => { + return cheerio.load(body); + } + }).then(($) => { + let closestLink, closestScore = -1; + _.forEach($('.search_results_row_color'), (e) => { + let artist = $(e).text().replace(/ - .+$/, ''); + let currentScore = levenshtein.get(artistName, artist); + if (closestScore === -1 || currentScore < closestScore) { + closestScore = currentScore; + closestLink = $(e).find('a').last().attr('href'); + } + }); + if (!closestLink) { + return Promise.reject(); + } + return request({ + uri: 'http://www.sweetslyrics.com/' + closestLink, + transform: (body) => { + return cheerio.load(body); + } + }); + }).then(($) => { + return textln($('.lyric_full_text')); + });*/ + + + // promises.push(reqWikia); + promises.push(reqParolesNet); + /* promises.push(reqLyricsMania1); + promises.push(reqLyricsMania2); + promises.push(reqLyricsMania3);*/ + // promises.push(reqSweetLyrics); + + return Promise.all(promises).then((lyrics) => { + console.log(lyrics); + return lyrics; + }); + /* .catch(err => { + console.log(err); + });*/ +} diff --git a/app/plugins/temp_lyrics.js b/app/plugins/temp_lyrics.js new file mode 100644 index 0000000000..bbf36fcbb1 --- /dev/null +++ b/app/plugins/temp_lyrics.js @@ -0,0 +1,19 @@ +import Plugin from './plugin'; + +class LyricsPlugin extends Plugin { + constructor() { + super(); + this.name = 'Lyrics Plugin'; + this.sourceName = 'Generic Lyric'; + this.description = 'A generic lyric plugin. Should never be instantiated directly'; + this.image = null; + } + + search (terms) { + console.error('search not implemented in plugin ' + this.name); + } + + +} + +export default LyricsPlugin; diff --git a/package.json b/package.json index 8ee9640fdb..54ee4f908e 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,11 @@ "homepage": "https://github.com/nukeop/nuclear#readme", "dependencies": { "billboard-top-100": "^2.0.8", + "cheerio": "^1.0.0-rc.2", "electron-platform": "^1.2.0", "electron-store": "^2.0.0", "electron-timber": "^0.5.1", + "fast-levenshtein": "^2.0.6", "font-awesome": "^4.7.0", "get-artist-title": "^1.1.1", "md5": "^2.2.1", @@ -60,6 +62,7 @@ "react-range-progress": "^4.0.3", "react-router-transition": "^1.2.1", "react-sound": "^1.1.0", + "request-promise": "^4.2.2", "semantic-ui-react": "^0.82.1", "styled-components": "^3.2.6", "uuid": "^3.2.1",