0

I am looking to write a small firefox add-on that detects when files that were downloaded are (or have been) deleted locally and removes the corresponding entry in the firefox download list.

Can anybody point me to the relevant api to manipulate the download list? I cannot seem to find it.

ARF
  • 7,420
  • 8
  • 45
  • 72
  • This is a good idea. I would download it once you release it. The other thing i would like to do is, when open download panel, is drag from there to a folder, and it should move the file from its current location to the new folder. Right now if you drag from the panel it just puts a copy into the new destination. – Noitidart Aug 12 '14 at 06:07

1 Answers1

3

The relevant API is PlacesUtils which abstracts the complexity of the Places database.

If your code runs in the context of a chrome window then you get a PlacesUtils glabal variable for free. Otherwise (bootstrapped, Add-on SDK, whatever) you have to import PlacesUtils.jsm.

Cu.import("resource://gre/modules/PlacesUtils.jsm");

As far as Places is concerned, downloaded files are nothing more than a special kind of visited pages, annotated accordingly. It's a matter of just one line of code to get an array of all downloaded files.

var results = PlacesUtils.annotations.getAnnotationsWithName("downloads/destinationFileURI");

Since we asked for the destinationFileURI annotation, each element of the resultarray holds the download location in the annotationValue property as a file: URI spec string.

With that you can check if the file actually exists

function getFileFromURIspec(fileurispec){
  // if Services is not available in your context Cu.import("resource://gre/modules/Services.jsm");
  var filehandler = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
  try{
    return filehandler.getFileFromURLSpec(fileurispec);
  }
  catch(e){
    return null;
  }
}

getFileFromURIspec will return an instance of nsIFile, or null if the spec is invalid which shouldn't happen in this case but a sanity check never hurts. With that you can call the exists() method and if it returns false then the associated page entry in Places is eligible for removal. We can tell which is that page by its uri, which conveniently is also a property of each element of the results.

PlacesUtils.bhistory.removePage(result.uri);

To sum it up

var results = PlacesUtils.annotations.getAnnotationsWithName("downloads/destinationFileURI");
results.forEach(function(result){
  var file = getFileFromURIspec(result.annotationValue);
  if(!file){
    // I don't know how you should treat this edge case
    // ask the user, just log, remove, some combination?
  }
  else if(!file.exists()){
    PlacesUtils.bhistory.removePage(result.uri);
  }
});
paa
  • 5,048
  • 1
  • 18
  • 22
  • Thanks for this very thorough answer. I finally got 'round to turning it into a add-on. It works great on the desktop but on firefox mobile it won't import `PlacesUtils`. As I understand the error message, `PlacesUtils` depends on `XPIProvider` which does not exist on Firefox Mobile. - Any idea on an alternative API? I was looking through the mobile API compatibility list, but could not find anything useful: https://developer.mozilla.org/de/Add-ons/SDK/Tutorials/Mobile_development#Module_Compatibility – ARF Jan 24 '15 at 19:16