-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
137 lines (110 loc) · 4.2 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// sources:
// how to add cookies: https://github.com/fent/node-ytdl-core/blob/master/example/cookies.js
const cliProgress = require('cli-progress');
const fs = require("fs");
const path = require("path");
const ytdl = require("ytdl-core");
const inquirer = require('inquirer');
const { getInfo } = ytdl;
const winston = require("winston");
const { format: winstonFormat } = winston;
const logger = winston.createLogger({
transports: [
// new winston.transports.Console(),
new winston.transports.File({
filename: './logs/combined.log',
format: winstonFormat.combine(winstonFormat.timestamp(), winstonFormat.splat(), winstonFormat.simple())
})
]
});
const BYTES_IN_ONE_MB = 1048576;
/**
* @type {string}
*/
let filePath;
const progressBar = new cliProgress.SingleBar({
format: 'Downloading [{bar}] {percentage}% | {totalDownloadedMegaBytes}/{totalMegaBytes} MB'
}, cliProgress.Presets.shades_classic);
StartUp();
function StartUp() {
Program().catch(catcher);
}
async function Program() {
const { value: video_url } = await inquirer.prompt([{ type: "input", name: "value", message: "Enter video link (Right-Click in black area to paste):" }]);
console.log("\nTrying to fetch video information..");
logger.info("Trying to fetch video information: %s", video_url);
const videoInfo = await getInfo(video_url);
console.log("\nVideo found! Title:", videoInfo.videoDetails.title, "\n");
logger.info("Video found! Title: %s", videoInfo.videoDetails.title);
const choices = videoInfo.formats.map((format, index) => {
const regexMatch = format.mimeType.match(/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+);*/);
const mediaTypeAndContainer = regexMatch[0];
const sizeInMb = format.contentLength === undefined ? "(unknown size)" : (format.contentLength / BYTES_IN_ONE_MB).toFixed(3) + " MB";
const qualityLabel = (format.qualityLabel || "").padEnd(11, ' ');
const choiceMessageSplitted = [
// i.toString().padStart(3, " "), // index
// v.itag.toString().padEnd(3, ' '), // itag
qualityLabel,
sizeInMb.padStart(14, ' '),
mediaTypeAndContainer,
format.hasAudio ? "" : "(without audio)",
];
return { name: choiceMessageSplitted.join(" "), value: index };
});
const { value: selectedIndex } = await inquirer.prompt([{
choices: choices,
type: "list",
name: "value",
message: "Select media type and format:",
loop: false,
pageSize: videoInfo.formats.length,
}]);
const format = videoInfo.formats[selectedIndex];
const { qualityLabel, itag, container } = format;
// to follow windows file naming convention.
const cleanedTitle = videoInfo.videoDetails.title.replace(/[\/\\\:\*\?\"\<\>\|]+/g, "");
filePath = `./${cleanedTitle}-${qualityLabel}-${itag}.${container}`;
console.log(`\nSaving file as: ${filePath}\n`);
logger.info("Saving file as: %s", filePath);
progressBar.start(100, 0, { totalDownloadedMegaBytes: 0, totalMegaBytes: 0 });
ytdl.downloadFromInfo(videoInfo, { quality: format.itag })
.on("end", onDownloadEnd)
.on("progress", onProgressCallback)
.pipe(fs.createWriteStream(filePath));
}
/**
* @param {Number} _
* @param {Number} totalBytesDownloaded
* @param {Number} totalBytes
*/
function onProgressCallback(_, totalBytesDownloaded, totalBytes) {
const percentage = parseInt((totalBytesDownloaded / totalBytes) * 100);
const totalDownloadedMegaBytes = (totalBytesDownloaded / BYTES_IN_ONE_MB).toFixed(3);
const totalMegaBytes = (totalBytes / BYTES_IN_ONE_MB).toFixed(3);
progressBar.update(percentage, { totalDownloadedMegaBytes, totalMegaBytes });
}
function onDownloadEnd() {
progressBar.stop();
console.log("\nDownload complete!");
const fileLocation = `Video has been saved at: ${path.resolve(filePath)}`;
console.log(fileLocation);
logger.info(fileLocation);
console.log("\nNeed to download another video?");
StartUp();
}
function catcher(error) {
if (progressBar) {
progressBar.stop();
}
if (typeof error.toString === "function") {
logger.error(error.toString());
}
else if (typeof error.message === "string") {
logger.error(error.message);
}
else {
logger.error(JSON.stringify(error));
}
console.log("\nSome error occurred! Try again.");
StartUp();
}