|
@@ -2,6 +2,7 @@ import { GuildMember } from "discord.js";
|
|
import { getRepository, In } from "typeorm";
|
|
import { getRepository, In } from "typeorm";
|
|
import { KnownUser } from "@shared/db/entity/KnownUser";
|
|
import { KnownUser } from "@shared/db/entity/KnownUser";
|
|
import { HTTPError } from "got/dist/source";
|
|
import { HTTPError } from "got/dist/source";
|
|
|
|
+import humanizeDuration from "humanize-duration";
|
|
|
|
|
|
const VALID_EXTENSIONS = new Set([
|
|
const VALID_EXTENSIONS = new Set([
|
|
"png",
|
|
"png",
|
|
@@ -105,4 +106,71 @@ export function isHttpError(err?: unknown): err is HTTPError {
|
|
|
|
|
|
export function hasStackTrace(reason?: unknown): reason is {stack: unknown} {
|
|
export function hasStackTrace(reason?: unknown): reason is {stack: unknown} {
|
|
return reason && Object.prototype.hasOwnProperty.call(reason, "stack");
|
|
return reason && Object.prototype.hasOwnProperty.call(reason, "stack");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export function parseArgs(str: string): string[] {
|
|
|
|
+ const result: string[] = [];
|
|
|
|
+
|
|
|
|
+ let quoteMode = false;
|
|
|
|
+ let escapeNext = false;
|
|
|
|
+ let buffer = "";
|
|
|
|
+ for (const char of str) {
|
|
|
|
+ if (!escapeNext)
|
|
|
|
+ if (char == "\"") {
|
|
|
|
+ if (!quoteMode) {
|
|
|
|
+ quoteMode = true;
|
|
|
|
+ } else {
|
|
|
|
+ quoteMode = false;
|
|
|
|
+ result.push(buffer);
|
|
|
|
+ buffer = "";
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ } else if (char == "\\") {
|
|
|
|
+ escapeNext = true;
|
|
|
|
+ continue;
|
|
|
|
+ } else if (/\s/.test(char)) {
|
|
|
|
+ if (buffer.length == 0)
|
|
|
|
+ continue;
|
|
|
|
+ if (!quoteMode) {
|
|
|
|
+ result.push(buffer);
|
|
|
|
+ buffer = "";
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ buffer += char;
|
|
|
|
+ escapeNext = false;
|
|
|
|
+ }
|
|
|
|
+ if (buffer.length != 0)
|
|
|
|
+ result.push(buffer);
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export const UNIT_MEASURES: humanizeDuration.UnitMeasuresOptions = {
|
|
|
|
+ ms: 1,
|
|
|
|
+ s: 1000,
|
|
|
|
+ m: 60 * 1000,
|
|
|
|
+ h: 60 * 60 * 1000,
|
|
|
|
+ d: 24 * 60 * 60 * 1000,
|
|
|
|
+ w: 7 * 24 * 60 * 60 * 1000,
|
|
|
|
+ mo: 30 * 24 * 60 * 60 * 1000,
|
|
|
|
+ y: 365 * 24 * 60 * 60 * 1000
|
|
|
|
+};
|
|
|
|
+const durationUnits = UNIT_MEASURES as Record<string, number>;
|
|
|
|
+const durationPattern = new RegExp(`(\\d+(?:[.,]?\\d+)?)\\s*(${Object.keys(durationUnits).sort((a, b) => b.length - a.length).join("|")})`, "g");
|
|
|
|
+
|
|
|
|
+export function parseDuration(s: string): number | undefined {
|
|
|
|
+ if (!s)
|
|
|
|
+ return undefined;
|
|
|
|
+ s = s.trim();
|
|
|
|
+ let buffer = s;
|
|
|
|
+ let result = 0;
|
|
|
|
+ let match;
|
|
|
|
+ while ((match = durationPattern.exec(s))) {
|
|
|
|
+ buffer = buffer.replace(match[0], "").trim();
|
|
|
|
+ result += +match[1] * durationUnits[match[2]];
|
|
|
|
+ }
|
|
|
|
+ if (buffer.length != 0)
|
|
|
|
+ return undefined;
|
|
|
|
+ return result;
|
|
}
|
|
}
|