mirror of
https://github.com/MasterAcnolo/Freedom-Loader.git
synced 2026-07-29 18:25:47 +02:00
Logs FIX + Bug FIX
This commit is contained in:
@@ -16,150 +16,98 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const express = require("express"); // importe le framework Express
|
const express = require("express");
|
||||||
const router = express.Router(); // crée un routeur Express pour modulariser les routes
|
const router = express.Router();
|
||||||
const { execFile } = require("child_process"); // permet d’exécuter un binaire externe sans passer par un shell
|
const { execFile } = require("child_process");
|
||||||
const path = require("path"); // module Node.js pour gérer les chemins de fichiers
|
const path = require("path");
|
||||||
const fs = require("fs"); // module Node.js pour manipuler le système de fichiers
|
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');
|
const ytDlpPath = path.join(__dirname, '../../yt-dlp.exe');
|
||||||
|
|
||||||
// route POST sur la racine (ex: POST /download)
|
|
||||||
router.post("/", (req, res) => {
|
router.post("/", (req, res) => {
|
||||||
try {
|
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 = {
|
const options = {
|
||||||
url: req.body.url, // URL à télécharger
|
url: req.body.url,
|
||||||
audioOnly: req.body.audioOnly === "1", // conversion audio uniquement (mp3)
|
audioOnly: req.body.audioOnly === "1",
|
||||||
quality: req.body.quality || "best", // qualité vidéo à télécharger
|
quality: req.body.quality || "best",
|
||||||
subtitles: req.body.subs === "1", // récupérer les sous-titres anglais
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!options.url) {
|
if (!options.url) {
|
||||||
// si l’URL est absente, on log et on renvoie 400
|
|
||||||
logger.warn("Requête POST /download sans URL");
|
logger.warn("Requête POST /download sans URL");
|
||||||
return res.status(400).send("❌ URL manquante !");
|
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;
|
const outputFolder = req.app.locals.outputFolder;
|
||||||
|
|
||||||
// s'il n'existe pas, on le crée automatiquement
|
|
||||||
if (!fs.existsSync(outputFolder)) {
|
if (!fs.existsSync(outputFolder)) {
|
||||||
fs.mkdirSync(outputFolder, { recursive: true });
|
fs.mkdirSync(outputFolder, { recursive: true });
|
||||||
logger.info("Dossier Freedom Loader Output créé à la volée dans Téléchargements.");
|
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");
|
const outputTemplate = path.join(outputFolder, "%(title)s.%(ext)s");
|
||||||
|
|
||||||
// tableau d'arguments pour yt-dlp
|
// tableau d'arguments yt-dlp
|
||||||
const args = [];
|
const args = ["--no-continue", "--restrict-filenames"];
|
||||||
|
|
||||||
if (options.audioOnly) {
|
if (options.audioOnly) {
|
||||||
// si audioOnly, on force extraction audio en mp3
|
|
||||||
args.push("--extract-audio", "--audio-format", "mp3");
|
args.push("--extract-audio", "--audio-format", "mp3");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.subtitles) {
|
// gestion qualité
|
||||||
// si l’utilisateur veut des sous-titres
|
const qualityMap = {
|
||||||
args.push("--write-subs", "--sub-lang", "en");
|
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
|
const format = qualityMap[options.quality] || "best";
|
||||||
// args.push("-f", options.quality);
|
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);
|
args.push("-o", outputTemplate);
|
||||||
// enfin, l'URL à télécharger
|
|
||||||
args.push(options.url);
|
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(" ")}`);
|
logger.info(`Commande yt-dlp : ${ytDlpPath} ${args.join(" ")}`);
|
||||||
|
|
||||||
// exécution du binaire yt-dlp
|
|
||||||
const child = execFile(ytDlpPath, args);
|
const child = execFile(ytDlpPath, args);
|
||||||
|
|
||||||
// gestion des logs stdout de yt-dlp
|
|
||||||
child.stdout.on("data", (data) => {
|
child.stdout.on("data", (data) => {
|
||||||
data.toString().split("\n").forEach(line => {
|
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) => {
|
child.stderr.on("data", (data) => {
|
||||||
data.toString().split("\n").forEach(line => {
|
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) => {
|
child.on("error", (err) => {
|
||||||
logger.error(`Erreur lancement yt-dlp : ${err.message}`);
|
logger.error(`Erreur lancement yt-dlp : ${err.message}`);
|
||||||
res.status(500).send(`❌ Erreur lors de l'exécution : ${err.message}`);
|
res.status(500).send(`❌ Erreur lors de l'exécution : ${err.message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// callback quand le processus se termine
|
|
||||||
child.on("close", (code) => {
|
child.on("close", (code) => {
|
||||||
logger.info(`yt-dlp terminé avec code de sortie : ${code}`);
|
logger.info(`yt-dlp terminé avec code de sortie : ${code}`);
|
||||||
if(code === 0) {
|
if (code === 0) {
|
||||||
// succès
|
|
||||||
res.send("✅ Téléchargement terminé !");
|
res.send("✅ Téléchargement terminé !");
|
||||||
} else {
|
} else {
|
||||||
// yt-dlp a échoué
|
|
||||||
res.status(500).send(`❌ yt-dlp a échoué avec le code : ${code}`);
|
res.status(500).send(`❌ yt-dlp a échoué avec le code : ${code}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// en cas d'erreur JavaScript
|
|
||||||
logger.error(`Erreur serveur dans /download : ${err.message}`);
|
logger.error(`Erreur serveur dans /download : ${err.message}`);
|
||||||
res.status(500).send(`Erreur serveur : ${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;
|
module.exports = router;
|
||||||
@@ -16,40 +16,56 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const express = require("express"); // importe Express
|
const express = require("express");
|
||||||
const router = express.Router(); // crée un routeur Express indépendant
|
const router = express.Router();
|
||||||
const { execFile } = require("child_process"); // permet d’exécuter un programme externe
|
const { execFile } = require("child_process");
|
||||||
const path = require("path"); // module pour gérer les chemins de fichiers
|
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");
|
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) => {
|
router.post("/", (req, res) => {
|
||||||
const url = req.body.url; // récupère l'URL depuis la requête POST
|
const url = req.body.url;
|
||||||
if (!url) return res.status(400).send("❌ URL manquante"); // validation simple
|
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
|
logger.info(`Requête metadata reçue pour ${url}`);
|
||||||
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 {
|
execFile(
|
||||||
// on parse le JSON envoyé par yt-dlp
|
ytDlpPath,
|
||||||
const info = JSON.parse(stdout);
|
["--dump-json", url],
|
||||||
// on renvoie l’objet JSON directement au frontend
|
{ timeout: 10_000 }, // 10s de timeout
|
||||||
res.json(info);
|
(error, stdout, stderr) => {
|
||||||
} catch (e) {
|
if (error) {
|
||||||
// le JSON est mal formé
|
logger.error(`Erreur exécution yt-dlp: ${error.message}`);
|
||||||
console.error("Erreur lors du parsing JSON :", e);
|
logger.debug(`stderr: ${stderr}`);
|
||||||
res.status(500).send("❌ JSON illisible.");
|
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;
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user