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.

MessageHelper.cs 7.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using Discord.API.Rest;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.Immutable;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using Model = Discord.API.Message;
  8. namespace Discord.Rest
  9. {
  10. internal static class MessageHelper
  11. {
  12. public static async Task<Model> ModifyAsync(IMessage msg, BaseDiscordClient client, Action<MessageProperties> func,
  13. RequestOptions options)
  14. {
  15. var args = new MessageProperties();
  16. func(args);
  17. var apiArgs = new API.Rest.ModifyMessageParams
  18. {
  19. Content = args.Content,
  20. Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>()
  21. };
  22. return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false);
  23. }
  24. public static async Task DeleteAsync(IMessage msg, BaseDiscordClient client,
  25. RequestOptions options)
  26. {
  27. await client.ApiClient.DeleteMessageAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false);
  28. }
  29. public static async Task AddReactionAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options)
  30. {
  31. await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name, options).ConfigureAwait(false);
  32. }
  33. public static async Task RemoveReactionAsync(IMessage msg, IUser user, IEmote emote, BaseDiscordClient client, RequestOptions options)
  34. {
  35. await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, user.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name, options).ConfigureAwait(false);
  36. }
  37. public static async Task RemoveAllReactionsAsync(IMessage msg, BaseDiscordClient client, RequestOptions options)
  38. {
  39. await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options);
  40. }
  41. public static async Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IMessage msg, IEmote emote,
  42. Action<GetReactionUsersParams> func, BaseDiscordClient client, RequestOptions options)
  43. {
  44. var args = new GetReactionUsersParams();
  45. func(args);
  46. string emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name);
  47. return (await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false)).Select(u => RestUser.Create(client, u)).ToImmutableArray();
  48. }
  49. public static async Task PinAsync(IMessage msg, BaseDiscordClient client,
  50. RequestOptions options)
  51. {
  52. await client.ApiClient.AddPinAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false);
  53. }
  54. public static async Task UnpinAsync(IMessage msg, BaseDiscordClient client,
  55. RequestOptions options)
  56. {
  57. await client.ApiClient.RemovePinAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false);
  58. }
  59. public static ImmutableArray<ITag> ParseTags(string text, IMessageChannel channel, IGuild guild, IReadOnlyCollection<IUser> userMentions)
  60. {
  61. var tags = ImmutableArray.CreateBuilder<ITag>();
  62. int index = 0;
  63. while (true)
  64. {
  65. index = text.IndexOf('<', index);
  66. if (index == -1) break;
  67. int endIndex = text.IndexOf('>', index + 1);
  68. if (endIndex == -1) break;
  69. string content = text.Substring(index, endIndex - index + 1);
  70. if (MentionUtils.TryParseUser(content, out ulong id))
  71. {
  72. IUser mentionedUser = null;
  73. foreach (var mention in userMentions)
  74. {
  75. if (mention.Id == id)
  76. {
  77. mentionedUser = channel?.GetUserAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult();
  78. if (mentionedUser == null)
  79. mentionedUser = mention;
  80. break;
  81. }
  82. }
  83. tags.Add(new Tag<IUser>(TagType.UserMention, index, content.Length, id, mentionedUser));
  84. }
  85. else if (MentionUtils.TryParseChannel(content, out id))
  86. {
  87. IChannel mentionedChannel = null;
  88. if (guild != null)
  89. mentionedChannel = guild.GetChannelAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult();
  90. tags.Add(new Tag<IChannel>(TagType.ChannelMention, index, content.Length, id, mentionedChannel));
  91. }
  92. else if (MentionUtils.TryParseRole(content, out id))
  93. {
  94. IRole mentionedRole = null;
  95. if (guild != null)
  96. mentionedRole = guild.GetRole(id);
  97. tags.Add(new Tag<IRole>(TagType.RoleMention, index, content.Length, id, mentionedRole));
  98. }
  99. else if (Emote.TryParse(content, out var emoji))
  100. tags.Add(new Tag<Emote>(TagType.Emoji, index, content.Length, emoji.Id, emoji));
  101. else //Bad Tag
  102. {
  103. index = index + 1;
  104. continue;
  105. }
  106. index = endIndex + 1;
  107. }
  108. index = 0;
  109. while (true)
  110. {
  111. index = text.IndexOf("@everyone", index);
  112. if (index == -1) break;
  113. var tagIndex = FindIndex(tags, index);
  114. if (tagIndex.HasValue)
  115. tags.Insert(tagIndex.Value, new Tag<object>(TagType.EveryoneMention, index, "@everyone".Length, 0, null));
  116. index++;
  117. }
  118. index = 0;
  119. while (true)
  120. {
  121. index = text.IndexOf("@here", index);
  122. if (index == -1) break;
  123. var tagIndex = FindIndex(tags, index);
  124. if (tagIndex.HasValue)
  125. tags.Insert(tagIndex.Value, new Tag<object>(TagType.HereMention, index, "@here".Length, 0, null));
  126. index++;
  127. }
  128. return tags.ToImmutable();
  129. }
  130. private static int? FindIndex(IReadOnlyList<ITag> tags, int index)
  131. {
  132. int i = 0;
  133. for (; i < tags.Count; i++)
  134. {
  135. var tag = tags[i];
  136. if (index < tag.Index)
  137. break; //Position before this tag
  138. }
  139. if (i > 0 && index < tags[i - 1].Index + tags[i - 1].Length)
  140. return null; //Overlaps tag before this
  141. return i;
  142. }
  143. public static ImmutableArray<ulong> FilterTagsByKey(TagType type, ImmutableArray<ITag> tags)
  144. {
  145. return tags
  146. .Where(x => x.Type == type)
  147. .Select(x => x.Key)
  148. .ToImmutableArray();
  149. }
  150. public static ImmutableArray<T> FilterTagsByValue<T>(TagType type, ImmutableArray<ITag> tags)
  151. {
  152. return tags
  153. .Where(x => x.Type == type)
  154. .Select(x => (T)x.Value)
  155. .Where(x => x != null)
  156. .ToImmutableArray();
  157. }
  158. public static MessageSource GetSource(Model msg)
  159. {
  160. if (msg.Type != MessageType.Default)
  161. return MessageSource.System;
  162. else if (msg.WebhookId.IsSpecified)
  163. return MessageSource.Webhook;
  164. else if (msg.Author.GetValueOrDefault()?.Bot.GetValueOrDefault(false) == true)
  165. return MessageSource.Bot;
  166. return MessageSource.User;
  167. }
  168. }
  169. }