-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
embed.ts
290 lines (261 loc) · 8.09 KB
/
embed.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
import type {
EmbedAuthor,
EmbedField,
EmbedFooter,
EmbedImage,
EmbedPayload,
EmbedProvider,
EmbedThumbnail,
EmbedTypes,
EmbedVideo
} from '../types/channel.ts'
import { Colors, ColorUtil } from '../utils/colorutil.ts'
import type { MessageAttachment } from './message.ts'
/** Message Embed Object */
export class Embed {
title?: string
type?: EmbedTypes
description?: string
url?: string
timestamp?: string
color?: number
footer?: EmbedFooter
image?: EmbedImage
thumbnail?: EmbedThumbnail
video?: EmbedVideo
provider?: EmbedProvider
author?: EmbedAuthor
fields?: EmbedField[]
files: MessageAttachment[] = []
static MAX_TITLE_LENGTH = 256
static MAX_DESCRIPTION_LENGTH = 4096
static MAX_FIELD_NAME_LENGTH = 256
static MAX_FIELD_VALUE_LENGTH = 1024
static MAX_FIELDS_LENGTH = 25
static MAX_FOOTER_TEXT_LENGTH = 2048
static MAX_AUTHOR_NAME_LENGTH = 256
static MAX_EMBED_LENGTH = 6000
constructor(data?: EmbedPayload) {
this.title = data?.title
this.type = data?.type
this.description = data?.description
this.url = data?.url
this.timestamp = data?.timestamp
this.color = data?.color
this.footer = data?.footer
this.image = data?.image
this.thumbnail = data?.thumbnail
this.video = data?.video
this.provider = data?.provider
this.author = data?.author
this.fields = data?.fields
}
/** Convert Embed Object to Embed Payload JSON */
toJSON(): EmbedPayload {
let total = 0
if (
this.title?.length !== undefined &&
this.title?.length > Embed.MAX_TITLE_LENGTH
) {
total += Number(this.title.length)
throw new Error(
`Embed title cannot exceed ${Embed.MAX_TITLE_LENGTH} characters.`
)
}
if (
this.description?.length !== undefined &&
this.description?.length > Embed.MAX_DESCRIPTION_LENGTH
) {
total += Number(this.description.length)
throw new Error(
`Embed description cannot exceed ${Embed.MAX_DESCRIPTION_LENGTH} characters.`
)
}
if (this.fields?.length !== undefined) {
this.fields.forEach((field) => {
if (field.name.length > Embed.MAX_FIELD_NAME_LENGTH) {
total += Number(field.name.length)
throw new Error(
`Embed field name cannot exceed ${Embed.MAX_FIELD_NAME_LENGTH} characters.`
)
}
if (field.value.length > Embed.MAX_FIELD_VALUE_LENGTH) {
total += Number(field.value.length)
throw new Error(
`Embed field value cannot exceed ${Embed.MAX_FIELD_VALUE_LENGTH} characters.`
)
}
})
if (this.fields.length > Embed.MAX_FIELDS_LENGTH)
throw new Error('Embed fields cannot exceed 25 field objects.')
}
if (
this.footer?.text?.length !== undefined &&
this.footer?.text?.length > Embed.MAX_FOOTER_TEXT_LENGTH
) {
total += Number(this.footer?.text?.length)
throw new Error(
`Embed footer text cannot exceed ${Embed.MAX_FOOTER_TEXT_LENGTH}.`
)
}
if (
this.author?.name?.length !== undefined &&
this.author?.name?.length > Embed.MAX_AUTHOR_NAME_LENGTH
) {
total += Number(this.author?.name?.length)
throw new Error(
`Embed author name cannot exceed ${Embed.MAX_AUTHOR_NAME_LENGTH}.`
)
}
if (total > Embed.MAX_EMBED_LENGTH)
throw new Error(
`Embed characters cannot exceed ${Embed.MAX_EMBED_LENGTH} characters in total.`
)
return {
title: this.title,
type: this.type,
description: this.description,
url: this.url,
timestamp: this.timestamp,
color: this.color,
footer: this.footer,
image: this.image,
thumbnail: this.thumbnail,
video: this.video,
provider: this.provider,
author: this.author,
fields: this.fields
}
}
/** Set Title of the Embed */
setTitle(title: string): Embed {
this.title = title
return this
}
/** Set Embed description */
setDescription(description: string): Embed {
this.description = description
return this
}
attach(...files: MessageAttachment[]): Embed {
for (const file of files) {
this.files.push(file)
}
return this
}
/** Set Embed Type */
setType(type: EmbedTypes): Embed {
this.type = type
return this
}
/** Set URL of the Embed */
setURL(url: string | URL): Embed {
this.url = typeof url === 'object' ? url.toString() : url
return this
}
/** Set Timestamp of the Embed */
setTimestamp(timeString: string): Embed
setTimestamp(unixTimestamp: number): Embed
setTimestamp(dateObject: Date): Embed
setTimestamp(timestamp: string | Date | number): Embed {
this.timestamp = new Date(timestamp).toISOString()
return this
}
/** Set Color of the Embed */
setColor(hexInt: number): Embed
setColor(r: number, g: number, b: number): Embed
setColor(random: 'random'): Embed
setColor(hexStr: string): Embed
setColor(namedColor: keyof Colors): Embed
setColor(
color: number | 'random' | string | keyof Colors,
g?: number,
b?: number
): Embed {
if (typeof color === 'number' && g === undefined && b === undefined) {
this.color = color
} else if (typeof color === 'string' && color.toLowerCase() === 'random') {
this.color = ColorUtil.resolveHex(ColorUtil.randomHex())
} else if (typeof color === 'string' && color.startsWith('#')) {
this.color = ColorUtil.resolveHex(color)
} else if (
typeof color === 'number' &&
g !== undefined &&
b !== undefined
) {
this.color = ColorUtil.resolveRGB([color, g, b])
} else if (typeof color === 'string') {
this.color = ColorUtil.resolveColor(color as keyof Colors)
} else
throw new Error(
'Invalid Embed Color. Must be RGB, Hex (string or number), valid color name or a valid CSS color.'
)
return this
}
/** Set Footer of the Embed */
setFooter(text: string, icon?: string): Embed
setFooter(footer: EmbedFooter): Embed
setFooter(footer: EmbedFooter | string, icon?: string): Embed {
this.footer =
typeof footer === 'string' ? { text: footer, icon_url: icon } : footer
return this
}
/** Set Image of the Embed */
setImage(image: EmbedImage | string): Embed {
this.image = typeof image === 'string' ? { url: image } : image
return this
}
/** Set Thumbnail Image of the Embed */
setThumbnail(thumbnail: EmbedThumbnail | string): Embed {
this.thumbnail =
typeof thumbnail === 'string' ? { url: thumbnail } : thumbnail
return this
}
/** Set Embed Video */
setVideo(video: EmbedVideo | string): Embed {
this.video = typeof video === 'string' ? { url: video } : video
return this
}
/** Set Provider of the Embed */
setProvider(name: string, url?: string): Embed
setProvider(provider: EmbedProvider): Embed
setProvider(provider: EmbedProvider | string, url?: string): Embed {
this.provider =
typeof provider === 'string' ? { name: provider, url } : provider
return this
}
/** Set Author of the Embed */
setAuthor(author: EmbedAuthor): Embed
setAuthor(name: string, image?: string): Embed
setAuthor(author: EmbedAuthor | string, image?: string): Embed {
this.author =
typeof author === 'string' ? { name: author, icon_url: image } : author
return this
}
setFields(fields: EmbedField[]): Embed {
this.fields = fields
return this
}
/** Adds a Field to the Embed */
addField(field: EmbedField): Embed
addField(name: string, value: string, inline?: boolean): Embed
addField(name: string | EmbedField, value?: string, inline?: boolean): Embed {
if (typeof name !== 'object' && value === undefined)
throw new Error('field value is required')
const field: EmbedField =
typeof name === 'object' ? name : { name, value: value as string, inline }
if (this.fields === undefined) {
this.fields = [field]
} else {
this.fields.push(field)
}
return this
}
/** Adds multiple fields to the Embed */
addFields(...fields: EmbedField[]): Embed {
for (const field of fields) {
this.addField(field)
}
return this
}
}