backend/src/helpers/char.ts

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;
}