/* * MIT License * * Copyright (c) 2022- Minteck * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ (async () => { const fs = require('fs'); const child_process = require("child_process"); const path = require("path"); const exec = require('child_process').execFileSync; let noLyrics = []; let yesLyrics = []; const Genius = require("genius-lyrics"); const g = new Genius.Client(); const artists = fs.readdirSync(process.argv[2]); const albums = []; const tracks = {}; for (let artist of artists) { if (fs.lstatSync(process.argv[2] + "/" + artist).isDirectory()) { const artistAlbums = fs.readdirSync(process.argv[2] + "/" + artist); for (let album of artistAlbums) { if (fs.lstatSync(process.argv[2] + "/" + artist + "/" + album).isDirectory()) { albums.push(process.argv[2] + "/" + artist + "/" + album); const albumTracks = fs.readdirSync(process.argv[2] + "/" + artist + "/" + album); for (let track of albumTracks) { if (fs.lstatSync(process.argv[2] + "/" + artist + "/" + album + "/" + track).isFile() && !track.startsWith(".")) { tracks[process.argv[2] + "/" + artist + "/" + album + "/" + track] = { artist, album, name: track }; } } } } } } for (let id of Object.keys(tracks)) { const track = tracks[id]; console.log(id); if (JSON.parse(child_process.execFileSync("ffprobe", [ "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", id ]).toString()).format.tags.lyrics === undefined) { let lyricsComplete = false; let lyrics = "[Instrumental]"; try { let geniusSearchArtist = track.artist; let geniusSearchTitle = track.name.substring(0, track.name.length - path.extname(track.name).length).replace(/[0-9]+-[0-9]+ (.*)/gm, "$1"); let geniusSong = (await g.songs.search(geniusSearchArtist + " - " + geniusSearchTitle))[0]; let geniusSongSec = (await g.songs.search(geniusSearchArtist + " - " + geniusSearchTitle))[1]; let geniusSongTer = (await g.songs.search(geniusSearchArtist + " - " + geniusSearchTitle))[2]; let geniusSongQua = (await g.songs.search(geniusSearchArtist + " - " + geniusSearchTitle))[3]; let geniusTitle = geniusSong.title.replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-( |)(.*)(\[(.*)\]|)/gm, "$3").replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replace(/(.*)\[(.*)\](.*)/gm, "$1").replace(/(.*)\((from|in|by)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replaceAll("’", "'").trim(); let geniusTitleSec; let geniusTitleTer; let geniusTitleQua; try { geniusTitleSec = geniusSongSec.title.replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-( |)(.*)(\[(.*)\]|)/gm, "$3").replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replace(/(.*)\[(.*)\](.*)/gm, "$1").replace(/(.*)\((from|in|by)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replaceAll("’", "'").trim(); } catch (e) { geniusTitleSec = ""; } try { geniusTitleTer = geniusSongTer.title.replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-( |)(.*)(\[(.*)\]|)/gm, "$3").replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replace(/(.*)\[(.*)\](.*)/gm, "$1").replace(/(.*)\((from|in|by)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replaceAll("’", "'").trim(); } catch (e) { geniusTitleTer = ""; } try { geniusTitleQua = geniusSongQua.title.replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-( |)(.*)(\[(.*)\]|)/gm, "$3").replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replace(/(.*)\[(.*)\](.*)/gm, "$1").replace(/(.*)\((from|in|by)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$1").replaceAll("’", "'").trim(); } catch (e) { geniusTitleQua = ""; } console.log("1. " + geniusTitle.toLowerCase().trim() + " <-> " + geniusSearchTitle.toLowerCase().trim(), geniusTitle.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim()); console.log("2. " + geniusTitleSec.toLowerCase().trim() + " <-> " + geniusSearchTitle.toLowerCase().trim(), geniusTitleSec.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim()); console.log("3. " + geniusTitleTer.toLowerCase().trim() + " <-> " + geniusSearchTitle.toLowerCase(), geniusTitleTer.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim()); console.log("4. " + geniusTitleQua.toLowerCase().trim() + " <-> " + geniusSearchTitle.toLowerCase().trim(), geniusTitleQua.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim()); if (geniusTitle.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim() && geniusSong.raw.lyrics_state === "complete") { lyricsComplete = true; lyrics = (await geniusSong.lyrics()).trim() } else if (geniusTitleSec.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim() && geniusSongSec.raw.lyrics_state === "complete") { lyricsComplete = true; lyrics = (await geniusSongSec.lyrics()).trim() } else if (geniusTitleTer.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim() && geniusSongTer.raw.lyrics_state === "complete") { lyricsComplete = true; lyrics = (await geniusSongTer.lyrics()).trim() } else if (geniusTitleQua.toLowerCase().trim() === geniusSearchTitle.toLowerCase().trim() && geniusSongQua.raw.lyrics_state === "complete") { lyricsComplete = true; lyrics = (await geniusSongQua.lyrics()).trim() } } catch (e) { console.error(e); lyrics = "[Instrumental]"; lyricsComplete = true; } if (lyricsComplete) { console.log("Found lyrics: yes"); yesLyrics.push(id); exec("ffmpeg", [ "-v", "quiet", "-y", "-i", id, "-c", "copy", "-metadata", "lyrics=" + lyrics, id + "-" + path.extname(id) ], { stdio: "inherit" }); fs.renameSync(id + "-" + path.extname(id), id); } else { console.log("Found lyrics: no"); noLyrics.push(id); } } } console.log(noLyrics.length + " song(s) doesn't have lyrics, see 'Missing.txt' for details"); console.log(yesLyrics.length + " song(s) have lyrics and were affected, see 'Changes.txt' for details"); fs.writeFileSync("Missing.txt", noLyrics.join("\n")) fs.writeFileSync("Changes.txt", yesLyrics.join("\n")) })()