import * as fsp from 'fs/promises'; import { tmpdir } from 'os'; import { join } from 'path'; import { randomBytes } from 'crypto'; import { Attachment, EmbedBuilder, Guild, GuildPremiumTier, Message, PartialMessage } from 'discord.js'; export async function exists(file: string) { try { await fsp.stat(file); return true; } catch(_err) { return false; } } export function getSign(n: number) { if (n > 0) return '+'; if (n < 0) return '-'; return ' '; } export async function writeTmpFile(data: string | Buffer, filename?: string, extension?: string): Promise { const file = `${filename ? filename + '-' : ''}${randomBytes(8).toString('hex')}${extension ? '.' + extension : (typeof data === 'string' ? '.txt' : '')}`; const path = join(tmpdir(), file); await fsp.writeFile(path, data); return path; } export function pickRandom(list: T[]): T { return list[Math.floor(Math.random() * list.length)]; } // WE OUT HERE export type Either = Left | Right export class Left { constructor(private readonly value: L) {} public getValue() { return this.value; } } export class Right { constructor(private readonly value: R) {} public getValue() { return this.value; } } export function* chunks(arr: T[], n: number) { for (let i = 0; i < arr.length; i += n) { yield arr.slice(i, i + n); } } export function shortenStr(str: string, chars: number) { if (str.length > chars) return str.slice(0, chars - 1) + '…'; return str; } export const MAX_MESSAGE_SIZE = 2000; export const defaultUploadLimit = 25 * 1024 * 1024; export const getUploadLimitForGuild = (guild: Guild) => { switch (guild.premiumTier) { case GuildPremiumTier.Tier3: return 100 * 1024 * 1024; case GuildPremiumTier.Tier2: return 50 * 1024 * 1024; default: return defaultUploadLimit; } }; export function formatMessageAsEmbed(message: Message | PartialMessage, uploadLimit: number): { embed: EmbedBuilder, attach: Attachment | null } { const embed = new EmbedBuilder() .setTimestamp(message.createdTimestamp); if (message.author) { embed.setAuthor({ name: message.author.tag, iconURL: message.author.displayAvatarURL(), }); } let attach = null; message.embeds.forEach(em => { if (em.image) { embed.setImage(em.image.url); } else if (em.thumbnail) { embed.setImage(em.thumbnail.url); } if (em.provider) { embed.addFields({ name: shortenStr(`${em.provider.name}:`, 256), value: shortenStr(`${em.author}: **${em.title}**\n${em.description || ''}`, 2048), }); } else if (!em.image) { embed.addFields({ name: 'Embed:', value: shortenStr(em.description || em.fields[0]?.value || em.title || 'Unknown content', 2048), }); } }); let msgEnd = null; const first = message.attachments.first(); if ( message.attachments.size === 1 && first && first.contentType && !first.spoiler && (first.contentType?.startsWith('image/') || first.contentType?.startsWith('video/')) && (first.size <= uploadLimit) ) { attach = first; } else { for (const attach of message.attachments.values()) { msgEnd = (msgEnd || '\n') + `\n[${attach.name}](${attach.url})`; } } if (message.content) { if (!msgEnd) { embed.setDescription(shortenStr(message.content, 4096)); } else { embed.setDescription(shortenStr(message.content, 4096 - msgEnd.length) + msgEnd); } } else if (msgEnd) { embed.setDescription('_Content unknown_' + msgEnd); } return { embed, attach }; }