import { SoundboardClip, SoundboardClipInfo } from './types'; /** Parallels custom-emoji/PackImageReader, for a soundboard clip. */ export class SoundboardClipReader { public readonly shortcode: string; public readonly url: string; private readonly clip: Omit; constructor(shortcode: string, url: string, clip: Omit) { this.shortcode = shortcode; this.url = url; this.clip = clip; } static fromClip(shortcode: string, clip: SoundboardClip): SoundboardClipReader | undefined { const { url } = clip; if (typeof url !== 'string' || !url.startsWith('mxc://')) return undefined; return new SoundboardClipReader(shortcode, url, clip); } get body(): string | undefined { const { body } = this.clip; return typeof body === 'string' ? body : undefined; } /** Display name — the clip body, falling back to the shortcode. */ get name(): string { return this.body ?? this.shortcode; } get emoji(): string | undefined { const { emoji } = this.clip; return typeof emoji === 'string' && emoji.length > 0 ? emoji : undefined; } /** Per-clip volume 0–100; defaults to 100 when unset/invalid. */ get volume(): number { const v = this.clip.volume; if (typeof v !== 'number' || Number.isNaN(v)) return 100; return Math.min(100, Math.max(0, v)); } get info(): SoundboardClipInfo | undefined { return this.clip.info; } get content(): SoundboardClip { return { url: this.url, body: this.clip.body, emoji: this.clip.emoji, volume: this.clip.volume, info: this.clip.info, }; } }