@xuanqikai/one-click-upload
Version:
A CLI tool for one-click file upload to cloud storage services (OSS, TOS)
214 lines • 6.81 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BatchProgress = exports.SimpleProgress = exports.ProgressBar = void 0;
const chalk_1 = __importDefault(require("chalk"));
const fileUtils_1 = require("./fileUtils");
class ProgressBar {
constructor(options = {}) {
this.speeds = [];
this.maxSpeedSamples = 10;
this.options = {
width: 40,
showPercentage: true,
showSpeed: true,
showETA: true,
showFileInfo: true,
...options
};
this.startTime = Date.now();
this.lastUpdate = this.startTime;
this.lastLoaded = 0;
}
/**
* 更新进度
*/
update(progress) {
const now = Date.now();
const timeDiff = now - this.lastUpdate;
// 计算速度(每秒字节数)
if (timeDiff > 0) {
const bytesDiff = progress.loaded - this.lastLoaded;
const speed = (bytesDiff / timeDiff) * 1000; // bytes per second
this.speeds.push(speed);
if (this.speeds.length > this.maxSpeedSamples) {
this.speeds.shift();
}
this.lastUpdate = now;
this.lastLoaded = progress.loaded;
}
return this.render(progress);
}
/**
* 渲染进度条
*/
render(progress) {
const { loaded, total, percentage, fileName } = progress;
let output = '';
// 文件信息
if (this.options.showFileInfo && fileName) {
output += chalk_1.default.cyan(`${fileName}\n`);
}
// 进度条
const progressBar = this.renderProgressBar(percentage);
output += progressBar;
// 百分比
if (this.options.showPercentage) {
output += ` ${percentage.toFixed(1)}%`;
}
// 文件大小信息
output += ` ${(0, fileUtils_1.formatFileSize)(loaded)}/${(0, fileUtils_1.formatFileSize)(total)}`;
// 速度
if (this.options.showSpeed) {
const speed = this.calculateAverageSpeed();
if (speed > 0) {
output += ` ${(0, fileUtils_1.formatFileSize)(speed)}/s`;
}
}
// 预计剩余时间
if (this.options.showETA && total > loaded) {
const eta = this.calculateETA(loaded, total);
if (eta > 0) {
output += ` ETA: ${(0, fileUtils_1.formatDuration)(eta)}`;
}
}
return output;
}
/**
* 渲染进度条图形
*/
renderProgressBar(percentage) {
const { width } = this.options;
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
const filledBar = '█'.repeat(filled);
const emptyBar = '░'.repeat(empty);
return chalk_1.default.green(filledBar) + chalk_1.default.gray(emptyBar);
}
/**
* 计算平均速度
*/
calculateAverageSpeed() {
if (this.speeds.length === 0)
return 0;
const sum = this.speeds.reduce((a, b) => a + b, 0);
return sum / this.speeds.length;
}
/**
* 计算预计剩余时间
*/
calculateETA(loaded, total) {
const speed = this.calculateAverageSpeed();
if (speed <= 0)
return 0;
const remaining = total - loaded;
return (remaining / speed) * 1000; // 转换为毫秒
}
/**
* 重置进度条
*/
reset() {
this.startTime = Date.now();
this.lastUpdate = this.startTime;
this.lastLoaded = 0;
this.speeds = [];
}
}
exports.ProgressBar = ProgressBar;
/**
* 简单的进度显示器
*/
class SimpleProgress {
constructor() {
this.lastPercentage = -1;
}
/**
* 显示进度
*/
show(progress) {
const { percentage, fileName } = progress;
// 只在百分比变化时更新显示
if (Math.floor(percentage) !== this.lastPercentage) {
this.lastPercentage = Math.floor(percentage);
const bar = this.createSimpleBar(percentage);
const info = fileName ? `${fileName} - ` : '';
process.stdout.write(`\r${info}${bar} ${percentage.toFixed(1)}%`);
if (percentage >= 100) {
process.stdout.write('\n');
}
}
}
/**
* 创建简单的进度条
*/
createSimpleBar(percentage, width = 20) {
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
return `[${'='.repeat(filled)}${' '.repeat(empty)}]`;
}
/**
* 清除当前行
*/
clear() {
process.stdout.write('\r' + ' '.repeat(80) + '\r');
}
}
exports.SimpleProgress = SimpleProgress;
/**
* 批量上传进度显示器
*/
class BatchProgress {
constructor(totalFiles) {
this.currentFile = 0;
this.totalFiles = 0;
this.fileProgress = new Map();
this.totalFiles = totalFiles;
}
/**
* 更新文件进度
*/
updateFile(fileIndex, progress) {
this.fileProgress.set(fileIndex, progress);
this.currentFile = Math.max(this.currentFile, fileIndex);
this.render();
}
/**
* 渲染批量进度
*/
render() {
// 计算总体进度
let totalLoaded = 0;
let totalSize = 0;
for (const progress of this.fileProgress.values()) {
totalLoaded += progress.loaded;
totalSize += progress.total;
}
const overallPercentage = totalSize > 0 ? (totalLoaded / totalSize) * 100 : 0;
// 获取当前文件进度
const currentProgress = this.fileProgress.get(this.currentFile);
const currentFileName = currentProgress?.fileName || 'Unknown';
const currentPercentage = currentProgress?.percentage || 0;
// 清除当前行并显示新进度
process.stdout.write('\r' + ' '.repeat(100) + '\r');
const output = [
`Files: ${this.currentFile + 1}/${this.totalFiles}`,
`Overall: ${overallPercentage.toFixed(1)}%`,
`Current: ${currentFileName} (${currentPercentage.toFixed(1)}%)`
].join(' | ');
process.stdout.write(output);
if (overallPercentage >= 100) {
process.stdout.write('\n');
}
}
/**
* 完成显示
*/
complete() {
process.stdout.write('\n');
console.log(chalk_1.default.green('✓ All files uploaded successfully'));
}
}
exports.BatchProgress = BatchProgress;
//# sourceMappingURL=progressBar.js.map