downthemall/lib/manager/renamer.ts
2019-09-21 09:44:38 +02:00

277 lines
6.2 KiB
TypeScript

/* eslint-disable @typescript-eslint/camelcase */
"use strict";
// License: MIT
import { _ } from "../i18n";
import { MimeDB } from "../mime";
// eslint-disable-next-line no-unused-vars
import { parsePath, PathInfo, sanitizePath } from "../util";
// eslint-disable-next-line no-unused-vars
import { BaseDownload } from "./basedownload";
const REPLACE_EXPR = /\*\w+\*/gi;
const BATCH_FORMATTER = new Intl.NumberFormat(undefined, {
style: "decimal",
useGrouping: false,
minimumIntegerDigits: 3,
maximumFractionDigits: 0
});
const DATE_FORMATTER = new Intl.NumberFormat(undefined, {
style: "decimal",
useGrouping: false,
minimumIntegerDigits: 2,
maximumFractionDigits: 0
});
export default class Renamer {
private readonly d: BaseDownload;
private readonly nameinfo: PathInfo;
constructor(download: BaseDownload) {
this.d = download;
const info = parsePath(this.d.finalName);
this.nameinfo = this.fixupExtension(info);
}
private fixupExtension(info: PathInfo): PathInfo {
if (!this.d.mime) {
return info;
}
const mime = MimeDB.getMime(this.d.mime);
if (!mime) {
return info;
}
const {ext} = info;
if (mime.major === "image" || mime.major === "video") {
if (ext && mime.extensions.has(ext.toLowerCase())) {
return info;
}
return new PathInfo(info.base, mime.primary, info.path);
}
if (ext) {
return info;
}
return new PathInfo(info.base, mime.primary, info.path);
}
get ref() {
return this.d.uReferrer;
}
get p_name() {
return this.nameinfo.base;
}
get p_ext() {
return this.nameinfo.ext;
}
get p_text() {
return this.d.description;
}
get p_title() {
return this.d.title;
}
get p_host() {
return this.d.uURL.host;
}
get p_domain() {
return this.d.uURL.domain;
}
get p_subdirs() {
return parsePath(this.d.uURL).path;
}
get p_qstring() {
const {search} = this.d.uURL;
return search && search.substr(1).replace(/\/+/g, "-");
}
get p_url() {
return this.d.usable.substr(this.d.uURL.protocol.length + 2);
}
get p_batch() {
return BATCH_FORMATTER.format(this.d.batch);
}
get p_num() {
return BATCH_FORMATTER.format(this.d.batch);
}
get p_idx() {
return BATCH_FORMATTER.format(this.d.idx);
}
get p_date() {
return `${this.p_y}${this.p_m}${this.p_d}T${this.p_hh}${this.p_mm}${this.p_ss}`;
}
get p_refname() {
const {ref} = this;
if (!ref) {
return null;
}
return parsePath(ref).base;
}
get p_refext() {
const {ref} = this;
if (!ref) {
return null;
}
return parsePath(ref).ext;
}
get p_refhost() {
const {ref} = this;
if (!ref) {
return null;
}
return ref.host;
}
get p_refdomain() {
const {ref} = this;
if (!ref) {
return null;
}
return ref.domain;
}
get p_refsubdirs() {
const {ref} = this;
if (!ref) {
return null;
}
return parsePath(ref).path;
}
get p_refqstring() {
const {ref} = this;
if (!ref) {
return null;
}
const {search} = ref;
return search && search.substr(1).replace(/\/+/g, "-");
}
get p_refurl() {
return this.d.usableReferrer.substr(
this.d.uReferrer.protocol.length + 2);
}
get p_hh() {
return DATE_FORMATTER.format(this.d.startDate.getHours());
}
get p_mm() {
return DATE_FORMATTER.format(this.d.startDate.getMinutes());
}
get p_ss() {
return DATE_FORMATTER.format(this.d.startDate.getSeconds());
}
get p_d() {
return DATE_FORMATTER.format(this.d.startDate.getDate());
}
get p_m() {
return DATE_FORMATTER.format(this.d.startDate.getMonth() + 1);
}
get p_y() {
return DATE_FORMATTER.format(this.d.startDate.getFullYear());
}
toString() {
const {mask, subfolder} = this.d;
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self: any = this;
const baseMask = subfolder ? `${subfolder}/${mask}` : mask;
return sanitizePath(baseMask.replace(REPLACE_EXPR, function(type: string) {
let prop = type.substr(1, type.length - 2);
const flat = prop.startsWith("flat");
if (flat) {
prop = prop.substr(4);
}
prop = `p_${prop}`;
let rv = (prop in self) ?
(self[prop] || "").trim() :
type;
if (flat) {
rv = rv.replace(/[/\\]+/g, "-");
}
return rv.replace(/\/{2,}/g, "/");
}));
}
}
export const SUPPORTED =
Object.keys(Object.getOwnPropertyDescriptors(Renamer.prototype)).
filter(k => k.startsWith("p_")).
map(k => k.slice(2));
function makeHTMLMap() {
const e = document.createElement("section");
e.className = "renamer-map";
const head = document.createElement("h2");
head.className = "renamer-head";
head.textContent = _("renamer-tags");
e.appendChild(head);
const tags = SUPPORTED;
const mid = Math.ceil(tags.length / 2);
for (const half of [tags.slice(0, mid), tags.slice(mid)]) {
const cont = document.createElement("div");
cont.className = "renamer-half";
for (const k of half) {
const tag = document.createElement("code");
tag.className = "renamer-tag";
tag.textContent = `*${k}*`;
cont.appendChild(tag);
const label = document.createElement("label");
label.className = "renamer-label";
label.textContent = _(`renamer-${k}`);
cont.appendChild(label);
}
e.appendChild(cont);
}
const info = document.createElement("em");
info.className = "renamer-info";
info.textContent = _("renamer-info");
e.appendChild(info);
return e;
}
export function hookButton(maskButton: HTMLElement) {
let maskMap: HTMLElement;
maskButton.addEventListener("click", (evt: MouseEvent) => {
evt.preventDefault();
evt.stopPropagation();
const {top, right} = maskButton.getBoundingClientRect();
if (!maskMap) {
maskMap = makeHTMLMap();
document.body.appendChild(maskMap);
maskMap.classList.add("hidden");
}
maskMap.classList.toggle("hidden");
if (!maskMap.classList.contains("hidden")) {
const maskRect = maskMap.getBoundingClientRect();
maskMap.style.top = `${top - maskRect.height - 10}px`;
maskMap.style.left = `${right - maskRect.width}px`;
}
});
}