var fs = require('fs'); var path = require('path'); var request = require('request'); var unzip = require('unzip'); var tracer = require('tracer'); var progress = require('request-progress'); var ProgressBar = require('progress'); var commander = require('commander'); commander .version('0.0.1') .option('-t, --to ', 'destination') .option('-f, --file ', 'run a file') .option('-u, --url ', 'the download url'); commander.allowUnknownOption(true); commander.parse(process.argv); var console = tracer.colorConsole({ format : "<{{title}}> {{message}}", dateformat : "HH:MM:ss.L" }); //var _url = 'http://x4mm.net/latest.zip'; var _url = commander.url || 'https://gitlab.com/xamiro/xcf-dist-windows/repository/archive.zip?ref=master'; var _to = path.resolve('./download.zip'); // The options argument is optional so you can omit it var bar = null; var unzipFolder = './update'; console.info('Download ' + _url + ' to ' + _to); var destination = path.resolve(commander.to || '../../'); /** * */ function finish(){ console.info('Download finish, extracting'); bar.terminate(); } /** * * @param err */ function error(err){ console.error('Error downloading file '+ _url,err) } /** * * @param secs * @returns {string} */ function toHHMMSS(secs) { var date = new Date(secs * 1000); var hh = date.getUTCHours(); var mm = date.getUTCMinutes(); var ss = date.getSeconds(); // If you were building a timestamp instead of a duration, you would uncomment the following line to get 12-hour (not 24) time // if (hh > 12) {hh = hh % 12;} // These lines ensure you have two-digits if (hh < 10) {hh = "0"+hh;} if (mm < 10) {mm = "0"+mm;} if (ss < 10) {ss = "0"+ss;} // This formats your string to HH:MM:SS return hh+":"+mm+":"+ss; } function bytesToSize(bytes) { var sizes = ['Bytes', '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]; } function updateBar(len,duration,now,tokens) { if(!bar) { bar = new ProgressBar(' downloading [:bar] :percent Remaining :time | :size of :sizeTotal | Speed: :speed / sec' , { complete: '=', incomplete: ' ', width: 40, total: len }); } bar.tick(now,tokens); } function download(_url) { progress(request(_url), { throttle: 1000, // Throttle the progress event to 2000ms, defaults to 1000ms delay: 100 // Only start to emit after 1000ms delay, defaults to 0ms //lengthHeader: 'x-transfer-length' // Length header to use, defaults to content-length }).on('progress', function (state) { // The state is an object that looks like this: // { // percentage: 0.5, // Overall percentage (between 0 to 1) // speed: 554732, // The download speed in bytes/sec // size: { // total: 90044871, // The total payload size in bytes // transferred: 27610959 // The transferred payload size in bytes // }, // time: { // elapsed: 36.235, // The total elapsed seconds since the start (3 decimals) // remaining: 81.403 // The remaining seconds to finish (3 decimals) // } // } //console.log('progress', state); if (state.size.total) { updateBar(state.size.total, null, state.size.transferred / 100, { size: bytesToSize(state.size.transferred), sizeTotal: bytesToSize(state.size.total), speed: bytesToSize(state.speed), time: toHHMMSS(state.time.remaining) }); } }) .on('error', function (err) { error(err); }) .on('end', function () { finish(); }).pipe(fs.createWriteStream(_to)); } var deleteFolderRecursive = function(path) { if( fs.existsSync(path) ) { fs.readdirSync(path).forEach(function(file,index){ var curPath = path + "/" + file; if(fs.lstatSync(curPath).isDirectory()) { // recurse deleteFolderRecursive(curPath); } else { // delete file fs.unlinkSync(curPath); } }); fs.rmdirSync(path); } }; function getFilesizeInBytes(filename) { if( fs.existsSync(filename) ) { var stats = fs.statSync(filename) var fileSizeInBytes = stats["size"]; return fileSizeInBytes } return false; } var showDiff = true; //download(_url); function unzipArchive(what,where){ deleteFolderRecursive(where); fs.mkdirSync('./update', '0777', function(err){ if(err){ console.log('Error deleting ' +where,err); } }); console.log('Extract into ' + destination); fs.createReadStream(what) .pipe(unzip.Parse()) .on('entry', function (entry) { var fileName = entry.path; var type = entry.type; // 'Directory' or 'File' var size = entry.size; var parts = fileName.split(path.sep); parts.shift(); parts.shift(); var relative = parts.join(path.sep); var dest = path.resolve(destination +'/'+relative); if(showDiff && dest && type ==='File' && relative) { var sizeD = getFilesizeInBytes(dest); var diff = sizeD - size; if(sizeD && sizeD!==size && Math.abs(diff)>300){ console.info('Have update for : ' + diff + ' ' + relative); }else{ //console.log('same ' + relative); } }else{ if( showDiff && !fs.existsSync(dest) && type ==='File' ) { console.log('new ' + relative); } } /* if (fileName === "this IS the file I'm looking for") { entry.pipe(fs.createWriteStream('output/path')); } else { entry.autodrain(); } */ entry.autodrain(); }); } unzipArchive(_to,unzipFolder);