mirror of
https://github.com/stoatchat/javascript-client-sdk.git
synced 2026-07-19 17:13:31 -04:00
feat: create MessageEmbed class
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -6,3 +6,4 @@ export { ServerMember } from "./ServerMember";
|
||||
export { User } from "./User";
|
||||
export { File } from "./File";
|
||||
export { ChannelUnread } from "./ChannelUnread";
|
||||
export * from "./MessageEmbed";
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user