0

So far I've made an extension that downloads PDF files in batch from a User Interface for work. It injects Javascript into the current tab which executes the neccesary clicks (JS Path > .click()) that lead to downloading the neccesary files.

popup.js


    const text = document.getElementById( 'notify-text' );
    const notify = document.getElementById( 'notify-button' );
    const reset = document.getElementById( 'notify-reset' );
    const stop = document.getElementById( 'notify-stop' );
    const counter = document.getElementById( 'notify-count' );
    
    
    async function stopOperation(){ // GETS INJECTED! Cancel button, stop= variable responsible for breaking the for loop in the injected script
        stop = true;
    }
    function settingsUpdate(arg_pdf, arg_edi, arg_safemode, arg_onlySpecial, arg_onlyNotSpecial, arg_all, arg_specialUpdate, arg_specialRollback, arg_specialNew) { // GETS INJECTED!
        
        conf_pdf = arg_pdf;
        conf_edi = arg_edi;
        conf_safeMode = arg_safemode;
        conf_onlySpecial = arg_onlySpecial;
        conf_onlyNotSpecial = arg_onlyNotSpecial;
        conf_all = arg_all;
        conf_specialUpdate = arg_specialUpdate;
        conf_specialRollback = arg_specialRollback;
        conf_specialNew = arg_specialNew;
        //alert(conf_onlyNotSpecial);
    }
    
    async function getCurrentTab() { //Gets current tab and injects scripts
      let queryOptions = { active: true, lastFocusedWindow: true };
      let [tab] = await chrome.tabs.query(queryOptions);
      tabid = parseInt(tab.id)
        
    
        inp_safeMode = document.getElementById( 'input-safeMode').checked ;
        inp_edi = document.getElementById( 'input-edi' ).checked;
        inp_pdf = document.getElementById( 'input-pdf' ).checked;
        inp_onlySpecial = document.getElementById('radio-onlySpecial').checked;
        inp_onlyNotSpecial = document.getElementById('radio-onlyNotSpecial').checked;
        inp_all = document.getElementById('radio-all').checked;
        inp_specialUpdate = document.getElementById( 'input-specialUpdate').checked ;
        inp_specialRollback = document.getElementById( 'input-specialRollback').checked;
        inp_specialNew = document.getElementById( 'input-specialNew').checked;
        
        
        chrome.scripting.executeScript({     //Parses the config from the extension popup page to the injected page
        target: {tabId: tabid, allFrames: true},
        args: [inp_pdf, inp_edi, inp_safeMode,inp_onlySpecial,inp_onlyNotSpecial,inp_all,inp_specialUpdate,inp_specialRollback,inp_specialNew],
        func: settingsUpdate,
        }, function() {
            if (chrome.runtime.lastError) 
            {
                alert('There was an error injecting script (Update Config) : \n' + chrome.runtime.lastError.message);
            }
        });
        chrome.scripting.executeScript({
        target: {tabId: tabid, allFrames: true},
        files: ['getPagesSource.js'],
        }, function() {
            if (chrome.runtime.lastError) 
            {
                alert('There was an error injecting script : \n' + chrome.runtime.lastError.message);
            }
        });
    
      return tabid;
    }
    
    
    async function cancel() {
        
      let queryOptions = { active: true, lastFocusedWindow: true };
      let [tab] = await chrome.tabs.query(queryOptions);
      tabid = parseInt(tab.id)
        chrome.scripting.executeScript({
            target: {tabId: tabid, allFrames: true},
            func: stopOperation,
            }, function() {
                if (chrome.runtime.lastError) {
                  alert('There was an error injecting script : \n' + chrome.runtime.lastError.message);
                }
            });
        //alert('called');
    }
    
    chrome.storage.local.get( ['notifyCount'], data => {
        let value = data.notifyCount || 0;
        counter.innerHTML = value;
    } );
    
    chrome.runtime.onMessage.addListener(function(request, sender) {
      if (request.action == "getSource") {
        message.innerText = request.source;
      }
    });
    
    chrome.storage.onChanged.addListener( ( changes, namespace ) => {
        if ( changes.notifyCount ) {
            let value = changes.notifyCount.newValue || 0;
            counter.innerHTML = value;
        }
    });
    
    reset.addEventListener( 'click', () => {
        chrome.storage.local.clear();
        text.value = '';
    } );
    
    stop.addEventListener( 'click', () => {
        cancel();
        window.close();
        
    } );
    notify.addEventListener( 'click', () => {
       //message = document.querySelector('#message');  
        
      var tab = getCurrentTab()
    } );
    //window.onload = onWindowLoad;

Injected Script [getPagesSource.js]


    var stop = false;
    
        
    function notify(title,txt)
    {
        chrome.runtime.sendMessage( '', {
                title: title,
                type: 'notification',
                message: txt
            });
    }
    
    async function downloadFiles(document_root) {
        //alert(conf_onlyNotSpecial);
        var cancelled = "";
        var elCount = document.querySelector("#root > div > div.ApplicationLayoutBody.has-footer > div > div > div:nth-child(4) > div:nth-child(1) > table > tbody").childNodes.length
        var count = 0;
        var countBadge = 0;
        var countRollback = 0;
        var countNew = 0;
        var countUpdate = 0;
        var elBadgeCount = 0;
        for(i = 1 ; i < elCount + 1; i++)
        {
            let badge = document_root.querySelector("#root > div > div.ApplicationLayoutBody.has-footer > div > div > div:nth-child(4) > div:nth-child(1) > table > tbody > tr:nth-child("+i+") > td.text-left.min-width-100.width-5pct")
            if(badge.childNodes.length > 0)
            {
                elBadgeCount += 1;
            }
            
        }
        alert(elCount + " tétel, amiből " + elBadgeCount + " Update/New/Rollback.");
        count = 0;
        for(i = 1 ; i < elCount+1; i++)
        {
            //continue; /// WARNING !!!!! #####
            try {
                    
                    if(stop)    //HANDLE CANCELLATION!
                    {
                        cancelled = "Megszakítva a felhasznaló felől! ";
                        stop = false;
                        break;
                    }
                    
                    
                    let tr = document_root.querySelector("#root > div > div.ApplicationLayoutBody.has-footer > div > div > div:nth-child(4) > div:nth-child(1) > table > tbody > tr:nth-child("+i+")");
                    let trBadge = document_root.querySelector("#root > div > div.ApplicationLayoutBody.has-footer > div > div > div:nth-child(4) > div:nth-child(1) > table > tbody > tr:nth-child("+i+") > td.text-left.min-width-100.width-5pct")
                    if(trBadge.childNodes.length <= 0 )
                    {
                        tr.style.backgroundColor = "#3254a8"; 
                        if(conf_onlySpecial) // SKIP NORMAL IF ONLY SPECIAL
                        {
                            tr.style.backgroundColor = "#ede853";
                            continue;
                        }
                        tr.click(); 
    
                    }
                    else
                    {
                        tr.style.backgroundColor = "#00FF00"; 
                        countBadge += 1;
                        let span = document_root.querySelector("#root > div > div.ApplicationLayoutBody.has-footer > div > div > div:nth-child(4) > div:nth-child(1) > table > tbody > tr:nth-child("+i+") > td.text-left.min-width-100.width-5pct > span").innerText;
    
                        if(conf_onlyNotSpecial) // SKIP SPECIAL IF ONLY NOT SPECIAL 
                        {
                            tr.style.backgroundColor = "#ede853";
                            continue;
                        }
                        switch (span)
                        {
                            case "Update":
                                if(conf_specialUpdate){
                                    countUpdate += 1;
                                }else
                                {
                                    continue;
                                }
                                break;
                            case "Rollback":
                                if(conf_specialRollback){
                                    countRollback += 1;
                                }else
                                {
                                    continue;
                                }
                                break;
                            case "New":
                                if(conf_specialNew){
                                    countNew += 1;
                                }else
                                {
                                    continue;
                                }
                            default:
                                break;
                        }
                        tr.click(); 
                    }
                    
                    
                    
                    // OPEN AND COLOR TABLE ROW
                    
                    await delay(1000); //WAIT 0.5 SEC
                    if(conf_edi){
                    let btnDropdown = document_root.querySelector("#uikit-root > div > div.modal-dialog.modal-xl > div > div.modal-header > div.modal-header-buttons > div.dropdown.btn-group > button");
                    btnDropdown.click();
                    
                    // DOWNLOAD DELIVERY
                    
                    await delay(1000);
                    
                    let btnDownloadEDI = document_root.querySelector("#uikit-root > div > div.modal-dialog.modal-xl > div > div.modal-header > div.modal-header-buttons > div.dropdown.btn-group.open > ul > li");
                    btnDownloadEDI.click();
                    }
                    if(conf_pdf){   
                    await delay(1000); //WAIT 0.5 SEC
                        
                    btnDropdown = document_root.querySelector("#uikit-root > div > div.modal-dialog.modal-xl > div > div.modal-header > div.modal-header-buttons > div.dropdown.btn-group:nth-child(2) > button");
                    btnDropdown.click();
                    
                    // DOWNLOAD DELIVERY
                    
                    await delay(1000);
                    
                    let btnDownloadPDF = document_root.querySelector("#uikit-root > div > div.modal-dialog.modal-xl > div > div.modal-header > div.modal-header-buttons > div.dropdown.btn-group.open > ul > li");
                    btnDownloadPDF.click();
                    }
                    // EXIT
                    
                    await delay(1000);
                    
                    let btnExit = document_root.querySelector("#uikit-root > div > div.modal-dialog.modal-xl > div > div.modal-header > div.modal-header-buttons > button");
                    btnExit.click();
                    
                    await delay(1000);
                        
                    chrome.storage.local.get( ['notifyCount'], data => {
                        let value = data.notifyCount || 0;
                        chrome.storage.local.set({ 'notifyCount': Number( value ) + 1 });
                        } );
                    count += 1;
                }
            catch (error) 
            {
                alert(error);
            }       
        }
        alert(cancelled + "Összesen letöltve: " + count + " tétel, amiből Update: "+ countUpdate + ", Rollback: " + countRollback + ", New: " + countNew);
    }
    
    function delay(time) {
      return new Promise(resolve => setTimeout(resolve, time));
    }
    
    
    chrome.runtime.sendMessage({
        action: "downloadFiles",
        source: downloadFiles(document)
    });

The downloading proccess on the webpage side is managed via javascript as far as i can tell, but the only thing that important to me that it works.

My problem is however that these files names are jibberish, therefore very difficult, to manage.

The question above says it all... Is there a way to rename a file as it is being downloaded or before it is downloaded?

I've tried to make an external python script that handles the downloaded files in real time, but it's just not as convenient, and having 2 scripts running in two seperate proccesses is just confusing and is too much trouble for the users.

Any help is much appreciated!

  • See [chrome.downloads](https://developer.chrome.com/extensions/downloads#event-onDeterminingFilename) API. You can also try to add `download` attribute on the `a` element that is used by the site to generate the download. – wOxxOm Nov 04 '22 at 10:45
  • Actually, it is a "li" element that takes us to the download. Most likely calls a javascript function, tho. – Komaromi Adrian Nov 04 '22 at 11:56
  • There are two ways for a web page to generate a download: clicking an `a` element or navigating to a server URL that responds with a file (inside a form or an iframe). You can investigate which method is used in devtools. If it's the element, you can override document.createElement in [page context](/a/9517879). For server response you can use chrome.webRequest in ManifestV2 or declarativeNetRequest in ManifestV3 to change or add the HTTP header that contains the file name. – wOxxOm Nov 04 '22 at 12:40
  • What about [chrome.downloads.onDeterminingFilename](https://developer.chrome.com/docs/extensions/reference/downloads/#event-onDeterminingFilename) ? – Thomas Mueller Nov 04 '22 at 13:32
  • @wOxxOm, thanks a lot for the help. But how can i investigate the button that is being pressed? I've tried to look at the button's click event listeners, and theres like 10 of them. There is in fact a nested element! And i can't find out which js function is it calling. Can i get the url of the file somehow? `
  • Delivery call-off
  • ` Also I'm using Manifest V3 – Komaromi Adrian Nov 05 '22 at 10:36