bashrecursionwgetprogress

Get Recursive wget progression


In the context of a bash script recursivly downloading the content of a folder i would like to display the progress in the terminal. if i use the progress argument i get multiple progress line (1 for each file) but i would like a global one showing progress of the whole download

My actual code

wget -np -r -R "index.html*" "$url" -q

I look in the documentation for a built in feature but found nothing, i also think about making a simulation to count the expected number to be downloaded and catch each file download finish to update a progress bar but nothing too.

I am a bit stuck because the download take a long time and i can't let user in front of a simple "downloading" during half an hour, the is a risk he thnik that there is an issue.

Thanks for reading


Solution

  • ⚠️ The provided code is not optimized, not handling error, it's just a POC it's not mean to be used as is in production ⚠️

    I just go back on this project some day ago, after reading lot of documentation and trying lot of weird command piped each others, it seems that it's not possible in command line to do what i want.

    As solution i have done a quick and dirty nodejs lib to do that

    download.js

    import exec from "await-exec"
    
    class Download {
    
        static async listFilesFromUrl(url,depth=10) {
    
            let fileList = new Set();
        
            const command = `wget -P "tmp" --spider -r --no-parent ${url} -l ${depth} 2>&1 | grep -E -o "${url}.*"`;
            const { stdout, stderr } = await exec(command)
            await exec(`rm -rf tmp`)
            stdout.split('\n').filter((line) => line.length > 0).forEach((line) => fileList.add(line));
            return fileList;
        }
    
        static async downloadFilesFromUrl(url,output) {
    
            return new Promise(async (resolve, reject) => {
        
                try {
                    const command = `wget -P ${output} ${url} -q > /dev/null`;
                    const { stdout, stderr } = await exec(command)
                    resolve(stdout)
                } catch (error) {
                    reject(error)
                }
        
            })
        
        }
    
        static async run(url,output,depth = 10){
    
            console.log('[ ] List files from', url);
            let fileList = await Download.listFilesFromUrl(url,1)
            console.log('\x1b[1A[\x1b[32m✓\x1b[0m] List files from', url);
            console.log(`[ ] Dowloading ${fileList.size} files`);
            Download.displayProgressBar(0,fileList.size);
            
            let downloaded = 0;
            let promiseList = [];
            
            fileList.forEach(async (file) => {
                let promise = Download.downloadFilesFromUrl(file,output)
                promise.then(() => {
                    downloaded++;
                    Download.displayProgressBar(downloaded,fileList.size);
                })
            
                promiseList.push(promise)
            });
    
            Promise.all(promiseList).then((values) => {
                console.log('\x1b[2A\x1b[2K[\x1b[32m✓\x1b[0m] Dowloaded', fileList.size, 'files');
            })
    
        }
    
        static displayProgressBar(current, total) {
            if(current > 0) console.log("\x1b[2A")
            const barSize = 50;
            const barPercent = Math.round(current / total * 100);
            const barCurrent = Math.round(barSize * current / total);
            console.log(`[${'='.repeat(barCurrent)}${' '.repeat(barSize - barCurrent)}] ${barPercent}% (${current}/${total})`)
        }
        
    
    }
    export default Download
    

    You can use it this way

    index.js

    import Download from "./download.js";
    Download.run(<URL>,<OUTPUT_FOLDER>,<RECURSIVE_DEPTH>)
    

    The result The result