const cp = require("child_process"); const os = require("os"); let ffmpeg; if (os.platform() === "win32") { ffmpeg = `"${__dirname}\\..\\ffmpeg.exe"`; } else if (os.platform() === "freebsd") { try { ffmpeg = cp.execSync("which ffmpeg").toString("utf8").split("\n")[0].trim(); } catch (error) { console.log(error) showPopup("No ffmpeg found in PATH."); } } else { ffmpeg = `"${__dirname}/../ffmpeg"`; } const fs = require("fs"); ///////////////////////////////////// // Do not change the lines at the top ///////////////////////////////////// const path = require("path"); const {shell, ipcRenderer, clipboard} = require("electron"); const {default: YTDlpWrap} = require("yt-dlp-wrap-plus"); const {constants} = require("fs/promises"); // Directories const homedir = os.homedir(); let appdir = path.join(homedir, "Downloads"); if (os.platform() === "linux") { try { const xdgDownloadDir = cp .execSync("xdg-user-dir DOWNLOAD") .toString() .trim(); if (xdgDownloadDir.length > 1) { appdir = xdgDownloadDir; console.log("xdg download dir:", xdgDownloadDir); } } catch (err) {} } const hiddenDir = path.join(homedir, ".ytDownloader"); const i18n = new (require("../translations/i18n"))(); fs.mkdir(hiddenDir, {recursive: true}, () => {}); // System tray const trayEnabled = localStorage.getItem("closeToTray"); if (trayEnabled == "true") { console.log("Tray is Enabled"); ipcRenderer.send("useTray", true); } // Ignore Python warnings process.env.PYTHONWARNINGS = "error"; // Download directory let downloadDir = ""; // Global variables let title, onlyvideo, id, thumbnail, ytdlp, duration, extractor_key; let audioExtensionList = []; let rangeCmd = ""; let subs = ""; let subLangs; let rangeOption = "--download-sections"; let cookieArg = ""; let browser = ""; let maxActiveDownloads = 5; let showMoreFormats = false; let configArg = ""; let configTxt = ""; let proxy = ""; let downloadedItemList = [] if (localStorage.getItem("configPath")) { configArg = "--config-location"; configTxt = `"${localStorage.getItem("configPath")}"`; } function checkMaxDownloads() { if (localStorage.getItem("maxActiveDownloads")) { const number = Number(localStorage.getItem("maxActiveDownloads")); if (number < 1) { maxActiveDownloads = 1; } else { maxActiveDownloads = number; } } } checkMaxDownloads(); // Check for auto updates let autoUpdate = true; const autoUpdateStatus = localStorage.getItem("autoUpdate"); if (autoUpdateStatus) { if (autoUpdateStatus == "false") { autoUpdate = false; } } ipcRenderer.send("autoUpdate", autoUpdate); let currentDownloads = 0; let controllers = new Object(); // Video and audio preferences let preferredVideoQuality = 720; let preferredAudioQuality = ""; let preferredVideoCodec = "avc1"; /** * * @param {string} id */ function getId(id) { return document.getElementById(id); } function downloadPathSelection() { let localPath = localStorage.getItem("downloadPath"); if (localPath) { downloadDir = localPath; try { fs.accessSync(localPath, constants.W_OK); downloadDir = localPath; } catch (err) { console.log( "Unable to write to download directory. Switching to default one." ); console.log(err); downloadDir = appdir; localStorage.setItem("downloadPath", appdir); } } else { downloadDir = appdir; localStorage.setItem("downloadPath", appdir); } getId("path").textContent = downloadDir; fs.mkdir(downloadDir, {recursive: true}, () => {}); } downloadPathSelection(); // Checking for yt-dlp let ytDlp; let ytdlpPath = path.join(os.homedir(), ".ytDownloader", "ytdlp"); // Use system yt-dlp for freebsd if (os.platform() === "freebsd") { try { ytdlpPath = cp.execSync('which yt-dlp').toString("utf8").split("\n")[0].trim(); } catch (error) { console.log(error) getId("incorrectMsg").textContent = i18n.__( "No yt-dlp found in PATH. Make sure you have the full executable. App will not work" ); } } // ytdlp download path let ytdlpDownloadPath; if (os.platform() == "win32") { ytdlpDownloadPath = path.join(os.homedir(), ".ytDownloader", "ytdlp.exe"); } else { ytdlpDownloadPath = path.join(os.homedir(), ".ytDownloader", "ytdlp"); } // Downloading yt-dlp async function downloadYtdlp() { document.querySelector("#popupBox p").textContent = i18n.__( "Please wait, necessary files are being downloaded" ); getId("popupSvg").style.display = "inline"; // Downloading appropriate version of yt-dlp await YTDlpWrap.downloadFromGithub(ytdlpDownloadPath); localStorage.setItem("fullYtdlpBinPresent", "true"); getId("popupBox").style.display = "none"; ytDlp = ytdlpPath; ytdlp = new YTDlpWrap(`"${ytDlp}"`); localStorage.setItem("ytdlp", ytDlp); getId("pasteUrl").style.display = "inline-block"; console.log("yt-dlp bin Path: " + ytDlp); } // Checking if yt-dlp has been installed by user // TODO: Remove this after some time const fullYtdlpBinIsPresent = !!localStorage.getItem("fullYtdlpBinPresent"); const removedOldMacYtdlp = !!localStorage.getItem("removedOldMacYtdlp") // Removing old yt-dlp for macos if (os.platform() === "darwin" && !removedOldMacYtdlp) { if (fs.existsSync(ytdlpPath)) { fs.rmSync(ytdlpPath) localStorage.setItem('removedOldMacYtdlp', "true") } } cp.exec(`"${ytdlpPath}" --version`, (error, _stdout, _stderr) => { if ((error || !fullYtdlpBinIsPresent) && os.platform() !== "freebsd") { getId("popupBox").style.display = "block"; process.on("uncaughtException", (reason, promise) => { document.querySelector("#popupBox p").textContent = i18n.__( "Failed to download necessary files. Please check your network and try again" ); getId("popupSvg").style.display = "none"; getId("popup").innerHTML += ``; console.log("Failed to download yt-dlp"); getId("tryBtn").addEventListener("click", () => { getId("popup").removeChild(getId("popup").lastChild); downloadYtdlp(); }); }); downloadYtdlp(); } else { console.log("yt-dlp binary is present in PATH"); ytDlp = ytdlpPath; ytdlp = new YTDlpWrap(`"${ytDlp}"`); localStorage.setItem("ytdlp", ytDlp); cp.spawn(`${ytDlp}`, ["-U"]).stdout.on("data", (data) => console.log(data.toString("utf8")) ); getId("pasteUrl").style.display = "inline-block"; console.log("yt-dlp bin Path: " + ytDlp); ipcRenderer.send("ready-for-links"); } }); function defaultVideoToggle() { let defaultWindow = "video"; if (localStorage.getItem("defaultWindow")) { defaultWindow = localStorage.getItem("defaultWindow"); } if (defaultWindow == "video") { selectVideo(); } else { selectAudio(); } } // Pasting url from clipboard function pasteUrl() { defaultVideoToggle(); hideHidden(); getId("loadingWrapper").style.display = "flex"; getId("incorrectMsg").textContent = ""; const url = clipboard.readText(); getInfo(url); } function pasteFromTray(url) { defaultVideoToggle(); hideHidden(); getId("loadingWrapper").style.display = "flex"; getId("incorrectMsg").textContent = ""; getInfo(url); } getId("closeHidden").addEventListener("click", () => { hideHidden(); getId("loadingWrapper").style.display = "none"; }); document.addEventListener("keydown", (event) => { if (event.ctrlKey && event.key == "v" && document.activeElement.tagName !== "INPUT") { pasteUrl(); } }); getId("pasteUrl").addEventListener("click", () => { pasteUrl(); }); // Getting video info /** * * @param {string} url */ async function getInfo(url) { audioExtensionList = []; let selected = false; onlyvideo = false; let audioIsPresent = false; downloadPathSelection(); // Cleaning text getId("videoFormatSelect").innerHTML = ""; getId("audioFormatSelect").innerHTML = ""; getId("audioForVideoFormatSelect").innerHTML = ``; const startTime = getId("startTime"); startTime.value = ""; getId("endTime").value = ""; getId("errorBtn").style.display = "none"; getId("errorDetails").style.display = "none"; getId("errorDetails").textContent = ""; if (localStorage.getItem("preferredVideoQuality")) { preferredVideoQuality = Number( localStorage.getItem("preferredVideoQuality") ); } if (localStorage.getItem("preferredAudioQuality")) { preferredAudioQuality = localStorage.getItem("preferredAudioQuality"); getId("extractSelection").value = preferredAudioQuality; } if (localStorage.getItem("preferredVideoCodec")) { preferredVideoCodec = localStorage.getItem("preferredVideoCodec"); } if (localStorage.getItem("showMoreFormats") === "true") { showMoreFormats = true; } else { showMoreFormats = false; } proxy = getLocalStorageItem("proxy"); // Whether to use browser cookies or not if (localStorage.getItem("browser")) { browser = localStorage.getItem("browser"); } if (browser) { cookieArg = "--cookies-from-browser"; } else { cookieArg = ""; } let validInfo = true; let info = ""; // Twitter/X compatibility url = url.replace("//x.com/", "//twitter.com/") const infoOptions = [ "-j", "--no-playlist", "--no-warnings", proxy ? "--no-check-certificate" : "", proxy ? "--proxy" : "", proxy, cookieArg, browser, configArg, configTxt, `"${url}"`, ].filter(item => item) const infoProcess = cp.spawn( `"${ytDlp}"`, infoOptions, { shell: true, } ); infoProcess.stdout.on("data", (data) => { info += data; }); infoProcess.stderr.on("data", (error) => { validInfo = false; // Error message handling console.log(error.toString("utf8")); getId("loadingWrapper").style.display = "none"; getId("incorrectMsg").textContent = i18n.__( "Some error has occurred. Check your network and use correct URL" ); getId("errorBtn").style.display = "inline-block"; getId("errorDetails").innerHTML = ` URL: ${url}

${error.toString("utf8")} `; getId("errorDetails").title = i18n.__("Click to copy"); }); infoProcess.on("close", () => { if (validInfo) { /** * @typedef {import("./types").info} info * @type {info} */ const parsedInfo = JSON.parse(info); console.log(parsedInfo); title = `${parsedInfo.title} [${parsedInfo.id}]`; id = parsedInfo.id; thumbnail = parsedInfo.thumbnail; duration = parsedInfo.duration; extractor_key = parsedInfo.extractor_key /** * @typedef {import("./types").format} format * @type {format[]} */ const formats = parsedInfo.formats || []; console.log(formats); /** * @type {HTMLInputElement[]} */ // @ts-ignore const urlElements = document.querySelectorAll(".url"); urlElements.forEach((element) => { element.value = url; }); getId("loadingWrapper").style.display = "none"; getId("hidden").style.display = "inline-block"; getId("hidden").classList.add("scaleUp"); getId("title").innerHTML = `${i18n.__("Title ")}: ` + ``; let audioSize = 0; let defaultVideoFormat = 144; let videoFormatCodecs = {}; let preferredAudioFormatLength = 0; let preferredAudioFormatCount = 0; let maxAudioFormatNoteLength = 10; // Initially going through all formats // Getting approx size of audio file and checking if audio is present for (let format of formats) { // Find the item with the preferred video format if ( format.height <= preferredVideoQuality && format.height >= defaultVideoFormat && (format.video_ext !== "none" && !( format.video_ext === "mp4" && format.vcodec && format.vcodec.split(".")[0] === "vp09" )) && (!showMoreFormats ? format.video_ext !== "webm" : true) ) { defaultVideoFormat = format.height; // Creating a list of available codecs for the required video height if (!videoFormatCodecs[format.height]) { videoFormatCodecs[format.height] = {codecs: []}; } if (format.vcodec) { videoFormatCodecs[format.height].codecs.push( format.vcodec.split(".")[0] ); } } // Going through audio list if ( format.audio_ext !== "none" || (format.acodec !== "none" && format.video_ext === "none") ) { audioIsPresent = true; onlyvideo = true; audioSize = Number(format.filesize || format.filesize_approx) / 1000000; if (!audioExtensionList.includes(format.audio_ext)) { audioExtensionList.push(format.audio_ext); } if (format.format_note && format.format_note.length > maxAudioFormatNoteLength) { maxAudioFormatNoteLength = format.format_note.length } } if ( format.audio_ext === preferredAudioQuality || format.acodec === preferredAudioQuality ) { preferredAudioFormatLength++; } } const availableCodecs = videoFormatCodecs[defaultVideoFormat] ? videoFormatCodecs[defaultVideoFormat].codecs : []; if (!availableCodecs.includes(preferredVideoCodec)) { preferredVideoCodec = availableCodecs[availableCodecs.length - 1]; } for (let format of formats) { let size; let selectedText = ""; let audioSelectedText = ""; if ( format.height == defaultVideoFormat && format.vcodec && format.vcodec.split(".")[0] === preferredVideoCodec && !selected && (format.video_ext !== "none" && !( format.video_ext === "mp4" && format.vcodec && format.vcodec.split(".")[0] === "vp09" )) && (!showMoreFormats ? format.video_ext !== "webm" : true) ) { selectedText = " selected "; selected = true; } if (format.filesize || format.filesize_approx) { size = ( Number(format.filesize || format.filesize_approx) / 1000000 ).toFixed(2); } else { // if (format.tbr) { // size = ( // (format.tbr * 50 * duration) / // 1000000 // ).toFixed(2); // } else { // } size = i18n.__("Unknown size"); } // For videos if ( (format.video_ext !== "none" && !( format.video_ext === "mp4" && format.vcodec && format.vcodec.split(".")[0] === "vp09" )) && (!showMoreFormats ? format.video_ext !== "webm" : true) ) { if (size !== i18n.__("Unknown size")) { size = (Number(size) + 0 || Number(audioSize)).toFixed( 1 ); size = size + " " + i18n.__("MB"); } const format_id = format.format_id + "|" + format.ext + "|" + (format.height || "NO"); // Video codec const vcodec = format.vcodec && showMoreFormats ? format.vcodec.split(".")[0] : ""; let spaceAfterVcodec = showMoreFormats ? " ".repeat(5 - vcodec.length) : ""; showMoreFormats ? (spaceAfterVcodec += "| ") : (spaceAfterVcodec += ""); // Quality const quality = (format.height ? format.height + "p" + (format.fps == 60 ? "60" : "") : "") || format.format_note || format.resolution || format.format_id || "Unknown quality"; const spaceAfterQuality = " ".repeat( quality.length <= 8 && 8 - quality.length > 0 ? 8 - quality.length : 1 ); // Extension const extension = format.ext; // Format and Quality Options const element = ""; getId("videoFormatSelect").innerHTML += element; } // For audios else if ( format.audio_ext !== "none" || (format.acodec !== "none" && format.video_ext === "none") ) { if (!showMoreFormats && format.audio_ext === "webm") { continue; } size = size !== i18n.__("Unknown size") ? size + " MB" : i18n.__("Unknown size"); let audio_ext; if (format.audio_ext === "webm") { audio_ext = "opus"; } else { audio_ext = format.audio_ext; } if ( format.audio_ext === preferredAudioQuality || format.acodec === preferredAudioQuality ) { preferredAudioFormatCount += 1; if ( preferredAudioFormatCount === preferredAudioFormatLength ) { audioSelectedText = " selected "; } } const format_id = format.format_id + "|" + audio_ext; /**@type {string} */ let formatNote = (i18n.__(format.format_note) || i18n.__("Unknown quality")); formatNote = formatNote.padEnd(maxAudioFormatNoteLength, "\xa0") const element = ""; getId("audioFormatSelect").innerHTML += element; getId("audioForVideoFormatSelect").innerHTML += element; } // Both audio and video available else if ( format.audio_ext !== "none" || (format.acodec !== "none" && format.video_ext !== "none") ) { // Skip them } // When there is no audio if (audioIsPresent === false) { getId("audioPresent").style.display = "none"; } else { getId("audioPresent").style.display = "block"; } } } }); } // Video download event getId("videoDownload").addEventListener("click", (event) => { checkMaxDownloads(); hideHidden(); console.log(`Current:${currentDownloads} Max:${maxActiveDownloads}`); if (currentDownloads < maxActiveDownloads) { manageAdvanced(duration); download("video"); currentDownloads++; } else { // Handling active downloads for video manageAdvanced(duration); const range1 = rangeOption; const range2 = rangeCmd; const subs1 = subs; const subs2 = subLangs; const url1 = getId("url").value; const thumb1 = thumbnail; const title1 = title; const randId = Math.random().toFixed(10).toString().slice(2); const item = `
No thumbnail ${i18n.__("Video")}
${title}

${i18n.__("Download pending")}

`; getId("list").innerHTML += item; const interval = setInterval(() => { if (currentDownloads < maxActiveDownloads) { getId(randId).remove(); download( "video", url1, range1, range2, subs1, subs2, thumb1, title1 ); currentDownloads++; clearInterval(interval); } }, 2000); } }); // Audio download event getId("audioDownload").addEventListener("click", (event) => { checkMaxDownloads(); hideHidden(); console.log(`Current:${currentDownloads} Max:${maxActiveDownloads}`); if (currentDownloads < maxActiveDownloads) { manageAdvanced(duration); download("audio"); currentDownloads++; } else { // Handling active downloads for audio manageAdvanced(duration); const range1 = rangeOption; const range2 = rangeCmd; const subs1 = subs; const subs2 = subLangs; const url1 = getId("url").value; const thumb1 = thumbnail; const title1 = title; const randId = Math.random().toFixed(10).toString().slice(2); const item = `
No thumbnail ${i18n.__("Audio")}
${title}

${i18n.__("Download pending")}

`; getId("list").innerHTML += item; const interval = setInterval(() => { if (currentDownloads < maxActiveDownloads) { getId(randId).remove(); download( "audio", url1, range1, range2, subs1, subs2, thumb1, title1 ); currentDownloads++; clearInterval(interval); } }, 2000); } }); getId("extractBtn").addEventListener("click", () => { checkMaxDownloads(); hideHidden(); console.log(`Current:${currentDownloads} Max:${maxActiveDownloads}`); if (currentDownloads < maxActiveDownloads) { manageAdvanced(duration); download("extract"); currentDownloads++; } else { manageAdvanced(duration); const range1 = rangeOption; const range2 = rangeCmd; const subs1 = subs; const subs2 = subLangs; const url1 = getId("url").value; const randId = Math.random().toFixed(10).toString().slice(2); const thumb1 = thumbnail; const title1 = title; const extractFormat = getId("extractSelection").value; const extractQuality = getId("extractQualitySelect").value; const item = `
No thumbnail ${i18n.__("Audio")}
${title}

${i18n.__("Download pending")}

`; getId("list").innerHTML += item; const interval = setInterval(() => { if (currentDownloads < maxActiveDownloads) { getId(randId).remove(); download( "extract", url1, range1, range2, subs1, subs2, thumb1, title1, extractFormat, extractQuality ); currentDownloads++; clearInterval(interval); } }, 2000); } }); // Time formatting function timeFormat(duration) { // Hours, minutes and seconds var hrs = ~~(duration / 3600); var mins = ~~((duration % 3600) / 60); var secs = ~~duration % 60; // Output like "1:01" or "4:03:59" or "123:03:59" var ret = ""; if (hrs > 0) { ret += "" + hrs + ":" + (mins < 10 ? "0" : ""); } ret += "" + mins + ":" + (secs < 10 ? "0" : ""); ret += "" + secs; return ret; } // Manage advanced options, needs to be called function manageAdvanced(duration) { let startTime = getId("startTime").value; let endTime = getId("endTime").value; if (startTime && !endTime) { rangeCmd = `*${startTime}-${timeFormat(duration)}`; rangeOption = "--download-sections"; } else if (!startTime && endTime) { rangeCmd = `*0-${endTime}`; rangeOption = "--download-sections"; } else if (startTime && endTime) { rangeCmd = `*${startTime}-${endTime}`; rangeOption = "--download-sections"; } else { rangeOption = ""; rangeCmd = ""; } // If subtitles are checked if (getId("subChecked").checked) { subs = "--write-subs"; subLangs = "--sub-langs all"; } else { subs = ""; subLangs = ""; } console.log("Range option: " + rangeOption); console.log("rangeCmd:" + rangeCmd); } ////////////////////////////// // Downloading with yt-dlp ////////////////////////////// function download( type, url1 = "", range1 = "", range2 = "", subs1 = "", subs2 = "", thumb1 = "", title1 = "", extractFormat = "", extractQuality = "" ) { // Config file const newTitle = title1 || title; if (localStorage.getItem("configPath")) { configArg = "--config-location"; configTxt = `"${localStorage.getItem("configPath")}"`; } const url = url1 || getId("url").value; console.log("URL", url); let ext, extractExt, extractFormat1, extractQuality1, audioForVideoExt; /**@type {string}*/ let format_id, audioForVideoFormat_id; const randomId = "a" + Math.random().toFixed(10).toString().slice(2); // Whether to close app let quit = Boolean(getId("quitChecked").checked); if (type === "video") { const videoValue = getId("videoFormatSelect").value; /**@type {string} */ const audioForVideoValue = getId("audioForVideoFormatSelect").value format_id = videoValue.split("|")[0]; const videoExt = videoValue.split("|")[1]; if (videoValue.split("|")[2] != "NO") { preferredVideoQuality = Number(videoValue.split("|")[2]); } audioForVideoFormat_id = audioForVideoValue.split("|")[0]; if (audioForVideoValue.split("|")[1] === "webm") { audioForVideoExt = "opus"; } else { audioForVideoExt = audioForVideoValue.split("|")[1]; } if ((videoExt === "mp4" && audioForVideoExt === "opus") || (videoExt === "webm" && (audioForVideoExt === "m4a" || audioForVideoExt === "mp4"))) { ext = "mkv" } else { ext = videoExt; } } else if (type === "audio") { format_id = getId("audioFormatSelect").value.split("|")[0]; if (getId("audioFormatSelect").value.split("|")[1] === "webm") { ext = "opus"; } else { ext = getId("audioFormatSelect").value.split("|")[1]; } } console.log("Download extension:", ext); const newItem = `
No thumbnail ${ type === "video" ? i18n.__("Video") : i18n.__("Audio") }
${newTitle}
`; getId("list").innerHTML += newItem; getId("loadingWrapper").style.display = "none"; getId(randomId + "prog").textContent = i18n.__("Preparing..."); getId(randomId + ".close").addEventListener("click", () => { if (getId(randomId)) { removeFromDownloadedList(randomId) fadeItem(randomId); } }); let downloadProcess; let filename = ""; // Filtering characters for Unix platforms let pattern = ["/", '"', "`", "#"]; if (os.platform() === "win32") { pattern = [ "[", "]", "*", "<", ">", "|", "\\", "/", "?", '"', "`", "#", ":", ":", ]; } // Trying to remove ambiguous characters for (let i = 0; i < newTitle.length; i++) { let letter = ""; if (pattern.includes(newTitle[i])) { letter = ""; } else { letter = newTitle[i]; } filename += letter; } filename = filename.slice(0, 100); if (filename[0] === ".") { filename = filename.slice(1, 100); } // Adding info about trimmed range to filename if (range2 || rangeCmd) { let rangeTxt = (range2 || rangeCmd).replace("*", ""); if (os.platform() === "win32") { rangeTxt = rangeTxt.replaceAll(":", "_"); console.log({rangeTxt}) } filename += `[${rangeTxt}]` } console.log("Filename:", filename); /**@type {string} */ let audioFormat = "+ba"; if (audioForVideoFormat_id === "auto") { if (ext === "mp4") { if (!(audioExtensionList.length == 0)) { if (audioExtensionList.includes("m4a")) { audioFormat = "+m4a"; } } else { audioFormat = ""; } } } else if (audioForVideoFormat_id === "none") { audioFormat = "" } else { audioFormat = `+${audioForVideoFormat_id}`; } const controller = new AbortController(); controllers[randomId] = controller; console.log(rangeOption + " " + rangeCmd); console.log(`-f ${format_id}${audioFormat}`); if (type === "video" && onlyvideo) { // If video has no sound, audio needs to be downloaded console.log("Downloading both video and audio"); const args = [ range1 || rangeOption, range2 || rangeCmd, "-f", `${format_id}${audioFormat}`, "-o", `"${path.join(downloadDir, filename + `.${ext}`)}"`, "--ffmpeg-location", ffmpeg, subs1 || subs, subs2 || subLangs, "--no-playlist", // "--embed-metadata", ext == "mp4" && audioForVideoExt === "m4a" && extractor_key === "Youtube" && os.platform() !== "darwin" ? "--embed-thumbnail" : "", configArg, configTxt, cookieArg, browser, "--no-mtime", proxy ? "--no-check-certificate" : "", proxy ? "--proxy" : "", proxy, `"${url}"`, ].filter(item => item); downloadProcess = ytdlp.exec( args, {shell: true, detached: false}, controller.signal ); } else if (type === "extract") { if (extractFormat == "alac") { extractExt = "m4a"; } else if (extractFormat == "vorbis") { extractExt = "ogg"; } else { extractExt = extractFormat || getId("extractSelection").value; } extractFormat1 = extractFormat || getId("extractSelection").value; extractQuality1 = extractQuality || getId("extractQualitySelect").value; console.log(extractFormat1); console.log(extractQuality1); const args = [ "-x", "--audio-format", extractFormat1, "--audio-quality", extractQuality1, "-o", `"${path.join(downloadDir, filename + `.${extractExt}`)}"`, "--ffmpeg-location", ffmpeg, "--no-playlist", // "--embed-metadata", (extractFormat1 == "m4a" || extractFormat1 == "mp3") && extractor_key === "Youtube" && os.platform() !== "darwin" ? "--embed-thumbnail" : "", cookieArg, browser, configArg, configTxt, "--no-mtime", proxy ? "--no-check-certificate" : "", proxy ? "--proxy" : "", proxy, `"${url}"`, ].filter(item => item) downloadProcess = ytdlp.exec( args, {shell: true, detached: false}, controller.signal ); } // If downloading only audio or video with audio else { console.log("downloading only audio or video with audio"); const args = [ range1 || rangeOption, range2 || rangeCmd, "-f", format_id, "-o", `"${path.join(downloadDir, filename + `.${ext}`)}"`, "--ffmpeg-location", ffmpeg, subs1 || subs, subs2 || subLangs, "--no-playlist", // "--embed-metadata", (ext == "m4a" || ext == "mp4") && extractor_key === "Youtube" && os.platform() !== "darwin" ? "--embed-thumbnail" : "", cookieArg, browser, configArg, configTxt, "--no-mtime", proxy ? "--no-check-certificate" : "", proxy ? "--proxy" : "", proxy, `"${url}"`, ].filter(item => item) downloadProcess = ytdlp.exec( args, {shell: true, detached: false}, controller.signal ); } console.log("Spawn args:" + downloadProcess.ytDlpProcess.spawnargs[downloadProcess.ytDlpProcess.spawnargs.length - 1]) getId(randomId + ".close").addEventListener("click", () => { controller.abort() try { process.kill(downloadProcess.ytDlpProcess.pid, 'SIGINT') } catch (_error) {} }); downloadProcess .on("progress", (progress) => { if (progress.percent == 100) { getId(randomId + "prog").textContent = i18n.__("Processing") + "..."; ipcRenderer.send("progress", 0) } else { getId(randomId + "speed").textContent = `${i18n.__("Speed")}: ${ progress.currentSpeed || 0 }`; ipcRenderer.send("progress", progress.percent) getId( randomId + "prog" ).innerHTML = ``; ipcRenderer.send("progress", progress.percent / 100) } }) .once("ytDlpEvent", (_eventType, _eventData) => { getId(randomId + "prog").textContent = i18n.__("Downloading..."); }) .once("close", (code) => { getId(randomId + "speed").textContent = ""; addToDownloadedList(randomId) currentDownloads--; console.log("Closed with code " + code); if (code == 0) { // If extration is done if (type === "extract") { console.log( path.join(downloadDir, filename + `.${extractFormat1}`) ); afterSave( downloadDir, filename + `.${extractExt}`, randomId + "prog", thumb1 || thumbnail ); } // If download is done else { console.log(path.join(downloadDir, filename + `.${ext}`)); afterSave( downloadDir, filename + `.${ext}`, randomId + "prog", thumb1 || thumbnail ); } } if (quit) { console.log("Quitting app"); quitApp(); } }) .once("error", (error) => { currentDownloads--; getId(randomId + "prog").textContent = i18n.__( "Some error has occurred. Hover to see details" ); getId(randomId + "prog").title = error.message; console.log(error.message); }); } function quitApp() { ipcRenderer.send("quit", "quit"); } // Removing item function fadeItem(id) { controllers[id].abort(); getId(id).classList.add("scale"); setTimeout(() => { if (getId(id)) { getId(id).remove(); } }, 500); } function clearAllDownloaded(){ downloadedItemList.forEach(item => { fadeItem(item) }) downloadedItemList = [] hideClearBtn() } function addToDownloadedList(id){ downloadedItemList.push(id) if (downloadedItemList.length > 1) { getId("clearBtn").style.display = "inline-block"; } } function removeFromDownloadedList(id){ downloadedItemList.splice(downloadedItemList.indexOf(id), 1); if (downloadedItemList.length < 2) { hideClearBtn(); } } function hideClearBtn(){ getId("clearBtn").style.display = "none" } // After saving video function afterSave(location, filename, progressId, thumbnail) { const notify = new Notification("ytDownloader", { body: filename, icon: thumbnail, }); notify.onclick = () => { showItem(finalLocation, finalFilename); }; let finalLocation = location; let finalFilename = filename; if (os.platform() === "win32") { finalLocation = location.split(path.sep).join("\\\\"); finalFilename = filename.split(path.sep).join("\\\\"); } const fileSavedElement = document.createElement("b") fileSavedElement.textContent = i18n.__("File saved. Click to Open") fileSavedElement.onclick = () => { showItem(finalLocation, finalFilename) } getId(progressId).innerHTML = ""; getId(progressId).appendChild(fileSavedElement); window.scrollTo(0, document.body.scrollHeight); } function showItem(location, filename) { shell.showItemInFolder(`${path.join(location, filename)}`); } // Rename title function renameTitle() { title = getId("titleName").value; console.log(title); } // Opening windows function closeMenu() { getId("menuIcon").style.transform = "rotate(0deg)"; let count = 0; let opacity = 1; const fade = setInterval(() => { if (count >= 10) { clearInterval(fade); getId("menu").style.display = "none"; } else { opacity -= 0.1; getId("menu").style.opacity = String(opacity); count++; } }, 50); } function hideHidden() { getId("hidden").classList.remove("scaleUp"); getId("hidden").classList.add("scale"); setTimeout(() => { getId("hidden").style.display = "none"; getId("hidden").classList.remove("scale"); }, 400); } // Popup message function showPopup(text) { console.log("Triggered showpopup"); getId("popupText").textContent = text; getId("popupText").style.display = "inline-block"; setTimeout(() => { getId("popupText").style.display = "none"; }, 2200); } /** * * @param {string} item * @returns string */ function getLocalStorageItem(item) { return localStorage.getItem(item) || ""; } // Menu getId("preferenceWin").addEventListener("click", () => { closeMenu(); ipcRenderer.send("load-page", __dirname + "/preferences.html"); }); getId("aboutWin").addEventListener("click", () => { closeMenu(); ipcRenderer.send("load-page", __dirname + "/about.html"); }); getId("playlistWin").addEventListener("click", () => { closeMenu(); ipcRenderer.send("load-win", __dirname + "/playlist.html"); }); getId("compressorWin").addEventListener("click", () => { closeMenu(); ipcRenderer.send("load-win", __dirname + "/compressor.html"); }); // getId("newPlaylistWin").addEventListener("click", () => { // closeMenu(); // ipcRenderer.send("load-win", __dirname + "/playlist_new.html"); // }); ipcRenderer.on("link", (event, text) => { pasteFromTray(text); }); // Selecting download directory getId("selectLocation").addEventListener("click", () => { ipcRenderer.send("select-location-main", ""); }); getId("clearBtn").addEventListener("click", () => { clearAllDownloaded(); }) ipcRenderer.on("downloadPath", (event, downloadPath) => { console.log(downloadPath); getId("path").textContent = downloadPath[0]; downloadDir = downloadPath[0]; });