From 9925dec0f4db6152a566b1c999057ade53304dfb Mon Sep 17 00:00:00 2001 From: Nils Maier Date: Thu, 26 Sep 2019 08:46:57 +0200 Subject: [PATCH] Use onDeterminingFilename when supported Closes #132 --- lib/browser.ts | 3 +- lib/manager/download.ts | 52 +++++++++++++++++++++++------ lib/manager/man.ts | 18 ++++++++++ lib/manager/preroller.ts | 72 +++++++++++++++++++++++++--------------- 4 files changed, 106 insertions(+), 39 deletions(-) diff --git a/lib/browser.ts b/lib/browser.ts index 8788360..d6166f6 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -57,7 +57,7 @@ type Header = {name: string; value: string}; export interface DownloadOptions { conflictAction: string; - filename: string; + filename?: string; saveAs: boolean; url: string; method?: string; @@ -85,6 +85,7 @@ interface Downloads { onCreated: ExtensionListener; onChanged: ExtensionListener; onErased: ExtensionListener; + onDeterminingFilename?: ExtensionListener; } interface WebRequest { diff --git a/lib/manager/download.ts b/lib/manager/download.ts index 179bda6..f74a40a 100644 --- a/lib/manager/download.ts +++ b/lib/manager/download.ts @@ -22,7 +22,8 @@ import { RUNNING, RETRYING } from "./state"; -import { Preroller } from "./preroller"; +// eslint-disable-next-line no-unused-vars +import { Preroller, PrerollResults } from "./preroller"; function isRecoverable(error: string) { switch (error) { @@ -130,11 +131,13 @@ export class Download extends BaseDownload { } const options: DownloadOptions = { conflictAction: await Prefs.get("conflict-action"), - filename: this.dest.full, saveAs: false, url: this.url, headers: [], }; + if (!CHROME) { + options.filename = this.dest.full; + } if (!CHROME && this.private) { options.incognito = true; } @@ -194,15 +197,7 @@ export class Download extends BaseDownload { if (!res) { return; } - if (res.mime) { - this.mime = res.mime; - } - if (res.name) { - this.serverName = res.name; - } - if (res.error) { - this.cancelAccordingToError(res.error); - } + this.adoptPrerollResults(res); } catch (ex) { console.error("Failed to preroll", this, ex.toString(), ex.stack, ex); @@ -215,6 +210,18 @@ export class Download extends BaseDownload { } } + adoptPrerollResults(res: PrerollResults) { + if (res.mime) { + this.mime = res.mime; + } + if (res.name) { + this.serverName = res.name; + } + if (res.error) { + this.cancelAccordingToError(res.error); + } + } + resume(forced = false) { if (!(FORCABLE & this.state)) { return; @@ -391,4 +398,27 @@ export class Download extends BaseDownload { this.setMissing(); } } + + updatefromSuggestion(state: any) { + const res: PrerollResults = {}; + if (state.mime) { + res.mime = state.mime; + } + if (state.filename) { + res.name = state.filename; + } + if (state.finalUrl) { + res.finalURL = state.finalUrl; + const detected = Preroller.maybeFindNameFromSearchParams(this, res); + if (detected) { + res.name = detected; + } + } + try { + this.adoptPrerollResults(res); + } + finally { + this.markDirty(); + } + } } diff --git a/lib/manager/man.ts b/lib/manager/man.ts index c9e40e5..6bac439 100644 --- a/lib/manager/man.ts +++ b/lib/manager/man.ts @@ -82,6 +82,10 @@ export class Manager extends EventEmitter { downloads.onChanged.addListener(this.onChanged.bind(this)); downloads.onErased.addListener(this.onErased.bind(this)); + if (CHROME && downloads.onDeterminingFilename) { + downloads.onDeterminingFilename.addListener( + this.onDeterminingFilename.bind(this)); + } Bus.onPort("manager", (port: Port) => { const mport = new ManagerPort(this, port); @@ -157,6 +161,20 @@ export class Manager extends EventEmitter { this.manIds.delete(downloadId); } + onDeterminingFilename(state: any, suggest: Function) { + const download = this.manIds.get(state.id); + if (!download) { + return; + } + try { + download.updatefromSuggestion(state); + } + finally { + const suggestion = {filename: download.dest.full}; + suggest(suggestion); + } + } + async resetScheduler() { this.scheduler = null; await this.startNext(); diff --git a/lib/manager/preroller.ts b/lib/manager/preroller.ts index 6e3b252..27fb34d 100644 --- a/lib/manager/preroller.ts +++ b/lib/manager/preroller.ts @@ -54,6 +54,9 @@ export class Preroller { } get shouldPreroll() { + if (CHROME) { + return false; + } const {uURL, renamer} = this.download; const {pathname, search, host} = uURL; if (PREROLL_NOPE.has(host)) { @@ -167,39 +170,15 @@ export class Preroller { rv.mime = type.essence; } - const {p_ext: ext} = this.download.renamer; const dispHeader = headers.get("content-disposition"); if (dispHeader) { const file = CDPARSER.parse(dispHeader); // Sanitize rv.name = sanitizePath(file.replace(/[/\\]+/g, "-")); } - else if (!ext || PREROLL_SEARCHEXTS.has(ext.toLocaleLowerCase())) { - const {searchParams} = this.download.uURL; - let detected = ""; - for (const [, value] of searchParams) { - if (!NAME_TESTER.test(value)) { - continue; - } - const p = parsePath(value); - if (!p.base || !p.ext) { - continue; - } - if (!MimeDB.hasExtension(p.ext)) { - continue; - } - if (rv.mime) { - const mime = MimeDB.getMime(rv.mime); - if (mime && !mime.extensions.has(p.ext.toLowerCase())) { - continue; - } - } - const sanitized = sanitizePath(p.name); - if (sanitized.length <= detected.length) { - continue; - } - detected = sanitized; - } + else { + const detected = Preroller.maybeFindNameFromSearchParams( + this.download, rv); if (detected) { rv.name = detected; } @@ -231,4 +210,43 @@ export class Preroller { return rv; } + + + static maybeFindNameFromSearchParams( + download: Download, res: PrerollResults) { + const {p_ext: ext} = download.renamer; + if (ext && !PREROLL_SEARCHEXTS.has(ext.toLocaleLowerCase())) { + return undefined; + } + return Preroller.findNameFromSearchParams(download.uURL, res.mime); + } + + static findNameFromSearchParams(url: URL, mimetype?: string) { + const {searchParams} = url; + let detected = ""; + for (const [, value] of searchParams) { + if (!NAME_TESTER.test(value)) { + continue; + } + const p = parsePath(value); + if (!p.base || !p.ext) { + continue; + } + if (!MimeDB.hasExtension(p.ext)) { + continue; + } + if (mimetype) { + const mime = MimeDB.getMime(mimetype); + if (mime && !mime.extensions.has(p.ext.toLowerCase())) { + continue; + } + } + const sanitized = sanitizePath(p.name); + if (sanitized.length <= detected.length) { + continue; + } + detected = sanitized; + } + return detected; + } }