jormungandr-bite/packages/backend/src/misc/emoji-meta.ts

59 lines
1.4 KiB
TypeScript
Raw Normal View History

2023-05-19 20:26:13 -06:00
import probeImageSize from "probe-image-size";
2023-07-02 18:37:46 -06:00
import { Mutex } from "redis-semaphore";
2023-05-19 20:26:13 -06:00
import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
import Logger from "@/services/logger.js";
import { Cache } from "./cache.js";
2023-07-02 18:37:46 -06:00
import { redisClient } from "@/db/redis.js";
2023-05-19 20:26:13 -06:00
export type Size = {
width: number;
height: number;
};
2023-07-02 18:55:20 -06:00
const cache = new Cache<boolean>("emojiMeta",1000 * 60 * 10); // once every 10 minutes for the same url
2023-07-02 18:37:46 -06:00
const logger = new Logger("emoji");
2023-05-19 20:26:13 -06:00
export async function getEmojiSize(url: string): Promise<Size> {
2023-07-02 18:37:46 -06:00
let attempted = true;
2023-05-19 20:26:13 -06:00
2023-07-02 18:37:46 -06:00
const lock = new Mutex(redisClient, "getEmojiSize");
await lock.acquire();
try {
attempted = (await cache.get(url)) === true;
2023-05-19 20:26:13 -06:00
if (!attempted) {
2023-07-02 18:37:46 -06:00
await cache.set(url, true);
2023-05-19 20:26:13 -06:00
}
2023-07-02 18:37:46 -06:00
} finally {
await lock.release();
}
if (attempted) {
logger.warn(`Attempt limit exceeded: ${url}`);
throw new Error("Too many attempts");
}
2023-05-19 20:26:13 -06:00
try {
2023-07-02 18:37:46 -06:00
logger.debug(`Retrieving emoji size from ${url}`);
2023-05-19 20:26:13 -06:00
const { width, height, mime } = await probeImageSize(url, {
timeout: 5000,
});
if (!(mime.startsWith("image/") && FILE_TYPE_BROWSERSAFE.includes(mime))) {
throw new Error("Unsupported image type");
2023-05-19 20:26:13 -06:00
}
return { width, height };
} catch (e) {
throw new Error(`Unable to retrieve metadata: ${e}`);
2023-05-19 20:26:13 -06:00
}
}
export function getNormalSize(
{ width, height }: Size,
orientation?: number,
): Size {
return (orientation || 0) >= 5
? { width: height, height: width }
: { width, height };
}