From ec6963cff3960970139efe2645fe7eb8b5d51334 Mon Sep 17 00:00:00 2001
From: MasterAcnolo <68693319+MasterAcnolo@users.noreply.github.com>
Date: Wed, 2 Jul 2025 13:49:55 +0200
Subject: [PATCH] Logs FIX + Bug FIX
---
server/routes/download.js | 110 ++++++++++----------------------------
server/routes/info.js | 70 ++++++++++++++----------
2 files changed, 72 insertions(+), 108 deletions(-)
diff --git a/server/routes/download.js b/server/routes/download.js
index bed0fe9..9c9d7d8 100644
--- a/server/routes/download.js
+++ b/server/routes/download.js
@@ -16,150 +16,98 @@
along with this program. If not, see .
*/
-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 express = require("express");
+const router = express.Router();
+const { execFile } = require("child_process");
+const path = require("path");
+const fs = require("fs");
-const logger = require("../logger").logger; // récupère l'instance de logger Winston personnalisée
+const logger = require("../logger").logger;
-// chemin vers l’exécutable yt-dlp packagé avec l’appli
+// Path vers le .exe de YT-DLP
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)
+ // récupère les options envoyées depuis le frontend
const options = {
- 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
+ url: req.body.url,
+ audioOnly: req.body.audioOnly === "1",
+ quality: req.body.quality || "best",
};
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 !");
}
- // 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.");
}
- // template du nom de fichier de sortie (ex: MonTitre.mp4 ou MonTitre.mp3)
const outputTemplate = path.join(outputFolder, "%(title)s.%(ext)s");
- // tableau d'arguments pour yt-dlp
- const args = [];
+ // tableau d'arguments yt-dlp
+ const args = ["--no-continue", "--restrict-filenames"];
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");
- }
+ // gestion qualité
+ const qualityMap = {
+ best: "bestvideo+bestaudio/best",
+ medium: "bestvideo[height<=720]+bestaudio/best[height<=720]",
+ worst: "worstvideo+worstaudio/worst",
+ 1080: "bestvideo[height<=1080]+bestaudio/best[height<=1080]",
+ 720: "bestvideo[height<=720]+bestaudio/best[height<=720]",
+ 480: "bestvideo[height<=480]+bestaudio/best[height<=480]",
+ };
- // // qualité souhaitée
- // args.push("-f", options.quality);
+ const format = qualityMap[options.quality] || "best";
+ args.push("-f", format);
- // 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
args.push(options.url);
- // log de la commande complète pour debug
+ logger.info(`Téléchargement demandé : url=${options.url}, audioOnly=${options.audioOnly}, quality=${options.quality}`);
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()}`);
+ 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()}`);
+ 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
+ if (code === 0) {
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}`);
}
});
-// on exporte ce routeur pour qu'il soit utilisé par l'app principale
-module.exports = router;
\ No newline at end of file
+module.exports = router;
diff --git a/server/routes/info.js b/server/routes/info.js
index 372e823..b7739d4 100644
--- a/server/routes/info.js
+++ b/server/routes/info.js
@@ -16,40 +16,56 @@
along with this program. If not, see .
*/
-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
+const express = require("express");
+const router = express.Router();
+const { execFile } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { logger } = require("../logger"); // on récupère ton logger Winston
-// chemin vers le binaire yt-dlp embarqué
const ytDlpPath = path.join(__dirname, "../../yt-dlp.exe");
-// route POST sur la racine de ce routeur
+// Check si ya YT DLP
+if (!fs.existsSync(ytDlpPath)) {
+ logger.error(`❌ yt-dlp.exe introuvable à ${ytDlpPath}`);
+ throw new Error(`yt-dlp.exe introuvable à ${ytDlpPath}`);
+}
+
router.post("/", (req, res) => {
- 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
+ const url = req.body.url;
+ if (!url) {
+ logger.warn("Requête metadata sans URL");
+ return res.status(400).send("❌ URL manquante");
+ }
- // 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.");
- }
+ logger.info(`Requête metadata reçue pour ${url}`);
- 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.");
+ execFile(
+ ytDlpPath,
+ ["--dump-json", url],
+ { timeout: 10_000 }, // 10s de timeout
+ (error, stdout, stderr) => {
+ if (error) {
+ logger.error(`Erreur exécution yt-dlp: ${error.message}`);
+ logger.debug(`stderr: ${stderr}`);
+ return res.status(500).send("❌ Impossible de récupérer les infos.");
+ }
+
+ try {
+ // découpe multi-JSON propre
+ const infos = stdout
+ .trim()
+ .split("\n")
+ .map(line => JSON.parse(line));
+
+ logger.info(`Infos récupérées pour ${url} (${infos.length} élément(s))`);
+ res.json(infos.length === 1 ? infos[0] : infos);
+ } catch (e) {
+ logger.error(`Erreur parsing JSON: ${e.message}`);
+ return res.status(500).send("❌ JSON illisible.");
+ }
}
- });
+ );
});
-// on exporte le routeur pour être utilisé dans app.js ou ailleurs
module.exports = router;