|
|
@@ -43,7 +43,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
async preparePageData() {
|
|
|
await this.processor.preparePageData();
|
|
|
}
|
|
|
- getPageData() {
|
|
|
+ async getPageData() {
|
|
|
return this.processor.getPageData();
|
|
|
}
|
|
|
};
|
|
|
@@ -171,7 +171,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
await this.executeStage(3);
|
|
|
}
|
|
|
|
|
|
- getPageData() {
|
|
|
+ async getPageData() {
|
|
|
if (!this.options.windowId) {
|
|
|
this.onprogress(new ProgressEvent(PAGE_ENDED, { pageURL: this.options.url }));
|
|
|
}
|
|
|
@@ -289,7 +289,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
await this.loadPage();
|
|
|
}
|
|
|
|
|
|
- getPageData() {
|
|
|
+ async getPageData() {
|
|
|
DOM.postProcessDoc(this.doc, this.options);
|
|
|
if (this.options.selected) {
|
|
|
const rootElement = this.doc.querySelector("[" + SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME + "]");
|
|
|
@@ -300,9 +300,10 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
}
|
|
|
const titleElement = this.doc.querySelector("title");
|
|
|
- let title;
|
|
|
if (titleElement) {
|
|
|
- title = titleElement.textContent.trim();
|
|
|
+ this.options.title = titleElement.textContent.trim();
|
|
|
+ } else {
|
|
|
+ this.options.title = "";
|
|
|
}
|
|
|
const matchTitle = this.baseURI.match(/([^/]*)\/?(\.html?.*)$/) || this.baseURI.match(/\/\/([^/]*)\/?$/);
|
|
|
const url = new URL(this.baseURI);
|
|
|
@@ -316,9 +317,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
this.stats.set("processed", "HTML bytes", contentSize);
|
|
|
this.stats.add("discarded", "HTML bytes", size - contentSize);
|
|
|
}
|
|
|
+ const filename = await DomProcessorHelper.getFilename(this.options, content);
|
|
|
return {
|
|
|
stats: this.stats.data,
|
|
|
- title: title || (this.baseURI && matchTitle ? matchTitle[1] : (url.hostname ? url.hostname : "Untitled page")),
|
|
|
+ title: this.options.title || (this.baseURI && matchTitle ? matchTitle[1] : (url.hostname ? url.hostname : "")),
|
|
|
+ filename,
|
|
|
content
|
|
|
};
|
|
|
}
|
|
|
@@ -780,6 +783,70 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const PREFIX_DATA_URI_IMAGE_SVG = "data:image/svg+xml";
|
|
|
|
|
|
class DomProcessorHelper {
|
|
|
+ static async getFilename(options, content) {
|
|
|
+ let filename = options.filenameTemplate;
|
|
|
+ const date = new Date();
|
|
|
+ const url = new URL(options.url);
|
|
|
+ filename = filename.replace(/{\s*title\s*}/g, options.title.replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*iso-datetime\s*}/g, date.toISOString().replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*iso-date\s*}/g, date.toISOString().split("T")[0].replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*iso-time\s*}/g, date.toISOString().split("T")[1].split("Z")[0].replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-date\s*}/g, date.toLocaleDateString().replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-time\s*}/g, date.toLocaleTimeString().replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-day\s*}/g, String(date.getDate()).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-month\s*}/g, String(date.getMonth() + 1).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-year\s*}/g, String(date.getFullYear()).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*locale-datetime\s*}/g, date.toLocaleString().replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*utc-datetime\s*}/g, date.toUTCString().replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*utc-day\s*}/g, String(date.getUTCDate()).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*utc-month\s*}/g, String(date.getUTCMonth() + 1).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*utc-year\s*}/g, String(date.getUTCFullYear()).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-hash\s*}/g, url.hash.substring(1).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-host\s*}/g, url.host.replace(/\/+/g, "_").replace(/\/$/, ""));
|
|
|
+ filename = filename.replace(/{\s*url-hostname\s*}/g, url.hostname.replace(/\/+/g, "_").replace(/\/$/, ""));
|
|
|
+ filename = filename.replace(/{\s*url-href\s*}/g, url.href.replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-password\s*}/g, url.password.replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-pathname\s*}/g, url.pathname.replace(/\/+/g, "_").replace(/\/$/, "").replace(/^\//, ""));
|
|
|
+ filename = filename.replace(/{\s*url-port\s*}/g, url.port.replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-protocol\s*}/g, url.protocol.replace(/\/+/g, "_").replace(/\/$/, ""));
|
|
|
+ filename = filename.replace(/{\s*url-search\s*}/g, url.search.substring(1).replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*url-username\s*}/g, url.username.replace(/\/+/g, "_"));
|
|
|
+ filename = filename.replace(/{\s*tab-id\s*}/g, String(options.tabId || "unknown"));
|
|
|
+ let lastSegmentMatch = url.pathname.match(/\/([^/]+)$/);
|
|
|
+ let lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
|
+ if (!lastSegment) {
|
|
|
+ lastSegmentMatch = url.href.match(/([^/]+)\/?$/);
|
|
|
+ lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
|
+ }
|
|
|
+ if (!lastSegment) {
|
|
|
+ lastSegmentMatch = lastSegment.match(/(.*)<\.[^.]+$/);
|
|
|
+ lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
|
+ }
|
|
|
+ if (!lastSegment) {
|
|
|
+ lastSegment = url.hostname.replace(/\/+/g, "_").replace(/\/$/, "");
|
|
|
+ }
|
|
|
+ filename = filename.replace(/{\s*url-last-segment\s*}/g, lastSegment.replace(/\/+/g, "").replace(/\/$/, "").replace(/^\//, ""));
|
|
|
+ if (filename.match(/{\s*digest-sha-256\s*}/g)) {
|
|
|
+ filename = filename.replace(/{\s*digest-sha-256\s*}/g, await DOM.digest("SHA-256", content));
|
|
|
+ }
|
|
|
+ if (filename.match(/{\s*digest-sha-384\s*}/g)) {
|
|
|
+ filename = filename.replace(/{\s*digest-sha-384\s*}/g, await DOM.digest("SHA-384", content));
|
|
|
+ }
|
|
|
+ if (filename.match(/{\s*digest-sha-512\s*}/g)) {
|
|
|
+ filename = filename.replace(/{\s*digest-sha-512\s*}/g, await DOM.digest("SHA-512", content));
|
|
|
+ }
|
|
|
+ filename = filename.replace(/[~\\?%*:|"<>\x00-\x1f\x7F]+/g, "_"); // eslint-disable-line no-control-regex
|
|
|
+ if (filename.length > 192) {
|
|
|
+ const extensionMatch = filename.match(/(\.[^.]{3,4})$/);
|
|
|
+ const extension = extensionMatch && extensionMatch[0] && extensionMatch[0].length > 1 ? extensionMatch[0] : "";
|
|
|
+ filename = filename.substring(0, 192 - extension.length) + "…" + extension;
|
|
|
+ }
|
|
|
+ if (!filename) {
|
|
|
+ filename = "Untitled page";
|
|
|
+ }
|
|
|
+ return filename;
|
|
|
+ }
|
|
|
+
|
|
|
static setFrameEmptySrc(frameElement) {
|
|
|
if (frameElement.tagName == "OBJECT") {
|
|
|
frameElement.setAttribute("data", "data:text/html,");
|