UNPKG

yt-dlx

Version:

Effortless Audio-Video Downloader And Streamer!

268 lines 12.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = AudioLowest; const fs = __importStar(require("fs")); const colors_1 = __importDefault(require("colors")); const path = __importStar(require("path")); const zod_1 = require("zod"); const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg")); const Agent_1 = __importDefault(require("../../utils/Agent")); const locator_1 = require("../../utils/locator"); const stream_1 = require("stream"); function formatTime(seconds) { if (!isFinite(seconds) || isNaN(seconds)) return "00h 00m 00s"; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); return `${hours.toString().padStart(2, "0")}h ${minutes.toString().padStart(2, "0")}m ${secs.toString().padStart(2, "0")}s`; } function calculateETA(startTime, percent) { const currentTime = new Date(); const elapsedTime = (currentTime.getTime() - startTime.getTime()) / 1000; if (percent <= 0) return NaN; const totalTimeEstimate = (elapsedTime / percent) * 100; const remainingTime = totalTimeEstimate - elapsedTime; return remainingTime; } function progbar({ percent, timemark, startTime }) { let displayPercent = isNaN(percent || 0) ? 0 : percent || 0; displayPercent = Math.min(Math.max(displayPercent, 0), 100); const colorFn = displayPercent < 25 ? colors_1.default.red : displayPercent < 50 ? colors_1.default.yellow : colors_1.default.green; const width = Math.floor((process.stdout.columns || 80) / 4); const scomp = Math.round((width * displayPercent) / 100); const progb = colorFn("━").repeat(scomp) + colorFn(" ").repeat(width - scomp); const etaSeconds = calculateETA(startTime, displayPercent); const etaFormatted = formatTime(etaSeconds); process.stdout.write(`\r${colorFn("@prog:")} ${progb} ${colorFn("| @percent:")} ${displayPercent.toFixed(2)}% ${colorFn("| @timemark:")} ${timemark} ${colorFn("| @eta:")} ${etaFormatted}`); } const ZodSchema = zod_1.z.object({ query: zod_1.z.string().min(2), output: zod_1.z.string().optional(), useTor: zod_1.z.boolean().optional(), stream: zod_1.z.boolean().optional(), verbose: zod_1.z.boolean().optional(), metadata: zod_1.z.boolean().optional(), showProgress: zod_1.z.boolean().optional(), filter: zod_1.z .enum(["echo", "slow", "speed", "phaser", "flanger", "panning", "reverse", "vibrato", "subboost", "surround", "bassboost", "nightcore", "superslow", "vaporwave", "superspeed"]) .optional(), }); async function AudioLowest({ query, output, useTor, stream, filter, metadata, verbose, showProgress, }) { try { ZodSchema.parse({ query, output, useTor, stream, filter, metadata, verbose, showProgress }); if (metadata && (stream || output || filter || showProgress)) { throw new Error(`${colors_1.default.red("@error:")} The 'metadata' parameter cannot be used with 'stream', 'output', 'filter', or 'showProgress'.`); } if (stream && output) { throw new Error(`${colors_1.default.red("@error:")} The 'stream' parameter cannot be used with 'output'.`); } const engineData = await (0, Agent_1.default)({ query, verbose, useTor }); if (!engineData) { throw new Error(`${colors_1.default.red("@error:")} Unable to retrieve a response from the engine.`); } if (!engineData.metaData) { throw new Error(`${colors_1.default.red("@error:")} Metadata was not found in the engine response.`); } if (metadata) { return { metadata: { metaData: engineData.metaData, BestAudioLow: engineData.BestAudioLow, AudioLowDRC: engineData.AudioLowDRC, filename: `yt-dlx_AudioLowest_${filter ? filter + "_" : ""}${engineData.metaData.title?.replace(/[^a-zA-Z0-9_]+/g, "_") || "audio"}.avi`, }, }; } const title = engineData.metaData.title?.replace(/[^a-zA-Z0-9_]+/g, "_") || "audio"; const folder = output ? output : process.cwd(); if (!stream && !fs.existsSync(folder)) { try { fs.mkdirSync(folder, { recursive: true }); } catch (mkdirError) { throw new Error(`${colors_1.default.red("@error:")} Failed to create the output directory: ${mkdirError.message}`); } } const instance = (0, fluent_ffmpeg_1.default)(); try { const paths = await (0, locator_1.locator)(); if (!paths.ffmpeg) { throw new Error(`${colors_1.default.red("@error:")} ffmpeg executable not found.`); } if (!paths.ffprobe) { throw new Error(`${colors_1.default.red("@error:")} ffprobe executable not found.`); } instance.setFfmpegPath(paths.ffmpeg); instance.setFfprobePath(paths.ffprobe); } catch (locatorError) { throw new Error(`${colors_1.default.red("@error:")} Failed to locate ffmpeg or ffprobe: ${locatorError.message}`); } if (!engineData.BestAudioLow?.url) { throw new Error(`${colors_1.default.red("@error:")} Lowest quality audio URL was not found.`); } instance.addInput(engineData.BestAudioLow.url); if (!engineData.metaData.thumbnail) { throw new Error(`${colors_1.default.red("@error:")} Thumbnail URL was not found.`); } instance.addInput(engineData.metaData.thumbnail); instance.withOutputFormat("avi"); const filterMap = { bassboost: ["bass=g=10,dynaudnorm=f=150"], echo: ["aecho=0.8:0.9:1000:0.3"], flanger: ["flanger"], nightcore: ["aresample=48000,asetrate=48000*1.25"], panning: ["apulsator=hz=0.08"], phaser: ["aphaser=in_gain=0.4"], reverse: ["areverse"], slow: ["atempo=0.8"], speed: ["atempo=2"], subboost: ["asubboost"], superslow: ["atempo=0.5"], superspeed: ["atempo=3"], surround: ["surround"], vaporwave: ["aresample=48000,asetrate=48000*0.8"], vibrato: ["vibrato=f=6.5"], }; if (filter && filterMap[filter]) { instance.withAudioFilter(filterMap[filter]); } else { instance.outputOptions("-c copy"); } let processStartTime; if (showProgress) { instance.on("start", () => { processStartTime = new Date(); }); instance.on("progress", progress => { if (processStartTime) { progbar({ ...progress, percent: progress.percent !== undefined ? progress.percent : 0, startTime: processStartTime }); } }); } if (stream) { const passthroughStream = new stream_1.PassThrough(); const filenameBase = `yt-dlx_AudioLowest_`; let filename = `${filenameBase}${filter ? filter + "_" : ""}${title}.avi`; passthroughStream.filename = filename; instance.on("start", command => { if (verbose) console.log(colors_1.default.green("@info:"), "FFmpeg stream started:", command); }); instance.pipe(passthroughStream, { end: true }); instance.on("end", () => { if (verbose) console.log(colors_1.default.green("@info:"), "FFmpeg streaming finished."); if (showProgress) process.stdout.write("\n"); }); instance.on("error", (error, stdout, stderr) => { const errorMessage = `${colors_1.default.red("@error:")} FFmpeg stream error: ${error?.message}`; console.error(errorMessage, "\nstdout:", stdout, "\nstderr:", stderr); passthroughStream.emit("error", new Error(errorMessage)); passthroughStream.destroy(new Error(errorMessage)); if (showProgress) process.stdout.write("\n"); }); instance.run(); if (verbose) console.log(colors_1.default.green("@info:"), "❣️ Thank you for using yt-dlx. Consider 🌟starring the GitHub repo https://github.com/yt-dlx."); return { stream: passthroughStream, filename: filename }; } else { const filenameBase = `yt-dlx_AudioLowest_`; let filename = `${filenameBase}${filter ? filter + "_" : ""}${title}.avi`; const outputPath = path.join(folder, filename); instance.output(outputPath); await new Promise((resolve, reject) => { instance.on("start", command => { if (verbose) console.log(colors_1.default.green("@info:"), "FFmpeg download started:", command); if (showProgress) processStartTime = new Date(); }); instance.on("progress", progress => { if (showProgress && processStartTime) { progbar({ ...progress, percent: progress.percent !== undefined ? progress.percent : 0, startTime: processStartTime }); } }); instance.on("end", () => { if (verbose) console.log(colors_1.default.green("@info:"), "FFmpeg download finished."); if (showProgress) process.stdout.write("\n"); resolve(); }); instance.on("error", (error, stdout, stderr) => { const errorMessage = `${colors_1.default.red("@error:")} FFmpeg download error: ${error?.message}`; console.error(errorMessage, "\nstdout:", stdout, "\nstderr:", stderr); if (showProgress) process.stdout.write("\n"); reject(new Error(errorMessage)); }); instance.run(); }); if (verbose) console.log(colors_1.default.green("@info:"), "❣️ Thank you for using yt-dlx. Consider 🌟starring the GitHub repo https://github.com/yt-dlx."); return { outputPath }; } } catch (error) { if (error instanceof zod_1.ZodError) { const errorMessage = `${colors_1.default.red("@error:")} Argument validation failed: ${error.errors.map(e => `${e.path.join(".")}: ${e.message}`).join(", ")}`; console.error(errorMessage); throw new Error(errorMessage); } else if (error instanceof Error) { console.error(error.message); throw error; } else { const unexpectedError = `${colors_1.default.red("@error:")} An unexpected error occurred: ${String(error)}`; console.error(unexpectedError); throw new Error(unexpectedError); } } finally { } } //# sourceMappingURL=Lowest.js.map