227 lines
4.6 KiB
TypeScript
227 lines
4.6 KiB
TypeScript
import { DateTime } from "luxon";
|
|
|
|
export function timestampToReadable(timestamp?: number): string {
|
|
const date: Date =
|
|
timestamp && !isNaN(timestamp) ? new Date(timestamp) : new Date();
|
|
if (isNaN(date.getTime())) return "Invalid Date";
|
|
return date.toISOString().replace("T", " ").replace("Z", "");
|
|
}
|
|
|
|
export function isUUID(uuid: string): boolean {
|
|
const regex: RegExp =
|
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
|
|
return regex.test(uuid);
|
|
}
|
|
|
|
export function getNewTimeUTC(
|
|
durationStr: string,
|
|
from: DateTime = DateTime.utc(),
|
|
): string | null {
|
|
const duration: DurationObject = parseDuration(durationStr);
|
|
|
|
const newTime: DateTime = from.plus({
|
|
years: duration.years,
|
|
months: duration.months,
|
|
weeks: duration.weeks,
|
|
days: duration.days,
|
|
hours: duration.hours,
|
|
minutes: duration.minutes,
|
|
seconds: duration.seconds,
|
|
});
|
|
|
|
return newTime.toSQL({ includeOffset: false });
|
|
}
|
|
|
|
export function parseDuration(input: string): DurationObject {
|
|
const regex: RegExp = /(\d+)(y|mo|w|d|h|m|s)/g;
|
|
const matches: RegExpMatchArray[] = [...input.matchAll(regex)];
|
|
|
|
const duration: DurationObject = {
|
|
years: 0,
|
|
months: 0,
|
|
weeks: 0,
|
|
days: 0,
|
|
hours: 0,
|
|
minutes: 0,
|
|
seconds: 0,
|
|
};
|
|
|
|
for (const match of matches) {
|
|
const value: number = parseInt(match[1], 10);
|
|
const unit: string = match[2];
|
|
|
|
switch (unit) {
|
|
case "y":
|
|
duration.years = value;
|
|
break;
|
|
case "mo":
|
|
duration.months = value;
|
|
break;
|
|
case "w":
|
|
duration.weeks = value;
|
|
break;
|
|
case "d":
|
|
duration.days = value;
|
|
break;
|
|
case "h":
|
|
duration.hours = value;
|
|
break;
|
|
case "m":
|
|
duration.minutes = value;
|
|
break;
|
|
case "s":
|
|
duration.seconds = value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return duration;
|
|
}
|
|
|
|
export function isValidTimezone(timezone: string): boolean {
|
|
return DateTime.local().setZone(timezone).isValid;
|
|
}
|
|
|
|
export function generateRandomString(length?: number): string {
|
|
if (!length) {
|
|
length = length || Math.floor(Math.random() * 10) + 5;
|
|
}
|
|
|
|
const characters: string =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
let result: string = "";
|
|
|
|
for (let i: number = 0; i < length; i++) {
|
|
result += characters.charAt(
|
|
Math.floor(Math.random() * characters.length),
|
|
);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function getBaseUrl(request: Request): string {
|
|
const url: URL = new URL(request.url);
|
|
const protocol: string = url.protocol.slice(0, -1);
|
|
const portSegment: string = url.port ? `:${url.port}` : "";
|
|
|
|
return `${protocol}://${url.hostname}${portSegment}`;
|
|
}
|
|
|
|
const knownExtensions: Set<string> = new Set([
|
|
"mp4",
|
|
"txt",
|
|
"pdf",
|
|
"gz",
|
|
"tar",
|
|
"zip",
|
|
"7z",
|
|
"rar",
|
|
"png",
|
|
"jpg",
|
|
"jpeg",
|
|
"webp",
|
|
"gif",
|
|
"js",
|
|
"ts",
|
|
"tsx",
|
|
"json",
|
|
"html",
|
|
"css",
|
|
"md",
|
|
"log",
|
|
"db",
|
|
"db3",
|
|
"sqlite",
|
|
"csv",
|
|
"xml",
|
|
"yaml",
|
|
"yml",
|
|
"toml",
|
|
"ini",
|
|
"cfg",
|
|
"conf",
|
|
"env",
|
|
"sh",
|
|
"bash",
|
|
"zsh",
|
|
"fish",
|
|
"ps1",
|
|
"bat",
|
|
"cmd",
|
|
"py",
|
|
"pyc",
|
|
"pyo",
|
|
"pyd",
|
|
"pyw",
|
|
"pyz",
|
|
"pyzw",
|
|
]);
|
|
|
|
export function getExtension(fileName: string): string | null {
|
|
const lastDotIndex: number = fileName.lastIndexOf(".");
|
|
if (lastDotIndex <= 0) return null;
|
|
|
|
const ext: string = fileName.slice(lastDotIndex + 1).toLowerCase();
|
|
return knownExtensions.has(ext) ? ext : null;
|
|
}
|
|
|
|
export function nameWithoutExtension(fileName: string): string {
|
|
const lastDotIndex: number = fileName.lastIndexOf(".");
|
|
if (lastDotIndex <= 0) return fileName;
|
|
|
|
const ext: string = fileName.slice(lastDotIndex + 1).toLowerCase();
|
|
return knownExtensions.has(ext)
|
|
? fileName.slice(0, lastDotIndex)
|
|
: fileName;
|
|
}
|
|
|
|
export function supportsExif(mimeType: string, extension: string): boolean {
|
|
const supportedMimeTypes: string[] = [
|
|
"image/jpeg",
|
|
"image/tiff",
|
|
"image/png",
|
|
"image/webp",
|
|
"image/heif",
|
|
"image/heic",
|
|
];
|
|
const supportedExtensions: string[] = [
|
|
"jpg",
|
|
"jpeg",
|
|
"tiff",
|
|
"png",
|
|
"webp",
|
|
"heif",
|
|
"heic",
|
|
];
|
|
|
|
return (
|
|
supportedMimeTypes.includes(mimeType.toLowerCase()) &&
|
|
supportedExtensions.includes(extension.toLowerCase())
|
|
);
|
|
}
|
|
|
|
export function supportsThumbnail(mimeType: string): boolean {
|
|
return /^(image\/(?!svg+xml)|video\/)/i.test(mimeType);
|
|
}
|
|
|
|
// Commands
|
|
export function parseArgs(): Record<string, string | boolean> {
|
|
const args: string[] = process.argv.slice(2);
|
|
const parsedArgs: Record<string, string | boolean> = {};
|
|
|
|
for (let i: number = 0; i < args.length; i++) {
|
|
if (args[i].startsWith("--")) {
|
|
const key: string = args[i].slice(2);
|
|
const value: string | boolean =
|
|
args[i + 1] && !args[i + 1].startsWith("--")
|
|
? args[i + 1]
|
|
: true;
|
|
parsedArgs[key] = value;
|
|
if (value !== true) i++;
|
|
}
|
|
}
|
|
|
|
return parsedArgs;
|
|
}
|