Files
youtube-music/plugins/lyrics-genius/back.js
2023-08-29 17:22:38 +09:00

124 lines
3.5 KiB
JavaScript

const { join } = require('node:path');
const { ipcMain } = require('electron');
const is = require('electron-is');
const { convert } = require('html-to-text');
const fetch = require('node-fetch');
const { cleanupName } = require('../../providers/song-info');
const { injectCSS } = require('../utils');
const eastAsianChars = /\p{Script=Han}|\p{Script=Katakana}|\p{Script=Hiragana}|\p{Script=Hangul}|\p{Script=Han}/u;
let revRomanized = false;
module.exports = async (win, options) => {
if (options.romanizedLyrics) {
revRomanized = true;
}
injectCSS(win.webContents, join(__dirname, 'style.css'));
ipcMain.on('search-genius-lyrics', async (event, extractedSongInfo) => {
const metadata = JSON.parse(extractedSongInfo);
event.returnValue = await fetchFromGenius(metadata);
});
};
const toggleRomanized = () => {
revRomanized = !revRomanized;
};
const fetchFromGenius = async (metadata) => {
const songTitle = `${cleanupName(metadata.title)}`;
const songArtist = `${cleanupName(metadata.artist)}`;
let lyrics;
/* Uses Regex to test the title and artist first for said characters if romanization is enabled. Otherwise normal
Genius Lyrics behavior is observed.
*/
let hasAsianChars = false;
if (revRomanized && (eastAsianChars.test(songTitle) || eastAsianChars.test(songArtist))) {
lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`);
hasAsianChars = true;
} else {
lyrics = await getLyricsList(`${songArtist} ${songTitle}`);
}
/* If the romanization toggle is on, and we did not detect any characters in the title or artist, we do a check
for characters in the lyrics themselves. If this check proves true, we search for Romanized lyrics.
*/
if (revRomanized && !hasAsianChars && eastAsianChars.test(lyrics)) {
lyrics = await getLyricsList(`${songArtist} ${songTitle} Romanized`);
}
return lyrics;
};
/**
* Fetches a JSON of songs which is then parsed and passed into getLyrics to get the lyrical content of the first song
* @param {*} queryString
* @returns The lyrics of the first song found using the Genius-Lyrics API
*/
const getLyricsList = async (queryString) => {
const response = await fetch(
`https://genius.com/api/search/multi?per_page=5&q=${encodeURIComponent(queryString)}`,
);
if (!response.ok) {
return null;
}
/* Fetch the first URL with the api, giving a collection of song results.
Pick the first song, parsing the json given by the API.
*/
const info = await response.json();
let url = '';
try {
url = info.response.sections.find((section) => section.type === 'song')
.hits[0].result.url;
} catch {
return null;
}
const lyrics = await getLyrics(url);
return lyrics;
};
/**
*
* @param {*} url
* @returns The lyrics of the song URL provided, null if none
*/
const getLyrics = async (url) => {
response = await fetch(url);
if (!response.ok) {
return null;
}
if (is.dev()) {
console.log('Fetching lyrics from Genius:', url);
}
const html = await response.text();
const lyrics = convert(html, {
baseElements: {
selectors: ['[class^="Lyrics__Container"]', '.lyrics'],
},
selectors: [
{
selector: 'a',
format: 'linkFormatter',
},
],
formatters: {
// Remove links by keeping only the content
linkFormatter(element, walk, builder) {
walk(element.children, builder);
},
},
});
return lyrics;
};
module.exports.toggleRomanized = toggleRomanized;
module.exports.fetchFromGenius = fetchFromGenius;