Handle missing-on-init

This commit is contained in:
Nils Maier 2019-08-21 16:15:31 +02:00
parent 3b5c5f0730
commit 6b07fa2d08
8 changed files with 35 additions and 13 deletions

View File

@ -461,6 +461,10 @@
"description": "", "description": "",
"message": "Show a notification when queueing new downloads" "message": "Show a notification when queueing new downloads"
}, },
"pref-remove-missing-on-init": {
"description": "",
"message": "Remove missing downloads after a restart"
},
"pref-show-urls": { "pref-show-urls": {
"description": "", "description": "",
"message": "Show URLs instead of Names" "message": "Show URLs instead of Names"

View File

@ -11,6 +11,7 @@
"nagging-next": 6, "nagging-next": 6,
"tooltip": true, "tooltip": true,
"show-urls": false, "show-urls": false,
"remove-missing-on-init": false,
"limits": [ "limits": [
{ {
"domain": "*", "domain": "*",

View File

@ -206,19 +206,22 @@ export class Download extends BaseDownload {
async maybeMissing() { async maybeMissing() {
if (!this.manId) { if (!this.manId) {
return; return null;
} }
const {manId: id} = this; const {manId: id} = this;
try { try {
const dls = await downloads.search({id}); const dls = await downloads.search({id});
if (!dls.length) { if (!dls.length) {
this.setMissing(); this.setMissing();
return this;
} }
} }
catch (ex) { catch (ex) {
console.error("oops", id, ex.toString(), ex); console.error("oops", id, ex.toString(), ex);
this.setMissing(); this.setMissing();
return this;
} }
return null;
} }
adoptSize(state: any) { adoptSize(state: any) {

View File

@ -10,7 +10,7 @@ import { Bus, Port } from "../bus";
import { sort } from "../sorting"; import { sort } from "../sorting";
import { Prefs } from "../prefs"; import { Prefs } from "../prefs";
import { _ } from "../i18n"; import { _ } from "../i18n";
import { CoalescedUpdate, mapFilterInSitu } from "../util"; import { CoalescedUpdate, mapFilterInSitu, filterInSitu } from "../util";
import { PromiseSerializer } from "../pserializer"; import { PromiseSerializer } from "../pserializer";
import {Download} from "./download"; import {Download} from "./download";
import {ManagerPort} from "./port"; import {ManagerPort} from "./port";
@ -94,8 +94,14 @@ export class Manager extends EventEmitter {
return this; return this;
} }
checkMissing() { async checkMissing() {
this.items.forEach(item => item.maybeMissing()); const serializer = new PromiseSerializer(2);
const missing = await Promise.all(this.items.map(
item => serializer.scheduleWithContext(item, item.maybeMissing)));
if (!(await Prefs.get("remove-missing-on-init"))) {
return;
}
this.remove(filterInSitu(missing, e => !!e));
} }
onChanged(changes: {id: number}) { onChanged(changes: {id: number}) {

View File

@ -91,19 +91,19 @@ export class PromiseSerializer {
return rv; return rv;
} }
schedule<T>(fn: Function, ...args: any[]): Promise<T> { schedule<T>(fn: Wrapped<T>, ...args: any[]): Promise<T> {
return this.scheduleWithContext(null, fn, ...args); return this.scheduleWithContext(null, fn, ...args);
} }
scheduleWithContext<T>(ctx: any, fn: Function, ...args: any[]): Promise<T> { scheduleWithContext<T>(ctx: any, fn: Wrapped<T>, ...args: any[]): Promise<T> {
return scheduleInternal.call(this, false, ctx, fn, ...args); return scheduleInternal.call(this, false, ctx, fn, ...args);
} }
prepend<T>(fn: Function, ...args: any[]): Promise<T> { prepend<T>(fn: Wrapped<T>, ...args: any[]): Promise<T> {
return this.prependWithContext(null, fn, ...args); return this.prependWithContext(null, fn, ...args);
} }
prependWithContext<T>(ctx: any, fn: Function, ...args: any[]): Promise<T> { prependWithContext<T>(ctx: any, fn: Wrapped<T>, ...args: any[]): Promise<T> {
return scheduleInternal.call(this, true, ctx, fn, ...args); return scheduleInternal.call(this, true, ctx, fn, ...args);
} }

View File

@ -165,17 +165,23 @@ Object.defineProperty(URL.prototype, "domain", {
* @param {Object} tp * @param {Object} tp
* @returns {Array} Filtered array (identity) * @returns {Array} Filtered array (identity)
*/ */
export function filterInSitu<T>(arr: T[], cb: (value: T) => boolean, tp?: any) { export function filterInSitu<T>(
arr: (T | null | undefined)[], cb: (value: T) => boolean, tp?: any) {
tp = tp || null; tp = tp || null;
let i; let k; let e; let i; let k; let e;
const carr = arr as unknown as T[];
for (i = 0, k = 0, e = arr.length; i < e; i++) { for (i = 0, k = 0, e = arr.length; i < e; i++) {
const a = arr[k] = arr[i]; // replace filtered items const a = arr[i]; // replace filtered items
if (a && cb.call(tp, a, i, arr)) { if (!a) {
continue;
}
if (cb.call(tp, a, i, arr)) {
carr[k] = a;
k += 1; k += 1;
} }
} }
arr.length = k; // truncate carr.length = k; // truncate
return arr; return carr;
} }
/** /**

View File

@ -61,6 +61,7 @@
<label><input type="checkbox" id="pref-open-manager-on-queue"> <span data-i18n="pref-open-manager-on-queue"></span></label> <label><input type="checkbox" id="pref-open-manager-on-queue"> <span data-i18n="pref-open-manager-on-queue"></span></label>
<label><input type="checkbox" id="pref-text-links"> <span data-i18n="pref-text-links"></span></label> <label><input type="checkbox" id="pref-text-links"> <span data-i18n="pref-text-links"></span></label>
<label><input type="checkbox" id="pref-add-paused"> <span data-i18n="pref-add-paused"></span></label> <label><input type="checkbox" id="pref-add-paused"> <span data-i18n="pref-add-paused"></span></label>
<label><input type="checkbox" id="pref-remove-missing-on-init"> <span data-i18n="pref-remove-missing-on-init"></span></label>
</fieldset> </fieldset>
<fieldset id="pref-conflict-action"> <fieldset id="pref-conflict-action">
<legend>When a file exists</legend> <legend>When a file exists</legend>

View File

@ -553,6 +553,7 @@ addEventListener("DOMContentLoaded", () => {
new BoolPref("pref-text-links", "text-links"); new BoolPref("pref-text-links", "text-links");
new BoolPref("pref-add-paused", "add-paused"); new BoolPref("pref-add-paused", "add-paused");
new BoolPref("pref-show-urls", "show-urls"); new BoolPref("pref-show-urls", "show-urls");
new BoolPref("pref-remove-missing-on-init", "show-urls");
new OptionPref("pref-conflict-action", "conflict-action"); new OptionPref("pref-conflict-action", "conflict-action");
$("#reset-confirmations").addEventListener("click", async () => { $("#reset-confirmations").addEventListener("click", async () => {