Skip to content

Instantly share code, notes, and snippets.

@benzBrake
Last active July 20, 2022 08:19
Show Gist options
  • Save benzBrake/83fd3f054c8b31f59d2ee2f0cf9226d9 to your computer and use it in GitHub Desktop.
Save benzBrake/83fd3f054c8b31f59d2ee2f0cf9226d9 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name DownloadPlus_ff98.uc.js
// @description 修改整合自(w13998686967、ywzhaiqi、黒仪大螃蟹、Alice0775、紫云飞)
// @author Ryan
// @include main
// @include chrome://browser/content/places/places.xhtml
// @include chrome://browser/content/places/places.xul
// @include chrome://mozapps/content/downloads/unknownContentType.xhtml
// @include chrome://mozapps/content/downloads/unknownContentType.xul
// @version 0.0.1
// @startup window.DownloadPlus.init();
// @compatibility Firefox 72
// @homepage https://github.com/benzBrake/FirefoxCustomize
// @note 20220719 修复 72~98 无法使用
// @note 20220717 修复另存为不提示文件名,修复改名后点保存会弹出保存对话框,修复 Firefox 104 OS is not defined
// @note 20220612 完成另存为,改名,转换编码,显示精确大小
// @note 20220611 完成调用第三方 App 下载
// @note 20220610 开始重写代码,完成保存并打开,从硬盘删除
// ==/UserScript==
(function (globalConfig, globalCss) {
if (window.DownloadPlus) return;
let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
if (!window.CustomizableUI) Cu.import("resource:///modules/CustomizableUI.jsm");
if (!window.Services) Cu.import("resource://gre/modules/Services.jsm");
if (!window.OS) Cu.import("resource://gre/modules/osfile/osfile_async_front.jsm")
if (!window.FileUtils) Cu.import("resource://gre/modules/FileUtils.jsm");
const LANG = {
'zh-CN': {
"save and open": "保存并打开",
"save as": "另存为",
"save to": "保存到",
"dobule click to copy link": "双击复制链接",
"convert tooltip": "Ctrl+点击转换url编码\n左键:UNICODE\n右键:GB2312",
"remove from disk": "从硬盘删除",
"file not found": "文件未找到 %s",
"desktop": "桌面",
"disk label": "%s 盘",
"button aria2": "Aria2",
"button idm": "IDM",
"button thunder": "迅雷",
"button flashgot default download manager": "FlashGot 默认",
"button flashgot select download manager": "FlashGot 其他",
"set to default download manger": "设置 %s 为默认下载器",
}
}
const _LOCALE = LANG.hasOwnProperty(Services.locale.appLocaleAsBCP47) ? Services.locale.appLocaleAsBCP47 : 'zh-CN';
const QUICK_SAVE_LIST = [
[Services.dirsvc.get('Desk', Ci.nsIFile).path, $L("desktop")],
["C:\\", $L("disk label", "C")],
["D:\\", $L("disk label", "D")],
["E:\\", $L("disk label", "E")],
["F:\\", $L("disk label", "F")]
]; // 快捷保存列表
const EXTRA_APP = {
"aria2": {
"config": "enable aria2 button",
"label": $L("button aria2"),
"exec": "\\chrome\\resources\\tools\\Aria2\\aria2c.exe",
"text": '-x 8 -k 10M --load-cookies={cookiePath} --referer={referer} -d {path} {link}',
},
"idm": {
config: "enable idm button",
label: $L("button idm"),
exec: "C:\\Program\ Files\ (x86)\\Internet\ Download\ Manager\\IDMan.exe", // 需要修改 IDM 路径
text: '/d {link}',
},
"thunder": {
config: "enable thunder button",
label: $L("button thunder"),
exec: "C:\\Program\ Files\ (x86)\\Thunder\\Thunder.exe", // 需要修改迅雷路径
text: '{link}',
}
}
window.DownloadPlus = {
_urls: [],
FLASHGOT_STRUCTURE: `{num};{download-manager};0;;\n{referer}\n{url}\n{description}\n{cookies}\n{post-data}\n{filename}\n{extension}\n{download-page-referer}\n{download-page-cookies}\n\n\n{user-agent}`,
get appVersion() {
return Services.appinfo.version.split(".")[0]
},
get dialogElement() {
return document.documentElement.getButton ? document.documentElement : document.getElementById('unknownContentType');
},
get topWin() {
return Services.wm.getMostRecentWindow("navigator:browser");
},
get tempDir() {
return OS.Constants.Path.tmpDir;
},
get flashgotPath() {
var flashgotPref,
flashgotPath;
try {
flashgotPref = Services.prefs.get(this.PREF_FLASHGOT);
} catch (e) {
flashgotPref = "\\chrome\\resources\\tools\\FlashGot.exe";
}
flashgotPref = this.handleRelativePath(flashgotPref);
var flashgotPath = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
flashgotPath.initWithPath(flashgotPref);
if (flashgotPath.exists())
return flashgotPath.path;
else
return false;
},
init: function () {
switch (location.href) {
case 'chrome://browser/content/browser.xul':
case 'chrome://browser/content/browser.xhtml':
if (globalConfig["enable save and open"]) this.saveAndOpenMain.init();
if (globalConfig["download complete notice"]) this.downloadCompleteNotice.init();
if (globalConfig["auto close blank tab"]) this.autoCloseBlankTab.init();
if (globalConfig["enable rename"]) this.changeNameMainInit();
this.loadDownloadManagersList();
break;
case 'chrome://mozapps/content/downloads/unknownContentType.xul':
case 'chrome://mozapps/content/downloads/unknownContentType.xhtml':
this.addExtraButtons();
if (globalConfig["enable double click to copy link"]) this.dblClickToCopyLink();
if (globalConfig["enable rename"]) this.downloadDialogChangeName();
if (globalConfig["show extract size"]) this.downloadDialogShowExtractSize();
window.sizeToContent();
break;
case 'chrome://browser/content/places/places.xul':
case 'chrome://browser/content/places/places.xhtml':
if (globalConfig["remove file menuitem"]) this.removeFileEnhance.init();
break;
}
this.styleSheetService = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService);
this.STYLE = {
url: Services.io.newURI('data:text/css;charset=UTF-8,' + encodeURIComponent(globalCss)),
type: this.styleSheetService.AGENT_SHEET
}
this.styleSheetService.loadAndRegisterSheet(this.STYLE.url, this.STYLE.type);
// this.style = addStyle(globalCss);
},
destroy: function () {
switch (location.href) {
case 'chrome://browser/content/browser.xhtml':
if (globalConfig["enable save and open"]) this.saveAndOpenMain.destroy();
if (globalConfig["download complete notice"]) this.downloadCompleteNotice.destroy();
if (globalConfig["auto close blank tab"]) this.autoCloseBlankTab.destroy();
break;
case 'chrome://mozapps/content/downloads/unknownContentType.xhtml':
break;
case 'chrome://browser/content/places/places.xhtml':
if (globalConfig["remove file menuitem"]) this.removeFileEnhance.destroy();
break;
}
this.styleSheetService.unregisterSheet(this.STYLE.url, this.STYLE.type);
// if (this.style && this.style.parentNode) this.style.parentNode.removeChild(this.style);
},
handleRelativePath: function (path) {
let OS = this.topWin.OS;
if (path) {
let handled = false;
Object.keys(OS.Constants.Path).forEach(key => {
if (path.includes("{" + key + "}")) {
path = path.replace("{" + key + "}", OS.Constants.Path[key]);
handled = true;
}
})
if (!handled) {
path = path.replace(/\//g, '\\').toLocaleLowerCase();
var ffdir = Cc['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile).path;
if (/^(\\)/.test(path)) {
path = ffdir + path;
}
}
return path;
}
},
exec: function (path, arg) {
var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
var process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
try {
var a;
if (typeof arg == "undefined") arg = []; // fix slice error
if (typeof arg == 'string' || arg instanceof String) {
a = arg.split(/\s+/)
} else if (Array.isArray(arg)) {
a = arg;
} else {
a = [arg];
}
file.initWithPath(path);
if (!file.exists()) {
DownloadPlus.alert($L("file not found", path), "error");
Cu.reportError($L("file not found", path));
return;
}
if (file.isExecutable()) {
process.init(file);
process.runw(false, a, a.length);
} else {
file.launch();
}
} catch (e) {
this.log(e);
}
},
copy: function (aText) {
Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper).copyString(aText);
},
dblClickToCopyLink: function (e) {
var s = document.querySelector("#source"),
l = s.previousSibling;
l.innerHTML = l.innerHTML + "(" + $L("dobule click to copy link") + ")";
s.value = dialog.mLauncher.source.spec;
s.setAttribute("crop", "center");
s.setAttribute("tooltiptext", $L("dobule click to copy link"));
s.style.setProperty('cursor', 'pointer');
l.setAttribute("ondblclick", 'DownloadPlus.copy(dialog.mLauncher.source.spec);');
s.setAttribute("ondblclick", 'DownloadPlus.copy(dialog.mLauncher.source.spec);');
},
changeNameMainInit: function () {
const obsService = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
const RESPONSE_TOPIC = 'http-on-examine-response';
var respObserver = {
observing: false,
observe: function (subject, topic, data) {
try {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
let header = channel.contentDispositionHeader;
let associatedWindow = channel.notificationCallbacks
.getInterface(Components.interfaces.nsILoadContext)
.associatedWindow;
associatedWindow.localStorage.setItem(channel.URI.spec, header.split("=")[1]);
} catch (ex) { };
},
start: function () {
if (!this.observing) {
obsService.addObserver(this, RESPONSE_TOPIC, false);
this.observing = true;
}
},
stop: function () {
if (this.observing) {
obsService.removeObserver(this, RESPONSE_TOPIC, false);
this.observing = false;
}
}
};
respObserver.start();
addEventListener("beforeunload", function () {
respObserver.stop();
})
},
downloadDialogChangeName: function () {
document.querySelector("#mode").addEventListener("select", function () {
if (dialog.dialogElement("save").selected) {
let rename = globalConfig["enable rename"],
encodingConvert = globalConfig["enable encoding convert"];
if (!document.querySelector("#locationtext")) {
if (rename || encodingConvert) {
var orginalString = "";
if (encodingConvert) {
try {
orginalString = (opener.localStorage.getItem(dialog.mLauncher.source.spec) ||
dialog.mLauncher.source.asciiSpec.substring(dialog.mLauncher.source.asciiSpec.lastIndexOf("/"))).replace(/[\/:*?"<>|]/g, "");
opener.localStorage.removeItem(dialog.mLauncher.source.spec)
} catch (e) {
orginalString = dialog.mLauncher.suggestedFileName;
}
}
var location = document.querySelector("#location"), locationtext;
if (encodingConvert)
locationtext = document.createXULElement("menulist");
else
locationtext = document.createElementNS("http://www.w3.org/1999/xhtml", "html:input");
locationtext.id = "locationtext";
if (rename && encodingConvert)
locationtext.setAttribute("editable", "true");
locationtext.setAttribute("style", "margin-top:-2px;margin-bottom:-3px");
locationtext.setAttribute("tooltiptext", $L("convert tooltip"));
location.parentNode.insertBefore(locationtext, location);
locationtext.addEventListener("click", function (e) {
if (e.ctrlKey) {
if (e.button == 0)
this.value = decodeURIComponent(this.value);
if (e.button == 2) {
e.preventDefault();
converter.charset = "GB2312";
this.value = converter.ConvertToUnicode(unescape(this.value));
}
}
}, false);
if (rename)
locationtext.value = dialog.mLauncher.suggestedFileName;
if (encodingConvert) {
locationtext.addEventListener("command", function (e) {
if (rename)
locationtext.value = e.target.value;
document.title = "Opening " + e.target.value;
});
let menupopup = locationtext.appendChild(document.createXULElement("menupopup"));
let menuitem = menupopup.appendChild(document.createXULElement("menuitem"));
menuitem.value = dialog.mLauncher.suggestedFileName;
menuitem.label = "Original: " + menuitem.value;
if (!rename)
locationtext.value = menuitem.value;
let converter = Components.classes['@mozilla.org/intl/scriptableunicodeconverter']
.getService(Components.interfaces.nsIScriptableUnicodeConverter);
function createMenuitem(encoding) {
converter.charset = encoding;
let menuitem = menupopup.appendChild(document.createXULElement("menuitem"));
menuitem.value = converter.ConvertToUnicode(orginalString).replace(/^"(.+)"$/, "$1");
menuitem.label = encoding + ": " + menuitem.value;
}
["GB18030", "BIG5", "Shift-JIS"].forEach(function (item) {
createMenuitem(item)
});
}
}
}
document.querySelector("#location").hidden = true;
document.querySelector("#locationtext").hidden = false;
} else {
document.querySelector("#locationtext").hidden = true;
document.querySelector("#location").hidden = false;
}
}, false)
dialog.dialogElement("save").selected && dialog.dialogElement("save").click();
window.addEventListener("dialogaccept", function (event) {
if ((document.querySelector("#locationtext").value != dialog.mLauncher.suggestedFileName) && dialog.dialogElement("save").selected) {
event.stopPropagation();
var mainwin = DownloadPlus.topWin;
mainwin.eval("(" + mainwin.internalSave.toString().replace("let ", "").replace("var fpParams", "fileInfo.fileExt=null;fileInfo.fileName=aDefaultFileName;var fpParams") + ")")(dialog.mLauncher.source.asciiSpec, null, document, (document.querySelector("#locationtext") ? document.querySelector("#locationtext").value : dialog.mLauncher.suggestedFileName), null, null, false, null, null, null, null, null, true, null, mainwin.PrivateBrowsingUtils.isBrowserPrivate(mainwin.gBrowser.selectedBrowser), Services.scriptSecurityManager.getSystemPrincipal());
close();
}
}, true);
},
downloadDialogShowExtractSize: () => {
Cu.import("resource://gre/modules/DownloadUtils.jsm");
function DU_convertByteUnits(aBytes) {
let unitIndex = 0;
while ((aBytes >= 999.5) && (unitIndex < 3)) {
aBytes /= 1024;
unitIndex++;
}
return [(aBytes > 0) && (aBytes < 100) && (unitIndex != 0) ? (aBytes < 10 ? (parseInt(aBytes * 100) / 100).toFixed(2) : (parseInt(aBytes * 10) / 10).toFixed(1)) : parseInt(aBytes), ['bytes', 'KB', 'MB', 'GB'][unitIndex]];
}
eval("DownloadUtils.convertByteUnits = " + DU_convertByteUnits.toString());
},
saveAndOpenView: {
onDownloadChanged: function (dl) {
if (dl.progress != 100) return;
if (window.DownloadPlus._urls.indexOf(dl.source.url) > -1) {
let target = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
target.initWithPath(dl.target.path);
target.launch();
window.DownloadPlus._urls[window.DownloadPlus._urls.indexOf(dl.source.url)] = "";
}
},
onDownloadAdded: function (dl) { },
onDownloadRemoved: function (dl) { },
},
saveAndOpenMain: {
init: function () {
Cu.import("resource://gre/modules/Downloads.jsm");
Downloads.getList(Downloads.ALL).then(list => { list.addView(window.DownloadPlus.saveAndOpenView).then(null, Cu.reportError); });
},
destroy: function () {
window.DownloadPlus._urls = [];
Cu.import("resource://gre/modules/Downloads.jsm");
Downloads.getList(Downloads.ALL).then(list => { list.removeView(window.DownloadPlus.saveAndOpenView).then(null, Cu.reportError); });
}
},
addExtraButtons: function () {
let refEl = this.dialogElement.getButton("accept").nextSibling;
if (globalConfig["enable save and open"]) {
let saveAndOpen = this.dialogElement.getButton('extra1');
saveAndOpen.parentNode.insertBefore(saveAndOpen, this.dialogElement.getButton("accept").nextSibling);
saveAndOpen.setAttribute("hidden", "false");
saveAndOpen.setAttribute("label", $L("save and open"));
saveAndOpen.addEventListener("command", () => {
Services.wm.getMostRecentWindow("navigator:browser").DownloadPlus._urls.push(dialog.mLauncher.source.asciiSpec);
document.querySelector("#save").click();
window.DownloadPlus.dialogElement.getButton("accept").disabled = 0;
window.DownloadPlus.dialogElement.getButton("accept").click()
});
refEl = saveAndOpen;
}
if (globalConfig["enable save as"]) {
let saveAs = this.dialogElement.getButton('extra2');
saveAs.setAttribute("hidden", "false");
saveAs.setAttribute("label", $L("save as"));
saveAs.addEventListener("command", () => {
var mainwin = DownloadPlus.topWin;
// 感谢 ycls006
mainwin.eval("(" + mainwin.internalSave.toString().replace("let ", "").replace("var fpParams", "fileInfo.fileExt=null;fileInfo.fileName=aDefaultFileName;var fpParams") + ")")(dialog.mLauncher.source.asciiSpec, null, null, (document.querySelector("#locationtext") ? document.querySelector("#locationtext").value : dialog.mLauncher.suggestedFileName), null, null, false, null, null, null, null, null, false, null, mainwin.PrivateBrowsingUtils.isBrowserPrivate(mainwin.gBrowser.selectedBrowser), Services.scriptSecurityManager.getSystemPrincipal());
close();
});
refEl.insertAdjacentElement('afterend', saveAs);
refEl = saveAs;
}
let shadowRoot = document.getElementById('unknownContentType').shadowRoot,
link = $CNS(document, 'http://www.w3.org/1999/xhtml', 'html:link', {
rel: 'stylesheet',
href: 'chrome://global/content/widgets.css'
});
shadowRoot.insertBefore(link, shadowRoot.firstChild);
refEl || (refEl = this.dialogElement.getButton("accept").nextSibling);
if (globalConfig["enable save to"]) {
let saveTo = $C(document, 'button', {
label: $L("save to"),
class: 'dialog-button',
hidden: false,
type: 'menu'
}), saveToMenu = $C(document, 'menupopup', {});
saveTo.appendChild(saveToMenu);
QUICK_SAVE_LIST.forEach(function (dir) {
var [name, dir] = [dir[1], dir[0]];
var item = saveToMenu.appendChild(document.createXULElement("menuitem"));
item.setAttribute("label", (name || (dir.match(/[^\\/]+$/) || [dir])[0]));
item.setAttribute("image", "moz-icon:file:///" + dir + "\\");
item.setAttribute("class", "menuitem-iconic");
item.onclick = function () {
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
var path = dir.replace(/^\./, Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile).path);
path = path.endsWith("\\") ? path : path + "\\";
file.initWithPath(path + (document.querySelector("#locationtext") ? document.querySelector("#locationtext").value : document.querySelector("#location").value).trim());
if (typeof dialog.mLauncher.saveToDisk === 'function') {
dialog.mLauncher.saveToDisk(file, 1);
} else {
dialog.mLauncher.MIMEInfo.preferredAction = dialog.mLauncher.MIMEInfo.saveToDisk;
dialog.mLauncher.saveDestinationAvailable(file);
}
dialog.onCancel = function () { };
close();
};
})
refEl.insertAdjacentElement('afterend', saveTo);
refEl = saveTo;
}
Object.keys(EXTRA_APP).forEach(function (key) {
let app = EXTRA_APP[key];
if (app.label && app.exec && app.text && app.config && globalConfig[app.config]) {
let btn = $C(document, 'button', app);
btn.setAttribute("hidden", "false");
btn.classList.add('dialog-button');
btn.setAttribute("onclick", "window.DownloadPlus.handleExtraAppBtnClick(event);");
refEl.insertAdjacentElement('afterend', btn);
refEl = btn;
}
});
if (globalConfig["elable flashgot button"]) {
if (this.flashgotPath) {
let flashgotDefault = $C(document, 'button', {
label: $L("button flashgot default download manager"),
class: 'dialog-button',
hidden: false,
manager: 'Internet Download Manager', // Need to implement read from about:config
onclick: 'window.DownloadPlus.handleFlashGotBtnClick(event);'
}), flashgotMore = $C(document, 'button', {
label: $L("button flashgot select download manager"),
class: 'dialog-button',
hidden: false,
type: 'menu'
}), flashgotPopup = $C(document, 'menupopup', {});
flashgotMore.appendChild(flashgotPopup);
refEl.insertAdjacentElement('afterend', flashgotMore);
refEl.insertAdjacentElement('afterend', flashgotDefault);
this.topWin.FLASHGOT_DOWNLOAD_MANSGERS.forEach(m => {
let menuitemDownload = $C(document, 'menuitem', {
label: m,
manager: m,
onclick: 'window.DownloadPlus.handleFlashGotBtnClick(event);'
});
flashgotPopup.appendChild(menuitemDownload);
})
} else {
this.log("open about:config and set " + this.PREF_FLASHGOT);
}
}
},
loadDownloadManagersList(callback) {
if (this.flashgotPath) {
// get download managers list from flashgot
var dmPathTextPath = PathUtils.join(this.tempDir, ".flashgot.dm.txt");
this.exec(this.flashgotPath, ["-o", dmPathTextPath]);
setTimeout(function () {
var dmText = readFile(dmPathTextPath);
this.FLASHGOT_DOWNLOAD_MANSGERS = dmText.split("\n").filter(l => l.includes("|OK")).map(l => l.replace("|OK", ""))
removeFile(dmPathTextPath);
if (callback)
callback(this);
}, 5000)
} else {
this.FLASHGOT_DOWNLOAD_MANSGERS = [];
}
},
handleFlashGotBtnClick: function (event) {
let { target } = event;
if (target.hasAttribute("manager")) {
// make string support replace with array
function replaceArray(replaceString, find, replace) {
var regex;
for (var i = 0; i < find.length; i++) {
regex = new RegExp(find[i], "g");
replaceString = replaceString.replace(regex, replace[i]);
}
return replaceString;
};
var { targetFile: partFile } = dialog.mLauncher; // Future may be take use of part file
var { asciiSpec, username, userPass } = dialog.mLauncher.source,
fileName = (document.querySelector("#locationtext") ? document.querySelector("#locationtext").value : dialog.mLauncher.suggestedFileName),
{ userAgent } = navigator;
var initData = replaceArray(this.FLASHGOT_STRUCTURE, [
'{num}',
'{download-manager}',
'{referer}',
'{url}',
'{description}',
'{cookies}',
'{post-data}',
'{filename}',
'{extension}',
'{download-page-referer}',
'{download-page-cookies}',
'{user-agent}'
], [
1,
target.getAttribute("manager"),
dialog.mSourcePath || "",
asciiSpec,
"",
$Cookie(asciiSpec),
"", // need to implement
fileName,
dialog.mLauncher.MIMEInfo.primaryExtension,
"", // need to implement
$Cookie(dialog.mSourcePath) || "",
userAgent // need to implement custom agent
])
var initFilePath = PathUtils.join(this.tempDir, hashText(asciiSpec) + ".dl.properties");
saveFile(initFilePath, initData);
this.exec(this.flashgotPath, initFilePath);
} else {
alert("not support");
}
close();
},
handleExtraAppBtnClick: async function (event) {
let target = event.target;
let exec = DownloadPlus.handleRelativePath(target.getAttribute('exec')) || "",
text = target.getAttribute('text') || "",
header = "",
cookie = $Cookie(dialog.mLauncher.source.asciiSpec) || "",
referer = dialog.mSourcePath || gBrowser.currentURI.spec || "",
link = dialog.mLauncher.source.asciiSpec,
path = Services.prefs.getStringPref("browser.download.lastDir", ""),
regEx = new RegExp("^data");
if (regEx.test(link)) {
internalSave(link, null, "", null, null, false, null, null, null, null, null, false, null, PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser), Services.scriptSecurityManager.getSystemPrincipal());
return;
}
if (exec.length) {
if (path.length == 0) {
let title;
if (document.l10n) {
[title] = await document.l10n.formatValues([
{ id: "choose-download-folder-title" },
]);
}
// firefox 选择保存目录对话框
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, title, Ci.nsIFilePicker.modeGetFolder);
let result = await new Promise(resolve => fp.open(resolve));
if (result != Ci.nsIFilePicker.returnOK) {
return;
}
path = fp.file.path;
Services.prefs.setStringPref("browser.download.lastDir", path);
}
if (text.indexOf("{cookiePath}") >= 0) {
// 无法读取 Firefox 的 cookies.sqlite
// text = text.replace("{cookiePath}", FileUtils.getDir("ProfD", ["cookies.sqlite"], true).path);
text = text.replace("{cookiePath}", $Cookie(dialog.mLauncher.source.asciiSpec, true));
}
if (cookie.length) {
header += "Cookie: " + cookie + "\r\n";
}
if (referer.length) {
header += "Referer: " + referer + "\r\n";
}
text = text.replace("{header}", header).replace("{cookie}", cookie).replace("{referer}", referer).replace("{link}", link).replace("{path}", path);
window.DownloadPlus.exec(exec, text);
}
window.close();
},
removeFile: function (event) {
function removeSelectFile(path) {
let file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
try {
file.initWithPath(path);
} catch (e) {
}
if (!file.exists()) {
if (/\..{0,10}(\.part)$/.test(file.path))
file.initWithPath(file.path.replace(".part", ""));
else
file.initWithPath(file.path + ".part");
}
if (file.exists()) {
file.permissions |= 0666;
file.remove(0);
}
}
var ddBox = document.getElementById("downloadsRichListBox");
if (!(ddBox && ddBox._placesView)) {
ddBox = document.getElementById("downloadsListBox");
}
if (!ddBox) return;
var len = ddBox.selectedItems.length;
for (var i = len - 1; i >= 0; i--) {
let sShell = ddBox.selectedItems[i]._shell;
let path = sShell.download.target.path;
removeSelectFile(path);
sShell.doCommand("cmd_delete");
}
},
removeFileEnhance: {
init: function () {
if (window.DownloadPlus.appVersion >= 98) {
window.DownloadPlus.clearHistoryOnDelete = Services.prefs.getIntPref("browser.download.clearHistoryOnDelete");
Services.prefs.setIntPref("browser.download.clearHistoryOnDelete", 2);
}
let context = $("downloadsContextMenu");
context.insertBefore(
$C(document, "menuitem", {
id: 'downloadRemoveFromHistoryEnhanceMenuItem',
class: 'downloadRemoveFromHistoryMenuItem',
onclick: "window.DownloadPlus.removeFile()",
label: $L("remove from disk")
}),
context.querySelector(".downloadRemoveFromHistoryMenuItem")
);
},
destroy: function () {
if (window.DownloadPlus.appVersion >= 98)
Services.prefs.setIntPref("browser.download.clearHistoryOnDelete", window.DownloadPlus.clearHistoryOnDelete);
let context = $("downloadsContextMenu");
context.removeChild(context.querySelector("#downloadRemoveFromHistoryEnhanceMenuItem"));
}
},
downloadCompleteNotice: {
DL_START: null,
DL_DONE: "file:///C:/WINDOWS/Media/chimes.wav",
DL_CANCEL: null,
DL_FAILED: null,
_list: null,
init: function sampleDownload_init() {
XPCOMUtils.defineLazyModuleGetter(window, "Downloads",
"resource://gre/modules/Downloads.jsm");
window.addEventListener("unload", this, false);
//**** 监视下载
if (!this._list) {
Downloads.getList(Downloads.ALL).then(list => {
this._list = list;
return this._list.addView(this);
}).then(null, Cu.reportError);
}
},
uninit: function () {
window.removeEventListener("unload", this, false);
if (this._list) {
this._list.removeView(this);
}
},
onDownloadAdded: function (aDownload) {
//**** 开始下载
if (this.DL_START);
this.playSoundFile(this.DL_START);
},
onDownloadChanged: function (aDownload) {
//**** 取消下载
if (aDownload.canceled && this.DL_CANCEL)
this.playSoundFile(this.DL_CANCEL)
//**** 下载失败
if (aDownload.error && this.DL_FAILED)
this.playSoundFile(this.DL_FAILED)
//**** 完成下载
if (aDownload.succeeded && this.DL_DONE)
this.playSoundFile(this.DL_DONE)
},
playSoundFile: function (aFilePath) {
if (!aFilePath)
return;
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.createInstance(Components.interfaces["nsIIOService"]);
try {
var uri = ios.newURI(aFilePath, "UTF-8", null);
} catch (e) {
return;
}
var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;
if (!file.exists())
return;
this.play(uri);
},
play: function (aUri) {
var sound = Components.classes["@mozilla.org/sound;1"]
.createInstance(Components.interfaces["nsISound"]);
sound.play(aUri);
},
handleEvent: function (event) {
switch (event.type) {
case "unload":
this.uninit();
break;
}
}
},
autoCloseBlankTab: {
eventListener: {
onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
if (!aRequest || !aWebProgress.isTopLevel) return;
let location;
try {
aRequest.QueryInterface(Ci.nsIChannel);
location = aRequest.URI;
} catch (ex) { }
if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
(aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) &&
location && location.spec !== 'about:blank' &&
aBrowser.documentURI && aBrowser.documentURI.spec === 'about:blank' &&
Components.isSuccessCode(aStatus) && !aWebProgress.isLoadingDocument
) {
setTimeout(() => {
gBrowser.removeTab(gBrowser.getTabForBrowser(aBrowser));
}, 100);
}
}
},
init: function () {
gBrowser.addProgressListener(this.eventListener);
},
destroy: function () {
gBrowser.removeProgressListener(this.eventListener);
}
},
alert: function (aMsg, aTitle, aCallback) {
var callback = aCallback ? {
observe: function (subject, topic, data) {
if ("alertclickcallback" != topic)
return;
aCallback.call(null);
}
} : null;
var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
alertsService.showAlertNotification(
this.appVersion >= 78 ? "chrome://global/skin/icons/info.svg" : "chrome://global/skin/icons/information-32.png", aTitle || "DownloadPlus",
aMsg + "", !!callback, "", callback);
},
log: function () {
Cu.reportError(Array.prototype.slice.call(arguments));
},
PREF_FLASHGOT: 'userChromeJS.downloadPlus.flashgotPath'
}
if (typeof gBrowserInit !== "undefined") {
if (gBrowserInit.delayedStartupFinished) window.DownloadPlus.init();
else {
let delayedListener = (subject, topic) => {
if (topic == "browser-delayed-startup-finished" && subject == window) {
Services.obs.removeObserver(delayedListener, topic);
window.DownloadPlus.init();
}
};
Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished");
}
} else {
window.DownloadPlus.init();
}
function inArray(arr, obj) {
var i = arr.length;
while (i--) {
if (arr[i] === obj) {
return true;
}
}
return false;
}
function $(id, aDoc) {
aDoc || (aDoc = document);
return aDoc.getElementById(id);
}
function $C(doc, tag, props, isHTML = false) {
let el = isHTML ? doc.createElement(tag) : doc.createXULElement(tag);
for (let prop in props) {
el.setAttribute(prop, props[prop])
}
if (inArray(['menu', 'menuitem'], tag))
el.classList.add(tag + "-iconic");
return el;
}
function $CNS(doc, namespace, type, props) {
if (!type) return null;
doc || (doc = document);
namespace || (namespace = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
let el = doc.createElementNS(namespace, type);
for (let prop in props) {
el.setAttribute(prop, props[prop])
}
return el;
}
function $L(key, replace) {
let str = LANG[_LOCALE].hasOwnProperty(key) ? LANG[_LOCALE][key] : (LANG['en-US'].hasOwnProperty(key) ? LANG['en-US'][key] : "undefined");
if (typeof replace !== "undefined") {
str = str.replace("%s", replace);
}
return str || "";
}
function $Cookie(link, saveToFile) {
saveToFile || (saveToFile = false);
if (!link) return "";
let uri = Services.io.newURI(link, null, null),
cookies = Services.cookies.getCookiesFromHost(uri.host, {}),
cookieSavePath = DownloadPlus.handleRelativePath(globalConfig["cookie save path"]);
if (saveToFile) {
let string = cookies.map(formatCookie).join('');
let file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
file.initWithPath(cookieSavePath);
file.append(uri.host + ".txt");
if (!file.exists()) {
file.create(0, 0644);
}
let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
foStream.write(string, string.length);
foStream.close();
return file.path;
} else {
return cookies.map((el) => el.name + ':' + el.value).join("; ");
}
function formatCookie(co) {
// 转换成 netscape 格式,抄袭自 cookie_txt 扩展
return [
[
co.isHttpOnly ? '#HttpOnly_' : '',
co.host
].join(''),
co.isDomain ? 'TRUE' : 'FALSE',
co.path,
co.isSecure ? 'TRUE' : 'FALSE',
co.expires,
co.name,
co.value + '\n'
].join('\t');
}
}
function addStyle(css) {
var pi = document.createProcessingInstruction(
'xml-stylesheet',
'type="text/css" href="data:text/css;utf-8,' + encodeURIComponent(css) + '"'
);
return document.insertBefore(pi, document.documentElement);
}
function saveFile(aFileOrPath, data, encoding) {
encoding || (encoding = "UTF-8");
var aFile;
if (typeof aFileOrPath == "string") {
aFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);;
aFile.initWithPath(aFileOrPath);
} else {
aFile = aFileOrPath;
}
var suConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
suConverter.charset = encoding;
data = suConverter.ConvertFromUnicode(data);
var foStream = Cc['@mozilla.org/network/file-output-stream;1'].createInstance(Ci.nsIFileOutputStream);
foStream.init(aFile, 0x02 | 0x08 | 0x20, 0664, 0);
foStream.write(data, data.length);
foStream.close();
}
function readFile(aFileOrPath, encoding) {
encoding || (encoding = "UTF-8");
var aFile;
if (typeof aFileOrPath == "string") {
aFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);;
aFile.initWithPath(aFileOrPath);
} else {
aFile = aFileOrPath;
}
if (aFile.exists()) {
let stream = Cc['@mozilla.org/network/file-input-stream;1'].createInstance(Ci.nsIFileInputStream);
stream.init(aFile, 0x01, 0, 0);
let cvstream = Cc['@mozilla.org/intl/converter-input-stream;1'].createInstance(Ci.nsIConverterInputStream);
cvstream.init(stream, encoding, 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
let content = '',
data = {};
while (cvstream.readString(4096, data)) {
content += data.value;
}
cvstream.close();
return content.replace(/\r\n?/g, '\n');
} else {
return "";
}
}
function removeFile(aFileOrPath) {
var aFile;
if (typeof aFileOrPath == "string") {
aFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);;
aFile.initWithPath(aFileOrPath);
} else {
aFile = aFileOrPath;
}
if (aFile.exists()) {
aFile.permissions |= 0666;
aFile.remove(0);
return true;
} else {
return false;
}
}
function hashText(text, type) {
if (!(typeof text == 'string' || text instanceof String)) {
text = "";
}
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var result = {};
var data = converter.convertToByteArray(text, result);
if (Ci.nsICryptoHash[type]) {
type = Ci.nsICryptoHash[type]
} else {
type = 2;
}
var hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
Ci.nsICryptoHash
);
text = null;
hasher.init(type);
hasher.update(data, data.length);
var hash = hasher.finish(false);
str = data = hasher = null;
function toHexString(charCode) {
return ("0" + charCode.toString(16)).slice(-2);
}
return Array.from(hash, (c, i) => toHexString(hash.charCodeAt(i))).join("");
}
})({
"remove file menuitem": true, // 下载管理增加超级删除菜单
"download complete notice": true, // 下载完成后播放提示音
"auto close blank tab": true, // 自动关闭空白的标签页
"enable rename": true, // 启用重命名
"enable encoding convert": false, // 启用编码转换
"enable double click to copy link": true, // 下载对话框双击来源复制链接
"show extract size": false, // 下载对话框显示文件精确大小 不知道哪个版本开始自带显示
"default select save button": true, // 下载对话框默认选择保存按钮
"enable save and open": true, // 下载对话框新增保存并打开按钮
"enable save as": true, // 下载对话框增加另存为按钮
"enable save to": true, // 显示快捷保存按钮
"cookie save path": "\\chrome\\resources\\cookies", // cookie 保存路径,可以是相对路径,相对于配置目录
"enable aria2 button": false, // 下载对话框增加aria2按钮
"enable idm button": false, // 下载对话框增加idm按钮
"enable thunder button": false, // 下载对话框增加thunder按钮
"elable flashgot button": true, // 下载对话框增加 FlashGot 按钮
}, `
@-moz-document url-prefix("chrome://mozapps/content/downloads/unknownContentType.x") {
#locationtext {
outline: none;
margin-left: 10px;
border: 1px solid var(--in-content-box-border-color, ThreeDDarkShadow);
}
}
`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment