From b4242e42955fec8f5d17bb4d5ba9e4a17c23932c Mon Sep 17 00:00:00 2001 From: MasterAcnolo <68693319+MasterAcnolo@users.noreply.github.com> Date: Sun, 29 Jun 2025 14:10:58 +0200 Subject: [PATCH 1/5] Correction Git Ignore --- .gitignore | 1 - forge.config.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 forge.config.js diff --git a/.gitignore b/.gitignore index afdf369..afc0ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ yt-dlp.exe -forge.config.js diff --git a/forge.config.js b/forge.config.js new file mode 100644 index 0000000..fa4a113 --- /dev/null +++ b/forge.config.js @@ -0,0 +1,44 @@ +const { FusesPlugin } = require('@electron-forge/plugin-fuses'); +const { FuseV1Options, FuseVersion } = require('@electron/fuses'); + +module.exports = { + packagerConfig: { + asar: true, + }, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: {}, + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: {}, + }, + { + name: '@electron-forge/maker-rpm', + config: {}, + }, + ], + plugins: [ + { + name: '@electron-forge/plugin-auto-unpack-natives', + config: {}, + }, + // Fuses are used to enable/disable various Electron functionality + // at package time, before code signing the application + new FusesPlugin({ + version: FuseVersion.V1, + [FuseV1Options.RunAsNode]: false, + [FuseV1Options.EnableCookieEncryption]: true, + [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, + [FuseV1Options.EnableNodeCliInspectArguments]: false, + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, + [FuseV1Options.OnlyLoadAppFromAsar]: true, + }), + ], +}; From 9026c63979d78a04b40c8d9cd0f1eefd5ace87ec Mon Sep 17 00:00:00 2001 From: MasterAcnolo <68693319+MasterAcnolo@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:48:06 +0200 Subject: [PATCH 2/5] Clarification --- server/logger.js | 41 +++++++++++++++++++++------------ server/routes/download.js | 48 +++++++++++++++++++++++++++------------ server/routes/info.js | 20 +++++++++++----- server/server.js | 40 ++++++++++++++++++++------------ 4 files changed, 100 insertions(+), 49 deletions(-) diff --git a/server/logger.js b/server/logger.js index 8e1cc7a..295268d 100644 --- a/server/logger.js +++ b/server/logger.js @@ -16,51 +16,61 @@ along with this program. If not, see . */ -const { createLogger, format, transports } = require("winston"); -const DailyRotateFile = require("winston-daily-rotate-file"); -const fs = require("fs"); -const path = require("path"); +const { createLogger, format, transports } = require("winston"); +// on importe Winston (logger populaire pour Node.js) +const DailyRotateFile = require("winston-daily-rotate-file"); +// plugin pour Winston qui permet la rotation automatique des fichiers de logs + +const fs = require("fs"); // pour vérifier/créer le dossier de logs +const path = require("path"); // pour gérer proprement les chemins + +// on définit le dossier de logs const logDir = path.join(__dirname, "../logs"); +// on le crée si inexistant if (!fs.existsSync(logDir)) fs.mkdirSync(logDir); +// fonction pour générer une ligne de début de session (date ISO) function getSessionStartLine() { const now = new Date().toISOString(); return `--- Démarrage de la session : ${now} ---`; } +// fonction pour générer une ligne de fin de session (date ISO) function getSessionEndLine() { const now = new Date().toISOString(); return `--- Fin de la session : ${now} ---`; } +// configuration principale de Winston const logger = createLogger({ - level: "info", + level: "info", // niveau de log minimum (info, warn, error, etc.) format: format.combine( - format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), + format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), // timestamp lisible format.printf(({ timestamp, level, message }) => - `${timestamp} | ${level.toUpperCase()} | ${message}` + `${timestamp} | ${level.toUpperCase()} | ${message}` // format de ligne de log ) ), transports: [ new DailyRotateFile({ - dirname: logDir, - filename: "combined-%DATE%.log", - datePattern: "YYYY-MM-DD", - zippedArchive: false, // tu peux mettre true si tu veux compresser - maxFiles: "14d", // conserve les logs des 14 derniers jours + dirname: logDir, // dossier de logs + filename: "combined-%DATE%.log", // nom de fichier journalier + datePattern: "YYYY-MM-DD", // pattern de rotation + zippedArchive: false, // true = compression des archives + maxFiles: "14d", // garde 14 jours d’historique format: format.combine( format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), format.printf(({ timestamp, level, message }) => `${timestamp} | ${level.toUpperCase()} | ${message}` ) ), - options: { flags: "a" }, + options: { flags: "a" }, // mode append }), new transports.Console({ + // sortie console colorisée (dev en local) format: format.combine( format.colorize(), - format.timestamp({ format: "HH:mm:ss" }), + format.timestamp({ format: "HH:mm:ss" }), // horodatage plus court format.printf(({ timestamp, level, message }) => `${timestamp} | ${level} | ${message}` ) @@ -69,14 +79,17 @@ const logger = createLogger({ ], }); +// fonction d'utilitaire pour marquer le début de la session function logSessionStart() { logger.info(getSessionStartLine()); } +// idem pour la fin de la session function logSessionEnd() { logger.info(getSessionEndLine()); } +// exporte le logger et les helpers pour les autres modules module.exports = { logger, logSessionStart, diff --git a/server/routes/download.js b/server/routes/download.js index 3bac042..af916b7 100644 --- a/server/routes/download.js +++ b/server/routes/download.js @@ -16,90 +16,110 @@ along with this program. If not, see . */ -const express = require("express"); -const router = express.Router(); -const { execFile } = require("child_process"); -const path = require("path"); -const fs = require("fs"); +const express = require("express"); // importe le framework Express +const router = express.Router(); // crée un routeur Express pour modulariser les routes +const { execFile } = require("child_process"); // permet d’exécuter un binaire externe sans passer par un shell +const path = require("path"); // module Node.js pour gérer les chemins de fichiers +const fs = require("fs"); // module Node.js pour manipuler le système de fichiers -const logger = require("../logger").logger; // importe ton logger Winston +const logger = require("../logger").logger; // récupère l'instance de logger Winston personnalisée +// chemin vers l’exécutable yt-dlp packagé avec l’appli const ytDlpPath = path.join(__dirname, '../../yt-dlp.exe'); +// route POST sur la racine (ex: POST /download) router.post("/", (req, res) => { try { + // récupère les options envoyées depuis le frontend (via formulaire ou requête AJAX) const options = { - url: req.body.url, - audioOnly: req.body.audioOnly === "1", - quality: req.body.quality || "best", - subtitles: req.body.subs === "1", + url: req.body.url, // URL à télécharger + audioOnly: req.body.audioOnly === "1", // conversion audio uniquement (mp3) + quality: req.body.quality || "best", // qualité vidéo à télécharger + subtitles: req.body.subs === "1", // récupérer les sous-titres anglais }; if (!options.url) { + // si l’URL est absente, on log et on renvoie 400 logger.warn("Requête POST /download sans URL"); return res.status(400).send("❌ URL manquante !"); } - // Récupérer le chemin Freedom Loader Output depuis app.locals + // on récupère le dossier de sortie depuis app.locals (défini ailleurs dans le serveur) const outputFolder = req.app.locals.outputFolder; + // s'il n'existe pas, on le crée automatiquement if (!fs.existsSync(outputFolder)) { fs.mkdirSync(outputFolder, { recursive: true }); logger.info("Dossier Freedom Loader Output créé à la volée dans Téléchargements."); } - // Construire le template de sortie + // template du nom de fichier de sortie (ex: MonTitre.mp4 ou MonTitre.mp3) const outputTemplate = path.join(outputFolder, "%(title)s.%(ext)s"); - // Construire les arguments pour execFile + // tableau d'arguments pour yt-dlp const args = []; if (options.audioOnly) { + // si audioOnly, on force extraction audio en mp3 args.push("--extract-audio", "--audio-format", "mp3"); } if (options.subtitles) { + // si l’utilisateur veut des sous-titres args.push("--write-subs", "--sub-lang", "en"); } + // qualité souhaitée args.push("-f", options.quality); + // modèle de sortie args.push("-o", outputTemplate); + // enfin, l'URL à télécharger args.push(options.url); + // log de la commande complète pour debug logger.info(`Commande yt-dlp : ${ytDlpPath} ${args.join(" ")}`); + // exécution du binaire yt-dlp const child = execFile(ytDlpPath, args); + // gestion des logs stdout de yt-dlp child.stdout.on("data", (data) => { data.toString().split("\n").forEach(line => { if(line.trim()) logger.info(`[yt-dlp stdout] ${line.trim()}`); }); }); + // gestion des logs stderr de yt-dlp (les erreurs) child.stderr.on("data", (data) => { data.toString().split("\n").forEach(line => { if(line.trim()) logger.error(`[yt-dlp stderr] ${line.trim()}`); }); }); + // si une erreur système survient (par ex : yt-dlp.exe introuvable) child.on("error", (err) => { logger.error(`Erreur lancement yt-dlp : ${err.message}`); res.status(500).send(`❌ Erreur lors de l'exécution : ${err.message}`); }); + // callback quand le processus se termine child.on("close", (code) => { logger.info(`yt-dlp terminé avec code de sortie : ${code}`); if(code === 0) { + // succès res.send("✅ Téléchargement terminé !"); } else { + // yt-dlp a échoué res.status(500).send(`❌ yt-dlp a échoué avec le code : ${code}`); } }); } catch (err) { + // en cas d'erreur JavaScript logger.error(`Erreur serveur dans /download : ${err.message}`); res.status(500).send(`Erreur serveur : ${err.message}`); } }); -module.exports = router; +// on exporte ce routeur pour qu'il soit utilisé par l'app principale +module.exports = router; \ No newline at end of file diff --git a/server/routes/info.js b/server/routes/info.js index 23eb652..372e823 100644 --- a/server/routes/info.js +++ b/server/routes/info.js @@ -16,32 +16,40 @@ along with this program. If not, see . */ -const express = require("express"); -const router = express.Router(); -const { execFile } = require("child_process"); -const path = require("path"); +const express = require("express"); // importe Express +const router = express.Router(); // crée un routeur Express indépendant +const { execFile } = require("child_process"); // permet d’exécuter un programme externe +const path = require("path"); // module pour gérer les chemins de fichiers +// chemin vers le binaire yt-dlp embarqué const ytDlpPath = path.join(__dirname, "../../yt-dlp.exe"); +// route POST sur la racine de ce routeur router.post("/", (req, res) => { - const url = req.body.url; - if (!url) return res.status(400).send("❌ URL manquante"); + const url = req.body.url; // récupère l'URL depuis la requête POST + if (!url) return res.status(400).send("❌ URL manquante"); // validation simple + // exécute yt-dlp avec --dump-json pour récupérer les métadonnées de la vidéo execFile(ytDlpPath, ["--dump-json", url], (error, stdout, stderr) => { if (error) { + // gestion d’erreur : par exemple yt-dlp plante ou l’URL est invalide console.error("Erreur lors de l'exécution de yt-dlp :", error); console.error("stderr :", stderr); return res.status(500).send("❌ Impossible de récupérer les infos."); } try { + // on parse le JSON envoyé par yt-dlp const info = JSON.parse(stdout); + // on renvoie l’objet JSON directement au frontend res.json(info); } catch (e) { + // le JSON est mal formé console.error("Erreur lors du parsing JSON :", e); res.status(500).send("❌ JSON illisible."); } }); }); +// on exporte le routeur pour être utilisé dans app.js ou ailleurs module.exports = router; diff --git a/server/server.js b/server/server.js index c2e98c3..ba05351 100644 --- a/server/server.js +++ b/server/server.js @@ -16,59 +16,68 @@ along with this program. If not, see . */ -const express = require("express"); -const { exec } = require("child_process"); -const fs = require("fs"); -const path = require("path"); -const debug = require("debug")("freedom-loader:server"); +const express = require("express"); // framework web +const { exec } = require("child_process"); // si besoin d’exécuter des commandes (pas utilisé ici directement) +const fs = require("fs"); // accès au système de fichiers +const path = require("path"); // gestion de chemins +const debug = require("debug")("freedom-loader:server"); +// petit debugger coloré en console + const { logger, logSessionStart, logSessionEnd } = require("./logger"); +// récupère notre logger Winston + helpers de session -const app = express(); +const app = express(); // instancie l'application Express -// // Lancement d'une nouvelle session de log -// logSessionStart(); +// logSessionStart(); // désactivé, mais pourrait logguer le début de session -// dossier de sortie +// on définit le dossier de téléchargement dans le dossier Téléchargements de l’utilisateur const downloadsPath = path.join(process.env.USERPROFILE, "Downloads"); const outputFolder = path.join(downloadsPath, "Freedom Loader Output"); +// création du dossier s’il n’existe pas if (!fs.existsSync(outputFolder)) { try { fs.mkdirSync(outputFolder, { recursive: true }); logger.info("Dossier Freedom Loader Output cree dans Telechargements."); } catch (err) { logger.error("Impossible de creer le dossier :", err); - process.exit(1); + process.exit(1); // arrêt du programme en cas d’échec } } else { logger.info("Dossier Freedom Loader Output deja existant."); } +// on rend ce dossier dispo via app.locals app.locals.outputFolder = outputFolder; + +// configuration pour parser les requêtes POST en urlencoded app.use(express.urlencoded({ extended: true })); +// sert les fichiers statiques (frontend) const staticPath = path.join(__dirname, "../public"); debug("Serveur statique sur", staticPath); app.use(express.static(staticPath)); -// routes +// enregistre les routes API const infoRoute = require("./routes/info"); const downloadRoute = require("./routes/download"); debug("Routes /download et /info installees"); app.use("/download", downloadRoute); app.use("/info", infoRoute); +// route GET / de base app.get("/", (req, res) => { debug("Requete GET / servie"); res.sendFile(path.join(__dirname, "../public/index.html")); }); +// fonction pour démarrer le serveur (Promise pour pouvoir await ailleurs) function startServer() { return new Promise((resolve, reject) => { logger.info("Demarrage du serveur Express..."); const serverInstance = app.listen(8080, () => { logger.info("Serveur Express pret sur http://localhost:8080"); - resolve(serverInstance); + resolve(serverInstance); // succès }); serverInstance.on("error", (err) => { logger.error("Erreur serveur Express :", err); @@ -77,17 +86,18 @@ function startServer() { }); } -// Gestion propre de la fin de session à la fermeture du process +// gestion de la fermeture propre du process // process.on("exit", () => { // logSessionEnd(); // }); -process.on("SIGINT", () => { +process.on("SIGINT", () => { // Ctrl+C logSessionEnd(); process.exit(); }); -process.on("SIGTERM", () => { +process.on("SIGTERM", () => { // kill logSessionEnd(); process.exit(); }); +// on exporte la fonction startServer pour que d’autres modules puissent la lancer module.exports = { startServer }; From c8889465885d9899c656527ed2b74db96f94b262 Mon Sep 17 00:00:00 2001 From: MasterAcnolo <68693319+MasterAcnolo@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:49:02 +0200 Subject: [PATCH 3/5] Logs Name Ajust + 1.0.1 Prepa --- README.md | 2 +- package-lock.json | 2308 ++++++++++----------------------------------- package.json | 2 +- server/logger.js | 14 +- 4 files changed, 521 insertions(+), 1805 deletions(-) diff --git a/README.md b/README.md index eeb6799..fa8f82e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Freedom Loader -![Static Badge](https://img.shields.io/badge/Version-1.0.0-blue?style=flat&logo=Test) +![Static Badge](https://img.shields.io/badge/Version-1.0.0-blue?style=flat&logo=Test) + +![Static Badge](https://img.shields.io/badge/Release-1.0.0-blue?style=flat&logo=Test) + + + +![Static Badge](https://img.shields.io/badge/Build-1.0.1--beta-yellow?style=flat&logo=Test) > This project aims to enable free, open-source, and unrestricted downloading of Video/Audio content. Eventually, it will allow users to choose diff --git a/README.md b/README.md index fa8f82e..20e6059 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ # Freedom Loader -![Static Badge](https://img.shields.io/badge/Version-1.0.0-blue?style=flat&logo=Test) + +![Static Badge](https://img.shields.io/badge/Release-1.0.0-blue?style=flat&logo=Test) + + + +![Static Badge](https://img.shields.io/badge/Build-1.0.1--beta-yellow?style=flat&logo=Test) > Ce projet a pour but de permettre le téléchargement de contenu Vidéo/Audio de manière gratuite, open source et libre. Il permettra à terme de choisir diff --git a/main.js b/main.js index f25a12e..af0e2b8 100644 --- a/main.js +++ b/main.js @@ -24,17 +24,22 @@ let mainWindow; async function createWindow() { logger.info("Creation de la fenetre..."); + if (mainWindow) { logger.warn("La fenetre existe deja, pas de nouvelle creation"); return; } mainWindow = new BrowserWindow({ - width: 1000, - height: 700, + title: "Freedom Loader", + width: 750, + height: 800, + minWidth: 750, + minHeight: 800, webPreferences: { nodeIntegration: false, contextIsolation: true, }, + // titleBarStyle: 'hidden', }); try { @@ -71,4 +76,4 @@ app.on("window-all-closed", () => { app.on("before-quit", () => { logSessionEnd(); -}); \ No newline at end of file +}); diff --git a/public/assets/icons/GitHub Icon.ico b/public/assets/icons/GitHub Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..798a0243427fd46f541c0dffec409ab6e454ed3d GIT binary patch literal 99678 zcmeI5ceE8nw(#$)^}e;R~8i&RjXF|d8&NBRKBZQ_xR^iii*1aPf<}xN$KZW zt%{2Nt9en;$dSiC|L1Rt8VxThswH*Et5Rd>_i`yJl6u@lIm*$aN7ct4eW?ES$Y0f- zJ>RB&*}HeIdhF4M)d&B6U-67r*}L~U^}v0jRkKF*Rms)HB<+ZPRsD`{VCa^*{YV z4d~ZfefQmW`uAhUj;ROlyGJ#ucb0l%-fQZ<(W6xNt~aao>(-^-|N85ds{UDLsFURV zlTZ9#UB~_Rj#kHx9aWz!`&cz=Twk}}w^t8U@2t~Rw_9#jpMUmg>ireVzf%0xsQy{{ z-IGrEy=u~+uEy1n+Xm|IPODj6wQ1E-{rmm*)XzWvoO;*XfVXAR)`jiPSG-R@1`X(| zE@*q6{#>*ApVahMrkclnuk&7;t4=%RB>hgi^UhUu�yE8=hT9t&)CbDjPR!P|c;k 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 + + diff --git a/public/index.html b/public/index.html index 5d76ae1..f25656b 100644 --- a/public/index.html +++ b/public/index.html @@ -41,8 +41,13 @@ + diff --git a/public/styles/layout/videoinfo.css b/public/styles/layout/videoinfo.css index b47fc17..bc8a43c 100644 --- a/public/styles/layout/videoinfo.css +++ b/public/styles/layout/videoinfo.css @@ -4,7 +4,7 @@ margin-left: auto; margin-right: auto; padding: 1.5em 2em; - background-color: #fff; + background-color: var(--infos-box-color); border-radius: 12px; box-shadow: 0 8px 16px rgba(0,0,0,0.1); color: #222; diff --git a/public/styles/styles.css b/public/styles/styles.css index 8651900..1f8f64c 100644 --- a/public/styles/styles.css +++ b/public/styles/styles.css @@ -27,7 +27,7 @@ body { background-attachment: fixed; */ width: 100%; height: 100%; - color: #F8FAFC; + color: var(--default-text-color); display: flex; justify-content: center; align-items: center; diff --git a/public/styles/variables.css b/public/styles/variables.css index 8494afc..fb2b848 100644 --- a/public/styles/variables.css +++ b/public/styles/variables.css @@ -1,9 +1,11 @@ :root{ --background-color : #0F172A; + --infos-box-color: #f1f1f1 ; --title-color: ; --subtitle-color : #a3aab4; --mp3-text-color: #0F172A; --default-text-color: #F8FAFC; --checkbox-pulse-color:#9bbcf1; + } \ No newline at end of file diff --git a/server/routes/download.js b/server/routes/download.js index af916b7..bed0fe9 100644 --- a/server/routes/download.js +++ b/server/routes/download.js @@ -69,8 +69,48 @@ router.post("/", (req, res) => { args.push("--write-subs", "--sub-lang", "en"); } - // qualité souhaitée - args.push("-f", options.quality); + // // qualité souhaitée + // args.push("-f", options.quality); + + // let format; + // if (options.quality === "best") { + // format = "bestvideo+bestaudio/best"; + // } else if (options.quality === "worst") { + // format = "worstvideo+worstaudio/worst"; + // } else { + // format = "best"; // fallback + // } + // args.push("-f", format); + + args.push("--no-continue"); + + let format; + + switch (options.quality) { + case "best": + format = "bestvideo+bestaudio/best"; + break; + case "medium": + // qualité moyenne, ex: 720p vidéo + meilleur audio + format = "bestvideo[height<=720]+bestaudio/best[height<=720]"; + break; + case "worst": + format = "worstvideo+worstaudio/worst"; + break; + case "1080": + format = "bestvideo[height<=1080]+bestaudio/best[height<=1080]"; + break; + case "720": + format = "bestvideo[height<=720]+bestaudio/best[height<=720]"; + break; + case "480": + format = "bestvideo[height<=480]+bestaudio/best[height<=480]"; + break; + default: + format = "best"; + } + args.push("-f", format); + // modèle de sortie args.push("-o", outputTemplate); // enfin, l'URL à télécharger