Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intercept new downloads in Firefox Addon SDK

I have written a simple download manager for Windows and I would like to create an addon for Firefox that when enabled intercepts new downloads in Firefox and sends them to the download manager.

I have already done this for Google Chrome using:

chrome.downloads.onCreated.addListener(function(details) {
    // stop the download
    chrome.downloads.cancel(details.id, null);
}

The question is how can I achieve something similar using the Firefox add-on SDK.

I see there is a way of intercepting page loads to view the content / headers which might be helpful but then I won't know if the request will turn into a download or not.

Firefox add-on SDK: Get http response headers

I could perhaps look for a content type that is not text/html or check for a content disposition header but that could cause problems if I don't correctly handle all cases.

Is there no way of accessing the download manager using the JS SDK or some way of knowing when a download has been started / being started and stop it?

like image 484
antfx Avatar asked Mar 19 '23 04:03

antfx


2 Answers

The http-on-examine-response observer that the linked question discusses is the wrong way to go. It concerns all requests not just downloads.

Instead use the Downloads.jsm to observe new downloads, then cancel them, and so on.

To load Downloads.jsm in the SDK use:

const {Cu} = require("chrome");
Cu.import("resource://gre/modules/Downloads.jsm");
Cu.import("resource://gre/modules/Task.jsm");

Then you can add your listener.

let view = {
  onDownloadAdded: function(download) { 
    console.log("Added", download);
  },
  onDownloadChanged: function(download) {
    console.log("Changed", download);
  },
  onDownloadRemoved: function(download) {
    console.log("Removed", download);
  }
};

Task.spawn(function() {
  try {
    let list = yield Downloads.getList(Downloads.ALL);
    yield list.addView(view);
  } catch (ex) {
    console.error(ex);
  }
});

The linked MDN docs have more information and samples.

Since your add-on is a restartless SDK add-on, you'll need to remove the listener again using .removeView on unload, or else there will be a memory leak.

like image 178
nmaier Avatar answered Mar 24 '23 14:03

nmaier


Here's the JSM way.

Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");

var view = {
    onDownloadChanged: function (download) {
        console.log(download, 'Changed');
        if (download.succeeded) {
            var file = new FileUtils.File(this.target.path);
            console.log('file', file);
        }
    }
};

var list;
Task.spawn(function () {
    list = yield Downloads.getList(Downloads.ALL);
    list.addView(view);
}).then(null, Components.utils.reportError);

Remember to removeView to stop listening. Can do this anywhere, like in shutdown function or whatever, doesn't have to be within that Task.spawn so list must be global var.

list.removeView(view); //to stop listening

Here's the old way, which seems to still work. Although I thought they said they're going to take out the old downloadManager:

var observerService = Components.classes["@mozilla.org/download-manager;1"].getService(Components.interfaces.nsIDownloadManager);

observerService.addListener({
    onDownloadStateChange: function (state, dl) {
        console.log('dl=', dl);
        console.log('state=', state);
        console.log('targetFile', dl.targetFile);
        if (state == 7 && dl.targetFile.leafName.substr(-4) == ".txt") {
            //guys just downloaded (succesfully) a .txt file
        }
    }
});

Heres a mozillazine with some more on this: http://forums.mozillazine.org/viewtopic.php?f=19&t=2792021

like image 35
Noitidart Avatar answered Mar 24 '23 13:03

Noitidart