[options]"))
46 | .command(
47 | "audio",
48 | audioDescription,
49 | (yargs) => {
50 | yargs
51 | .option("url", {
52 | describe: `${chalk.cyan("YouTube video URL")}`,
53 | demandOption: true,
54 | type: "string",
55 | })
56 | .option("folder", {
57 | describe: `${chalk.cyan("Output folder name")}`,
58 | type: "string",
59 | })
60 | .option("quality", {
61 | describe: `${chalk.cyan("Audio quality (best/lowest)")}`,
62 | type: "string",
63 | default: "best",
64 | })
65 | .option("filename", {
66 | describe: `${chalk.cyan("Output filename (excluding extension)")}`,
67 | type: "string",
68 | });
69 | },
70 | async (argv) => {
71 | logger.info(audioDescription);
72 |
73 | try {
74 | await dlAudio(argv);
75 |
76 | logger.info(`${chalk.green("✅")} Audio download completed.`);
77 | } catch (err) {
78 | logger.error(
79 | `${chalk.red("❌")} Error downloading audio:`,
80 | err.message
81 | );
82 | }
83 | }
84 | )
85 | .command(
86 | "video-with-audio",
87 | videoWithAudioDescription,
88 | (yargs) => {
89 | yargs
90 | .option("url", {
91 | describe: `${chalk.cyan("YouTube video URL")}`,
92 | demandOption: true,
93 | type: "string",
94 | })
95 | .option("folder", {
96 | describe: `${chalk.cyan("Output folder name")}`,
97 | type: "string",
98 | })
99 | .option("filename", {
100 | describe: `${chalk.cyan("Output filename (excluding extension)")}`,
101 | type: "string",
102 | })
103 | .option("resolution", {
104 | describe: `${chalk.cyan(
105 | "Available video resolution (144 | 240 | 360 | 480 | 720 | 1080 | 1440 | 2160 | 4320)"
106 | )}`,
107 | type: "number",
108 | demandOption: true,
109 | default: 480,
110 | });
111 | },
112 | async (argv) => {
113 | logger.info(videoWithAudioDescription);
114 |
115 | try {
116 | await dlAudioVideo(argv);
117 |
118 | logger.info(
119 | `${chalk.green("✅")} Video with audio download completed.`
120 | );
121 | } catch (err) {
122 | logger.error(
123 | `${chalk.red("❌")} Error downloading video with audio:`,
124 | err.message
125 | );
126 | }
127 | }
128 | )
129 | .command(
130 | "video",
131 | videoWithoutAudioDescription,
132 | (yargs) => {
133 | yargs
134 | .option("url", {
135 | describe: `${chalk.cyan("YouTube video URL")}`,
136 | demandOption: true,
137 | type: "string",
138 | })
139 | .option("folder", {
140 | describe: `${chalk.cyan("Output folder name")}`,
141 | type: "string",
142 | })
143 | .option("filename", {
144 | describe: `${chalk.cyan("Output filename (excluding extension)")}`,
145 | type: "string",
146 | })
147 | .option("resolution", {
148 | describe: `${chalk.cyan(
149 | "Available video resolution (144 | 240 | 360 | 480 | 720 | 1080 | 1440 | 2160 | 4320)"
150 | )}`,
151 | type: "number",
152 | demandOption: true,
153 | default: 480,
154 | });
155 | },
156 | async (argv) => {
157 | logger.info(videoWithoutAudioDescription);
158 |
159 | try {
160 | await dlVideo(argv);
161 |
162 | logger.info(
163 | `${chalk.green("✅")} Video without audio download completed.`
164 | );
165 | } catch (err) {
166 | logger.error(
167 | `${chalk.red("❌")} Error downloading video without audio:`,
168 | err.message
169 | );
170 | }
171 | }
172 | )
173 | .demandCommand()
174 | .recommendCommands()
175 | .strict()
176 | .showHelpOnFail(true)
177 | .help().argv;
178 |
179 | // Show default values for options when not provided
180 | yargs.parse(process.argv.slice(2), (err, argv, output) => {
181 | if (output) {
182 | const defaultValuesRegex = /Default: (\S+)/g;
183 | const formattedOutput = output.replace(
184 | defaultValuesRegex,
185 | (match, defaultValue) => {
186 | return chalk.gray(`(Default: ${defaultValue})`);
187 | }
188 | );
189 | console.log(formattedOutput);
190 | }
191 | });
192 |
--------------------------------------------------------------------------------
/src/mjs/audio.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // =====================================( youtube-exec: Unleash the Power of YouTube Downloads! )=============================================
3 | // 🌟 Once upon a time in the vast realm of the Internet, a remarkable tool was born: YOUTUBE-EXEC. 📽️✨
4 | //
5 | // 🎥 Step into a world where you can effortlessly download the mesmerizing audio and captivating video content from YouTube. 🎵🎬💽
6 | // 💡 Powered by the mighty and ingenious "youtube-dl-exec" library, this tool possesses the uncanny ability to extract the finest details from YouTube's vast kingdom of videos. 📚🔍💡
7 | // ⚙️ Equipped with the seamless and reliable "fluent-ffmpeg" library, youtube-exec embarks on a quest to fetch files with utmost precision and grace.
8 | // With each step, it transforms the abstract bits and bytes into a symphony of sights and sounds. 🔄⚙️🔊
9 | // 🌟 Unlock the gates to a realm where your favorite audio harmonies and video treasures await.
10 | // Dive into the enchanting world of YouTube's vast library, and let your imagination soar. 🎉🔑💎
11 | // 🔓 Embrace the freedom to break free from limitations and embrace a world of boundless possibilities.
12 | // Bid farewell to the boundaries that once held you back and embark on an adventure beyond your wildest dreams. 🚫🌍🔓💫
13 | // 📖 This is the tale of youtube-exec, a tool that empowers you to shape your own narrative in the realm of YouTube.
14 | // Let your journey begin! 🚀🎬🔥
15 | //
16 | // =====================================( youtube-exec by magneum )=============================================
17 | import progLogger from "progress-estimator";
18 | import logger from "../../utils/logger.mjs";
19 | import youtubedl from "youtube-dl-exec";
20 | import ffmpeg from "fluent-ffmpeg";
21 | import urlRegex from "url-regex";
22 | import readline from "readline";
23 | const plogger = progLogger();
24 | import chalk from "chalk";
25 | import path from "path";
26 | import fs from "fs";
27 |
28 | const createFolderIfNotExists = (folder) => {
29 | if (!folder) {
30 | folder = "youtube-exec";
31 | }
32 | const outputFolder = path.resolve(process.cwd(), folder);
33 | if (!fs.existsSync(outputFolder)) {
34 | fs.mkdirSync(outputFolder);
35 | logger.info(`📂 Created folder: ${outputFolder}`);
36 | }
37 | };
38 |
39 | const fetchAudioDetails = async ({ url, quality }) => {
40 | logger.info("🔍 Fetching audio details...");
41 | try {
42 | const promise = youtubedl(url, {
43 | dumpSingleJson: true,
44 | noCheckCertificates: true,
45 | noWarnings: true,
46 | preferFreeFormats: true,
47 | addHeader: ["referer:youtube.com", "user-agent:googlebot"],
48 | });
49 | const result = await plogger(promise, "⏳ Obtaining...");
50 | const videoTitle = result.title;
51 | const reqAudio = findReqAudioFormat(result.formats, quality);
52 | return { reqAudio, videoTitle };
53 | } catch (err) {
54 | logger.info(chalk.red(`❌ Error fetching audio details: ${err.message}`));
55 | throw err;
56 | }
57 | };
58 |
59 | const findReqAudioFormat = (formats, quality) => {
60 | let reqAudio = null;
61 | logger.info(`🔍 Fetching Audio Quality: ${quality}`);
62 | if (quality === "best") {
63 | let highestBitrate = 0;
64 | for (let i = 0; i < formats.length; i++) {
65 | const format = formats[i];
66 | if (format.acodec === "none" || format.vcodec !== "none") {
67 | continue;
68 | }
69 | const bitrate = format.tbr || format.abr;
70 | if (bitrate && bitrate > highestBitrate) {
71 | highestBitrate = bitrate;
72 | reqAudio = format;
73 | }
74 | }
75 | return reqAudio;
76 | } else if (quality === "lowest") {
77 | let lowBitrate = Infinity;
78 | for (let i = 0; i < formats.length; i++) {
79 | const format = formats[i];
80 | if (format.acodec === "none" || format.vcodec !== "none") {
81 | continue;
82 | }
83 | const bitrate = format.tbr || format.abr;
84 | if (bitrate && bitrate < lowBitrate) {
85 | lowBitrate = bitrate;
86 | reqAudio = format;
87 | }
88 | }
89 | return reqAudio;
90 | } else {
91 | logger.info(chalk.red("❌ Error: Audio Quality supported: best,lowest"));
92 | throw new Error("Error: Audio Quality supported: best,lowest");
93 | }
94 | };
95 |
96 | const downloadAudioFile = async (ffmpegUrl, outputFile, quality, filename) => {
97 | let outputFilename;
98 | if (filename) {
99 | outputFilename = filename;
100 | } else {
101 | const videoTitle = path.basename(ffmpegUrl, path.extname(ffmpegUrl));
102 | outputFilename = `[${quality}]${videoTitle}`;
103 | }
104 | outputFile = path.join(outputFile, `${outputFilename}.mp3`);
105 |
106 | return new Promise((resolve, reject) => {
107 | const ffmpegCommand = ffmpeg()
108 | .input(ffmpegUrl)
109 | .audioBitrate(320)
110 | .toFormat("ipod")
111 | .on("start", () => {
112 | logger.info("📥 Audio download started...");
113 | })
114 | .on("progress", (progress) => {
115 | readline.clearLine(process.stdout, 0);
116 | readline.cursorTo(process.stdout, 0);
117 | process.stdout.write(`⬇️ Downloading: ${progress.percent}%`);
118 | })
119 | .on("end", () => {
120 | readline.clearLine(process.stdout, 0);
121 | readline.cursorTo(process.stdout, 0);
122 | logger.info(
123 | chalk.bold(chalk.green("✅ Audio downloaded successfully!"))
124 | );
125 | resolve();
126 | })
127 | .on("error", (err) => {
128 | readline.clearLine(process.stdout, 0);
129 | readline.cursorTo(process.stdout, 0);
130 | logger.info(
131 | chalk.bold(
132 | chalk.red(`❌ Error downloading audio file: ${err.message}`)
133 | )
134 | );
135 | reject(err);
136 | })
137 | .saveToFile(outputFile);
138 | ffmpegCommand.run();
139 | });
140 | };
141 |
142 | const validateUrl = (url) => {
143 | const regex = urlRegex({ strict: false });
144 | return regex.test(url);
145 | };
146 |
147 | const displayAudioDetails = (reqAudio, videoTitle, url) => {
148 | logger.info(
149 | chalk.bold(
150 | chalk.bgCyanBright("🎥 Video Title:"),
151 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
152 | )
153 | );
154 | Object.entries(reqAudio).forEach(([key, value]) => {
155 | switch (key) {
156 | case "url":
157 | url = value;
158 | break;
159 | case "fragments":
160 | logger.info(chalk.bold(`▶️ ${chalk.yellow(key)}:`));
161 | value.forEach((fragment, index) => {
162 | logger.info(chalk.bold(chalk.yellow(`- Fragment no ${index + 1}:`)));
163 | Object.entries(fragment).forEach(([fKey, fValue]) => {
164 | logger.info(
165 | `${chalk.bold(chalk.yellow(fKey))}: ${chalk.bold(
166 | chalk.italic(chalk.white(fValue))
167 | )}`
168 | );
169 | });
170 | });
171 | break;
172 | default:
173 | logger.info(
174 | chalk.bold(
175 | chalk.yellow(
176 | `${key}: ${chalk.bold(chalk.italic(chalk.white(value)))}`
177 | )
178 | )
179 | );
180 | break;
181 | }
182 | });
183 | return url;
184 | };
185 |
186 | const dlAudio = ({ url, folder, quality, filename }) => {
187 | return new Promise(async (resolve, reject) => {
188 | try {
189 | if (!validateUrl(url)) {
190 | logger.info(chalk.red("❌ Invalid URL format."));
191 | throw new Error("Invalid URL format.");
192 | }
193 | const { reqAudio, videoTitle } = await fetchAudioDetails({
194 | url,
195 | quality,
196 | });
197 | if (reqAudio) {
198 | url = displayAudioDetails(reqAudio, videoTitle, url);
199 | if (!folder) {
200 | folder = "youtube-exec";
201 | }
202 | createFolderIfNotExists(folder);
203 | let outputFilename;
204 | if (filename) {
205 | outputFilename = `${filename}`;
206 | } else {
207 | outputFilename = `[${quality}]${videoTitle}`;
208 | }
209 | await downloadAudioFile(url, folder, quality, outputFilename);
210 | } else {
211 | logger.info(chalk.bold(chalk.yellow("⚠️ No audio details found.")));
212 | }
213 | resolve();
214 | } catch (err) {
215 | logger.info(chalk.red(`❌ An error occurred: ${err.message}`));
216 | reject(err);
217 | }
218 | });
219 | };
220 |
221 | export default dlAudio;
222 |
--------------------------------------------------------------------------------
/src/cjs/audio.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // =====================================( youtube-exec: Unleash the Power of YouTube Downloads! )=============================================
3 | // 🌟 Once upon a time in the vast realm of the Internet, a remarkable tool was born: YOUTUBE-EXEC. 📽️✨
4 | //
5 | // 🎥 Step into a world where you can effortlessly download the mesmerizing audio and captivating video content from YouTube. 🎵🎬💽
6 | // 💡 Powered by the mighty and ingenious "youtube-dl-exec" library, this tool possesses the uncanny ability to extract the finest details from YouTube's vast kingdom of videos. 📚🔍💡
7 | // ⚙️ Equipped with the seamless and reliable "fluent-ffmpeg" library, youtube-exec embarks on a quest to fetch files with utmost precision and grace.
8 | // With each step, it transforms the abstract bits and bytes into a symphony of sights and sounds. 🔄⚙️🔊
9 | // 🌟 Unlock the gates to a realm where your favorite audio harmonies and video treasures await.
10 | // Dive into the enchanting world of YouTube's vast library, and let your imagination soar. 🎉🔑💎
11 | // 🔓 Embrace the freedom to break free from limitations and embrace a world of boundless possibilities.
12 | // Bid farewell to the boundaries that once held you back and embark on an adventure beyond your wildest dreams. 🚫🌍🔓💫
13 | // 📖 This is the tale of youtube-exec, a tool that empowers you to shape your own narrative in the realm of YouTube.
14 | // Let your journey begin! 🚀🎬🔥
15 | //
16 | // =====================================( youtube-exec by magneum )=============================================
17 | const progLogger = require("progress-estimator");
18 | const youtubedl = require("youtube-dl-exec");
19 | const logger = require("../../utils/logger.js");
20 | const ffmpeg = require("fluent-ffmpeg");
21 | const urlRegex = require("url-regex");
22 | const readline = require("readline");
23 | const chalk = require("chalk");
24 | const path = require("path");
25 | const fs = require("fs");
26 |
27 | const plogger = progLogger();
28 | const createFolderIfNotExists = (folder) => {
29 | if (!folder) {
30 | folder = "youtube-exec";
31 | }
32 | const outputFolder = path.resolve(process.cwd(), folder);
33 | if (!fs.existsSync(outputFolder)) {
34 | fs.mkdirSync(outputFolder);
35 | logger.info(`📂 Created folder: ${outputFolder}`);
36 | }
37 | };
38 |
39 | const fetchAudioDetails = async ({ url, quality }) => {
40 | logger.info("🔍 Fetching audio details...");
41 | try {
42 | const promise = youtubedl(url, {
43 | dumpSingleJson: true,
44 | noCheckCertificates: true,
45 | noWarnings: true,
46 | preferFreeFormats: true,
47 | addHeader: ["referer:youtube.com", "user-agent:googlebot"],
48 | });
49 | const result = await plogger(promise, "⏳ Obtaining...");
50 | const videoTitle = result.title;
51 | const reqAudio = findReqAudioFormat(result.formats, quality);
52 | return { reqAudio, videoTitle };
53 | } catch (err) {
54 | logger.info(chalk.red(`❌ Error fetching audio details: ${err.message}`));
55 | throw err;
56 | }
57 | };
58 |
59 | const findReqAudioFormat = (formats, quality) => {
60 | let reqAudio = null;
61 | logger.info(`🔍 Fetching Audio Quality: ${quality}`);
62 | if (quality === "best") {
63 | let highestBitrate = 0;
64 | for (let i = 0; i < formats.length; i++) {
65 | const format = formats[i];
66 | if (format.acodec === "none" || format.vcodec !== "none") {
67 | continue;
68 | }
69 | const bitrate = format.tbr || format.abr;
70 | if (bitrate && bitrate > highestBitrate) {
71 | highestBitrate = bitrate;
72 | reqAudio = format;
73 | }
74 | }
75 | return reqAudio;
76 | } else if (quality === "lowest") {
77 | let lowBitrate = Infinity;
78 | for (let i = 0; i < formats.length; i++) {
79 | const format = formats[i];
80 | if (format.acodec === "none" || format.vcodec !== "none") {
81 | continue;
82 | }
83 | const bitrate = format.tbr || format.abr;
84 | if (bitrate && bitrate < lowBitrate) {
85 | lowBitrate = bitrate;
86 | reqAudio = format;
87 | }
88 | }
89 | return reqAudio;
90 | } else {
91 | logger.info(chalk.red("❌ Error: Audio Quality supported: best,lowest"));
92 | throw new Error("Error: Audio Quality supported: best,lowest");
93 | }
94 | };
95 |
96 | const downloadAudioFile = async (ffmpegUrl, outputFile, quality, filename) => {
97 | let outputFilename;
98 | if (filename) {
99 | outputFilename = filename;
100 | } else {
101 | const videoTitle = path.basename(ffmpegUrl, path.extname(ffmpegUrl));
102 | outputFilename = `[${quality}]${videoTitle}`;
103 | }
104 | outputFile = path.join(outputFile, `${outputFilename}.mp3`);
105 |
106 | return new Promise((resolve, reject) => {
107 | const ffmpegCommand = ffmpeg()
108 | .input(ffmpegUrl)
109 | .audioBitrate(320)
110 | .toFormat("ipod")
111 | .on("start", () => {
112 | logger.info("📥 Audio download started...");
113 | })
114 | .on("progress", (progress) => {
115 | readline.clearLine(process.stdout, 0);
116 | readline.cursorTo(process.stdout, 0);
117 | process.stdout.write(`⬇️ Downloading: ${progress.percent}%`);
118 | })
119 | .on("end", () => {
120 | readline.clearLine(process.stdout, 0);
121 | readline.cursorTo(process.stdout, 0);
122 | logger.info(
123 | chalk.bold(chalk.green("✅ Audio downloaded successfully!"))
124 | );
125 | resolve();
126 | })
127 | .on("error", (err) => {
128 | readline.clearLine(process.stdout, 0);
129 | readline.cursorTo(process.stdout, 0);
130 | logger.info(
131 | chalk.bold(
132 | chalk.red(`❌ Error downloading audio file: ${err.message}`)
133 | )
134 | );
135 | reject(err);
136 | })
137 | .saveToFile(outputFile);
138 | ffmpegCommand.run();
139 | });
140 | };
141 |
142 | const validateUrl = (url) => {
143 | const regex = urlRegex({ strict: false });
144 | return regex.test(url);
145 | };
146 |
147 | const displayAudioDetails = (reqAudio, videoTitle, url) => {
148 | logger.info(
149 | chalk.bold(
150 | chalk.bgCyanBright("🎥 Video Title:"),
151 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
152 | )
153 | );
154 | Object.entries(reqAudio).forEach(([key, value]) => {
155 | switch (key) {
156 | case "url":
157 | url = value;
158 | break;
159 | case "fragments":
160 | logger.info(chalk.bold(`▶️ ${chalk.yellow(key)}:`));
161 | value.forEach((fragment, index) => {
162 | logger.info(chalk.bold(chalk.yellow(`- Fragment no ${index + 1}:`)));
163 | Object.entries(fragment).forEach(([fKey, fValue]) => {
164 | logger.info(
165 | `${chalk.bold(chalk.yellow(fKey))}: ${chalk.bold(
166 | chalk.italic(chalk.white(fValue))
167 | )}`
168 | );
169 | });
170 | });
171 | break;
172 | default:
173 | logger.info(
174 | chalk.bold(
175 | chalk.yellow(
176 | `${key}: ${chalk.bold(chalk.italic(chalk.white(value)))}`
177 | )
178 | )
179 | );
180 | break;
181 | }
182 | });
183 | return url;
184 | };
185 |
186 | const dlAudio = ({ url, folder, quality, filename }) => {
187 | return new Promise(async (resolve, reject) => {
188 | try {
189 | if (!validateUrl(url)) {
190 | logger.info(chalk.red("❌ Invalid URL format."));
191 | throw new Error("Invalid URL format.");
192 | }
193 | const { reqAudio, videoTitle } = await fetchAudioDetails({
194 | url,
195 | quality,
196 | });
197 | if (reqAudio) {
198 | url = displayAudioDetails(reqAudio, videoTitle, url);
199 | if (!folder) {
200 | folder = "youtube-exec";
201 | }
202 | createFolderIfNotExists(folder);
203 | let outputFilename;
204 | if (filename) {
205 | outputFilename = `${filename}`;
206 | } else {
207 | outputFilename = `[${quality}]${videoTitle}`;
208 | }
209 | await downloadAudioFile(url, folder, quality, outputFilename);
210 | } else {
211 | logger.info(chalk.bold(chalk.yellow("⚠️ No audio details found.")));
212 | }
213 | resolve();
214 | } catch (err) {
215 | logger.info(chalk.red(`❌ An error occurred: ${err.message}`));
216 | reject(err);
217 | }
218 | });
219 | };
220 |
221 | module.exports = dlAudio;
222 |
--------------------------------------------------------------------------------
/src/mjs/vid_aud.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // =====================================( youtube-exec: Unleash the Power of YouTube Downloads! )=============================================
3 | // 🌟 Once upon a time in the vast realm of the Internet, a remarkable tool was born: YOUTUBE-EXEC. 📽️✨
4 | //
5 | // 🎥 Step into a world where you can effortlessly download the mesmerizing audio and captivating video content from YouTube. 🎵🎬💽
6 | // 💡 Powered by the mighty and ingenious "youtube-dl-exec" library, this tool possesses the uncanny ability to extract the finest details from YouTube's vast kingdom of videos. 📚🔍💡
7 | // ⚙️ Equipped with the seamless and reliable "fluent-ffmpeg" library, youtube-exec embarks on a quest to fetch files with utmost precision and grace.
8 | // With each step, it transforms the abstract bits and bytes into a symphony of sights and sounds. 🔄⚙️🔊
9 | // 🌟 Unlock the gates to a realm where your favorite audio harmonies and video treasures await.
10 | // Dive into the enchanting world of YouTube's vast library, and let your imagination soar. 🎉🔑💎
11 | // 🔓 Embrace the freedom to break free from limitations and embrace a world of boundless possibilities.
12 | // Bid farewell to the boundaries that once held you back and embark on an adventure beyond your wildest dreams. 🚫🌍🔓💫
13 | // 📖 This is the tale of youtube-exec, a tool that empowers you to shape your own narrative in the realm of YouTube.
14 | // Let your journey begin! 🚀🎬🔥
15 | //
16 | // =====================================( youtube-exec by magneum )=============================================
17 | import progLogger from "progress-estimator";
18 | import logger from "../../utils/logger.mjs";
19 | import youtubedl from "youtube-dl-exec";
20 | import ffmpeg from "fluent-ffmpeg";
21 | import urlRegex from "url-regex";
22 | import readline from "readline";
23 | import chalk from "chalk";
24 | import path from "path";
25 | import fs from "fs";
26 |
27 | const plogger = progLogger();
28 |
29 | const log = (message) => {
30 | logger.info(message);
31 | };
32 | const createFolderIfNotExists = (folder) => {
33 | if (!folder) {
34 | folder = "youtube-exec";
35 | }
36 | const outputFolder = path.resolve(process.cwd(), folder);
37 | if (!fs.existsSync(outputFolder)) {
38 | fs.mkdirSync(outputFolder);
39 | logger.info(`📂 Created folder: ${outputFolder}`);
40 | }
41 | };
42 |
43 | const fetchVideoAndAudioDetails = async ({ url, requestedResolution }) => {
44 | log("🔍 Fetching video and audio details...");
45 | try {
46 | const promise = youtubedl(url, {
47 | dumpSingleJson: true,
48 | noCheckCertificates: true,
49 | noWarnings: true,
50 | preferFreeFormats: true,
51 | addHeader: ["referer:youtube.com", "user-agent:googlebot"],
52 | });
53 | const result = await plogger(promise, "⏳ Obtaining...");
54 | const videoTitle = result.title;
55 | const reqVideo = findReqVideoFormat(result.formats, requestedResolution);
56 | const reqAudio = findReqAudioFormat(result.formats);
57 | return { reqVideo, reqAudio, videoTitle };
58 | } catch (err) {
59 | throw new Error(
60 | `❌ Error fetching video and audio details: ${err.message}`
61 | );
62 | }
63 | };
64 |
65 | const findReqVideoFormat = (formats, requestedResolution) => {
66 | let reqVideo = null;
67 | const availableFormats = formats.filter(
68 | (format) => format.ext === "mp4" && format.format_note !== "none"
69 | );
70 | const sortedFormats = availableFormats.sort((a, b) => a.height - b.height);
71 | reqVideo = sortedFormats.find(
72 | (format) => format.height >= requestedResolution
73 | );
74 | return reqVideo;
75 | };
76 |
77 | const findReqAudioFormat = (formats) => {
78 | let reqAudio = null;
79 | const availableFormats = formats.filter(
80 | (format) => format.ext === "m4a" && format.format_note !== "none"
81 | );
82 | const sortedFormats = availableFormats.sort((a, b) => b.abr - a.abr);
83 | reqAudio = sortedFormats[0];
84 | return reqAudio;
85 | };
86 |
87 | const downloadVideoAndAudioFiles = async (
88 | videoUrl,
89 | audioUrl,
90 | outputFile,
91 | videoFormat
92 | ) => {
93 | return new Promise((resolve, reject) => {
94 | const ffmpegCommand = ffmpeg()
95 | .input(videoUrl)
96 | .input(audioUrl)
97 | .videoCodec("copy")
98 | .audioCodec("copy")
99 | .on("start", () => {
100 | log("📥 Video and audio download started...");
101 | })
102 | .on("progress", (progress) => {
103 | readline.clearLine(process.stdout, 0);
104 | readline.cursorTo(process.stdout, 0);
105 | process.stdout.write(`⬇️ Downloading: ${progress.percent}%`);
106 | })
107 | .on("end", () => {
108 | readline.clearLine(process.stdout, 0);
109 | readline.cursorTo(process.stdout, 0);
110 | log(
111 | chalk.bold(chalk.green("✅ Video and audio downloaded successfully!"))
112 | );
113 | resolve();
114 | })
115 | .on("error", (err) => {
116 | readline.clearLine(process.stdout, 0);
117 | readline.cursorTo(process.stdout, 0);
118 | logger.error(
119 | chalk.bold(
120 | chalk.red(
121 | `❌ Error downloading video and audio files: ${err.message}`
122 | )
123 | )
124 | );
125 | reject(err);
126 | })
127 | .save(outputFile);
128 | ffmpegCommand.run();
129 | });
130 | };
131 |
132 | const validateUrl = (url) => {
133 | const regex = urlRegex({ strict: false });
134 | return regex.test(url);
135 | };
136 |
137 | const displayVideoAndAudioDetails = (reqVideo, reqAudio, videoTitle, url) => {
138 | log(
139 | chalk.bold(
140 | chalk.bgCyanBright("🎥 Video Title:"),
141 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
142 | )
143 | );
144 | if (reqVideo) {
145 | log(
146 | chalk.bold(
147 | chalk.yellow(
148 | `🎞️ Video Format: ${chalk.bold(
149 | chalk.italic(chalk.white(reqVideo.format_id))
150 | )}`
151 | )
152 | )
153 | );
154 | log(
155 | chalk.bold(
156 | chalk.yellow(
157 | `🖥️ Video Resolution: ${chalk.bold(
158 | chalk.italic(chalk.white(reqVideo.height))
159 | )}`
160 | )
161 | )
162 | );
163 | log(
164 | chalk.bold(
165 | chalk.yellow(
166 | `🔗 Video URL: ${chalk.bold(chalk.italic(chalk.white(reqVideo.url)))}`
167 | )
168 | )
169 | );
170 | } else {
171 | log(chalk.bold(chalk.yellow("⚠️ No video details found.")));
172 | }
173 | if (reqAudio) {
174 | log(
175 | chalk.bold(
176 | chalk.yellow(
177 | `🔊 Audio Format: ${chalk.bold(
178 | chalk.italic(chalk.white(reqAudio.format_id))
179 | )}`
180 | )
181 | )
182 | );
183 | log(
184 | chalk.bold(
185 | chalk.yellow(
186 | `🔉 Audio Bitrate: ${chalk.bold(
187 | chalk.italic(chalk.white(reqAudio.abr))
188 | )}kbps`
189 | )
190 | )
191 | );
192 | log(
193 | chalk.bold(
194 | chalk.yellow(
195 | `🔗 Audio URL: ${chalk.bold(chalk.italic(chalk.white(reqAudio.url)))}`
196 | )
197 | )
198 | );
199 | } else {
200 | log(chalk.bold(chalk.yellow("⚠️ No audio details found.")));
201 | }
202 | return url;
203 | };
204 |
205 | const displayVideoDetails = (reqVideo, videoTitle, url) => {
206 | log(
207 | chalk.bold(
208 | chalk.bgCyanBright("🎥 Video Title:"),
209 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
210 | )
211 | );
212 | Object.entries(reqVideo).forEach(([key, value]) => {
213 | switch (key) {
214 | case "url":
215 | url = value;
216 | break;
217 | default:
218 | log(
219 | chalk.bold(
220 | chalk.yellow(
221 | `${key}: ${chalk.bold(chalk.italic(chalk.white(value)))}`
222 | )
223 | )
224 | );
225 | break;
226 | }
227 | });
228 | return url;
229 | };
230 |
231 | const dlAudioVideo = async ({ url, folder, filename, resolution }) => {
232 | return new Promise(async (resolve, reject) => {
233 | try {
234 | if (!validateUrl(url)) {
235 | throw new Error("❌ Invalid URL format.");
236 | }
237 | const { reqVideo, reqAudio, videoTitle } =
238 | await fetchVideoAndAudioDetails({
239 | url,
240 | requestedResolution: resolution,
241 | });
242 | if (reqVideo && reqAudio) {
243 | url = displayVideoAndAudioDetails(reqVideo, reqAudio, videoTitle, url);
244 | url = displayVideoDetails(reqVideo, videoTitle, url);
245 | if (!folder) {
246 | folder = "youtube-exec";
247 | }
248 | createFolderIfNotExists(folder);
249 | const outputFilename = filename
250 | ? `${filename}.mp4`
251 | : `[${reqVideo.height}]${videoTitle}.mp4`;
252 | const outputPath = path.join(folder, outputFilename);
253 | await downloadVideoAndAudioFiles(
254 | reqVideo.url,
255 | reqAudio.url,
256 | outputPath,
257 | reqVideo
258 | );
259 | log(chalk.bold(chalk.green("✅ Video downloaded successfully!")));
260 | resolve();
261 | } else {
262 | throw new Error("⚠️ No video and audio details found.");
263 | }
264 | } catch (err) {
265 | reject(err);
266 | }
267 | });
268 | };
269 |
270 | export default dlAudioVideo;
271 |
--------------------------------------------------------------------------------
/src/cjs/vid_aud.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // =====================================( youtube-exec: Unleash the Power of YouTube Downloads! )=============================================
3 | // 🌟 Once upon a time in the vast realm of the Internet, a remarkable tool was born: YOUTUBE-EXEC. 📽️✨
4 | //
5 | // 🎥 Step into a world where you can effortlessly download the mesmerizing audio and captivating video content from YouTube. 🎵🎬💽
6 | // 💡 Powered by the mighty and ingenious "youtube-dl-exec" library, this tool possesses the uncanny ability to extract the finest details from YouTube's vast kingdom of videos. 📚🔍💡
7 | // ⚙️ Equipped with the seamless and reliable "fluent-ffmpeg" library, youtube-exec embarks on a quest to fetch files with utmost precision and grace.
8 | // With each step, it transforms the abstract bits and bytes into a symphony of sights and sounds. 🔄⚙️🔊
9 | // 🌟 Unlock the gates to a realm where your favorite audio harmonies and video treasures await.
10 | // Dive into the enchanting world of YouTube's vast library, and let your imagination soar. 🎉🔑💎
11 | // 🔓 Embrace the freedom to break free from limitations and embrace a world of boundless possibilities.
12 | // Bid farewell to the boundaries that once held you back and embark on an adventure beyond your wildest dreams. 🚫🌍🔓💫
13 | // 📖 This is the tale of youtube-exec, a tool that empowers you to shape your own narrative in the realm of YouTube.
14 | // Let your journey begin! 🚀🎬🔥
15 | //
16 | // =====================================( youtube-exec by magneum )=============================================
17 | const progLogger = require("progress-estimator");
18 | const youtubedl = require("youtube-dl-exec");
19 | const logger = require("../../utils/logger.js");
20 | const ffmpeg = require("fluent-ffmpeg");
21 | const urlRegex = require("url-regex");
22 | const readline = require("readline");
23 | const chalk = require("chalk");
24 | const path = require("path");
25 | const fs = require("fs");
26 |
27 | const log = (message) => {
28 | logger.info(message);
29 | };
30 |
31 | const plogger = progLogger();
32 | const createFolderIfNotExists = (folder) => {
33 | if (!folder) {
34 | folder = "youtube-exec";
35 | }
36 | const outputFolder = path.resolve(process.cwd(), folder);
37 | if (!fs.existsSync(outputFolder)) {
38 | fs.mkdirSync(outputFolder);
39 | logger.info(`📂 Created folder: ${outputFolder}`);
40 | }
41 | };
42 |
43 | const fetchVideoAndAudioDetails = async ({ url, requestedResolution }) => {
44 | log("🔍 Fetching video and audio details...");
45 | try {
46 | const promise = youtubedl(url, {
47 | dumpSingleJson: true,
48 | noCheckCertificates: true,
49 | noWarnings: true,
50 | preferFreeFormats: true,
51 | addHeader: ["referer:youtube.com", "user-agent:googlebot"],
52 | });
53 | const result = await plogger(promise, "⏳ Obtaining...");
54 | const videoTitle = result.title;
55 | const reqVideo = findReqVideoFormat(result.formats, requestedResolution);
56 | const reqAudio = findReqAudioFormat(result.formats);
57 | return { reqVideo, reqAudio, videoTitle };
58 | } catch (err) {
59 | throw new Error(
60 | `❌ Error fetching video and audio details: ${err.message}`
61 | );
62 | }
63 | };
64 |
65 | const findReqVideoFormat = (formats, requestedResolution) => {
66 | let reqVideo = null;
67 | const availableFormats = formats.filter(
68 | (format) => format.ext === "mp4" && format.format_note !== "none"
69 | );
70 | const sortedFormats = availableFormats.sort((a, b) => a.height - b.height);
71 | reqVideo = sortedFormats.find(
72 | (format) => format.height >= requestedResolution
73 | );
74 | return reqVideo;
75 | };
76 |
77 | const findReqAudioFormat = (formats) => {
78 | let reqAudio = null;
79 | const availableFormats = formats.filter(
80 | (format) => format.ext === "m4a" && format.format_note !== "none"
81 | );
82 | const sortedFormats = availableFormats.sort((a, b) => b.abr - a.abr);
83 | reqAudio = sortedFormats[0];
84 | return reqAudio;
85 | };
86 |
87 | const downloadVideoAndAudioFiles = async (
88 | videoUrl,
89 | audioUrl,
90 | outputFile,
91 | videoFormat
92 | ) => {
93 | return new Promise((resolve, reject) => {
94 | const ffmpegCommand = ffmpeg()
95 | .input(videoUrl)
96 | .input(audioUrl)
97 | .videoCodec("copy")
98 | .audioCodec("copy")
99 | .on("start", () => {
100 | log("📥 Video and audio download started...");
101 | })
102 | .on("progress", (progress) => {
103 | readline.clearLine(process.stdout, 0);
104 | readline.cursorTo(process.stdout, 0);
105 | process.stdout.write(`⬇️ Downloading: ${progress.percent}%`);
106 | })
107 | .on("end", () => {
108 | readline.clearLine(process.stdout, 0);
109 | readline.cursorTo(process.stdout, 0);
110 | log(
111 | chalk.bold(chalk.green("✅ Video and audio downloaded successfully!"))
112 | );
113 | resolve();
114 | })
115 | .on("error", (err) => {
116 | readline.clearLine(process.stdout, 0);
117 | readline.cursorTo(process.stdout, 0);
118 | logger.error(
119 | chalk.bold(
120 | chalk.red(
121 | `❌ Error downloading video and audio files: ${err.message}`
122 | )
123 | )
124 | );
125 | reject(err);
126 | })
127 | .save(outputFile);
128 | ffmpegCommand.run();
129 | });
130 | };
131 |
132 | const validateUrl = (url) => {
133 | const regex = urlRegex({ strict: false });
134 | return regex.test(url);
135 | };
136 |
137 | const displayVideoAndAudioDetails = (reqVideo, reqAudio, videoTitle, url) => {
138 | log(
139 | chalk.bold(
140 | chalk.bgCyanBright("🎥 Video Title:"),
141 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
142 | )
143 | );
144 | if (reqVideo) {
145 | log(
146 | chalk.bold(
147 | chalk.yellow(
148 | `🎞️ Video Format: ${chalk.bold(
149 | chalk.italic(chalk.white(reqVideo.format_id))
150 | )}`
151 | )
152 | )
153 | );
154 | log(
155 | chalk.bold(
156 | chalk.yellow(
157 | `🖥️ Video Resolution: ${chalk.bold(
158 | chalk.italic(chalk.white(reqVideo.height))
159 | )}`
160 | )
161 | )
162 | );
163 | log(
164 | chalk.bold(
165 | chalk.yellow(
166 | `🔗 Video URL: ${chalk.bold(chalk.italic(chalk.white(reqVideo.url)))}`
167 | )
168 | )
169 | );
170 | } else {
171 | log(chalk.bold(chalk.yellow("⚠️ No video details found.")));
172 | }
173 | if (reqAudio) {
174 | log(
175 | chalk.bold(
176 | chalk.yellow(
177 | `🔊 Audio Format: ${chalk.bold(
178 | chalk.italic(chalk.white(reqAudio.format_id))
179 | )}`
180 | )
181 | )
182 | );
183 | log(
184 | chalk.bold(
185 | chalk.yellow(
186 | `🔉 Audio Bitrate: ${chalk.bold(
187 | chalk.italic(chalk.white(reqAudio.abr))
188 | )}kbps`
189 | )
190 | )
191 | );
192 | log(
193 | chalk.bold(
194 | chalk.yellow(
195 | `🔗 Audio URL: ${chalk.bold(chalk.italic(chalk.white(reqAudio.url)))}`
196 | )
197 | )
198 | );
199 | } else {
200 | log(chalk.bold(chalk.yellow("⚠️ No audio details found.")));
201 | }
202 | return url;
203 | };
204 |
205 | const displayVideoDetails = (reqVideo, videoTitle, url) => {
206 | log(
207 | chalk.bold(
208 | chalk.bgCyanBright("🎥 Video Title:"),
209 | chalk.bold(chalk.italic(chalk.white(videoTitle)))
210 | )
211 | );
212 | Object.entries(reqVideo).forEach(([key, value]) => {
213 | switch (key) {
214 | case "url":
215 | url = value;
216 | break;
217 | default:
218 | log(
219 | chalk.bold(
220 | chalk.yellow(
221 | `${key}: ${chalk.bold(chalk.italic(chalk.white(value)))}`
222 | )
223 | )
224 | );
225 | break;
226 | }
227 | });
228 | return url;
229 | };
230 |
231 | const dlAudioVideo = async ({ url, folder, filename, resolution }) => {
232 | return new Promise(async (resolve, reject) => {
233 | try {
234 | if (!validateUrl(url)) {
235 | throw new Error("❌ Invalid URL format.");
236 | }
237 | const { reqVideo, reqAudio, videoTitle } =
238 | await fetchVideoAndAudioDetails({
239 | url,
240 | requestedResolution: resolution,
241 | });
242 | if (reqVideo && reqAudio) {
243 | url = displayVideoAndAudioDetails(reqVideo, reqAudio, videoTitle, url);
244 | url = displayVideoDetails(reqVideo, videoTitle, url);
245 | if (!folder) {
246 | folder = "youtube-exec";
247 | }
248 | createFolderIfNotExists(folder);
249 | const outputFilename = filename
250 | ? `${filename}.mp4`
251 | : `[${reqVideo.height}]${videoTitle}.mp4`;
252 | const outputPath = path.join(folder, outputFilename);
253 | await downloadVideoAndAudioFiles(
254 | reqVideo.url,
255 | reqAudio.url,
256 | outputPath,
257 | reqVideo
258 | );
259 | log(chalk.bold(chalk.green("✅ Video downloaded successfully!")));
260 | resolve();
261 | } else {
262 | throw new Error("⚠️ No video and audio details found.");
263 | }
264 | } catch (err) {
265 | reject(err);
266 | }
267 | });
268 | };
269 |
270 | module.exports = dlAudioVideo;
271 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 📥🎥 YouTube-Exec 🎥📥
2 |
3 | ### **⭐️ If you find YouTube-Exec useful, give it a star on [GitHub](https://github.com/magneum/youtube-exec)**
4 |
5 |
6 |

7 |
8 |
9 | ## **Unleash the Power of YouTube Downloads!** 💪🔥💻
10 |
11 | - Effortlessly download audio and video content from YouTube. 🎵🎬💽
12 | - Utilizes the powerful `youtube-dl-exec` library for extracting details. 📚🔍💡
13 | - Seamless fetching of files using the reliable `fluent-ffmpeg` library. 🔄⚙️🔊
14 | - Access and download your favorite audio and video treasures from YouTube. 🎉🔑💎
15 | - Say goodbye to limitations and enjoy a world of boundless possibilities. 🚫🌍🔓💫
16 |
17 | | | |
18 | | -------------- | --------------------------------------------------------------------------------------------------- |
19 | | License | [](LICENSE) |
20 | | Latest Version | [](https://www.npmjs.com/package/youtube-exec) |
21 |
22 | Installation: 📥💻🔧
23 |
24 | To embark on your YouTube downloading adventure with YouTube-Exec, you'll need to have Node.js installed on your system. Fear not! The installation process is as easy as a few simple commands:
25 |
26 | - Using yarn or npm or pnpm
27 |
28 | ```
29 | $ yarn add youtube-exec
30 | $ npm install youtube-exec
31 | $ pnpm install youtube-exec
32 | ```
33 |
34 | Usage (w/o CLI): 🖥️🔧📚
35 |
36 |
37 | 🎵 Download Audio 🔊
38 |
39 | To download audio from YouTube, you can use the `dlAudio` function provided by YouTube-Exec. Here's an example of how to use it:
40 |
41 | ```javascript
42 | const { dlAudio } = require("youtube-exec");
43 |
44 | // Using async/await
45 | try {
46 | await dlAudio({
47 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
48 | folder: "downloads", // optional, default: "youtube-exec"
49 | filename: "filename", // optional, default: video title
50 | quality: "best", // or "lowest"; default: "best"
51 | });
52 | console.log("Audio downloaded successfully! 🔊🎉");
53 | } catch (err) {
54 | console.error("An error occurred:", err.message);
55 | }
56 |
57 | // Using Promises
58 | dlAudio({
59 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
60 | folder: "downloads", // optional, default: "youtube-exec"
61 | filename: "filename", // optional, default: video title
62 | quality: "best", // or "lowest"; default: "best"
63 | })
64 | .then(() => {
65 | console.log("Audio downloaded successfully! 🔊🎉");
66 | })
67 | .catch((err) => {
68 | console.error("An error occurred:", err.message);
69 | });
70 | ```
71 |
72 |
73 |
74 |
75 | 🎥🔊 Download Video with Audio 🎥🔊
76 |
77 | To download videos with audio from YouTube, you can use the `dlAudioVideo` function provided by YouTube-Exec. Here's an example of how to use it:
78 |
79 | ```javascript
80 | const { dlAudioVideo } = require("youtube-exec");
81 |
82 | // Using async/await
83 | try {
84 | await dlAudioVideo({
85 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
86 | folder: "downloads", // optional, default: "youtube-exec"
87 | filename: "filename", // optional, default: video title
88 | resolution: 720, // 144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320; default: 480
89 | });
90 | console.log("Video downloaded successfully! 🎥🔊🎉");
91 | } catch (err) {
92 | console.error("An error occurred:", err.message);
93 | }
94 |
95 | // Using Promises
96 | dlAudioVideo({
97 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
98 | folder: "downloads", // optional, default: "youtube-exec"
99 | filename: "filename", // optional, default: video title
100 | resolution: 720, // 144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320; default: 480
101 | })
102 | .then(() => {
103 | console.log("Video downloaded successfully! 🎥🔊🎉");
104 | })
105 | .catch((err) => {
106 | console.error("An error occurred:", err.message);
107 | });
108 | ```
109 |
110 |
111 |
112 |
113 | 🎥 Download Video w/o Audio 🎥
114 |
115 | To download videos without audio from YouTube, you can use the `dlVideo` function provided by YouTube-Exec. Here's an example of how to use it:
116 |
117 | ```javascript
118 | const { dlVideo } = require("youtube-exec");
119 |
120 | // Using async/await
121 | try {
122 | await dlVideo({
123 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
124 | folder: "downloads", // optional, default: "youtube-exec"
125 | filename: "filename", // optional, default: video title
126 | resolution: 720, // 144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320; default: 480
127 | });
128 | console.log("Video downloaded successfully! 🎥🎉");
129 | } catch (err) {
130 | console.error("An error occurred:", err.message);
131 | }
132 |
133 | // Using Promises
134 | dlVideo({
135 | url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
136 | folder: "downloads", // optional, default: "youtube-exec"
137 | filename: "filename", // optional, default: video title
138 | resolution: 720, // 144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320; default: 480
139 | })
140 | .then(() => {
141 | console.log("Video downloaded successfully! 🎥🎉");
142 | })
143 | .catch((err) => {
144 | console.error("An error occurred:", err.message);
145 | });
146 | ```
147 |
148 |
149 |
150 | Usage (with CLI): 🖥️💻🔧📚
151 |
152 | - Install the package globally:
153 |
154 | ```bash
155 | $ npm install -g youtube-exec # sudo required for global install
156 | ```
157 |
158 |
159 | Download Audio 🔊 (with CLI usage)
160 |
161 | The "audio" command allows you to download audio from a YouTube video. It accepts the following options:
162 |
163 | - `url`: The URL of the YouTube video (required).
164 | - `folder`: The output folder name (optional).
165 | - `filename`: The output filename (excluding extension) (optional, defaults to video title).
166 | - `quality`: The audio quality ("best" or "lowest") (optional, defaults to "best").
167 |
168 | Here's an example of how to use the "audio" command:
169 |
170 | ```bash
171 | $ yarn global add youtube-exec # needs to be installed globally
172 | $ youtube-exec audio --url "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --folder "downloads" --filename "filename" --quality "best"
173 | ```
174 |
175 |
176 |
177 |
178 | Download Video with Audio 🎥🔊 (with CLI usage)
179 |
180 | The "video-with-audio" command allows you to download video with audio from a YouTube video. It accepts the following options:
181 |
182 | - `url`: The URL of the YouTube video (required).
183 | - `folder`: The output folder name (optional).
184 | - `filename`: The output filename (excluding extension) (optional, defaults to video title).
185 | - `resolution`: The video resolution (144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320) (optional, defaults to 480).
186 |
187 | Here's an example of how to use the "video-with-audio" command:
188 |
189 | ```bash
190 | $ yarn global add youtube-exec # needs to be installed globally
191 | $ youtube-exec video-with-audio --url "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --folder "downloads" --filename "filename" --resolution 720
192 | ```
193 |
194 |
195 |
196 |
197 | Download Video without Audio 🎥🔊 (with CLI usage)
198 |
199 | The "video" command allows you to download video without audio from a YouTube video. It accepts the following options:
200 |
201 | - `url`: The URL of the YouTube video (required).
202 | - `folder`: The output folder name (optional).
203 | - `filename`: The output filename (excluding extension) (optional, defaults to video title).
204 | - `resolution`: The video resolution (144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320) (optional, defaults to 480).
205 |
206 | Here's an example of how to use the "video" command:
207 |
208 | ```bash
209 | $ yarn global add youtube-exec # needs to be installed globally
210 | $ youtube-exec video --url "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --folder "downloads" --filename "filename" --resolution 720
211 | ```
212 |
213 |
214 |
215 | Features: 🎯🔥🌟
216 |
217 | - Extract video and audio details from YouTube effortlessly
218 | - Download audio files from YouTube videos 🎵🔊
219 | - Download videos with audio from YouTube 🎥🔊
220 | - Choose audio quality (best or lowest) 🔊🥇
221 | - Choose video resolution (144, 240, 360, 480, 720, 1080, 1440, 2160, or 4320) 🎥📺
222 | - Simple and intuitive API 🚀
223 | - CLI support for easy downloading 💻⚡
224 |
225 | License: 📜🔐
226 |
227 |
228 | YouTube-Exec is released under the MIT License. Feel free to use, modify, and distribute it as you like.
229 | The MIT License grants you the following permissions:
230 |
231 |
232 | - ✅ Permission is hereby granted, free of charge, to any person obtaining a copy of the YouTube-Exec software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
233 |
234 | - 📋 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
235 |
236 | - 🚀 The Software is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
237 |
238 | - 🔗 The Software may utilize third-party libraries, including but not limited to `youtube-dl-exec` and `fluent-ffmpeg`. Any such libraries are subject to their respective licenses and terms.
239 |
240 | - 🔒 Users of the Software acknowledge that the extraction and downloading of audio and video content from YouTube may be subject to legal restrictions and terms of use imposed by YouTube or other relevant entities. It is the responsibility of the users to comply with all applicable laws, regulations, and terms of use when using the Software.
241 |
242 | - 👥 The Software is intended for personal and non-commercial use only. Any commercial use of the Software requires explicit permission from the authors.
243 |
--------------------------------------------------------------------------------