aboutsummaryrefslogtreecommitdiff
path: root/lyrics.js
diff options
context:
space:
mode:
Diffstat (limited to 'lyrics.js')
-rw-r--r--lyrics.js136
1 files changed, 136 insertions, 0 deletions
diff --git a/lyrics.js b/lyrics.js
new file mode 100644
index 0000000..f2edf2c
--- /dev/null
+++ b/lyrics.js
@@ -0,0 +1,136 @@
+/*
+ * 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"))
+})() \ No newline at end of file