Add progress bar

This commit is contained in:
the1812 2019-04-22 18:02:45 +08:00
parent f37f42234b
commit 1db542d458
6 changed files with 105 additions and 30 deletions

View File

@ -0,0 +1,2 @@
*.flv
*.part*

View File

@ -0,0 +1,4 @@
{
"parts": 30,
"info": "test.json"
}

View File

@ -0,0 +1,7 @@
const commandLineArgs = require("command-line-args");
const optionDefinitions = [
{ name: 'info', alias: 'i', defaultOption: true, type: String, defaultValue: undefined },
{ name: 'parts', alias: 'p', type: Number, defaultValue: undefined },
];
console.log(commandLineArgs(optionDefinitions));

View File

@ -1,6 +1,6 @@
{
"urls": [
"https://upos-hz-mirrorcosu.acgvideo.com/upgcxcode/28/51/85135128/85135128-1-64.flv?e=ig8euxZM2rNcNbh37zUVhoMznwuBhwdEto8g5X10ugNcXBlqNxHxNEVE5XREto8KqJZHUa6m5J0SqE85tZvEuENvNC8xNEVE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==&deadline=1555924643&gen=playurl&nbs=1&oi=1880223831&os=cosu&platform=pc&trid=45a4f29cb06f40168f60745b18d2062e&uipk=5&upsig=c8609d4926d27f696d74375112cf51bf&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk"
"https://upos-hz-mirrorcosu.acgvideo.com/upgcxcode/28/51/85135128/85135128-1-64.flv?e=ig8euxZM2rNcNbh37zUVhoMznwuBhwdEto8g5X10ugNcXBlqNxHxNEVE5XREto8KqJZHUa6m5J0SqE85tZvEuENvNC8xNEVE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==&deadline=1555931845&gen=playurl&nbs=1&oi=1879749890&os=cosu&platform=pc&trid=2f286aa498ce4d24bd4020040e6997ba&uipk=5&upsig=d3498e7a0552a644dcc92b0e3be9f87a&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk"
],
"title": "【东方自作Arrange】 利己主義者のススメ 【今宵は飄逸なエゴイスト】",
"totalSize": 50339950

View File

@ -4,10 +4,17 @@ const commandLineArgs = require("command-line-args");
const clipboardy = require("clipboardy");
const request = require("request");
const fs = require("fs");
const ProgressBar = require("progress");
const optionDefinitions = [
{ name: 'parts', alias: 'p', type: Number, defaultValue: 30 },
{ name: 'info', alias: 'i', defaultOption: true, type: String, defaultValue: undefined },
{ name: 'parts', alias: 'p', type: Number, defaultValue: undefined },
];
const options = commandLineArgs(optionDefinitions);
const commandLineOptions = commandLineArgs(optionDefinitions);
let options = commandLineOptions;
if (fs.existsSync("settings.json")) {
const jsonOptions = JSON.parse(fs.readFileSync("settings.json").toString("utf-8"));
options = Object.assign(jsonOptions, options);
}
class Downloader {
constructor(inputData, progress) {
this.inputData = inputData;
@ -21,11 +28,14 @@ class Downloader {
}
cancelDownload() {
[...this.progressMap.keys()].forEach(it => it.abort());
const files = fs.readdirSync(".");
const parts = files.filter(it => it.includes(this.inputData.title));
parts.forEach(file => fs.unlinkSync(file));
console.log("已取消下载");
}
async downloadUrl(url, index = -1) {
const partialLength = Math.round(this.inputData.totalSize / options.parts);
console.log(partialLength);
const title = (index === -1 ? this.inputData.title : this.inputData.title + " - " + index.toString());
let startByte = 0;
let part = 0;
const promises = [];
@ -59,7 +69,7 @@ class Downloader {
// makeRequest();
console.error(error);
});
req.pipe(fs.createWriteStream(`${this.inputData.title}.part${part}`));
req.pipe(fs.createWriteStream(`${title}.part${part}`));
return req;
};
this.progressMap.set(makeRequest(), 0);
@ -68,43 +78,68 @@ class Downloader {
part++;
}
await Promise.all(promises);
const dest = (index === -1 ? this.inputData.title : this.inputData.title + " - " + index.toString()) + ".flv";
await new Promise(resolve => {
const dest = title + ".flv";
return await new Promise(resolve => {
fs.readdir(".", (_, files) => {
const parts = files.filter(it => it.includes(this.inputData.title));
const data = parts.map(file => fs.readFileSync(file));
const parts = files.filter(it => it.includes(title + ".part"));
const partRegex = /.*\.part([\d]+)/;
const data = parts.sort((a, b) => {
const partA = parseInt(a.replace(partRegex, "$1"));
const partB = parseInt(b.replace(partRegex, "$1"));
return partA - partB;
}).map(file => fs.readFileSync(file));
const stream = fs.createWriteStream(dest);
data.forEach(it => stream.write(it));
stream.close();
parts.forEach(file => fs.unlinkSync(file));
resolve();
resolve(dest);
});
});
}
async download() {
if (this.inputData.urls.length === 1) {
await this.downloadUrl(this.inputData.urls[0]);
return await this.downloadUrl(this.inputData.urls[0]);
}
else {
await Promise.all(this.inputData.urls.map((url, i) => this.downloadUrl(url, i)));
return await Promise.all(this.inputData.urls.map((url, i) => this.downloadUrl(url, i)));
}
}
}
(async () => {
console.log(options);
const jsonText = await clipboardy.read();
console.log(`分段值: ${options.parts}`);
let jsonText = '';
if (fs.existsSync(options.info)) {
jsonText = fs.readFileSync(options.info).toString("utf-8");
}
else {
jsonText = await clipboardy.read();
}
try {
const inputData = JSON.parse(jsonText);
const progressBar = new ProgressBar(":percent [:bar]", {
total: inputData.totalSize,
width: 20,
incomplete: ' ',
});
const downloader = new Downloader(inputData, progress => {
console.log((progress * 100).toFixed(2) + "%");
progressBar.update(progress);
});
process.on("SIGINT", () => {
progressBar.terminate();
downloader.cancelDownload();
process.exit();
});
await downloader.download();
progressBar.render();
const result = await downloader.download();
console.log(`下载完成: `);
if (typeof result === "string") {
console.log(result);
}
else {
result.forEach(console.log);
}
}
catch (error) {
console.error(`未在剪贴板找到足够的数据: ${error}`);
console.error(`错误: ${error}`);
}
})();

View File

@ -10,11 +10,23 @@ interface InputData
title: string;
totalSize: number;
}
interface Settings
{
parts: number;
info: string;
}
const optionDefinitions = [
{ name: 'parts', alias: 'p', type: Number, defaultValue: 30 },
{ name: 'info', alias: 'i', defaultOption: true, type: String, defaultValue: undefined },
{ name: 'parts', alias: 'p', type: Number, defaultValue: undefined },
];
const options = commandLineArgs(optionDefinitions) as { parts: number };
const commandLineOptions = commandLineArgs(optionDefinitions) as Settings;
let options = commandLineOptions;
if (fs.existsSync("settings.json"))
{
const jsonOptions = JSON.parse(fs.readFileSync("settings.json").toString("utf-8"));
options = Object.assign(jsonOptions, options);
}
type ProgressHandler = (p: number) => void;
class Downloader
@ -33,11 +45,9 @@ class Downloader
cancelDownload()
{
[...this.progressMap.keys()].forEach(it => it.abort());
fs.readdir(".", (_, files) =>
{
const parts = files.filter(it => it.includes(this.inputData.title));
parts.forEach(file => fs.unlinkSync(file));
});
const files = fs.readdirSync(".");
const parts = files.filter(it => it.includes(this.inputData.title));
parts.forEach(file => fs.unlinkSync(file));
console.log("已取消下载");
}
private async downloadUrl(url: string, index: number = -1)
@ -100,7 +110,13 @@ class Downloader
fs.readdir(".", (_, files) =>
{
const parts = files.filter(it => it.includes(title + ".part"));
const data = parts.map(file => fs.readFileSync(file));
const partRegex = /.*\.part([\d]+)/;
const data = parts.sort((a, b) =>
{
const partA = parseInt(a.replace(partRegex, "$1"));
const partB = parseInt(b.replace(partRegex, "$1"));
return partA - partB;
}).map(file => fs.readFileSync(file));
const stream = fs.createWriteStream(dest);
data.forEach(it => stream.write(it));
stream.close();
@ -123,21 +139,32 @@ class Downloader
}
(async () =>
{
console.log(options);
const jsonText = await clipboardy.read();
console.log(`分段值: ${options.parts}`);
let jsonText = '';
if (fs.existsSync(options.info))
{
jsonText = fs.readFileSync(options.info).toString("utf-8");
}
else
{
jsonText = await clipboardy.read();
}
try
{
const inputData = JSON.parse(jsonText) as InputData;
const progressBar = new ProgressBar(":percent [:bar]", inputData.totalSize);
const progressBar = new ProgressBar(":percent [:bar]", {
total: inputData.totalSize,
width: 20,
incomplete: ' ',
});
const downloader = new Downloader(inputData, progress =>
{
// console.log((progress * 100).toFixed(2) + "%");
progressBar.update(progress);
});
process.on("SIGINT", () =>
{
downloader.cancelDownload();
progressBar.terminate();
downloader.cancelDownload();
process.exit();
});
progressBar.render();