import type { Embed, ImageSize, Special } from "stoat-api"; import type { Client } from "../Client.js"; import { File } from "./File.js"; /** * Message Embed */ export abstract class MessageEmbed { protected client?: Client; readonly type: Embed["type"]; /** * Construct Embed * @param client Client * @param type Type */ constructor(client?: Client, type: Embed["type"] = "None") { this.client = client; this.type = type; } /** * Create an Embed from an API Embed * @param client Client * @param embed Data * @returns Embed */ static from(client: Client, embed: Embed): MessageEmbed { switch (embed.type) { case "Image": return new ImageEmbed(client, embed); case "Video": return new VideoEmbed(client, embed); case "Website": return new WebsiteEmbed(client, embed); case "Text": return new TextEmbed(client, embed); default: return new UnknownEmbed(client); } } } /** * Embed of unknown type */ export class UnknownEmbed extends MessageEmbed {} /** * Image Embed */ export class ImageEmbed extends MessageEmbed { readonly url: string; readonly width: number; readonly height: number; readonly size: ImageSize; /** * Construct Image Embed * @param client Client * @param embed Embed */ constructor(client: Client, embed: Omit) { super(client, "Image"); this.url = embed.url; this.width = embed.width; this.height = embed.height; this.size = embed.size; } /** * Proxied image URL */ get proxiedURL(): string | undefined { return this.client?.proxyFile(this.url); } } /** * Video Embed */ export class VideoEmbed extends MessageEmbed { readonly url: string; readonly width: number; readonly height: number; /** * Construct Video Embed * @param client Client * @param embed Embed */ constructor(client: Client, embed: Omit) { super(client, "Video"); this.url = embed.url; this.width = embed.width; this.height = embed.height; } /** * Proxied video URL */ get proxiedURL(): string | undefined { return this.client?.proxyFile(this.url); } } /** * Website Embed */ export class WebsiteEmbed extends MessageEmbed { readonly url?: string; readonly originalUrl?: string; readonly specialContent?: Special; readonly title?: string; readonly description?: string; readonly image?: ImageEmbed; readonly video?: VideoEmbed; readonly siteName?: string; readonly iconUrl?: string; readonly colour?: string; /** * Construct Video Embed * @param client Client * @param embed Embed */ constructor( client: Client, embed: Omit, ) { super(client, "Website"); this.url = embed.url!; this.originalUrl = embed.original_url!; this.specialContent = embed.special!; this.title = embed.title!; this.description = embed.description!; this.image = embed.image ? new ImageEmbed(client, embed.image) : undefined; this.video = embed.video ? new VideoEmbed(client, embed.video) : undefined; this.siteName = embed.site_name!; this.iconUrl = embed.icon_url!; this.colour = embed.colour!; } /** * Proxied icon URL */ get proxiedIconURL(): string | undefined { return this.iconUrl ? this.client?.proxyFile(this.iconUrl) : undefined; } /** * If special content is present, generate the embed URL */ get embedURL(): string | undefined { switch (this.specialContent?.type) { case "YouTube": { let timestamp = ""; if (this.specialContent.timestamp) { timestamp = `&start=${this.specialContent.timestamp}`; } return `https://www.youtube-nocookie.com/embed/${this.specialContent.id}?modestbranding=1${timestamp}`; } case "Twitch": return `https://player.twitch.tv/?${this.specialContent.content_type.toLowerCase()}=${ this.specialContent.id }&parent=${(window ?? {})?.location?.hostname}&autoplay=false`; case "Lightspeed": return `https://new.lightspeed.tv/embed/${this.specialContent.id}/stream`; case "Spotify": return `https://open.spotify.com/embed/${this.specialContent.content_type}/${this.specialContent.id}`; case "Soundcloud": return `https://w.soundcloud.com/player/?url=${encodeURIComponent( this.url!, )}&color=%23FF7F50&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true`; case "Bandcamp": { return `https://bandcamp.com/EmbeddedPlayer/${this.specialContent.content_type.toLowerCase()}=${ this.specialContent.id }/size=large/bgcol=181a1b/linkcol=056cc4/tracklist=false/transparent=true/`; } case "Streamable": { return `https://streamable.com/e/${this.specialContent.id}?loop=0`; } } } } /** * Text Embed */ export class TextEmbed extends MessageEmbed { readonly iconUrl?: string; readonly url?: string; readonly title?: string; readonly description?: string; readonly media?: File; readonly colour?: string; /** * Construct Video Embed * @param client Client * @param embed Embed */ constructor(client: Client, embed: Omit) { super(client, "Text"); this.iconUrl = embed.icon_url!; this.url = embed.url!; this.title = embed.title!; this.description = embed.description!; this.media = embed.media ? new File(client, embed.media) : undefined; this.colour = embed.colour!; } /** * Proxied icon URL */ get proxiedIconURL(): string | undefined { return this.iconUrl ? this.client?.proxyFile(this.iconUrl) : undefined; } }