using Newtonsoft.Json; using System; using System.Collections.Generic; namespace Oxide.Plugins { [Info("Discord Message API", "bsdinis", "0.0.9")] class DiscordMessageAPI : CovalencePlugin { void SendDiscordMessage(string webhook, string username, string avatarUrl, string content, bool tts, List> embeds) { if (string.IsNullOrWhiteSpace(webhook) || !IsValidUrl(webhook, out webhook)) { PrintError("\nThe first argument (webhook) is not a valid URL. Unable to send Discord message!"); return; } if (string.IsNullOrWhiteSpace(username)) { PrintError("\nThe second argument (username) must not be empty. Unable to send Discord message!"); return; } if (string.IsNullOrWhiteSpace(content) && (embeds == null || embeds.Count < 1)) { PrintError("\nThe message must contain content or an embed. Unable to send an empty Discord message!"); return; } int characters = 0; bool limit = false; if (avatarUrl == null) { avatarUrl = string.Empty; } if (content == null) { content = string.Empty; } if (username.Length > 80) { PrintWarning("\nDiscord limits the amount of characters in message's username to 80. Only the first 80 characters from the message's username will be added to the message."); } if (!IsValidUrl(avatarUrl, out avatarUrl)) { PrintWarning("\nThe message's avatar URL is not a valid URL and will not be added to the message."); } if (content.Length > 2000) { PrintWarning("\nDiscord limits the amount of characters in message's content to 2000. Only the first 2000 characters from the message's content will be added to the message."); } DiscordMessage message = new DiscordMessage { username = Concatenate(username, 80), avatar_url = avatarUrl, content = Concatenate(content, 2000), tts = tts, embeds = new List() }; if (embeds != null) { for (int i = 0; i < embeds.Count; i++) { List embedList = embeds[i] as List; if (embedList == null) { PrintError($"\nUnable to read Embed[{i}]."); continue; } if (embedList.Count < 12) { PrintError($"\nEmbed[{i}] has less than 12 objects and will not be added to the message."); continue; } string authorName = embedList[0] as string; if (authorName == null) { PrintError($"\nThe first object (author name) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string authorUrl = embedList[1] as string; if (authorUrl == null) { PrintError($"\nThe second object (author URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string authorIconUrl = embedList[2] as string; if (authorIconUrl == null) { PrintError($"\nThe third object (author icon URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string embedTitle = embedList[3] as string; if (embedTitle == null) { PrintError($"\nThe fourth object (embed title) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string embedURL = embedList[4] as string; if (embedURL == null) { PrintError($"\nThe fifth object (URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string embedDescription = embedList[5] as string; if (embedDescription == null) { PrintError($"\nThe sixth object (description) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } if (!(embedList[6] is int)) { PrintError($"\nThe seventh object (color) from Embed[{i}] is not an int value and the whole embed will not be added to the message."); continue; } string thumbnailUrl = embedList[8] as string; if (thumbnailUrl == null) { PrintError($"\nThe nineth object (thumbnail URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string imageUrl = embedList[9] as string; if (imageUrl == null) { PrintError($"\nThe tenth object (image URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string footerText = embedList[10] as string; if (footerText == null) { PrintError($"\nThe eleventh object (footer text) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } string footerIconUrl = embedList[11] as string; if (footerIconUrl == null) { PrintError($"\nThe twelveth object (footer icon URL) from Embed[{i}] is not a string and the whole embed will not be added to the message."); continue; } DiscordMessage.Embed embed = new DiscordMessage.Embed { author = new DiscordMessage.Embed.Author { name = authorName, url = authorUrl, icon_url = authorIconUrl }, title = embedTitle, url = embedURL, description = embedDescription, color = (int)embedList[6], fields = new List(), thumbnail = new DiscordMessage.Embed.ImageURL { url = imageUrl }, image = new DiscordMessage.Embed.ImageURL { url = thumbnailUrl }, footer = new DiscordMessage.Embed.Footer { text = footerText, icon_url = footerIconUrl } }; List> fields = embedList[7] as List>; if (fields != null) { for (int ii = 0; ii < fields.Count; ii++) { List fieldList = fields[ii] as List; if (fieldList == null) { PrintError($"\nUnable to read Field[{ii}] from Embed[{i}]."); continue; } if (fieldList.Count < 3) { PrintError($"\nField[{ii}] from Embed[{i}] has less than 3 objects and will not be added to the message."); continue; } string fieldName = fieldList[0] as string; if (fieldName == null) { PrintError($"\nThe first object (field name) from Field[{ii}] from Embed[{i}] is not a string and the whole field will not be added to the message."); continue; } string fieldValue = fieldList[1] as string; if (fieldValue == null) { PrintError($"\nThe second object (field value) from Field[{ii}] from Embed[{i}] is not a string and the whole field will not be added to the message."); continue; } if (!(fieldList[2] is bool)) { PrintError($"\nThe third object (field inline) from Field[{ii}] from Embed[{i}] is not a bool and the whole field will not be added to the message."); continue; } if (fieldName.Length > 256) { PrintWarning($"\nDiscord limits the amount of characters in embed's field's name to 256. Only the first 256 characters from the name of Field[{ii}] from Embed[{i}] will be added to the message."); } fieldName = Concatenate(fieldName, 256); if (fieldValue.Length > 1024) { PrintWarning($"\nDiscord limits the amount of characters in embed's field's value to 1024. Only the first 1024 characters from the value of Field[{ii}] from Embed[{i}] will be added to the message."); } fieldValue = Concatenate(fieldValue, 1024); if ((characters + fieldName.Length + fieldValue.Length) > 6000) { PrintError($"\nThe message would exceed the 6000 characters limit if Field[{ii}] from Embed[{i}] is added to the message. No more fields or embeds will be added to the message."); limit = true; break; } characters += fieldName.Length; characters += fieldValue.Length; DiscordMessage.Embed.Field field = new DiscordMessage.Embed.Field { name = fieldName, value = fieldValue, inline = (bool)fieldList[2] }; embed.fields.Add(field); if (ii < 24) { continue; } limit = true; PrintWarning($"\nDiscord limits the amount of fields to 25 per embed. Only the first 25 fields from Embed[{i}] will be added to the message."); break; } } DiscordMessage.Embed.Author author = embed.author; if (author.name.Length > 256) { PrintWarning($"\nDiscord limits the amount of characters in embed's author name to 256. Only the first 256 characters from the author name of Embed[{i}] will be added to the message."); } author.name = Concatenate(author.name, 256); characters += author.name.Length; if (!IsValidUrl(author.url, out author.url)) { PrintWarning($"\nThe author URL from Embed[{i}] is not a valid URL and will not be added to the message."); } if (!IsValidUrl(author.icon_url, out author.icon_url)) { PrintWarning($"\nThe author icon URL from Embed[{i}] is not a valid URL and will not be added to the message."); } if (embed.title.Length > 256) { PrintWarning($"\nDiscord limits the amount of characters in embed's title to 256. Only the first 256 characters from the title of Embed[{i}] will be added to the message."); } embed.title = Concatenate(embed.title, 256); characters += embed.title.Length; if (!IsValidUrl(embed.url, out embed.url)) { PrintWarning($"\nThe URL from Embed[{i}] is not a valid URL and will not be added to the message."); } if (embed.description.Length > 4096) { PrintWarning($"\nDiscord limits the amount of characters in embed's description to 4096. Only the first 4096 characters from the description of Embed[{i}] will be added to the message."); } embed.description = Concatenate(embed.description, 4096); characters += embed.description.Length; if (!IsValidUrl(embed.thumbnail.url, out embed.thumbnail.url)) { PrintWarning($"\nThe thumbnail image URL from Embed[{i}] is not a valid URL and will not be added to the message."); } if (!IsValidUrl(embed.image.url, out embed.image.url)) { PrintWarning($"\nThe image URL from Embed[{i}] is not a valid URL and will not be added to the message."); } DiscordMessage.Embed.Footer footer = embed.footer; if (footer.text.Length > 2048) { PrintWarning($"\nDiscord limits the amount of characters in embed's footer text to 2048. Only the first 2048 characters from the footer text of Embed[{i}] will be added to the message."); } footer.text = Concatenate(footer.text, 2048); characters += footer.text.Length; if (characters > 6000) { PrintError($"\nThe message would exceed the 6000 characters limit if Embed[{i}] is added to the message. No more embeds will be added to the message."); limit = true; break; } if (!IsValidUrl(footer.icon_url, out footer.icon_url)) { PrintWarning($"\nThe footer icon URL from Embed[{i}] is not a valid URL and will not be added to the message."); } message.embeds.Add(embed); if (i < 9) { continue; } limit = true; PrintWarning("\nDiscord limits the amount of embeds to 10 per message. Only the first 10 embeds will be added to the message."); break; } } webrequest.Enqueue( webhook, JsonConvert.SerializeObject(message), (c, r) => { if (c == 204) { PrintWarning("Discord message " + (limit ? "embeds PARTIALLY sent to avoid exceeding the 6000 characters limit." : "successfully sent.")); } else { PrintError($"Code {c}\n{JsonConvert.DeserializeObject(r)}"); } }, this, Core.Libraries.RequestMethod.POST, headers ); } static readonly Dictionary headers = new Dictionary { ["Content-Type"] = "application/json" }; string Concatenate(string s, int i) { if (string.IsNullOrEmpty(s) || s.Length <= i) { return s; } return s.Substring(0, i); } bool IsValidUrl(string s, out string url) { url = string.Empty; if (string.IsNullOrWhiteSpace(s)) { return true; } Uri uri; if (!Uri.TryCreate(s, UriKind.Absolute, out uri) || !(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) { return false; } url = s; return true; } class DiscordMessage { public string username; public string avatar_url; public string content; public bool tts; public List embeds; public class Embed { public Author author; public string title; public string url; public string description; public int color; public List fields; public ImageURL thumbnail; public ImageURL image; public Footer footer; public class Author { public string name; public string url; public string icon_url; } public class Field { public string name; public string value; public bool inline; } public class ImageURL { public string url; } public class Footer { public string text; public string icon_url; } } } } }