diff --git a/src/NadekoBot/Services/CustomReactions/Extensions.cs b/src/NadekoBot/Services/CustomReactions/Extensions.cs index 9f4444ed..e2c5481f 100644 --- a/src/NadekoBot/Services/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Services/CustomReactions/Extensions.cs @@ -1,10 +1,13 @@ -using Discord; +using AngleSharp; +using AngleSharp.Dom.Html; +using Discord; using Discord.WebSocket; using NadekoBot.DataStructures; using NadekoBot.Extensions; using NadekoBot.Services.Database.Models; using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -14,13 +17,7 @@ namespace NadekoBot.Services.CustomReactions { public static Dictionary> responsePlaceholders = new Dictionary>() { - {"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } } - }; - - public static Dictionary> placeholders = new Dictionary>() - { - {"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } }, - {"%user%", (ctx, client) => { return ctx.Author.Mention; } }, + {"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } }, {"%rnduser%", (ctx, client) => { //var ch = ctx.Channel as ITextChannel; //if(ch == null) @@ -40,15 +37,22 @@ namespace NadekoBot.Services.CustomReactions //var users = g.Users.ToArray(); //return users[new NadekoRandom().Next(0, users.Length-1)].Mention; - } } + } }, + }; + + public static Dictionary> placeholders = new Dictionary>() + { + {"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } }, + {"%user%", (ctx, client) => { return ctx.Author.Mention; } }, //{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } } }; private static readonly Regex rngRegex = new Regex("%rng(?:(?(?:-)?\\d+)-(?(?:-)?\\d+))?%", RegexOptions.Compiled); + private static readonly Regex imgRegex = new Regex("%(img|image):(?.*?)%", RegexOptions.Compiled); private static readonly NadekoRandom rng = new NadekoRandom(); - public static Dictionary regexPlaceholders = new Dictionary() + public static Dictionary>> regexPlaceholders = new Dictionary>>() { { rngRegex, (match) => { int from = 0; @@ -59,13 +63,34 @@ namespace NadekoBot.Services.CustomReactions if(from == 0 && to == 0) { - return rng.Next(0, 11).ToString(); + return Task.FromResult(rng.Next(0, 11).ToString()); } if(from >= to) + return Task.FromResult(string.Empty); + + return Task.FromResult(rng.Next(from,to+1).ToString()); + } }, + { imgRegex, async (match) => { + var tag = match.Groups["tag"].ToString(); + if(string.IsNullOrWhiteSpace(tag)) return ""; - return rng.Next(from,to+1).ToString(); + var fullQueryLink = $"http://imgur.com/search?q={ tag }"; + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + + var elems = document.QuerySelectorAll("a.image-list-link").ToArray(); + + if (!elems.Any()) + return ""; + + var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Length))?.Children?.FirstOrDefault() as IHtmlImageElement); + + if (img?.Source == null) + return ""; + + return " "+img.Source.Replace("b.", ".") + " "; } } }; @@ -73,26 +98,31 @@ namespace NadekoBot.Services.CustomReactions { foreach (var ph in placeholders) { - str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx, client)); + if (str.Contains(ph.Key)) + str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx, client)); } return str; } - private static string ResolveResponseString(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger) + private static async Task ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger) { foreach (var ph in placeholders) { - str = str.Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx, client)); + var lowerKey = ph.Key.ToLowerInvariant(); + if (str.Contains(lowerKey)) + str = str.Replace(lowerKey, ph.Value(ctx, client)); } foreach (var ph in responsePlaceholders) { - str = str.Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx, resolvedTrigger)); + var lowerKey = ph.Key.ToLowerInvariant(); + if (str.Contains(lowerKey)) + str = str.Replace(lowerKey, ph.Value(ctx, resolvedTrigger)); } foreach (var ph in regexPlaceholders) { - str = ph.Key.Replace(str, ph.Value); + str = await ph.Key.ReplaceAsync(str, ph.Value); } return str; } @@ -100,8 +130,8 @@ namespace NadekoBot.Services.CustomReactions public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) => cr.Trigger.ResolveTriggerString(ctx, client); - public static string ResponseWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) - => cr.Response.ResolveResponseString(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client)); + public static Task ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) + => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client)); public static async Task Send(this CustomReaction cr, IUserMessage context, DiscordShardedClient client, CustomReactionsService crs) { @@ -113,7 +143,7 @@ namespace NadekoBot.Services.CustomReactions { return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); } - return await channel.SendMessageAsync(cr.ResponseWithContext(context, client).SanitizeMentions()); + return await channel.SendMessageAsync((await cr.ResponseWithContextAsync(context, client)).SanitizeMentions()); } } } diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 4520ebd4..cafb5d32 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -11,6 +11,7 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Security.Cryptography; +using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -18,6 +19,23 @@ namespace NadekoBot.Extensions { public static class Extensions { + public static async Task ReplaceAsync(this Regex regex, string input, Func> replacementFn) + { + var sb = new StringBuilder(); + var lastIndex = 0; + + foreach (Match match in regex.Matches(input)) + { + sb.Append(input, lastIndex, match.Index - lastIndex) + .Append(await replacementFn(match).ConfigureAwait(false)); + + lastIndex = match.Index + match.Length; + } + + sb.Append(input, lastIndex, input.Length - lastIndex); + return sb.ToString(); + } + public static void ThrowIfNull(this T obj, string name) where T : class { if (obj == null)