Files
2022-08-16 15:11:37 +02:00

133 lines
3.9 KiB
JavaScript

/**
* @author Luuxis
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
'use strict';
const nodeFetch = require("node-fetch");
const fs = require("fs");
module.exports = class Downloader {
async start(url) {
let size = await nodeFetch(url, { method: "HEAD" }).then(res => parseInt(res.headers.get("content-length")));
this.emit("progress", 0, size);
let res = await nodeFetch(url);
let data = Buffer.allocUnsafe(size);
let downloaded = 0;
res.body.on('data', (chunk) => {
data.fill(chunk, downloaded, downloaded + chunk.length);
downloaded += chunk.length;
this.emit("progress", downloaded, size);
});
let start = new Date().getTime();
let before = 0;
let speeds = [];
let interval = setInterval(() => {
let duration = (new Date().getTime() - start) / 1000;
let loaded = (downloaded - before) * 8;
if (speeds.length >= 5) speeds = speeds.slice(1);
speeds.push((loaded / duration) / 8);
let speed = 0;
for (let s of speeds) speed += s;
speed /= speeds.length;
this.emit("speed", speed);
let time = (size - downloaded) / (speed);
this.emit("estimated", time);
start = new Date().getTime();
before = downloaded;
}, 1000);
res.body.on('end', () => {
clearInterval(interval);
this.emit("finish", data);
});
}
multiple(files, totalsize, limit = 1) {
this.emit("progress", 0, totalsize);
let complete = 0;
let queued = 0;
let i = 0;
let start = new Date().getTime();
let before = 0;
let downloaded = 0;
let speeds = [];
let interval = setInterval(() => {
let duration = (new Date().getTime() - start) / 1000;
let loaded = (downloaded - before) * 8;
if (speeds.length >= 5) speeds = speeds.slice(1);
speeds.push((loaded / duration) / 8);
let speed = 0;
for (let s of speeds) speed += s;
speed /= speeds.length;
this.emit("speed", speed);
let time = (totalsize - downloaded) / (speed);
this.emit("estimated", time);
start = new Date().getTime();
before = downloaded;
}, 1000);
let progressInterval = setInterval(() => {
this.emit("progress", downloaded, totalsize);
}, 100);
queue();
let finish = this.finish;
function queue() {
if (complete == files.length) {
clearInterval(interval);
clearInterval(progressInterval);
if (finish) finish();
return;
}
while (queued < limit) {
if (i == files.length) break;
download();
}
}
async function download() {
let file = files[i++];
queued++;
if (!fs.existsSync(file.folder)) fs.mkdirSync(file.folder, { recursive: true, mode: 0o777 });
let flag = fs.openSync(file.path, "w", 0o777);
let position = 0;
let res = await nodeFetch(file.url);
res.body.on('data', (chunk) => {
downloaded += chunk.length;
position += chunk.length;
fs.writeSync(flag, chunk, 0, chunk.length, position - chunk.length, (e) => { if (e) throw e });
});
res.body.on('end', () => {
fs.closeSync(flag);
complete += 1
queued -= 1
queue();
});
}
}
on(event, func) {
this[event] = func;
}
emit(event, ...args) {
if (this[event]) this[event](...args);
}
}