downthemall/lib/item.ts
Nils Maier 31cb23923a Add a subfolders dropdown
The dropdown will help users switch between folders easier than using the mask.
Also, the dropdown is more discoverable than masked folders.

See #2
2019-09-14 01:07:29 +02:00

140 lines
2.7 KiB
TypeScript

"use strict";
// License: MIT
import { ALLOWED_SCHEMES } from "./constants";
import { TRANSFERABLE_PROPERTIES } from "./constants";
export interface BaseItem {
url: string;
usable: string;
referrer?: string;
usableReferrer?: string;
description?: string;
title?: string;
fileName?: string;
batch?: number;
idx: number;
mask?: string;
subfolder?: string;
startDate?: number;
private?: boolean;
postData?: string;
paused?: boolean;
}
const OPTIONPROPS = Object.freeze([
"referrer", "usableReferrer",
"description", "title",
"fileName",
"batch", "idx",
"mask",
"subfolder",
"startDate",
"private",
"postData",
"paused"
]);
function maybeAssign(options: any, what: any) {
const type = typeof this[what];
if (type === "number" || type === "string" || type === "boolean") {
return;
}
if (type === "object" && this[what]) {
return;
}
let val;
if (what in options) {
val = options[what];
}
this[what] = val;
}
export class Item implements BaseItem {
public url: string;
public usable: string;
public referrer: string;
public usableReferrer: string;
public idx: number;
constructor(raw: any, options?: any) {
Object.assign(this, raw);
OPTIONPROPS.forEach(maybeAssign.bind(this, options || {}));
this.usable = Item.makeUsable(this.url, this.usable);
this.usableReferrer = Item.makeUsable(this.referrer, this.usableReferrer);
}
static makeUsable(unusable: string, usable: string | boolean) {
if (usable === true) {
return unusable;
}
if (usable) {
return usable;
}
try {
return decodeURIComponent(unusable);
}
catch (ex) {
return unusable;
}
}
toString() {
return `<Item(${this.url})>`;
}
}
export class Finisher {
public referrer: string;
public usableReferrer: string;
constructor(options: any) {
this.referrer = options.baseURL;
this.usableReferrer = Item.makeUsable(
options.baseURL, options.usable || null);
}
finish(item: any) {
if (!ALLOWED_SCHEMES.has(new URL(item.url).protocol)) {
return null;
}
return new Item(item, this);
}
}
function transfer(e: any, other: any) {
for (const p of TRANSFERABLE_PROPERTIES) {
if (!other[p] && e[p]) {
other[p] = e[p];
}
}
}
export function makeUniqueItems(items: any[][], mapping?: Function) {
const known = new Map();
const unique = [];
for (const itemlist of items) {
for (const e of itemlist) {
const other = known.get(e.url);
if (other) {
transfer(e, other);
continue;
}
const finished = mapping ? mapping(e) : e;
if (!finished) {
continue;
}
known.set(finished.url, finished);
unique.push(finished);
}
}
return unique;
}