shpck
Version:
Ultra-fast, multi-threaded file compression tool for images, videos, and media files
144 lines (116 loc) • 4.96 kB
JavaScript
const shcl = require('@impulsedev/shcl');
class ProgressManager {
constructor(totalFiles) {
this.totalFiles = totalFiles;
this.processedFiles = 0;
this.startTime = Date.now();
this.totalOriginalSize = 0;
this.totalCompressedSize = 0;
this.results = [];
}
update(fileName, result) {
this.processedFiles++;
this.totalOriginalSize += result.originalSize;
this.totalCompressedSize += result.compressedSize;
this.results.push(result);
this.displayProgress(fileName, result);
}
displayProgress(fileName, result) {
const progress = ((this.processedFiles / this.totalFiles) * 100).toFixed(1);
const reduction = ((result.originalSize - result.compressedSize) / result.originalSize * 100).toFixed(1);
process.stdout.write('\r\x1b[K');
process.stdout.write(
`${shcl.cyan(`[${progress}%]`)} ` +
`${shcl.green('✓')} ${fileName} ` +
`${shcl.gray(`(-${reduction}%)`)}`
);
}
getStats() {
const elapsedTime = Date.now() - this.startTime;
const totalReduction = this.totalOriginalSize > 0
? ((this.totalOriginalSize - this.totalCompressedSize) / this.totalOriginalSize * 100).toFixed(2)
: 0;
return {
totalFiles: this.totalFiles,
processedFiles: this.processedFiles,
elapsedTime,
totalOriginalSize: this.totalOriginalSize,
totalCompressedSize: this.totalCompressedSize,
totalReduction,
averageReduction: this.getAverageReduction(),
spaceSaved: this.totalOriginalSize - this.totalCompressedSize,
filesPerSecond: this.processedFiles / (elapsedTime / 1000)
};
}
getAverageReduction() {
if (this.results.length === 0) return 0;
const reductions = this.results.map(result =>
((result.originalSize - result.compressedSize) / result.originalSize * 100)
);
return (reductions.reduce((sum, reduction) => sum + reduction, 0) / reductions.length).toFixed(2);
}
formatTime(milliseconds) {
const seconds = Math.floor(milliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
} else if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
} else {
return `${seconds}s`;
}
}
formatSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
displayFinalStats() {
const stats = this.getStats();
console.log('\n' + shcl.cyan('📊 Final Statistics'));
console.log(shcl.gray('─'.repeat(50)));
console.log(`${shcl.green('✓')} Files processed: ${shcl.bold(stats.processedFiles)}/${stats.totalFiles}`);
console.log(`⏱️ Total time: ${shcl.bold(this.formatTime(stats.elapsedTime))}`);
console.log(`📏 Original size: ${shcl.bold(this.formatSize(stats.totalOriginalSize))}`);
console.log(`📦 Compressed size: ${shcl.bold(this.formatSize(stats.totalCompressedSize))}`);
console.log(`💾 Space saved: ${shcl.bold.green(this.formatSize(stats.spaceSaved))} ${shcl.gray(`(${stats.totalReduction}%)`)}`);
console.log(`📈 Average reduction: ${shcl.bold(stats.averageReduction)}%`);
console.log(`⚡ Processing speed: ${shcl.bold(stats.filesPerSecond.toFixed(1))} files/sec`);
}
getProgressBar(current, total, width = 30) {
const progress = current / total;
const completed = Math.floor(progress * width);
const remaining = width - completed;
const bar = shcl.green('█'.repeat(completed)) + shcl.gray('░'.repeat(remaining));
const percentage = (progress * 100).toFixed(1);
return `[${bar}] ${percentage}%`;
}
estimateTimeRemaining() {
if (this.processedFiles === 0) return null;
const elapsedTime = Date.now() - this.startTime;
const averageTimePerFile = elapsedTime / this.processedFiles;
const remainingFiles = this.totalFiles - this.processedFiles;
return remainingFiles * averageTimePerFile;
}
displayProgressBar() {
const progressBar = this.getProgressBar(this.processedFiles, this.totalFiles);
const timeRemaining = this.estimateTimeRemaining();
process.stdout.write('\r\x1b[K');
process.stdout.write(
`${progressBar} ` +
`${this.processedFiles}/${this.totalFiles} files ` +
(timeRemaining ? `ETA: ${this.formatTime(timeRemaining)}` : '')
);
}
reset() {
this.processedFiles = 0;
this.startTime = Date.now();
this.totalOriginalSize = 0;
this.totalCompressedSize = 0;
this.results = [];
}
}
module.exports = { ProgressManager };