export interface AttachmentAudioMeta { title: string | null artist: string | null album: string | null voice?: boolean } export interface CommentAttachment { id: number name: string url: string mimeType: string | null size: number | null cover?: string | null meta?: AttachmentAudioMeta | null } export const MAX_COMMENT_ATTACHMENTS = 8 export const MAX_ATTACHMENT_SIZE = 200 * 1024 * 1024 // 200 MB export function isImageAttachment(a: { mimeType?: string | null, name?: string }): boolean { return !!a.mimeType?.startsWith('image/') || (!!a.name && /\.(avif|bmp|gif|jpe?g|png|svg|webp)$/i.test(a.name)) } export function isAudioAttachment(a: { mimeType?: string | null, name?: string }): boolean { return !!a.mimeType?.startsWith('audio/') || (!!a.name && /\.(mp3|flac|ogg|wav|m4a|aac|opus)$/i.test(a.name)) } export function isVideoAttachment(a: { mimeType?: string | null, name?: string }): boolean { return !!a.mimeType?.startsWith('video/') || (!!a.name && /\.(mp4|webm|mov|mkv|avi|m4v|mpg|mpeg|ts|mts)$/i.test(a.name)) } export function isVoiceAttachment(a: { meta?: { voice?: boolean } | null }): boolean { return a.meta?.voice === true } export function formatFileSize(bytes: number | null | undefined): string { if (!bytes || bytes <= 0) return '' return bytes >= 1024 * 1024 ? `${(bytes / 1024 / 1024).toFixed(1)} MB` : `${Math.max(1, Math.round(bytes / 1024))} KB` }