Skip to content

Instantly share code, notes, and snippets.

@Infocatcher
Last active December 22, 2015 09:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Infocatcher/6452231 to your computer and use it in GitHub Desktop.
Save Infocatcher/6452231 to your computer and use it in GitHub Desktop.
Firefox: don't remove finished downloads (browser.download.useToolkitUI = false), code for Custom Buttons extension https://addons.mozilla.org/addon/custom-buttons/ ("initialization" section)
// https://gist.github.com/Infocatcher/6452231
// More: https://github.com/Infocatcher/Download_Panel_Tweaker
// (c) Infocatcher 2013
var retentionDays = 21;
function dontRemoveFinishedDownloads(patch) {
// See https://github.com/Infocatcher/Download_Panel_Tweaker/issues/5 for details
try { // Firefox 26+
// http://mxr.mozilla.org/mozilla-central/source/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
var {DownloadIntegration} = Components.utils.import("resource://gre/modules/DownloadIntegration.jsm", {});
}
catch(e) {
}
if(DownloadIntegration && "shouldPersistDownload" in DownloadIntegration) {
const bakKey = "_customButtonsDontRemoveFinishedDownloads_shouldPersistDownload";
if(!patch ^ bakKey in DownloadIntegration)
return;
//LOG("dontRemoveFinishedDownloads(" + patch + ")");
var store = "_store" in DownloadIntegration && DownloadIntegration._store;
if(patch) {
DownloadIntegration[bakKey] = DownloadIntegration.shouldPersistDownload;
var wrapped = DownloadIntegration.shouldPersistDownload = function downloadPanelTweakerWrapper(download) {
if(download.hasPartialData || !download.stopped)
return true;
//var retentionDays = prefs.get("downloadsMaxRetentionDays");
return retentionDays > 0
&& download.startTime > (Date.now() - retentionDays*24*60*60*1000);
};
if(store) {
//LOG("dontRemoveFinishedDownloads(" + patch + "): override DownloadStore.onsaveitem");
store[bakKey] = store.onsaveitem;
store.onsaveitem = wrapped;
}
}
else {
DownloadIntegration.shouldPersistDownload = DownloadIntegration[bakKey];
delete DownloadIntegration[bakKey];
if(store && bakKey in store) {
//LOG("dontRemoveFinishedDownloads(" + patch + "): restore DownloadStore.onsaveitem");
store.onsaveitem = store[bakKey];
delete store[bakKey];
}
}
}
else {
dontRemoveFinishedDownloadsLegacy(patch);
}
}
function dontRemoveFinishedDownloadsLegacy(patch) {
const bakKey = "_customButtonsDontRemoveFinishedDownloads_downloads";
const newKey = "_customButtonsDontRemoveFinishedDownloads_downloadsWrapper";
if(!patch ^ bakKey in Services)
return;
//var logPrefix = "dontRemoveFinishedDownloadsLegacy(" + patch + "): ";
if(patch) {
var cleanUp = function downloadPanelTweakerWrapper() {
var stack = new Error().stack;
//LOG("Services.downloads.cleanUp()\n" + stack);
if(
stack.indexOf("@resource://app/components/DownloadsStartup.js:") != -1
|| stack.indexOf("@resource://gre/components/DownloadsStartup.js:") != -1 // Firefox 20 and older
) {
//LOG("Prevent Services.downloads.cleanUp()");
return undefined;
}
return downloads.cleanUp.apply(downloads, arguments);
};
if(newKey in Services) {
var downloads = Services[newKey].__proto__;
Services[bakKey] = null;
setProperty(Services[newKey], "cleanUp", cleanUp);
//LOG(logPrefix + "Will use old wrapper for Services.downloads");
}
else {
var downloads = Services[bakKey] = Services.downloads;
var downloadsWrapper = Services[newKey] = {
__proto__: downloads,
cleanUp: cleanUp
};
setProperty(Services, "downloads", downloadsWrapper);
//LOG(logPrefix + "Create wrapper for Services.downloads");
}
}
else {
if(Services.downloads == Services[newKey] && Services[bakKey]) {
setProperty(Services, "downloads", Services[bakKey]);
delete Services[newKey];
//LOG(logPrefix + "Restore Services.downloads");
}
else {
// Yes, we create some memory leaks here, but it's better than break other extensions
delete Services[newKey].cleanUp;
//LOG(logPrefix + "Can't completely restore Services.downloads: detected third-party wrapper");
}
delete Services[bakKey];
}
}
function setProperty(o, p, v) {
Object.defineProperty(o, p, {
value: v,
configurable: true,
writable: true,
enumerable: true
});
}
function destructor(reason) {
if(reason == "update" || reason == "delete")
dontRemoveFinishedDownloads(false);
}
if(
typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
&& addDestructor != ("addDestructor" in window && window.addDestructor)
)
addDestructor(destructor, this);
else
this.onDestroy = destructor;
dontRemoveFinishedDownloads(true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment