diff --git a/assets/css/extra.css b/assets/css/extra.css index 7534119..29567e6 100644 --- a/assets/css/extra.css +++ b/assets/css/extra.css @@ -186,6 +186,12 @@ input[type="text"], background-color: var(--box-main); } +#ytDlpArgBox { + margin: 15px 15px; + padding: 20px 15px; + border-radius: 15px; + background-color: var(--box-main); +} #path { font-family: "JetBrains"; font-size: medium; @@ -331,3 +337,14 @@ body::-webkit-scrollbar-thumb { #proxyTxt:invalid { border: 2px solid var(--redBtn); } + +#customArgsInput { + padding: 8px; + width: 94%; + margin: auto; + outline: none; + font-family: "JetBrains"; + border-radius: 8px; + resize: none; + overflow: hidden; +} diff --git a/html/index.html b/html/index.html index e1bbcc3..bfbab0c 100644 --- a/html/index.html +++ b/html/index.html @@ -160,7 +160,7 @@

Custom yt-dlp arguments

- +
Close app when download finishes diff --git a/html/preferences.html b/html/preferences.html index 7c34dbb..93022c0 100644 --- a/html/preferences.html +++ b/html/preferences.html @@ -26,10 +26,12 @@
- Current download location - + Current download location -
- +

@@ -130,6 +132,14 @@ pattern="^(http:\/\/|https:\/\/|socks5:\/\/)?[a-zA-Z0-9.]+:[\d]+$">
+
+

+ Set custom yt-dlp arguments. + Learn more +

+ +
+
diff --git a/main.js b/main.js index dc37332..14b01a5 100644 --- a/main.js +++ b/main.js @@ -18,7 +18,7 @@ process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "true"; autoUpdater.autoDownload = false; const USER_DATA_PATH = app.getPath("userData"); -const CONFIG_FILE_PATH = path.join(USER_DATA_PATH, "config.json"); +const CONFIG_FILE_PATH = path.join(USER_DATA_PATH, "ytdownloader.json"); const appState = { /** @type {BrowserWindow | null} */ @@ -199,14 +199,14 @@ function createTray() { const contextMenu = Menu.buildFromTemplate([ { - label: i18n("Open app"), + label: i18n("openApp"), click: () => { appState.mainWindow?.show(); if (app.dock) app.dock.show(); }, }, { - label: i18n("Paste video link"), + label: i18n("pasteVideoLink"), click: async () => { const text = clipboard.readText(); appState.mainWindow?.show(); @@ -226,7 +226,7 @@ function createTray() { }, }, { - label: i18n("Download playlist"), + label: i18n("downloadPlaylistButton"), click: () => { appState.indexPageIsOpen = false; appState.mainWindow?.loadFile("html/playlist.html"); @@ -235,7 +235,7 @@ function createTray() { }, }, { - label: i18n("Quit"), + label: i18n("quit"), click: () => { app.quit(); }, @@ -445,9 +445,9 @@ function registerAutoUpdaterEvents() { autoUpdater.on("update-available", async (info) => { const dialogOpts = { type: "info", - buttons: [i18n("Update"), i18n("No")], + buttons: [i18n("update"), i18n("no")], title: "Update Available", - message: `A new version (${info.version}) is available. Do you want to update?`, + message: i18n("updateAvailablePrompt"), detail: info.releaseNotes?.toString().replace(/<[^>]*>?/gm, "") || "No details available.", @@ -464,9 +464,9 @@ function registerAutoUpdaterEvents() { autoUpdater.on("update-downloaded", async () => { const dialogOpts = { type: "info", - buttons: [i18n("Restart"), i18n("Later")], + buttons: [i18n("restart"), i18n("later")], title: "Update Ready", - message: "The update has been downloaded. Install and restart now?", + message: i18n("installAndRestartPrompt"), }; const {response} = await dialog.showMessageBox( appState.mainWindow, @@ -481,7 +481,7 @@ function registerAutoUpdaterEvents() { console.error("Auto-update error:", error); dialog.showErrorBox( "Update Error", - `An error occurred during the update process: ${error.message}` + i18n("updateError") ); }); } @@ -501,21 +501,6 @@ async function loadConfiguration() { try { const fileContent = await fs.readFile(CONFIG_FILE_PATH, "utf8"); appState.config = JSON.parse(fileContent); - - if (appState.config && typeof appState.config.bounds === "string") { - console.log("Old config format detected. Migrating..."); - - try { - appState.config.bounds = JSON.parse(appState.config.bounds); - } catch (migrationError) { - console.error( - "Failed to migrate from old config. Resetting to default.", - migrationError - ); - - appState.config.bounds = {width: 1024, height: 768}; - } - } } catch (error) { console.log( "Could not load config file, using defaults.", diff --git a/src/preferences.js b/src/preferences.js index 7229869..9c173a5 100644 --- a/src/preferences.js +++ b/src/preferences.js @@ -24,7 +24,7 @@ if (rightToLeft == "true") { let downloadPath = localStorage.getItem("downloadPath"); getId("path").textContent = downloadPath; -const {ipcRenderer} = require("electron"); +const {ipcRenderer, shell} = require("electron"); /** * * @param {string} id @@ -162,6 +162,24 @@ getId("proxyTxt").addEventListener("change", () => { localStorage.setItem("proxy", proxy); }); +// Custom yt-dlp args +const ytDlpArgsInput = getId("customArgsInput"); +let customYtDlpArgs = localStorage.getItem("customYtDlpArgs"); +if (customYtDlpArgs) { + ytDlpArgsInput.value = customYtDlpArgs; + ytDlpArgsInput.style.height = ytDlpArgsInput.scrollHeight + "px"; +} +ytDlpArgsInput.addEventListener("input", () => { + customYtDlpArgs = getId("customArgsInput").value; + localStorage.setItem("customYtDlpArgs", customYtDlpArgs.trim()); + ytDlpArgsInput.style.height = "auto"; + ytDlpArgsInput.style.height = ytDlpArgsInput.scrollHeight + "px"; +}); + +getId("learnMoreLink").addEventListener("click", () => { + shell.openExternal("https://github.com/aandrew-me/ytDownloader/wiki/Custom-yt%E2%80%90dlp-options") +}) + // Reload function reload() { ipcRenderer.send("reload"); diff --git a/src/renderer.js b/src/renderer.js index bb81833..1306dc1 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -73,6 +73,7 @@ const CONSTANTS = { CONFIG_PATH: "configPath", AUTO_UPDATE: "autoUpdate", CLOSE_TO_TRAY: "closeToTray", + YT_DLP_CUSTOM_ARGS: "customYtDlpArgs", }, }; @@ -116,7 +117,7 @@ class YtDownloaderApp { showMoreFormats: false, proxy: "", browserForCookies: "", - configPath: "", + customYtDlpArgs: "", }, downloadControllers: new Map(), downloadedItems: new Set(), @@ -368,11 +369,25 @@ class YtDownloaderApp { } // Priority 4: Default location or download + const ytDlpPath = await this.ensureYtDlpBinary(defaultYtDlpPath) + return ytDlpPath + } + + /** + * Checks for the presence of the yt-dlp binary at the default path. + * If not found, it attempts to download it from GitHub. + * + * @param {string} defaultYtDlpPath The expected path to the yt-dlp binary. + * @returns {Promise} A promise that resolves with the path to the yt-dlp binary. + * @throws {Error} Throws an error if the download fails. + */ + async ensureYtDlpBinary(defaultYtDlpPath) { try { await promises.access(defaultYtDlpPath); return defaultYtDlpPath; } catch { console.log("yt-dlp not found, downloading..."); + $(CONSTANTS.DOM_IDS.POPUP_BOX).style.display = "block"; $(CONSTANTS.DOM_IDS.POPUP_SVG).style.display = "inline"; document.querySelector("#popupBox p").textContent = i18n.__( @@ -411,6 +426,16 @@ class YtDownloaderApp { ); $(CONSTANTS.DOM_IDS.POPUP_SVG).style.display = "none"; + + const tryAgainBtn = document.createElement("button"); + tryAgainBtn.id = "tryBtn"; + tryAgainBtn.textContent = i18n.__("tryAgain") + tryAgainBtn.addEventListener("click", () => { + // TODO: Improve it + ipcRenderer.send("reload"); + }); + document.getElementById("popup").appendChild(tryAgainBtn) + throw new Error("Failed to download yt-dlp."); } } @@ -505,14 +530,22 @@ class YtDownloaderApp { localStorage.getItem( CONSTANTS.LOCAL_STORAGE_KEYS.BROWSER_COOKIES ) || ""; - prefs.configPath = - localStorage.getItem(CONSTANTS.LOCAL_STORAGE_KEYS.CONFIG_PATH) || - ""; + prefs.customYtDlpArgs = + localStorage.getItem( + CONSTANTS.LOCAL_STORAGE_KEYS.YT_DLP_CUSTOM_ARGS + ) || ""; + this.state.downloadDir = localStorage.getItem( + CONSTANTS.LOCAL_STORAGE_KEYS.DOWNLOAD_PATH + ); const maxDownloads = Number( localStorage.getItem(CONSTANTS.LOCAL_STORAGE_KEYS.MAX_DOWNLOADS) ); this.state.maxActiveDownloads = maxDownloads >= 1 ? maxDownloads : 5; + + // Update UI with loaded settings + $(CONSTANTS.DOM_IDS.CUSTOM_ARGS_INPUT).value = prefs.customYtDlpArgs; + $(CONSTANTS.DOM_IDS.PATH_DISPLAY).textContent = this.state.downloadDir; } /** diff --git a/translations/en.json b/translations/en.json index 73b14d5..88842cb 100644 --- a/translations/en.json +++ b/translations/en.json @@ -157,5 +157,7 @@ "updatedYtdlp": "Updated yt-dlp", "ytDlpUpdateRequired": "If yt-dlp is updating, wait for the update to finish. If you have installed yt-dlp by yourself, please update it.", "failedToDeleteHistoryItem": "Failed to delete history item", - "customArgsTxt": "Custom yt-dlp arguments" + "customArgsTxt": "Set custom yt-dlp options.", + "learnMore": "Learn more", + "updateError": "An error occurred during the update process" }