feat: create MessageEmbed class

This commit is contained in:
Paul Makles
2023-04-09 18:02:25 +01:00
parent 103ed9eff0
commit 8bd37b77e8
3 changed files with 241 additions and 14 deletions
+232
View File
@@ -0,0 +1,232 @@
import { API, Client, File } from "..";
/**
* Message Embed
*/
export abstract class MessageEmbed {
protected client?: Client;
readonly type: API.Embed["type"];
/**
* Construct Embed
* @param client Client
* @param type Type
*/
constructor(client?: Client, type: API.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: API.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: API.ImageSize;
/**
* Construct Image Embed
* @param client Client
* @param embed Embed
*/
constructor(
client: Client,
embed: Omit<API.Embed & { type: "Image" }, "type">
) {
super(client, "Image");
this.url = embed.url;
this.width = embed.width;
this.height = embed.height;
this.size = embed.size;
}
/**
* Proxied image URL
*/
get proxiedURL() {
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<API.Embed & { type: "Video" }, "type">
) {
super(client, "Video");
this.url = embed.url;
this.width = embed.width;
this.height = embed.height;
}
/**
* Proxied video URL
*/
get proxiedURL() {
return this.client?.proxyFile(this.url);
}
}
/**
* Website Embed
*/
export class WebsiteEmbed extends MessageEmbed {
readonly url?: string;
readonly originalUrl?: string;
readonly specialContent?: API.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<API.Embed & { type: "Website" }, "type">
) {
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() {
return this.iconUrl ? this.client?.proxyFile(this.iconUrl) : undefined;
}
/**
* If special content is present, generate the embed URL
*/
get embedURL() {
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<API.Embed & { type: "Text" }, "type">
) {
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() {
return this.iconUrl ? this.client?.proxyFile(this.iconUrl) : undefined;
}
}
+1
View File
@@ -6,3 +6,4 @@ export { ServerMember } from "./ServerMember";
export { User } from "./User";
export { File } from "./File";
export { ChannelUnread } from "./ChannelUnread";
export * from "./MessageEmbed";
+8 -14
View File
@@ -1,14 +1,7 @@
import { ReactiveMap } from "@solid-primitives/map";
import { ReactiveSet } from "@solid-primitives/set";
import {
Message as ApiMessage,
Embed,
Interactions,
Masquerade,
SystemMessage,
} from "revolt-api";
import { File } from "..";
import { API, File, MessageEmbed } from "..";
import type { Merge } from "../lib/merge";
import { Hydrate } from ".";
@@ -19,18 +12,18 @@ export type HydratedMessage = {
channelId: string;
authorId?: string;
content?: string;
systemMessage?: SystemMessage;
systemMessage?: API.SystemMessage;
attachments?: File[];
editedAt?: Date;
embeds?: Embed[];
embeds?: MessageEmbed[];
mentionIds?: string[];
replyIds?: string[];
reactions: ReactiveMap<string, ReactiveSet<string>>;
interactions?: Interactions;
masquerade?: Masquerade;
interactions?: API.Interactions;
masquerade?: API.Masquerade;
};
export const messageHydration: Hydrate<Merge<ApiMessage>, HydratedMessage> = {
export const messageHydration: Hydrate<Merge<API.Message>, HydratedMessage> = {
keyMapping: {
_id: "id",
channel: "channelId",
@@ -50,7 +43,8 @@ export const messageHydration: Hydrate<Merge<ApiMessage>, HydratedMessage> = {
attachments: (message, ctx) =>
message.attachments!.map((file) => new File(ctx, file)),
editedAt: (message) => new Date(message.edited!),
embeds: (message) => message.embeds!,
embeds: (message, ctx) =>
message.embeds!.map((embed) => MessageEmbed.from(ctx, embed)),
mentionIds: (message) => message.mentions!,
replyIds: (message) => message.replies!,
reactions: (message) => {