From 31d8b20a761c4ed693ac5bc4edc96afa70ee195b Mon Sep 17 00:00:00 2001 From: MasterAcnolo <68693319+MasterAcnolo@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:03:32 +0100 Subject: [PATCH] Feat: Implement Config File. Read by Front and Back. It aims to give possibility to disable some features quickly. Currenty: DiscordRPC, AutoCheckInfo, AutoUpdate, Custom TopBar, AddMetadata, Add Thumbail were put and implement. Other need to be implement. That's the begin of Settings Panel --- config.js | 29 ++-- config/config.json | 13 ++ main.js | 15 ++- preload.js | 3 +- public/index.html | 6 +- public/script/fetchinfo.js | 262 +++++++++++++++++++----------------- public/script/topbar.js | 10 +- server/helpers/buildArgs.js | 7 +- 8 files changed, 193 insertions(+), 152 deletions(-) create mode 100644 config/config.json diff --git a/config.js b/config.js index a8362a8..0df8abb 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,20 @@ const packageJson = require("./package.json"); const { app } = require("electron"); +const fs = require("fs"); +const path = require("path"); + +const featuresPath = path.join(__dirname, "./config/config.json"); + +let features = {}; + +function loadFeatures() { + const raw = fs.readFileSync(featuresPath, "utf-8"); + features = JSON.parse(raw); + console.log(features) + return features; +} + +const configFeatures = loadFeatures(); module.exports = { version: packageJson.version, @@ -7,17 +22,5 @@ module.exports = { debugMode: true, localMode: !app.isPackaged, DiscordRPCID: "1410934537051181146", - - // Variables Used to toggle main features - autoUpdate: true, - discordRPC: true, - customTopBar: true, // (Will be active on next launch) - autoDownloadPlaylist: true, - logSystem: true, // Disable = Dangerous - autoCheckInfo: true, // To Improve speed ? (NO) - outputTitleCheck: true, // For Non latin characters (Russian) - addThumbail: true, // The Pictures in the files (audio files) - addMetadata: true, // Looks Explicit - downloadSystem: true, // Why would you disable this ? I don't know but why not - notifySystem: true // Notification when download + configFeatures } \ No newline at end of file diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..f969fb6 --- /dev/null +++ b/config/config.json @@ -0,0 +1,13 @@ +{ + "autoUpdate": true, + "discordRPC": true, + "customTopBar": true, + "autoDownloadPlaylist": true, + "logSystem": true, + "autoCheckInfo": true, + "outputTitleCheck": true, + "addThumbnail": true, + "addMetadata": true, + "downloadSystem": true, + "notifySystem": true +} \ No newline at end of file diff --git a/main.js b/main.js index aa43415..b8680de 100644 --- a/main.js +++ b/main.js @@ -3,8 +3,11 @@ const { app, BrowserWindow, ipcMain, dialog, Menu, shell } = require("electron") const path = require("path"); const os = require("os"); const fs = require("fs"); + const { logger, logSessionStart, logSessionEnd, logDir } = require("./server/logger"); const { AutoUpdater } = require("./server/update.js"); +const { configFeatures } = require("./config.js"); +const { startRPC } = require("./server/discordRPC"); let mainWindow; const logsFolderPath = logDir; @@ -77,7 +80,7 @@ async function createMainWindow() { height: 800, minWidth: 750, minHeight: 800, - frame:false, + frame: !configFeatures.customTopBar, webPreferences: { nodeIntegration: false, contextIsolation: true, @@ -163,11 +166,15 @@ app.whenReady().then(async () => { await expressServer.startServer(); logger.info("Express Server Started"); - const { startRPC } = require("./server/discordRPC"); - startRPC(); + ipcMain.handle("features", () => { + return configFeatures; + }); + + configFeatures.discordRPC ? startRPC() : ""; await createMainWindow(); - AutoUpdater(mainWindow); + configFeatures.AutoUpdater ? AutoUpdater(mainWindow) : ""; // Auto Update + } catch (err) { logger.error("Window or Server error :", err); app.quit(); diff --git a/preload.js b/preload.js index 2f0e8e8..5da0c1c 100644 --- a/preload.js +++ b/preload.js @@ -3,7 +3,8 @@ const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("electronAPI", { getDefaultDownloadPath: () => ipcRenderer.invoke("get-default-download-path"), selectDownloadFolder: () => ipcRenderer.invoke("select-download-folder"), - setProgress: (percent) => ipcRenderer.send("set-progress", percent) + setProgress: (percent) => ipcRenderer.send("set-progress", percent), + getFeatures: () => ipcRenderer.invoke("features") }); // Contrôles de fenêtre et outils custom pour la topbar diff --git a/public/index.html b/public/index.html index 76d9296..3f8e077 100644 --- a/public/index.html +++ b/public/index.html @@ -17,7 +17,7 @@ -
+
@@ -31,12 +31,12 @@
-
+
-
+

Freedom Loader

diff --git a/public/script/fetchinfo.js b/public/script/fetchinfo.js index bffb928..9db3040 100644 --- a/public/script/fetchinfo.js +++ b/public/script/fetchinfo.js @@ -25,156 +25,164 @@ async function fetchVideoInfo(url) { return { error: "Network or JSON Issue" }; } } +async function init() { + const configFeatures = await window.electronAPI.getFeatures(); -document.addEventListener("DOMContentLoaded", () => { - const urlInput = document.getElementById("UrlInput"); - const infoDiv = document.getElementById("videoInfo"); - const loaderBox = document.getElementById("loaderBox"); + if (!configFeatures.autoCheckInfo) return; - let lastFetchedUrl = ""; + document.addEventListener("DOMContentLoaded", () => { + const urlInput = document.getElementById("UrlInput"); + const infoDiv = document.getElementById("videoInfo"); + const loaderBox = document.getElementById("loaderBox"); - urlInput.addEventListener("input", async () => { - const url = urlInput.value.trim(); + let lastFetchedUrl = ""; - // Si champ vide -> reset total - if (!url || url.length < 2) { - infoDiv.innerHTML = ""; - infoDiv.classList.remove("visible", "playlist-mode"); - lastFetchedUrl = ""; - return; - } + urlInput.addEventListener("input", async () => { + const url = urlInput.value.trim(); - if (url === lastFetchedUrl) return; - lastFetchedUrl = url; + // Si champ vide -> reset total + if (!url || url.length < 2) { + infoDiv.innerHTML = ""; + infoDiv.classList.remove("visible", "playlist-mode"); + lastFetchedUrl = ""; + return; + } - loaderBox.style.display = "flex"; - const data = await fetchVideoInfo(url); - loaderBox.style.display = "none"; + if (url === lastFetchedUrl) return; + lastFetchedUrl = url; - // Gestion des erreurs - if (data.error) { - infoDiv.innerHTML = ` -
- ${data.error} -
- `; - infoDiv.classList.add("visible"); - infoDiv.classList.remove("playlist-mode"); + loaderBox.style.display = "flex"; + const data = await fetchVideoInfo(url); loaderBox.style.display = "none"; - return; - } - // ---------- PLAYLIST ---------- - if (data.type === "playlist") { - infoDiv.classList.add("playlist-mode"); - infoDiv.innerHTML = ` -

Playlist Detected: ${data.title}

-

Video Count: ${data.count}

-

Channel : ${data.channel || "Unknown"}

-
- `; - - const listDiv = document.getElementById("playlistVideos"); - - data.videos.forEach(v => { - const durationStr = v.duration - ? `${Math.floor(v.duration / 60)}m ${(v.duration % 60).toString().padStart(2,"0")}s` : "Inconnue"; - - const videoUrl = v.id ? `https://www.youtube.com/watch?v=${v.id}` : v.url; - - listDiv.innerHTML += ` -
- Thumbnail -

${v.title}

-

Duration : ${durationStr}

-

URL - -

+ // Gestion des erreurs + if (data.error) { + infoDiv.innerHTML = ` +
+ ${data.error}
`; - }); + infoDiv.classList.add("visible"); + infoDiv.classList.remove("playlist-mode"); + loaderBox.style.display = "none"; + return; + } - // Gestion du bouton copier - listDiv.addEventListener("click", (event) => { - if (event.target.classList.contains("copy-btn")) { - const btn = event.target; - if (btn.disabled) return; + // ---------- PLAYLIST ---------- + if (data.type === "playlist") { + infoDiv.classList.add("playlist-mode"); + infoDiv.innerHTML = ` +

Playlist Detected: ${data.title}

+

Video Count: ${data.count}

+

Channel : ${data.channel || "Unknown"}

+
+ `; - btn.disabled = true; - const url = btn.dataset.url; - navigator.clipboard.writeText(url) - .then(() => { - const original = btn.textContent; + const listDiv = document.getElementById("playlistVideos"); - btn.style.opacity = 0; - btn.style.transform = "scale(0.7)"; + data.videos.forEach(v => { + const durationStr = v.duration + ? `${Math.floor(v.duration / 60)}m ${(v.duration % 60).toString().padStart(2,"0")}s` : "Inconnue"; - setTimeout(() => { - btn.textContent = "✅"; - btn.style.opacity = 1; - btn.style.transform = "scale(1)"; + const videoUrl = v.id ? `https://www.youtube.com/watch?v=${v.id}` : v.url; + + listDiv.innerHTML += ` +
+ Thumbnail +

${v.title}

+

Duration : ${durationStr}

+

URL + +

+
+ `; + }); + + // Gestion du bouton copier + listDiv.addEventListener("click", (event) => { + if (event.target.classList.contains("copy-btn")) { + const btn = event.target; + if (btn.disabled) return; + + btn.disabled = true; + const url = btn.dataset.url; + navigator.clipboard.writeText(url) + .then(() => { + const original = btn.textContent; + + btn.style.opacity = 0; + btn.style.transform = "scale(0.7)"; setTimeout(() => { - btn.style.opacity = 0; - btn.style.transform = "scale(0.7)"; + btn.textContent = "✅"; + btn.style.opacity = 1; + btn.style.transform = "scale(1)"; setTimeout(() => { - btn.textContent = original; - btn.style.opacity = 1; - btn.style.transform = "scale(1)"; - btn.disabled = false; - }, 300); + btn.style.opacity = 0; + btn.style.transform = "scale(0.7)"; - }, 1000); + setTimeout(() => { + btn.textContent = original; + btn.style.opacity = 1; + btn.style.transform = "scale(1)"; + btn.disabled = false; + }, 300); - }, 300); - }) - .catch(() => { - const original = btn.textContent; - btn.textContent = "❌"; - setTimeout(() => { - btn.textContent = original; - btn.disabled = false; - }, 1500); - }); - } - }); + }, 1000); + + }, 300); + }) + .catch(() => { + const original = btn.textContent; + btn.textContent = "❌"; + setTimeout(() => { + btn.textContent = original; + btn.disabled = false; + }, 1500); + }); + } + }); + + infoDiv.classList.add("visible"); + return; + } + + infoDiv.classList.remove("playlist-mode"); + + // ---------- VIDEO NORMALE ---------- + const durationStr = data.duration + ? `${Math.floor(data.duration/60)}m ${(data.duration%60).toString().padStart(2,"0")}s` + : "Unknown"; + + const sizeStr = formatSize(data.filesize_approx); + const readableDate = formatDate(data.upload_date); + const categories = data.categories?.join(", ") || "Non spécifiées"; + + infoDiv.innerHTML = ` +

${data.title}

+ Thumbnail +
    +
  • Duration : ${durationStr}
  • +
  • Uploader : ${data.uploader || "Inconnu"}
  • +
  • Upload Date : ${readableDate}
  • +
  • Views : ${data.view_count?.toLocaleString() || "?"}
  • +
  • Likes : ${data.like_count?.toLocaleString() || "?"}
  • +
  • URL : ${data.webpage_url}
  • +
  • Channel : ${data.channel_url}
  • +
  • Estimed Size : ${sizeStr}
  • +
  • Category : ${categories}
  • +
+ `; infoDiv.classList.add("visible"); - return; - } + }); - infoDiv.classList.remove("playlist-mode"); + }) - // ---------- VIDEO NORMALE ---------- - const durationStr = data.duration - ? `${Math.floor(data.duration/60)}m ${(data.duration%60).toString().padStart(2,"0")}s` - : "Unknown"; +}; - const sizeStr = formatSize(data.filesize_approx); - const readableDate = formatDate(data.upload_date); - const categories = data.categories?.join(", ") || "Non spécifiées"; - - infoDiv.innerHTML = ` -

${data.title}

- Thumbnail -
    -
  • Duration : ${durationStr}
  • -
  • Uploader : ${data.uploader || "Inconnu"}
  • -
  • Upload Date : ${readableDate}
  • -
  • Views : ${data.view_count?.toLocaleString() || "?"}
  • -
  • Likes : ${data.like_count?.toLocaleString() || "?"}
  • -
  • URL : ${data.webpage_url}
  • -
  • Channel : ${data.channel_url}
  • -
  • Estimed Size : ${sizeStr}
  • -
  • Category : ${categories}
  • -
- `; - - infoDiv.classList.add("visible"); - }); - -}) \ No newline at end of file +init(); \ No newline at end of file diff --git a/public/script/topbar.js b/public/script/topbar.js index 0225ea8..2221667 100644 --- a/public/script/topbar.js +++ b/public/script/topbar.js @@ -21,4 +21,12 @@ function setupTopbarListeners() { }); } -setupTopbarListeners(); +setupTopbarListeners(); // IF it put it the if check. It don't work. Why ? + +const features = await window.electronAPI.getFeatures(); + +if(!features.customTopBar){ + document.getElementById("topbar").style.display = "none"; + document.getElementById("container").style.marginTop = "0"; + document.getElementById("theme-switcher").style.top = "30px"; +} \ No newline at end of file diff --git a/server/helpers/buildArgs.js b/server/helpers/buildArgs.js index eb48215..16586f3 100644 --- a/server/helpers/buildArgs.js +++ b/server/helpers/buildArgs.js @@ -2,6 +2,7 @@ const path = require("path"); const getUserBrowser = require("./getBrowser"); const { ffmpegPath, denoPath} = require("./path"); +const { configFeatures } = require("../../config.js"); function buildYtDlpArgs({ url, audioOnly, quality, outputFolder }) { @@ -10,8 +11,8 @@ function buildYtDlpArgs({ url, audioOnly, quality, outputFolder }) { "--cookies-from-browser", `${getUserBrowser()}`, "--no-continue", "--no-overwrites", - "--embed-thumbnail", - "--add-metadata", + configFeatures.addThumbail ? "--embed-thumbnail" : null, + configFeatures.addMetadata ? "--add-metadata" : null, "--concurrent-fragments", "8", "--retries", "10", "--fragment-retries", "10", @@ -37,7 +38,7 @@ function buildYtDlpArgs({ url, audioOnly, quality, outputFolder }) { args.push("-o", path.join(outputFolder, "%(title)s.%(ext)s")); args.push(url); - return args; + return args.filter(Boolean); } module.exports = { buildYtDlpArgs };