You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

EmbedBuilder.cs 14 kB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Immutable;
  4. namespace Discord
  5. {
  6. public class EmbedBuilder
  7. {
  8. private readonly Embed _embed;
  9. public const int MaxFieldCount = 25;
  10. public const int MaxTitleLength = 256;
  11. public const int MaxDescriptionLength = 2048;
  12. public const int MaxEmbedLength = 6000; // user bot limit is 2000, but we don't validate that here.
  13. public EmbedBuilder()
  14. {
  15. _embed = new Embed(EmbedType.Rich);
  16. Fields = new List<EmbedFieldBuilder>();
  17. }
  18. public string Title
  19. {
  20. get => _embed.Title;
  21. set
  22. {
  23. if (value?.Length > MaxTitleLength) throw new ArgumentException($"Title length must be less than or equal to {MaxTitleLength}.", nameof(Title));
  24. _embed.Title = value;
  25. }
  26. }
  27. public string Description
  28. {
  29. get => _embed.Description;
  30. set
  31. {
  32. if (value?.Length > MaxDescriptionLength) throw new ArgumentException($"Description length must be less than or equal to {MaxDescriptionLength}.", nameof(Description));
  33. _embed.Description = value;
  34. }
  35. }
  36. public string Url
  37. {
  38. get => _embed.Url;
  39. set
  40. {
  41. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(Url));
  42. _embed.Url = value;
  43. }
  44. }
  45. public string ThumbnailUrl
  46. {
  47. get => _embed.Thumbnail?.Url;
  48. set
  49. {
  50. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(ThumbnailUrl));
  51. _embed.Thumbnail = new EmbedThumbnail(value, null, null, null);
  52. }
  53. }
  54. public string ImageUrl
  55. {
  56. get => _embed.Image?.Url;
  57. set
  58. {
  59. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(ImageUrl));
  60. _embed.Image = new EmbedImage(value, null, null, null);
  61. }
  62. }
  63. public string VideoUrl
  64. {
  65. get => _embed.Video?.Url;
  66. set
  67. {
  68. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(VideoUrl));
  69. _embed.Video = new EmbedVideo(value, null, null);
  70. }
  71. }
  72. public DateTimeOffset? Timestamp { get => _embed.Timestamp; set { _embed.Timestamp = value; } }
  73. public Color? Color { get => _embed.Color; set { _embed.Color = value; } }
  74. public EmbedAuthorBuilder Author { get; set; }
  75. public EmbedFooterBuilder Footer { get; set; }
  76. public EmbedProviderBuilder Provider { get; set; }
  77. private List<EmbedFieldBuilder> _fields;
  78. public List<EmbedFieldBuilder> Fields
  79. {
  80. get => _fields;
  81. set
  82. {
  83. if (value == null) throw new ArgumentNullException("Cannot set an embed builder's fields collection to null", nameof(Fields));
  84. if (value.Count > MaxFieldCount) throw new ArgumentException($"Field count must be less than or equal to {MaxFieldCount}.", nameof(Fields));
  85. _fields = value;
  86. }
  87. }
  88. public EmbedBuilder WithTitle(string title)
  89. {
  90. Title = title;
  91. return this;
  92. }
  93. public EmbedBuilder WithDescription(string description)
  94. {
  95. Description = description;
  96. return this;
  97. }
  98. public EmbedBuilder WithUrl(string url)
  99. {
  100. Url = url;
  101. return this;
  102. }
  103. public EmbedBuilder WithThumbnailUrl(string thumbnailUrl)
  104. {
  105. ThumbnailUrl = thumbnailUrl;
  106. return this;
  107. }
  108. public EmbedBuilder WithImageUrl(string imageUrl)
  109. {
  110. ImageUrl = imageUrl;
  111. return this;
  112. }
  113. public EmbedBuilder WithVideoUrl(string videoUrl)
  114. {
  115. VideoUrl = videoUrl;
  116. return this;
  117. }
  118. public EmbedBuilder WithCurrentTimestamp()
  119. {
  120. Timestamp = DateTimeOffset.UtcNow;
  121. return this;
  122. }
  123. public EmbedBuilder WithTimestamp(DateTimeOffset dateTimeOffset)
  124. {
  125. Timestamp = dateTimeOffset;
  126. return this;
  127. }
  128. public EmbedBuilder WithColor(Color color)
  129. {
  130. Color = color;
  131. return this;
  132. }
  133. public EmbedBuilder WithAuthor(EmbedAuthorBuilder author)
  134. {
  135. Author = author;
  136. return this;
  137. }
  138. public EmbedBuilder WithAuthor(Action<EmbedAuthorBuilder> action)
  139. {
  140. var author = new EmbedAuthorBuilder();
  141. action(author);
  142. Author = author;
  143. return this;
  144. }
  145. public EmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
  146. {
  147. var author = new EmbedAuthorBuilder
  148. {
  149. Name = name,
  150. IconUrl = iconUrl,
  151. Url = url
  152. };
  153. Author = author;
  154. return this;
  155. }
  156. public EmbedBuilder WithFooter(EmbedFooterBuilder footer)
  157. {
  158. Footer = footer;
  159. return this;
  160. }
  161. public EmbedBuilder WithFooter(Action<EmbedFooterBuilder> action)
  162. {
  163. var footer = new EmbedFooterBuilder();
  164. action(footer);
  165. Footer = footer;
  166. return this;
  167. }
  168. public EmbedBuilder WithFooter(string text, string iconUrl = null)
  169. {
  170. var footer = new EmbedFooterBuilder
  171. {
  172. Text = text,
  173. IconUrl = iconUrl
  174. };
  175. Footer = footer;
  176. return this;
  177. }
  178. public EmbedBuilder WithProvider(EmbedProviderBuilder provider)
  179. {
  180. Provider = provider;
  181. return this;
  182. }
  183. public EmbedBuilder WithProvider(Action<EmbedProviderBuilder> action)
  184. {
  185. var provider = new EmbedProviderBuilder();
  186. action(provider);
  187. Provider = provider;
  188. return this;
  189. }
  190. public EmbedBuilder WithProvider(string name, string url = null)
  191. {
  192. var provider = new EmbedProviderBuilder
  193. {
  194. Name = name,
  195. Url = url
  196. };
  197. Provider = provider;
  198. return this;
  199. }
  200. public EmbedBuilder AddField(string name, object value, bool inline = false)
  201. {
  202. var field = new EmbedFieldBuilder()
  203. .WithIsInline(inline)
  204. .WithName(name)
  205. .WithValue(value);
  206. AddField(field);
  207. return this;
  208. }
  209. public EmbedBuilder AddField(EmbedFieldBuilder field)
  210. {
  211. if (Fields.Count >= MaxFieldCount)
  212. {
  213. throw new ArgumentException($"Field count must be less than or equal to {MaxFieldCount}.", nameof(field));
  214. }
  215. Fields.Add(field);
  216. return this;
  217. }
  218. public EmbedBuilder AddField(Action<EmbedFieldBuilder> action)
  219. {
  220. var field = new EmbedFieldBuilder();
  221. action(field);
  222. this.AddField(field);
  223. return this;
  224. }
  225. public Embed Build()
  226. {
  227. _embed.Footer = Footer?.Build();
  228. _embed.Author = Author?.Build();
  229. _embed.Provider = Provider?.Build();
  230. var fields = ImmutableArray.CreateBuilder<EmbedField>(Fields.Count);
  231. for (int i = 0; i < Fields.Count; i++)
  232. fields.Add(Fields[i].Build());
  233. _embed.Fields = fields.ToImmutable();
  234. if (_embed.Length > MaxEmbedLength)
  235. {
  236. throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}");
  237. }
  238. return _embed;
  239. }
  240. }
  241. public class EmbedFieldBuilder
  242. {
  243. private EmbedField _field;
  244. public const int MaxFieldNameLength = 256;
  245. public const int MaxFieldValueLength = 1024;
  246. public string Name
  247. {
  248. get => _field.Name;
  249. set
  250. {
  251. if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException($"Field name must not be null, empty or entirely whitespace.", nameof(Name));
  252. if (value.Length > MaxFieldNameLength) throw new ArgumentException($"Field name length must be less than or equal to {MaxFieldNameLength}.", nameof(Name));
  253. _field.Name = value;
  254. }
  255. }
  256. public object Value
  257. {
  258. get => _field.Value;
  259. set
  260. {
  261. var stringValue = value?.ToString();
  262. if (string.IsNullOrEmpty(stringValue)) throw new ArgumentException($"Field value must not be null or empty.", nameof(Value));
  263. if (stringValue.Length > MaxFieldValueLength) throw new ArgumentException($"Field value length must be less than or equal to {MaxFieldValueLength}.", nameof(Value));
  264. _field.Value = stringValue;
  265. }
  266. }
  267. public bool IsInline { get => _field.Inline; set { _field.Inline = value; } }
  268. public EmbedFieldBuilder()
  269. {
  270. _field = new EmbedField();
  271. }
  272. public EmbedFieldBuilder WithName(string name)
  273. {
  274. Name = name;
  275. return this;
  276. }
  277. public EmbedFieldBuilder WithValue(object value)
  278. {
  279. Value = value;
  280. return this;
  281. }
  282. public EmbedFieldBuilder WithIsInline(bool isInline)
  283. {
  284. IsInline = isInline;
  285. return this;
  286. }
  287. public EmbedField Build()
  288. => _field;
  289. }
  290. public class EmbedAuthorBuilder
  291. {
  292. private EmbedAuthor _author;
  293. public const int MaxAuthorNameLength = 256;
  294. public string Name
  295. {
  296. get => _author.Name;
  297. set
  298. {
  299. if (value?.Length > MaxAuthorNameLength) throw new ArgumentException($"Author name length must be less than or equal to {MaxAuthorNameLength}.", nameof(Name));
  300. _author.Name = value;
  301. }
  302. }
  303. public string Url
  304. {
  305. get => _author.Url;
  306. set
  307. {
  308. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(Url));
  309. _author.Url = value;
  310. }
  311. }
  312. public string IconUrl
  313. {
  314. get => _author.IconUrl;
  315. set
  316. {
  317. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(IconUrl));
  318. _author.IconUrl = value;
  319. }
  320. }
  321. public EmbedAuthorBuilder()
  322. {
  323. _author = new EmbedAuthor();
  324. }
  325. public EmbedAuthorBuilder WithName(string name)
  326. {
  327. Name = name;
  328. return this;
  329. }
  330. public EmbedAuthorBuilder WithUrl(string url)
  331. {
  332. Url = url;
  333. return this;
  334. }
  335. public EmbedAuthorBuilder WithIconUrl(string iconUrl)
  336. {
  337. IconUrl = iconUrl;
  338. return this;
  339. }
  340. public EmbedAuthor Build()
  341. => _author;
  342. }
  343. public class EmbedFooterBuilder
  344. {
  345. private EmbedFooter _footer;
  346. public const int MaxFooterTextLength = 2048;
  347. public string Text
  348. {
  349. get => _footer.Text;
  350. set
  351. {
  352. if (value?.Length > MaxFooterTextLength) throw new ArgumentException($"Footer text length must be less than or equal to {MaxFooterTextLength}.", nameof(Text));
  353. _footer.Text = value;
  354. }
  355. }
  356. public string IconUrl
  357. {
  358. get => _footer.IconUrl;
  359. set
  360. {
  361. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(IconUrl));
  362. _footer.IconUrl = value;
  363. }
  364. }
  365. public EmbedFooterBuilder()
  366. {
  367. _footer = new EmbedFooter();
  368. }
  369. public EmbedFooterBuilder WithText(string text)
  370. {
  371. Text = text;
  372. return this;
  373. }
  374. public EmbedFooterBuilder WithIconUrl(string iconUrl)
  375. {
  376. IconUrl = iconUrl;
  377. return this;
  378. }
  379. public EmbedFooter Build()
  380. => _footer;
  381. }
  382. public class EmbedProviderBuilder
  383. {
  384. private EmbedProvider _provider;
  385. public string Name
  386. {
  387. get => _provider.Name;
  388. set => _provider.Name = value;
  389. }
  390. public string Url
  391. {
  392. get => _provider.Url;
  393. set
  394. {
  395. if (!value.IsNullOrUri()) throw new ArgumentException("Url must be a well-formed URI", nameof(Url));
  396. }
  397. }
  398. public EmbedProviderBuilder WithName(string name)
  399. {
  400. Name = name;
  401. return this;
  402. }
  403. public EmbedProviderBuilder WithUrl(string url)
  404. {
  405. Url = url;
  406. return this;
  407. }
  408. public EmbedProvider Build()
  409. => _provider;
  410. }
  411. }