aboutsummaryrefslogtreecommitdiff
path: root/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'index.js')
-rw-r--r--index.js398
1 files changed, 199 insertions, 199 deletions
diff --git a/index.js b/index.js
index 9a4082c..4f6c96e 100644
--- a/index.js
+++ b/index.js
@@ -1,200 +1,200 @@
-/*
- * 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.
- *
- */
-
-'use strict';
-
-(async () => {
- function die(message, code) {
- if (message) { console.log(message) }
- if (code) {
- process.exit(code);
- } else {
- process.exit(0);
- }
- }
-
- String.prototype.isBase64 = function () {
- return Buffer.from(this, 'base64').toString('base64').split("=")[0].substring(0, Buffer.from(this, 'base64').toString('base64').split("=")[0].length - 1) === this.substring(0, this.length - 1);
- }
-
- const exec = require('child_process').execFileSync;
- const fs = require('fs');
- const axios = require('axios');
-
- const Genius = require("genius-lyrics");
- const g = new Genius.Client();
-
- if (process.argv[2] !== undefined) {
- global.id = process.argv[2];
- if (!id.isBase64() || id.length !== 34) {
- die("Invalid playlist ID");
- }
- } else {
- console.log("Please specify playlist ID");
- }
-
- if (process.argv[3] !== undefined) {
- global.overrideAlbum = true;
- global.overrideAlbumName = process.argv[3];
- } else {
- global.overrideAlbum = false;
- }
-
- console.log("Preparing folder structure...");
- if (!fs.existsSync("./_youtoo")) fs.mkdirSync("./_youtoo");
- if (!fs.existsSync("./_youtoo/Dumps")) fs.mkdirSync("./_youtoo/Dumps");
- if (!fs.existsSync("./_youtoo/Result")) fs.mkdirSync("./_youtoo/Result");
- if (!fs.existsSync("./_youtoo/Metadata")) fs.mkdirSync("./_youtoo/Metadata");
- if (!fs.existsSync("./_youtoo/AlbumArts")) fs.mkdirSync("./_youtoo/AlbumArts");
-
- console.log("Gathering playlist data...");
- let playlist = JSON.parse(exec("yt-dlp", [ "--flat-playlist", "--dump-single-json", "https://www.youtube.com/playlist?list=" + id ]).toString());
- fs.writeFileSync("./_youtoo/Dumps/PlaylistDataRaw.json", JSON.stringify(playlist, null, 4));
- let songs = playlist.entries.map(i => i.id);
- fs.writeFileSync("./_youtoo/Dumps/PlaylistDataList.json", JSON.stringify(songs, null, 4));
- console.log("Found " + songs.length + " songs");
-
- for (let song of songs) {
- if (!fs.existsSync("./_youtoo/Result/" + song + ".mp3")) {
- console.log("[" + song + "] Gathering metadata...");
- exec("yt-dlp", [ "-o", "./_youtoo/_audio", "--skip-download", "--write-info-json", "https://www.youtube.com/watch?v=" + song ], { stdio: "inherit" })
- let metadata = JSON.parse(fs.readFileSync("./_youtoo/_audio.info.json").toString());
- fs.writeFileSync("./_youtoo/Dumps/MetadataRaw" + song + ".json", JSON.stringify(metadata, null, 4));
-
- console.log("[" + song + "] Parsing metadata...");
- let partists = (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-(.*)/gm, "$1") !== (metadata.track ?? metadata.alt_title ?? metadata.title) ? (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-(.*)/gm, "$1") : "";
- let partists2 = (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$5") !== (metadata.track ?? metadata.alt_title ?? metadata.title) ? (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$5") : "";
- let artistsList = Array.from(new Set([...(metadata.artist ?? metadata.creator ?? metadata.uploader).replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim()), ...partists.replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim()), ...partists2.replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim())])).filter(i => i.trim() !== "");
- let songTitle = (metadata.track ?? metadata.alt_title ?? metadata.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").trim();
- console.log("[" + song + "] Gathering lyrics...");
- let lyricsComplete = false;
- let lyrics = "";
- try {
- let geniusSearchArtist = artistsList[0];
- let geniusSong = (await g.songs.search(geniusSearchArtist + " - " + songTitle))[0];
- 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").trim();
- console.log(geniusTitle.toLowerCase() + " <-> " + songTitle.toLowerCase(), geniusTitle.toLowerCase() === songTitle.toLowerCase());
- if (geniusTitle.toLowerCase() === songTitle.toLowerCase() && geniusSong.raw.lyrics_state === "complete") {
- lyricsComplete = true;
- lyrics = (await geniusSong.lyrics()).trim()
- }
- } catch (e) {
- console.error(e);
- lyrics = "";
- }
- if (!lyricsComplete) {
- console.log("[" + song + "] Incomplete/nonexistent lyrics, will try to fetch at every sync.");
- }
- let rmeta = {
- video: metadata.title,
- title: songTitle,
- date: metadata.release_year ?? (metadata.upload_date.substring(0, 4) - 1 +1),
- album: overrideAlbum ? overrideAlbumName : metadata.album ?? ((metadata.track ?? metadata.alt_title ?? metadata.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").trim()),
- potentialArtists: partists,
- potentialArtists2: partists2,
- artists: artistsList,
- lyrics,
- complete: lyricsComplete
- }
- fs.writeFileSync("./_youtoo/Metadata/" + song + ".json", JSON.stringify(rmeta, null, 4));
- console.log("[" + song + "] Downloading audio...");
- exec("yt-dlp", [ "-f", "bestaudio[ext=m4a]", "-x", "-o", "./_youtoo/_audio.m4a", "--audio-format", "m4a", "https://www.youtube.com/watch?v=" + song ], { stdio: "inherit" });
- console.log("[" + song + "] Downloading thumbnail...");
- fs.writeFileSync("./_youtoo/_audio.webp", (await axios.get(metadata.thumbnail, { responseType: "arraybuffer" })).data);
- console.log("[" + song + "] Processing thumbnail...");
- exec("magick", [ "-define", "jpeg:size=1024x1024", "./_youtoo/_audio.webp", "-thumbnail", "512x512^", "-gravity", "center", "-extent", "512x512", "./_youtoo/_audio.jpg" ]);
- console.log("[" + song + "] Processing audio...");
- let additionalArrayItems = [ "-metadata", "date=" + rmeta.date.toString() ]
- if (overrideAlbum) {
- additionalArrayItems = [ "-metadata", "album_artist=" + overrideAlbumName ];
- }
- exec("ffmpeg", [ "-y", "-i", "./_youtoo/_audio.m4a", "-metadata", "artist=" + rmeta.artists.join(", ") + "", "-metadata", "title=" + rmeta.title, ...additionalArrayItems, "-metadata", "album=" + rmeta.album, "-metadata", "publisher=YouTube", "-metadata", "copyright=© " + rmeta.date.toString() + " " + rmeta.artists[0], "-metadata", "lyrics=" + lyrics, "-metadata", "encoded_by=" + require('./package.json').name + "/" + require('./package.json').version, "./_youtoo/_audio.1.mp3" ], { stdio: "inherit" });
- if (!overrideAlbum) {
- exec("ffmpeg", [ "-y", "-i", "./_youtoo/_audio.1.mp3", "-i", "./_youtoo/_audio.jpg", "-map", "0:0", "-map", "1:0", "-c", "copy", "-id3v2_version", "3", "-metadata:s:v", "title=Album cover", "-metadata:s:v", "comment=Cover (front)", "./_youtoo/_audio.mp3" ], { stdio: "inherit" });
- fs.renameSync("./_youtoo/_audio.mp3", "./_youtoo/Result/" + song + ".mp3");
- } else {
- fs.renameSync("./_youtoo/_audio.1.mp3", "./_youtoo/Result/" + song + ".mp3");
- }
- fs.renameSync("./_youtoo/_audio.jpg", "./_youtoo/AlbumArts/" + song + ".jpg");
- console.log("[" + song + "] Cleaning up...");
- if (fs.existsSync("./_youtoo/_audio.1.mp3")) { fs.rmSync("./_youtoo/_audio.1.mp3"); }
- if (fs.existsSync("./_youtoo/_audio.jpg")) { fs.rmSync("./_youtoo/_audio.jpg"); }
- if (fs.existsSync("./_youtoo/_audio.webp")) { fs.rmSync("./_youtoo/_audio.webp"); }
- if (fs.existsSync("./_youtoo/_audio.m4a")) { fs.rmSync("./_youtoo/_audio.m4a"); }
- if (fs.existsSync("./_youtoo/_audio.info.json")) { fs.rmSync("./_youtoo/_audio.info.json"); }
- } else {
- console.log("[" + song + "] Song already in destination");
- }
- }
-
- console.log("Deleting removed songs...")
- for (let file of fs.readdirSync("./_youtoo/Result")) {
- let song = file.substring(0, file.length - 4);
- if (!songs.includes(song)) {
- console.log("[" + song + "] Deleting...");
- fs.unlinkSync("./_youtoo/Result/" + file);
- if (fs.existsSync("./_youtoo/Metadata/" + song + ".json")) fs.unlinkSync("./_youtoo/Metadata/" + song + ".json");
- }
- }
-
- console.log("Cleaning up...")
- if (fs.existsSync("./_youtoo/Dumps")) { fs.rmSync("./_youtoo/Dumps", { recursive: true }); }
-
- console.log("Fetching lyrics for incomplete songs...")
- for (let file of fs.readdirSync("./_youtoo/Result")) {
- let song = file.substring(0, file.length - 4);
- if (fs.existsSync("./_youtoo/Metadata/" + song + ".json")) {
- console.log("[" + song + "] Fetching metadata...");
- let metadata = JSON.parse(fs.readFileSync("./_youtoo/Metadata/" + song + ".json").toString());
- if (typeof metadata.complete !== "boolean" || !metadata.complete) {
- console.log("[" + song + "] Gathering lyrics...");
- let lyricsComplete = false;
- let lyrics = "";
- try {
- let geniusSearchArtist = metadata.artists[0];
- let geniusSong = (await g.songs.search(geniusSearchArtist + " - " + metadata.title))[0];
- 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").trim();
- console.log(geniusTitle.toLowerCase() + " <-> " + metadata.title.toLowerCase(), geniusTitle.toLowerCase() === metadata.title.toLowerCase());
- if (geniusTitle.toLowerCase() === metadata.title.toLowerCase() && geniusSong.raw.lyrics_state === "complete") {
- lyricsComplete = true;
- lyrics = (await geniusSong.lyrics()).trim()
- }
- } catch (e) {
- console.error(e);
- lyrics = "";
- }
- if (!lyricsComplete) {
- console.log("[" + song + "] Incomplete/nonexistent lyrics, will try to fetch at every sync.");
- }
- metadata.complete = lyricsComplete;
- metadata.lyrics = lyrics;
- fs.writeFileSync("./_youtoo/Metadata/" + song + ".json", JSON.stringify(metadata, null, 4));
- console.log("[" + song + "] Processing audio...");
- exec("ffmpeg", [ "-y", "-i", "./_youtoo/Result/" + file, "-c", "copy", "-metadata", "lyrics=" + lyrics, "-metadata", "encoded_by=" + require('./package.json').name + "/" + require('./package.json').version, "./_youtoo/_audio.mp3" ], { stdio: "inherit" });
- fs.renameSync("./_youtoo/_audio.mp3", "./_youtoo/Result/" + song + ".mp3");
- }
- }
- }
+/*
+ * 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.
+ *
+ */
+
+'use strict';
+
+(async () => {
+ function die(message, code) {
+ if (message) { console.log(message) }
+ if (code) {
+ process.exit(code);
+ } else {
+ process.exit(0);
+ }
+ }
+
+ String.prototype.isBase64 = function () {
+ return Buffer.from(this, 'base64').toString('base64').split("=")[0].substring(0, Buffer.from(this, 'base64').toString('base64').split("=")[0].length - 1) === this.substring(0, this.length - 1);
+ }
+
+ const exec = require('child_process').execFileSync;
+ const fs = require('fs');
+ const axios = require('axios');
+
+ const Genius = require("genius-lyrics");
+ const g = new Genius.Client();
+
+ if (process.argv[2] !== undefined) {
+ global.id = process.argv[2];
+ if (!id.isBase64() || id.length !== 34) {
+ die("Invalid playlist ID");
+ }
+ } else {
+ console.log("Please specify playlist ID");
+ }
+
+ if (process.argv[3] !== undefined) {
+ global.overrideAlbum = true;
+ global.overrideAlbumName = process.argv[3];
+ } else {
+ global.overrideAlbum = false;
+ }
+
+ console.log("Preparing folder structure...");
+ if (!fs.existsSync("./_youtoo")) fs.mkdirSync("./_youtoo");
+ if (!fs.existsSync("./_youtoo/Dumps")) fs.mkdirSync("./_youtoo/Dumps");
+ if (!fs.existsSync("./_youtoo/Result")) fs.mkdirSync("./_youtoo/Result");
+ if (!fs.existsSync("./_youtoo/Metadata")) fs.mkdirSync("./_youtoo/Metadata");
+ if (!fs.existsSync("./_youtoo/AlbumArts")) fs.mkdirSync("./_youtoo/AlbumArts");
+
+ console.log("Gathering playlist data...");
+ let playlist = JSON.parse(exec("yt-dlp", [ "--flat-playlist", "--dump-single-json", "https://www.youtube.com/playlist?list=" + id ]).toString());
+ fs.writeFileSync("./_youtoo/Dumps/PlaylistDataRaw.json", JSON.stringify(playlist, null, 4));
+ let songs = playlist.entries.map(i => i.id);
+ fs.writeFileSync("./_youtoo/Dumps/PlaylistDataList.json", JSON.stringify(songs, null, 4));
+ console.log("Found " + songs.length + " songs");
+
+ for (let song of songs) {
+ if (!fs.existsSync("./_youtoo/Result/" + song + ".mp3")) {
+ console.log("[" + song + "] Gathering metadata...");
+ exec("yt-dlp", [ "-o", "./_youtoo/_audio", "--skip-download", "--write-info-json", "https://www.youtube.com/watch?v=" + song ], { stdio: "inherit" })
+ let metadata = JSON.parse(fs.readFileSync("./_youtoo/_audio.info.json").toString());
+ fs.writeFileSync("./_youtoo/Dumps/MetadataRaw" + song + ".json", JSON.stringify(metadata, null, 4));
+
+ console.log("[" + song + "] Parsing metadata...");
+ let partists = (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-(.*)/gm, "$1") !== (metadata.track ?? metadata.alt_title ?? metadata.title) ? (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/^([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)-(.*)/gm, "$1") : "";
+ let partists2 = (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$5") !== (metadata.track ?? metadata.alt_title ?? metadata.title) ? (metadata.track ?? metadata.alt_title ?? metadata.title).replace(/(.*)\((feat|ft|with)(\.|:| |)(| |)([:\"'a-zA-Z0-9 .\-*\_\/\\,&]*)\)(.*)/gmi, "$5") : "";
+ let artistsList = Array.from(new Set([...(metadata.artist ?? metadata.creator ?? metadata.uploader).replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim()), ...partists.replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim()), ...partists2.replace(/(, |,|and |And |&)/gm, "|").split("|").map(i => i.trim())])).filter(i => i.trim() !== "");
+ let songTitle = (metadata.track ?? metadata.alt_title ?? metadata.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").trim();
+ console.log("[" + song + "] Gathering lyrics...");
+ let lyricsComplete = false;
+ let lyrics = "";
+ try {
+ let geniusSearchArtist = artistsList[0];
+ let geniusSong = (await g.songs.search(geniusSearchArtist + " - " + songTitle))[0];
+ 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").trim();
+ console.log(geniusTitle.toLowerCase() + " <-> " + songTitle.toLowerCase(), geniusTitle.toLowerCase() === songTitle.toLowerCase());
+ if (geniusTitle.toLowerCase() === songTitle.toLowerCase() && geniusSong.raw.lyrics_state === "complete") {
+ lyricsComplete = true;
+ lyrics = (await geniusSong.lyrics()).trim()
+ }
+ } catch (e) {
+ console.error(e);
+ lyrics = "";
+ }
+ if (!lyricsComplete) {
+ console.log("[" + song + "] Incomplete/nonexistent lyrics, will try to fetch at every sync.");
+ }
+ let rmeta = {
+ video: metadata.title,
+ title: songTitle,
+ date: metadata.release_year ?? (metadata.upload_date.substring(0, 4) - 1 +1),
+ album: overrideAlbum ? overrideAlbumName : metadata.album ?? ((metadata.track ?? metadata.alt_title ?? metadata.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").trim()),
+ potentialArtists: partists,
+ potentialArtists2: partists2,
+ artists: artistsList,
+ lyrics,
+ complete: lyricsComplete
+ }
+ fs.writeFileSync("./_youtoo/Metadata/" + song + ".json", JSON.stringify(rmeta, null, 4));
+ console.log("[" + song + "] Downloading audio...");
+ exec("yt-dlp", [ "-f", "bestaudio[ext=m4a]", "-x", "-o", "./_youtoo/_audio.m4a", "--audio-format", "m4a", "https://www.youtube.com/watch?v=" + song ], { stdio: "inherit" });
+ console.log("[" + song + "] Downloading thumbnail...");
+ fs.writeFileSync("./_youtoo/_audio.webp", (await axios.get(metadata.thumbnail, { responseType: "arraybuffer" })).data);
+ console.log("[" + song + "] Processing thumbnail...");
+ exec("magick", [ "-define", "jpeg:size=1024x1024", "./_youtoo/_audio.webp", "-thumbnail", "512x512^", "-gravity", "center", "-extent", "512x512", "./_youtoo/_audio.jpg" ]);
+ console.log("[" + song + "] Processing audio...");
+ let additionalArrayItems = [ "-metadata", "date=" + rmeta.date.toString() ]
+ if (overrideAlbum) {
+ additionalArrayItems = [ "-metadata", "album_artist=" + overrideAlbumName ];
+ }
+ exec("ffmpeg", [ "-y", "-i", "./_youtoo/_audio.m4a", "-metadata", "artist=" + rmeta.artists.join(", ") + "", "-metadata", "title=" + rmeta.title, ...additionalArrayItems, "-metadata", "album=" + rmeta.album, "-metadata", "publisher=YouTube", "-metadata", "copyright=© " + rmeta.date.toString() + " " + rmeta.artists[0], "-metadata", "lyrics=" + lyrics, "-metadata", "encoded_by=" + require('./package.json').name + "/" + require('./package.json').version, "./_youtoo/_audio.1.mp3" ], { stdio: "inherit" });
+ if (!overrideAlbum) {
+ exec("ffmpeg", [ "-y", "-i", "./_youtoo/_audio.1.mp3", "-i", "./_youtoo/_audio.jpg", "-map", "0:0", "-map", "1:0", "-c", "copy", "-id3v2_version", "3", "-metadata:s:v", "title=Album cover", "-metadata:s:v", "comment=Cover (front)", "./_youtoo/_audio.mp3" ], { stdio: "inherit" });
+ fs.renameSync("./_youtoo/_audio.mp3", "./_youtoo/Result/" + song + ".mp3");
+ } else {
+ fs.renameSync("./_youtoo/_audio.1.mp3", "./_youtoo/Result/" + song + ".mp3");
+ }
+ fs.renameSync("./_youtoo/_audio.jpg", "./_youtoo/AlbumArts/" + song + ".jpg");
+ console.log("[" + song + "] Cleaning up...");
+ if (fs.existsSync("./_youtoo/_audio.1.mp3")) { fs.rmSync("./_youtoo/_audio.1.mp3"); }
+ if (fs.existsSync("./_youtoo/_audio.jpg")) { fs.rmSync("./_youtoo/_audio.jpg"); }
+ if (fs.existsSync("./_youtoo/_audio.webp")) { fs.rmSync("./_youtoo/_audio.webp"); }
+ if (fs.existsSync("./_youtoo/_audio.m4a")) { fs.rmSync("./_youtoo/_audio.m4a"); }
+ if (fs.existsSync("./_youtoo/_audio.info.json")) { fs.rmSync("./_youtoo/_audio.info.json"); }
+ } else {
+ console.log("[" + song + "] Song already in destination");
+ }
+ }
+
+ console.log("Deleting removed songs...")
+ for (let file of fs.readdirSync("./_youtoo/Result")) {
+ let song = file.substring(0, file.length - 4);
+ if (!songs.includes(song)) {
+ console.log("[" + song + "] Deleting...");
+ fs.unlinkSync("./_youtoo/Result/" + file);
+ if (fs.existsSync("./_youtoo/Metadata/" + song + ".json")) fs.unlinkSync("./_youtoo/Metadata/" + song + ".json");
+ }
+ }
+
+ console.log("Cleaning up...")
+ if (fs.existsSync("./_youtoo/Dumps")) { fs.rmSync("./_youtoo/Dumps", { recursive: true }); }
+
+ console.log("Fetching lyrics for incomplete songs...")
+ for (let file of fs.readdirSync("./_youtoo/Result")) {
+ let song = file.substring(0, file.length - 4);
+ if (fs.existsSync("./_youtoo/Metadata/" + song + ".json")) {
+ console.log("[" + song + "] Fetching metadata...");
+ let metadata = JSON.parse(fs.readFileSync("./_youtoo/Metadata/" + song + ".json").toString());
+ if (typeof metadata.complete !== "boolean" || !metadata.complete) {
+ console.log("[" + song + "] Gathering lyrics...");
+ let lyricsComplete = false;
+ let lyrics = "";
+ try {
+ let geniusSearchArtist = metadata.artists[0];
+ let geniusSong = (await g.songs.search(geniusSearchArtist + " - " + metadata.title))[0];
+ 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").trim();
+ console.log(geniusTitle.toLowerCase() + " <-> " + metadata.title.toLowerCase(), geniusTitle.toLowerCase() === metadata.title.toLowerCase());
+ if (geniusTitle.toLowerCase() === metadata.title.toLowerCase() && geniusSong.raw.lyrics_state === "complete") {
+ lyricsComplete = true;
+ lyrics = (await geniusSong.lyrics()).trim()
+ }
+ } catch (e) {
+ console.error(e);
+ lyrics = "";
+ }
+ if (!lyricsComplete) {
+ console.log("[" + song + "] Incomplete/nonexistent lyrics, will try to fetch at every sync.");
+ }
+ metadata.complete = lyricsComplete;
+ metadata.lyrics = lyrics;
+ fs.writeFileSync("./_youtoo/Metadata/" + song + ".json", JSON.stringify(metadata, null, 4));
+ console.log("[" + song + "] Processing audio...");
+ exec("ffmpeg", [ "-y", "-i", "./_youtoo/Result/" + file, "-c", "copy", "-metadata", "lyrics=" + lyrics, "-metadata", "encoded_by=" + require('./package.json').name + "/" + require('./package.json').version, "./_youtoo/_audio.mp3" ], { stdio: "inherit" });
+ fs.renameSync("./_youtoo/_audio.mp3", "./_youtoo/Result/" + song + ".mp3");
+ }
+ }
+ }
})() \ No newline at end of file