Add embeds, forwards, and voice flags to the message shape
This commit is contained in:
+1
-1
@@ -23,7 +23,7 @@ mobile draft at 390px.
|
|||||||
|
|
||||||
Checkpoints, push after each:
|
Checkpoints, push after each:
|
||||||
- [x] C1 design docs, AGENTS/INDEX pointers, `.gitignore`
|
- [x] C1 design docs, AGENTS/INDEX pointers, `.gitignore`
|
||||||
- [ ] C2 core message shape: embeds, forwards, attachment metadata
|
- [x] C2 core message shape: embeds, forwards, attachment metadata
|
||||||
- [ ] C3 media-scrape store and puppet walker, tests
|
- [ ] C3 media-scrape store and puppet walker, tests
|
||||||
- [ ] C4 slopbot backend, tests
|
- [ ] C4 slopbot backend, tests
|
||||||
- [ ] C5 Web UI Media and Bot tabs, API routes
|
- [ ] C5 Web UI Media and Bot tabs, API routes
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ Event line:
|
|||||||
| `user.search` | `query`, optional `guildId`, optional `limit` | Users from the client cache. Guild members when `guildId` is set. |
|
| `user.search` | `query`, optional `guildId`, optional `limit` | Users from the client cache. Guild members when `guildId` is set. |
|
||||||
| `dm.list` | optional `limit` | Cached DM and group DM channels with recipients, icons, and avatars. Cache-only. |
|
| `dm.list` | optional `limit` | Cached DM and group DM channels with recipients, icons, and avatars. Cache-only. |
|
||||||
| `message.send` | `channelId`, `content` | `{ channelId, messageId, sent: true }` |
|
| `message.send` | `channelId`, `content` | `{ channelId, messageId, sent: true }` |
|
||||||
| `message.read` | `channelId`, `limit` | `{ cached, messages }`. Cache-only. Messages include the author avatar, attachment CDN links, `editedAt`, and `replyTo`. |
|
| `message.read` | `channelId`, `limit` | `{ cached, messages }`. Cache-only. Messages carry the author avatar, attachment metadata (id, filename, URL, content type, size, dimensions, duration), embeds (video, image, and thumbnail URLs), sticker items, forwarded snapshots, a voice-message flag, `editedAt`, and `replyTo`. |
|
||||||
| `message.fetch` | `channelId`, `limit`, optional `before` or `after` | `{ fetched, messages }`. Fetches from Discord. Same message shape. |
|
| `message.fetch` | `channelId`, `limit`, optional `before` or `after` | `{ fetched, messages }`. Fetches from Discord. Same message shape. |
|
||||||
| `reaction.add` | `channelId`, `messageId`, `emoji` | `{ added: true }` |
|
| `reaction.add` | `channelId`, `messageId`, `emoji` | `{ added: true }` |
|
||||||
| `dm.send` | `userId`, `content` | `{ userId, channelId, sent: true }` |
|
| `dm.send` | `userId`, `content` | `{ userId, channelId, sent: true }` |
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ const SENDABLE_CHANNEL_TYPES = new Set([0, 1, 3, 5, 10, 11, 12]);
|
|||||||
/** Channel types that are voice channels. */
|
/** Channel types that are voice channels. */
|
||||||
const VOICE_CHANNEL_TYPES = new Set([2, 13]);
|
const VOICE_CHANNEL_TYPES = new Set([2, 13]);
|
||||||
|
|
||||||
|
/** Discord message flag for a voice message. */
|
||||||
|
const VOICE_MESSAGE_FLAG = 1 << 13;
|
||||||
|
|
||||||
/** Discord's message fetch action, located lazily at runtime. */
|
/** Discord's message fetch action, located lazily at runtime. */
|
||||||
const MessageActions = findByPropsLazy("fetchMessages");
|
const MessageActions = findByPropsLazy("fetchMessages");
|
||||||
|
|
||||||
@@ -188,10 +191,64 @@ function getSendableChannel(channelId: string) {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Pull a URL from an embed part. Discord gives some parts as strings and some as objects. */
|
||||||
|
function embedUrl(value: any): string | null {
|
||||||
|
if (typeof value === "string") return value;
|
||||||
|
return value?.url ?? value?.proxyURL ?? value?.proxy_url ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapAttachments(message: any) {
|
||||||
|
return (message?.attachments ?? []).map((attachment: any) => ({
|
||||||
|
id: attachment.id ?? null,
|
||||||
|
filename: attachment.filename,
|
||||||
|
url: attachment.url ?? null,
|
||||||
|
contentType: attachment.contentType ?? attachment.content_type ?? null,
|
||||||
|
size: attachment.size ?? null,
|
||||||
|
width: attachment.width ?? null,
|
||||||
|
height: attachment.height ?? null,
|
||||||
|
durationSecs: attachment.durationSecs ?? attachment.duration_secs ?? null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapEmbeds(message: any) {
|
||||||
|
return (message?.embeds ?? []).map((embed: any) => ({
|
||||||
|
type: embed?.type ?? null,
|
||||||
|
url: embed?.url ?? null,
|
||||||
|
title: embed?.title ?? null,
|
||||||
|
provider: embed?.provider?.name ?? null,
|
||||||
|
videoUrl: embedUrl(embed?.video),
|
||||||
|
imageUrl: embedUrl(embed?.image),
|
||||||
|
thumbnailUrl: embedUrl(embed?.thumbnail)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStickers(message: any) {
|
||||||
|
return (message?.stickerItems ?? message?.sticker_items ?? []).map((sticker: any) => ({
|
||||||
|
id: sticker.id ?? null,
|
||||||
|
name: sticker.name ?? null,
|
||||||
|
formatType: sticker.formatType ?? sticker.format_type ?? null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shape a forwarded snapshot. Snapshots carry no channel fields and are one level deep. */
|
||||||
|
function mapSnapshot(snapshot: any) {
|
||||||
|
const message = snapshot?.message ?? snapshot;
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: message?.content ?? "",
|
||||||
|
timestamp: message?.timestamp ?? null,
|
||||||
|
attachments: mapAttachments(message),
|
||||||
|
embeds: mapEmbeds(message),
|
||||||
|
stickerItems: mapStickers(message),
|
||||||
|
voiceMessage: Boolean((message?.flags ?? 0) & VOICE_MESSAGE_FLAG)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** Shape a Discord message for the daemon. Attachments carry CDN links only. */
|
/** Shape a Discord message for the daemon. Attachments carry CDN links only. */
|
||||||
function mapMessage(message: any) {
|
function mapMessage(message: any) {
|
||||||
const reference = message.messageReference;
|
const reference = message.messageReference;
|
||||||
const referenced = message.referencedMessage ?? message.referenced_message;
|
const referenced = message.referencedMessage ?? message.referenced_message;
|
||||||
|
const snapshots = message.messageSnapshots ?? message.message_snapshots ?? [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: message.id,
|
id: message.id,
|
||||||
@@ -210,13 +267,11 @@ function mapMessage(message: any) {
|
|||||||
authorName: referenced?.author?.username ?? null
|
authorName: referenced?.author?.username ?? null
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
attachments: (message.attachments ?? []).map((attachment: any) => ({
|
attachments: mapAttachments(message),
|
||||||
filename: attachment.filename,
|
embeds: mapEmbeds(message),
|
||||||
url: attachment.url ?? null,
|
stickerItems: mapStickers(message),
|
||||||
contentType: attachment.contentType ?? null,
|
forwarded: snapshots.map(mapSnapshot),
|
||||||
width: attachment.width ?? null,
|
voiceMessage: Boolean((message.flags ?? 0) & VOICE_MESSAGE_FLAG)
|
||||||
height: attachment.height ?? null
|
|
||||||
}))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user