Use onDeterminingFilename when supported

Closes #132
This commit is contained in:
Nils Maier 2019-09-26 08:46:57 +02:00
parent 09b2b4be10
commit 9925dec0f4
4 changed files with 106 additions and 39 deletions

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -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();

View File

@ -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;
}
}