private Executable GetSafariExe(EmbedBuilder embed, IUserMessage msg, Card newCard, SafariImage pokeImage, ICharacterInfo character, ITextChannel trashChannel, IUser winner) { return(new Executable("safari", new Task(() => { using (var db = new Database.UserContext(_config)) { var botUser = db.GetUserOrCreateAsync(winner.Id).Result; newCard.FirstIdOwner = winner.Id; newCard.Affection += botUser.GameDeck.AffectionFromKarma(); botUser.GameDeck.RemoveCharacterFromWishList(newCard.Character); botUser.GameDeck.Cards.Add(newCard); db.SaveChanges(); QueryCacheManager.ExpireTag(new string[] { $"user-{botUser.Id}", "users" }); using (var dba = new Database.AnalyticsContext(_config)) { dba.UsersData.Add(new Database.Models.Analytics.UserAnalytics { Value = 1, UserId = winner.Id, MeasureDate = DateTime.Now, GuildId = trashChannel?.Guild?.Id ?? 0, Type = Database.Models.Analytics.UserAnalyticsEventType.Card }); dba.SaveChanges(); } } _ = Task.Run(async() => { try { embed.ImageUrl = await _waifu.GetSafariViewAsync(pokeImage, newCard, trashChannel); embed.Description = $"{winner.Mention} zdobył na polowaniu i wsadził do klatki:\n" + $"{newCard.GetString(false, false, true)}\n({newCard.Title})"; await msg.ModifyAsync(x => x.Embed = embed.Build()); var privEmb = new EmbedBuilder() { Color = EMType.Info.Color(), Description = $"Na [polowaniu]({msg.GetJumpUrl()}) zdobyłeś: {newCard.GetString(false, false, true)}" }; var priv = await winner.GetOrCreateDMChannelAsync(); if (priv != null) { await priv.SendMessageAsync("", false, privEmb.Build()); } } catch (Exception ex) { _logger.Log($"In Safari: {ex}"); } }); }))); }
public async Task AddSubmissionMessagesAsync(IMessage[] messages) { ReviewInfo info = null; foreach (IMessage message in messages) { IUserMessage user_message = message as IUserMessage; if (user_message is null) { continue; } // Consider sequences of messages by the same user to be part of the same submission. // If there is a signficant amount of time between messages, consider them separate submissions. long max_seconds_difference = 60 * 60 * 1; // 1 hour if (info is null || info.SubmitterUserId != user_message.Author.Id || Math.Abs(user_message.Timestamp.ToUnixTimeSeconds() - info.SubmissionTimestamp) > max_seconds_difference) { _review_info.Add(new ReviewInfo { SubmissionMessageUrl = user_message.GetJumpUrl(), SubmissionChannelId = user_message.Channel.Id, SubmissionMessageId = user_message.Id, SubmitterUserId = user_message.Author.Id, Title = _generateReviewTitle(user_message.Content), SubmissionTimestamp = user_message.Timestamp.ToUnixTimeSeconds() }); info = _review_info.Last(); } if (info.ReviewerUserId <= 0) { // Check the message reactions to determine the state of the review, as well as the reviewer. ulong reviewer_id = 0; if ((reviewer_id = await _getReviewIdFromReactionAsync(user_message, new Emoji("✅"))) > 0) { info.Status = ReviewStatus.Accepted; } else if ((reviewer_id = await _getReviewIdFromReactionAsync(user_message, new Emoji("📝"))) > 0) { info.Status = ReviewStatus.InReview; } else if ((reviewer_id = await _getReviewIdFromReactionAsync(user_message, new Emoji("❌"))) > 0) { info.Status = ReviewStatus.Denied; } if (reviewer_id > 0) { info.ReviewerUserId = reviewer_id; } } } }
/// <summary> /// Sends the notitificatoin about a reached threshold to the starboard log post target. /// The notification containsn the user causing the change and a link to the starred message. /// </summary> /// <param name="text">The text of the notification</param> /// <param name="user">The <see cref="Discord.IUser"> adding/removing the reaction</param> /// <param name="message">The starred <see cref="Discord.IUserMessage"> for which the reaction was added/removed</param> /// <returns></returns> protected async Task SendNotification(string text, IUser user, IUserMessage message) { var notificationBuilder = new EmbedBuilder(); var userFormatted = Extensions.FormatUserNameDetailed(user); var messageLink = $"[Here]({message.GetJumpUrl()})"; notificationBuilder.WithDescription(text); notificationBuilder.AddField("User", userFormatted); notificationBuilder.AddField("Link", messageLink); notificationBuilder.WithThumbnailUrl(user.GetAvatarUrl()); var guild = Global.Bot.GetGuild(Global.ServerID); var target = guild.GetTextChannel(Global.PostTargets[PostTarget.STARBOARD_LOG]); await target.SendMessageAsync(embed : notificationBuilder.Build()); }
internal async Task <string> UpdateSuggestion(GuildSettings gset, ulong id, string status) { var suggestionChannel = gset.GetChannel(GuildSettings.AssignedChannels.Suggestion); if (suggestionChannel == null) { throw NeitsilliaError.ReplyError("Suggestions are currently deactivated."); } IUserMessage msg = (IUserMessage)await suggestionChannel.GetMessageAsync(id); if (msg == null) { throw NeitsilliaError.ReplyError("Message not found."); } else if (msg.Author.Id != Program.clientCopy.CurrentUser.Id) { throw NeitsilliaError.ReplyError("Message not sent by this bot."); } IEmbed[] embeds = Enumerable.ToArray(msg.Embeds); if (embeds.Length < 1) { await msg.DeleteAsync(); throw NeitsilliaError.ReplyError("Message had no embeds and was deleted."); } EmbedAuthor a = (EmbedAuthor)embeds[0].Author; string footer = ((EmbedFooter)embeds[0].Footer).Text; EmbedBuilder embed = DUtils.BuildEmbed(null, embeds[0].Description, footer, embeds[0].Color ?? new Color(), DUtils.NewField("Reply", status)); embed.WithAuthor(a.Name, a.IconUrl, a.Url); await msg.ModifyAsync(x => { x.Embed = embed.Build(); }); if (ulong.TryParse(footer, out ulong userId)) { Program.clientCopy.GetUser(userId)?.SendMessageAsync("Your suggestion has a new response.", embed: embed.Build()); } return(msg.GetJumpUrl()); }
private Executable GetSafariExe(EmbedBuilder embed, IUserMessage msg, Card newCard, SafariImage pokeImage, ICharacterInfo character, ITextChannel trashChannel, IUser winner) { return(new Executable("safari", new Task(() => { using (var db = new Database.UserContext(_config)) { var botUser = db.GetUserOrCreateAsync(winner.Id).Result; botUser.GameDeck.Cards.Add(newCard); db.SaveChanges(); QueryCacheManager.ExpireTag(new string[] { $"user-{botUser.Id}", "users" }); } _ = Task.Run(async() => { try { embed.ImageUrl = await _waifu.GetSafariViewAsync(pokeImage, character, newCard, trashChannel); embed.Description = $"{winner.Mention} zdobył na polowaniu i wsadził do klatki:\n" + $"{newCard.GetString(false, false, true)}\n({newCard.Title})"; await msg.ModifyAsync(x => x.Embed = embed.Build()); var privEmb = new EmbedBuilder() { Color = EMType.Info.Color(), Description = $"Na [polowaniu]({msg.GetJumpUrl()}) zdobyłeś: {newCard.GetString(false, false, true)}" }; var priv = await winner.GetOrCreateDMChannelAsync(); if (priv != null) { await priv.SendMessageAsync("", false, privEmb.Build()); } } catch (Exception ex) { _logger.Log($"In Safari: {ex}"); } }); }))); }
public async Task <Issue> CreateIssue(IUserMessage message, string title, params string[] labels) { var ghClient = new GitHubClient(new ProductHeaderValue("OctcordBot")); ghClient.Credentials = new Credentials(_config["github_token"]); var newIssue = new NewIssue(title); foreach (string label in labels) { newIssue.Labels.Add(label); } var issueBody = new StringBuilder(); issueBody.AppendLine($"**{message.Author.Username} at {message.Timestamp}**"); using (var reader = new StringReader(message.Content)) { string line; while ((line = reader.ReadLine()) != null) { issueBody.AppendLine($"> {line}"); } } issueBody.AppendLine(); foreach (var embed in message.Embeds.Where(embeds => !string.IsNullOrEmpty(embeds.Url))) { issueBody.AppendLine(embed.Url); } issueBody.AppendLine(); issueBody.AppendLine($"REF: {message.GetJumpUrl()}"); newIssue.Body = issueBody.ToString(); return(await ghClient.Issue.Create(_config["github_owner"], _config["github_repo"], newIssue)); }
private async Task <IUserMessage> PostAndCacheMessage(IUserMessage msg, ITextChannel starboardChannel, int reactionCount) { var eb = new EmbedBuilder() { Color = SoraSocketCommandModule.Purple, Author = new EmbedAuthorBuilder() { IconUrl = msg.Author.GetAvatarUrl() ?? msg.Author.GetDefaultAvatarUrl(), Name = Formatter.UsernameDiscrim(msg.Author) } }; if (!TryAddImageAttachment(msg, eb)) // First check if there's an attached image { if (!TryAddImageLink(msg, eb)) // Check if there's an image link { TryAddArticleThumbnail(msg, eb); // Is it a link? } } // Otherwise make a normal embed if (!string.IsNullOrWhiteSpace(msg.Content)) { eb.WithDescription(msg.Content); } eb.AddField("Posted in", $"[#{msg.Channel.Name} (take me!)]({msg.GetJumpUrl()})"); eb.WithTimestamp(msg.Timestamp); var postedMsg = await starboardChannel .SendMessageAsync($"**{reactionCount.ToString()}** {STAR_EMOTE}", embed : eb.Build()) .ConfigureAwait(false); _cache.Set(CacheId.GetMessageId(postedMsg.Id), postedMsg, _postedMsgTtl); return(postedMsg); }
public async Task ProcessVoteCommandAsync(IUserMessage voteCommandMessage, string voteDefinitionText) { if (voteCommandMessage.Channel is not IGuildChannel guildChannel) { return; } var parse = await Parser.TryParse(new CommandContext(Client, voteCommandMessage), voteDefinitionText); if (!parse.Success) { await UpdateVoteReplyAsync(voteCommandMessage, parse.ProblemDescription); return; } var allEmotes = new HashSet <IEmote>(parse.Definition.Options.Keys); allEmotes.UnionWith(voteCommandMessage.Reactions.Keys); var failedEmotes = new List <IEmote>(); var summary = ComposeSummary(voteCommandMessage, parse.Definition); foreach (var emote in allEmotes) { var shouldBePresent = parse.Definition.Options.ContainsKey(emote); var isPresent = voteCommandMessage.Reactions.TryGetValue(emote, out var reaction); if (!shouldBePresent && isPresent) { await voteCommandMessage.RemoveAllReactionsForEmoteAsync(emote); } else if (shouldBePresent && !isPresent) { try { await voteCommandMessage.AddReactionAsync(emote); } catch (HttpException) { failedEmotes.Add(emote); } } } var tail = failedEmotes.Count == 0 ? string.Empty : Environment.NewLine + string.Format( VoteTranslations.UnaccessibleEmotes, new FormatByValue(failedEmotes.Count), string.Join(", ", failedEmotes.Select(e => $"`{e}`")) ); await UpdateVoteReplyAsync(voteCommandMessage, summary + tail); if (parse.Definition.Deadline is DateTimeOffset votingDeadline) { var scheduledTaskTag = voteCommandMessage.GetJumpUrl(); var previouslyScheduledEndsOfVote = await ScheduledTasksService.LookupAsync(EndOfVotingScheduledTask.Identifier, scheduledTaskTag); foreach (var endOfVoteTask in previouslyScheduledEndsOfVote) { await ScheduledTasksService.CancelAsync(endOfVoteTask.ScheduledTaskId); } await ScheduledTasksService.EnqueueAsync(new ScheduledTask { Discriminator = EndOfVotingScheduledTask.Identifier, Tag = scheduledTaskTag, When = votingDeadline, Data = JsonConvert.SerializeObject(new EndOfVotingScheduledTask { GuildId = guildChannel.GuildId, ChannelId = guildChannel.Id, MessageId = voteCommandMessage.Id }) }); } }
private Embed GetStarEmbed(IUserMessage message, Color color) { var author = message.Author as IGuildUser; var embed = _quoteService.BuildQuoteEmbed(message, author) .WithTimestamp(message.Timestamp) .WithColor(color) .WithUserAsAuthor(author); embed.Description = new StringBuilder() .AppendLine($"_Posted in **[#{message.Channel.Name}]({message.GetJumpUrl()})**_") .AppendLine() .AppendLine("**Message**") .AppendLine(embed.Description) .ToString(); embed.Fields.RemoveAt(embed.Fields.Count - 1); //Remove the "Quoted by" field embed.Footer = null; return(embed.Build()); }
public async Task ScheduleAsync([Remainder] string content) // Schedules a sink. { var guildConfig = Db.Guilds.FirstOrDefault(g => g.Id == Context.Guild.Id); if (guildConfig == null) { return; } if (Context.Channel.Id != guildConfig.ScheduleInputChannel) { return; } var prefix = guildConfig.Prefix == ' ' ? Db.Config.Prefix : guildConfig.Prefix; var splitIndex = content.IndexOf("|", StringComparison.Ordinal); if (splitIndex == -1) { await ReplyAsync($"{Context.User.Mention}, please provide parameters with that command.\n" + "A well-formed command would look something like:\n" + $"`{prefix}schedule OZ Tuesday 5:00PM | This is a fancy description!`"); return; } var parameters = content.Substring(0, splitIndex).Trim(); var description = content.Substring(splitIndex + 1).Trim(); if (parameters.IndexOf(":", StringComparison.Ordinal) == -1) { await ReplyAsync($"{Context.User.Mention}, please specify a time for your run in your command!"); return; } var coolParameters = RegexSearches.Whitespace.Split(parameters); if (coolParameters.Length == 0) { await ReplyAsync($"{Context.User.Mention}, please provide parameters with that command.\n" + "A well-formed command would look something like:\n" + $"`{prefix}schedule OZ Tuesday 5:00PM | This is a fancy description!`"); return; } IUserMessage message = Context.Message; var multiplier = 1; for (var i = 0; i < multiplier; i++) { if (i != 0) { message = await ReplyAsync($"This message carries the RSVPs for run {i + 1} of this sequence."); } var @event = new ScheduledEvent { Description = description, LeaderId = Context.User.Id, GuildId = Context.Guild.Id, MessageId3 = message.Id, SubscribedUsers = new List <string>(), }; foreach (var coolParameter in coolParameters) { if (RegexSearches.Multiplier.Match(coolParameter).Success) { multiplier = int.Parse(RegexSearches.NonNumbers.Replace(coolParameter, string.Empty)); if (multiplier > 12) { await ReplyAsync( $"{Context.User.Mention}, for your own sake, you cannot schedule more than 36 hours-worth of runs at a time."); return; } } foreach (var runType in Enum.GetNames(typeof(RunDisplayTypeBA))) { if (string.Equals(coolParameter, runType, StringComparison.InvariantCultureIgnoreCase)) { @event.RunKind = Enum.Parse <RunDisplayTypeBA>(runType, true); break; } } } if (Context.Channel.Id == guildConfig.ScheduleInputChannel) { if (!Enum.IsDefined(typeof(RunDisplayTypeBA), @event.RunKind)) { await ReplyAsync( $"{Context.User.Mention}, please specify a kind of run in your parameter list.\n" + $"Run kinds include: `[{string.Join(' ', Enum.GetNames(typeof(RunDisplayTypeBA)))}]`"); return; } } else { @event.RunKindCastrum = RunDisplayTypeCastrum.LL; } DateTime runTime; try { runTime = Util.GetDateTime(parameters).AddHours(3 * i); } catch (ArgumentOutOfRangeException) { await ReplyAsync($"{Context.User.Mention}, that date or time is invalid."); return; } if (!await RuntimeIsValid(runTime)) { return; } @event.RunTime = runTime.ToBinary(); var tzi = TimeZoneInfo.FindSystemTimeZoneById(Util.PstIdString()); var tzAbbrs = TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US"); var tzAbbr = tzi.IsDaylightSavingTime(DateTime.Now) ? tzAbbrs.Daylight : tzAbbrs.Standard; await Context.Channel.SendMessageAsync( $"{Context.User.Mention} has just scheduled a run on {runTime.DayOfWeek} at {runTime.ToShortTimeString()} ({tzAbbr})!\n" + $"React to the 📳 on their message to be notified 30 minutes before it begins!"); await message.AddReactionAsync(new Emoji("📳")); var color = @event.RunKindCastrum == RunDisplayTypeCastrum.None ? RunDisplayTypes.GetColor(@event.RunKind) : RunDisplayTypes.GetColorCastrum(); var leaderName = (Context.User as IGuildUser)?.Nickname ?? Context.User.Username; if (Context.Channel.Id == guildConfig.ScheduleInputChannel) { var embed = new EmbedBuilder() .WithTitle( $"Run scheduled by {leaderName} on {runTime.DayOfWeek} at {runTime.ToShortTimeString()} ({tzAbbr}) " + $"[{runTime.DayOfWeek}, {(Month) runTime.Month} {runTime.Day}]!") .WithColor(new Color(color.RGB[0], color.RGB[1], color.RGB[2])) .WithDescription( "React to the :vibration_mode: on their message to be notified 30 minutes before it begins!\n\n" + $"**{Context.User.Mention}'s full message: {message.GetJumpUrl()}**\n\n" + $"{new string(@event.Description.Take(1650).ToArray())}{(@event.Description.Length > 1650 ? "..." : "")}\n\n" + $"**Schedule Overview: <{guildConfig.BASpreadsheetLink}>**") .WithFooter(footer => { footer.Text = "Localized time:"; }) .WithTimestamp(runTime.AddHours(-tzi.BaseUtcOffset.Hours)) .Build(); var scheduleOutputChannel = Context.Guild.GetTextChannel(guildConfig.ScheduleOutputChannel); var embedMessage = await scheduleOutputChannel.SendMessageAsync(embed : embed); @event.EmbedMessageId = embedMessage.Id; await Db.AddScheduledEvent(@event); await Sheets.AddEvent(@event, guildConfig.BASpreadsheetId); } } }
public async Task OnReactionAdded(Cacheable <IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction) { ulong currentGuild = ((SocketGuildChannel)channel).Guild.Id; // return when currentGuild isn't in _StarEmote if (!_StarEmote.ContainsKey(currentGuild)) { return; } // we support both 'Emote' and 'Emoji', // so check the type if (_StarEmote[currentGuild].GetType() == typeof(Emote)) { // return when it's not the 'Emote' we need if (!((Emote)_StarEmote[currentGuild]).Equals(reaction.Emote)) { return; } } else { // return when it's not the 'Emoji' we need if (!((Emoji)_StarEmote[currentGuild]).Equals(reaction.Emote)) { return; } } // return when it's in a StarBoard channel if (_StarBoardMessageChannel[currentGuild].Id == channel.Id) { return; } IUserMessage msg = message.GetOrDownloadAsync().Result; // return when we failed to retrieve the message if (msg == null) { return; } // discard everything that's >=24 hours old if (msg.Timestamp <= DateTime.Now.AddHours(-24)) { return; } lock (_StarredMessagesLock) { int emoteCount = (msg.GetReactionUsersAsync((IEmote)_StarEmote[currentGuild], _StarEmoteAmount[currentGuild]).FlattenAsync()).Result.Count(); // once we have less emotes than required // or if it's already starred, // return if (emoteCount < _StarEmoteAmount[currentGuild] || _StarredMessages[currentGuild].Contains(msg.Id)) { return; } // store the message id in a List _StarredMessages[currentGuild].Add(msg.Id); // strip _PinnedMessages once the limit has been reached while (_StarredMessages[currentGuild].Count > _StarredMessagesLimitPerGuild) { _StarredMessages[currentGuild].RemoveAt(0); } } await DiscordHelper.SendEmbed(new EmbedBuilder() { Author = new EmbedAuthorBuilder() { Name = DiscordHelper.GetUserName(msg.Author), IconUrl = msg.Author.GetAvatarUrl(), Url = msg.GetJumpUrl() }, Description = DiscordHelper.GetMessageContent(msg), ImageUrl = msg.Attachments.Count != 0 ? msg.Attachments.First().ProxyUrl : null, Timestamp = msg.Timestamp, Footer = new EmbedFooterBuilder() { Text = $"#{msg.Channel.Name} • {msg.Id}" } }, _StarBoardMessageChannel[currentGuild]); }
private async Task SendToBestChannelAsync(IUserMessage userMessage) { if (alreadyBest.Contains(userMessage.Id) || !settings.SourceChannelIds.Contains(userMessage.Channel.Id) || userMessage.Channel.Id == settings.BestChannelId) { return; } if (!userMessage.Reactions .Where(x => x.Key.Name != "tip") .Any(r => r.Value.ReactionCount >= settings.ReactionCountToBeBest)) { return; } alreadyBest.Add(userMessage.Id); var emotes = string.Join("", userMessage .Reactions .OrderByDescending(r => r.Value.ReactionCount) .SelectMany(e => Enumerable.Repeat(Core.ToEmojiString(e.Key.Name), e.Value.ReactionCount))); var description = userMessage.Content.StartsWith("https://") ? userMessage.Content : $"[оригинал]({userMessage.GetJumpUrl()})\n{emotes}"; var embed = new EmbedBuilder() .WithAuthor(userMessage.Author) .WithTitle(userMessage.Content.Length > 250 ? "Длиннопост" : userMessage.Content) .WithFooter("#бичехосты-лучшее") .WithDescription(userMessage.Content.Length > 250 ? userMessage.Content + " " + description : description) .WithTimestamp(userMessage.Timestamp); if (userMessage.Attachments.Count > 0) { embed.WithImageUrl(userMessage.Attachments.First().Url); } await Core.Guild.GetTextChannel(settings.BestChannelId).SendMessageAsync(embed: embed.Build()) .ConfigureAwait(false); IUser GetRecipient() { if (userMessage.Author.IsBot && userMessage.Content.StartsWith("Шляпа от") && userMessage.MentionedUserIds.Count > 0) { return(Core.Guild.GetUser(userMessage.MentionedUserIds.First())); } return(userMessage.Author); } var recipient = GetRecipient(); var newAmount = Core.Bank.Add(recipient.Id, settings.Reward); if (newAmount.IsFail) { await userMessage.Channel .SendMessageAsync( $"{recipient.Username} попадает в лучшее, но не получает награду: {newAmount.Error}") .ConfigureAwait(false); } else { await userMessage.Channel .SendMessageAsync( $"{recipient.Username} получает {settings.Reward} ({newAmount.Value}) бичекоинов за попадание в лучшее") .ConfigureAwait(false); } }
public async Task WarnWithSizeUserAsync([RequireHierarchy] UserRef userRef, float size, [Remainder] string reason) { IUserMessage logMessage = await DiscordLogging.LogWarn(Context.Guild, Context.Message.Author, userRef.ID, reason, Context.Message.GetJumpUrl()); WarnResult result = await userRef.Warn(size, reason, Context.Channel as ITextChannel, logLink : logMessage?.GetJumpUrl()); if (result.success) { Context.Message.DeleteOrRespond($"{userRef.Mention()} has gotten their {result.warnsAmount.Suffix()} infraction for {reason}", Context.Guild); } else { if (logMessage != null) { DiscordLogging.deletedMessagesCache.Enqueue(logMessage.Id); await logMessage.DeleteAsync(); } await ReplyAsync(result.description.Truncate(1500)); } }
/// <summary> /// Creates an embed containing the starred message and a field containing al link to the starred message /// </summary> /// <param name="message">The <see cref="Discord.IUserMessage"> object containing the message which is getting starred.</param> /// <returns>The rendered embed containing the desired info</returns> private Embed GetStarboardEmbed(IUserMessage message) { var builder = Extensions.GetMessageAsEmbed(message); builder.AddField("Original", OnePlusBot.Helpers.Extensions.FormatLinkWithDisplay("Jump!", message.GetJumpUrl())); return(builder.Build()); }
public async Task Translate(IUserMessage arg, IUser manualRequester, string language) { if (!(Watched.TryGetValue(arg.Author.Id, out var users))) { if (manualRequester == null) { return; // manual request doesn't need to send to all users, so we can continue } } if (users != null && users.Count == 0) { Watched.Remove(arg.Author.Id); if (manualRequester == null) { return; } } var client = TranslationClient.Create(); var response = await client.TranslateTextAsync(arg.Content, language); if (response.DetectedSourceLanguage == language) { if (manualRequester != null) { await manualRequester.SendMessageAsync($"Message has same detected language as wanting to translate into."); } } else { var embedB = new EmbedBuilder(); embedB.Title = $"Translation from {LanguageCodesUtils.ToName(response.DetectedSourceLanguage)}"; embedB.Url = arg.GetJumpUrl(); embedB.WithFooter(arg.Author.Username, arg.Author.GetAnyAvatarUrl()); embedB.Description = response.TranslatedText; if (response.OriginalText.Length > 1024) { embedB.AddField($"Original, part 1", Program.Clamp(response.OriginalText, 1024)); // 0 -> 1023 // 1024 -> embedB.AddField($"Original, part 2", response.OriginalText.Substring(1024)); } else { embedB.AddField("Original", Program.Clamp(response.OriginalText, 1024)); } var embed = embedB.Build(); if (manualRequester != null) { await manualRequester.SendMessageAsync(embed : embed); return; } var rm = new List <ulong>(); foreach (var id in users) { var usr = Program.Client.GetUser(id); if (usr == null) { rm.Add(id); continue; } await usr.SendMessageAsync(embed : embed); } foreach (var x in rm) { users.Remove(x); } if (rm.Count > 0) { Watched[arg.Author.Id] = users; this.OnSave(); } } }