401 lines
10 KiB
JavaScript
401 lines
10 KiB
JavaScript
const fs = require("fs");
|
|
const axios = require("axios");
|
|
const {SingleBar} = require("cli-progress");
|
|
const minimist = require("minimist");
|
|
|
|
module.exports = {
|
|
getCookies,
|
|
getOptions,
|
|
getExtractor,
|
|
cookieToString,
|
|
log,
|
|
download,
|
|
countdown,
|
|
defaultHost,
|
|
defaultHeaders: {
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
|
"Accept-Encoding": "gzip, deflate",
|
|
"Accept-Language": "en-US,en;q=0.9",
|
|
"Connection": "keep-alive",
|
|
"DNT": "1",
|
|
"Sec-Fetch-Dest": "document",
|
|
"Sec-Fetch-Mode": "navigate",
|
|
"Sec-Fetch-Site": "same-origin",
|
|
"Sec-Fetch-User": "?1",
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0",
|
|
"Upgrade-Insecure-Requests": "1"
|
|
}
|
|
}
|
|
|
|
function getOptions() {
|
|
if (process.argv0.includes("node")) args = minimist(process.argv.slice(2));
|
|
else args = minimist(process.argv.slice(1));
|
|
|
|
let options = {};
|
|
|
|
if (args.d == true || args.debug == true) options.debug = true;
|
|
else options.debug = false;
|
|
|
|
if (args.dry == true || args["dry-run"] == true) options.dry = true;
|
|
else options.dry = false;
|
|
|
|
if (args.cookie || args.cookies || args.cookieFile) options.cookieFile = (args.cookie || args.cookies || args.cookieFile);
|
|
|
|
options.urls = [];
|
|
for (let index in args._) {
|
|
options.urls.push(args._[index]);
|
|
}
|
|
|
|
if (args.file) {
|
|
if (args.file.endsWith("txt")) {
|
|
let file = fs.readFileSync(args.file).toString().split(`\n`);
|
|
for (let i in file) {
|
|
if (file[i].startsWith("http://") || file[i].startsWith("https://")) options.urls.push(file[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (args["preferred-host"]) options.preferredHost = args["preferred-host"];
|
|
|
|
return options;
|
|
}
|
|
|
|
async function getExtractor(url) {
|
|
let hostname = new URL(url).hostname;
|
|
hostname = `${hostname.split(".")[hostname.split(".").length - 2]}.${hostname.split(".")[hostname.split(".").length - 1]}`;
|
|
|
|
let extractors = fs.readdirSync(`${__dirname}/extractors`);
|
|
|
|
for (let i in extractors) {
|
|
let extractor = require(`${__dirname}/extractors/${extractors[i]}`);
|
|
if (extractor.hostnames?.includes(hostname)) return extractor;
|
|
else continue;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function log(origin, message, etc, force, options) {
|
|
if (!options) options = getOptions();
|
|
|
|
if (options?.allowForceLogs == false) return;
|
|
|
|
if (options.debug == true || force == true) {
|
|
if (etc?.length !== 0 && etc !== undefined) console.log(`[${origin}] ${message}`, ...etc);
|
|
else console.log(`[${origin}] ${message}`);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
function cookieToString(cookies) {
|
|
let s = ``;
|
|
for (let c in cookies) {
|
|
if (cookies[c].value == "deleted") continue;
|
|
s = `${s} ${cookies[c].name}=${encodeURIComponent(cookies[c].value)};`;
|
|
}
|
|
s = s.substring(0, s.length - 1);
|
|
return s.substring(1);
|
|
}
|
|
|
|
async function download(data) {
|
|
log(`downloader`, `Destination: "./${data?.metadata?.fileName}"`, [], true);
|
|
|
|
let pb = new SingleBar({format: `[downloader] {status} {percent} of {fullSize} @ {speed}/s {extra}`});
|
|
|
|
try {
|
|
let name = data?.metadata?.fileName;
|
|
|
|
let speed = 0;
|
|
setInterval(function() {
|
|
speed = 0;
|
|
}, 1000);
|
|
|
|
if (data.axiosData) {
|
|
let axiosData = data.axiosData;
|
|
axiosData.responseType = "stream";
|
|
|
|
let resp = await axios(axiosData);
|
|
let size = (resp?.headers["content-length"] || file.size);
|
|
|
|
if (size == undefined) {
|
|
pb.start(size, 0, {
|
|
percent: `(Unknown)%`,
|
|
speed: bytesToSize(0),
|
|
status: `Downloading`,
|
|
fullSize: `?GB`,
|
|
extra: ``
|
|
});
|
|
|
|
resp.data.on("data", function(chunk) {
|
|
if (!speed) speed = chunk.length;
|
|
else speed = (speed + chunk.length);
|
|
|
|
let humanSpeed = bytesToSize(speed);
|
|
|
|
pb.increment(0, {
|
|
speed: humanSpeed
|
|
});
|
|
});
|
|
} else {
|
|
size = parseInt(size);
|
|
|
|
let fullSize = bytesToSize(size);
|
|
let currSize = 0;
|
|
|
|
pb.start(size, 0, {
|
|
percent: `0.00%`,
|
|
speed: bytesToSize(0),
|
|
status: `Downloading`,
|
|
fullSize: fullSize,
|
|
extra: ``
|
|
});
|
|
|
|
resp.data.on("data", function(chunk) {
|
|
if (!speed) speed = chunk.length;
|
|
else speed = (speed + chunk.length);
|
|
|
|
let humanSpeed = bytesToSize(speed);
|
|
currSize = (currSize + chunk.length);
|
|
let percent = ((currSize / size) * 100).toFixed(2);
|
|
percent = `${percent}%`
|
|
|
|
pb.increment(chunk.length, {
|
|
percent: percent,
|
|
speed: humanSpeed
|
|
});
|
|
});
|
|
}
|
|
|
|
resp.data.pipe(fs.createWriteStream(`./${name}`));
|
|
|
|
let start = (new Date() * 1);
|
|
|
|
return (await returnWhenEnded(resp.data, pb, start));
|
|
} else if (data.stream && data?.metadata?.size) {
|
|
let size = data?.metadata?.size
|
|
let fullSize = bytesToSize(size);
|
|
let currSize = 0;
|
|
|
|
pb.start(size, 0, {
|
|
percent: `0.00%`,
|
|
speed: bytesToSize(0),
|
|
status: `Downloading`,
|
|
fullSize: fullSize,
|
|
extra: ``
|
|
});
|
|
|
|
data.stream.on("data", function(chunk) {
|
|
if (!speed) speed = chunk.length;
|
|
else speed = (speed + chunk.length);
|
|
|
|
let humanSpeed = bytesToSize(speed);
|
|
currSize = (currSize + chunk.length);
|
|
let percent = ((currSize / size) * 100).toFixed(2);
|
|
percent = `${percent}%`
|
|
|
|
pb.increment(chunk.length, {
|
|
percent: percent,
|
|
speed: humanSpeed
|
|
});
|
|
});
|
|
|
|
data.stream.pipe(fs.createWriteStream(`./${name}`));
|
|
|
|
let start = (new Date() * 1);
|
|
|
|
return (await returnWhenEnded(data.stream, pb, start));
|
|
} else throw new Error("Gave invalid download data.");
|
|
} catch(err) {
|
|
return {
|
|
success: false,
|
|
error: err
|
|
};
|
|
}
|
|
}
|
|
|
|
function bytesToSize(bytes) {
|
|
var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
if (bytes == 0) return '0 Byte';
|
|
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
|
|
}
|
|
|
|
async function returnWhenEnded(dl, pb, time) {
|
|
return new Promise(function(resolve, reject) {
|
|
try {
|
|
dl.on("end", function() {
|
|
let end = (new Date() * 1);
|
|
let totalTime = ((end - time)/ 1000)
|
|
pb.increment(0, {status: `Downloaded`, percent: `100.00%`, extra: `in ${totalTime}s`});
|
|
pb.stop();
|
|
resolve({success: true})
|
|
});
|
|
} catch(err) {
|
|
reject({success: false, error: err});
|
|
}
|
|
})
|
|
}
|
|
|
|
async function getCookies(file, domain) {
|
|
if (!file) throw new Error("Could not find cookie file.");
|
|
if (!fs.existsSync(file)) throw new Error("Could not find cookie file.");
|
|
|
|
let baseDomain;
|
|
if (domain) {
|
|
baseDomain = `${domain.split(".")[domain.split(".").length - 2]}.${domain.split(".").length - 1}`;
|
|
}
|
|
|
|
let cookies = fs.readFileSync(file).toString();
|
|
let parsedCookies = [];
|
|
|
|
for (let i in cookies.split(`\n`)) {
|
|
let cookie = cookies.split(`\n`)[i];
|
|
if (cookie.startsWith("#")) continue;
|
|
if (cookie == "" || cookie == " ") continue;
|
|
cookie = cookie.split(`\t`);
|
|
|
|
let exp = cookie[4];
|
|
if (exp == "0") continue;
|
|
else exp = new Date(parseInt(cookie[4] * 1000));
|
|
|
|
// filters expired cookies
|
|
|
|
let currDate = new Date() * 1;
|
|
let expDate = new Date() * 1;
|
|
|
|
if (expDate > currDate) continue;
|
|
|
|
cookie = {
|
|
domain: cookie[0],
|
|
path: cookie[2],
|
|
secure: toBool(cookie[3]),
|
|
expires: exp,
|
|
name: cookie[5],
|
|
value: cookie[6]
|
|
};
|
|
|
|
parsedCookies.push(cookie);
|
|
}
|
|
|
|
if (domain) {
|
|
// filtering out invalid cookies for the domain
|
|
for (let i in parsedCookies) {
|
|
let cookieDomain;
|
|
|
|
if (parsedCookies[i].domain.startsWith(".")) cookieDomain = parsedCookies[i].domain.substring(1);
|
|
else cookieDomain = parsedCookies[i].domain;
|
|
|
|
if (
|
|
cookieDomain !== baseDomain &&
|
|
cookieDomain !== domain
|
|
) delete parsedCookies[i];
|
|
}
|
|
}
|
|
|
|
return parsedCookies;
|
|
}
|
|
|
|
function toBool(string) {
|
|
if (typeof string == "string") {
|
|
string = string.toLowerCase();
|
|
switch(string) {
|
|
case "t":
|
|
case "tr":
|
|
case "tru":
|
|
case "true":
|
|
case "y":
|
|
case "ye":
|
|
case "yes":
|
|
return true;
|
|
case "f":
|
|
case "fa":
|
|
case "fal":
|
|
case "fals":
|
|
case "false":
|
|
case "n":
|
|
case "no":
|
|
return false;
|
|
}
|
|
} else return string;
|
|
}
|
|
|
|
async function countdown(ms, options) {
|
|
if (!options) options = {allowForceLogs: true};
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
try {
|
|
if (typeof ms == "number") ms = parseInt(ms);
|
|
|
|
let pb = new SingleBar({format: `[countdown] {status}: {remaining} {extra}`});
|
|
|
|
if (options.allowForceLogs !== false) {
|
|
pb.start(9999999, 0, {
|
|
remaining: toTimeString(ms),
|
|
status: "Waiting",
|
|
extra: "remaining"
|
|
});
|
|
}
|
|
|
|
setInterval(function() {
|
|
ms = ms - 1000;
|
|
|
|
if (ms <= 999) {
|
|
if (options.allowForceLogs !== false) {
|
|
pb.increment(1, {
|
|
remaining: toTimeString(ms),
|
|
status: "Waited",
|
|
extra: ""
|
|
})
|
|
pb.stop();
|
|
}
|
|
resolve(true);
|
|
}
|
|
|
|
if (options.allowForceLogs !== false) {
|
|
pb.increment(1, {
|
|
remaining: toTimeString(ms),
|
|
status: "Waiting"
|
|
});
|
|
}
|
|
}, 1000);
|
|
} catch(err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
function toTimeString(ms) {
|
|
if (typeof ms == "string") ms = parseFloat(ms);
|
|
|
|
let timeString = "";
|
|
|
|
let days = Math.floor(ms / (1000 * 60 * 60 * 24));
|
|
let hours = Math.floor((ms / (1000 * 60 * 60)) % 24);
|
|
let mins = Math.floor((ms / 1000 / 60) % 60);
|
|
let secs = Math.floor((ms / 1000) % 60);
|
|
|
|
if (days !== 0) timeString = `${days} days,`;
|
|
if (hours !== 0) timeString = `${timeString} ${hours} hours,`;
|
|
if (mins !== 0) timeString = `${timeString} ${mins} minutes,`;
|
|
if (secs !== 0) timeString = `${timeString} ${secs} seconds`;
|
|
|
|
if (days == 0) timeString = timeString.substring(1);
|
|
|
|
return timeString;
|
|
}
|
|
|
|
function defaultHost(mirror) {
|
|
let inOrderofPref = [
|
|
"zippyshare",
|
|
"send",
|
|
"yodbox",
|
|
"krakenfiles",
|
|
"anonfiles"
|
|
]
|
|
|
|
for (let i in mirror) {
|
|
let host = mirror[i].link.split(`.`)[0];
|
|
|
|
}
|
|
}
|