From c898027952dd5e5f384addceab930265d03b77d3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 24 Jan 2017 18:30:21 +0100 Subject: [PATCH] img and rimg will use google images first. if it fails, then fallback to imgur closes #970 --- src/NadekoBot/Modules/Searches/Searches.cs | 117 +++++++++++------- .../Services/Impl/GoogleApiService.cs | 40 +++++- 2 files changed, 113 insertions(+), 44 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 34ef1074..ad160599 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -115,33 +115,50 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(terms)) return; - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + try + { + var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") + .WithIconUrl("http://i.imgur.com/G46fm8J.png")) + .WithDescription(res.Link) + .WithImageUrl(res.Link) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + catch + { + _log.Warn("Falling back to Imgur search."); + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); - var fullQueryLink = $"http://imgur.com/search?q={ terms }"; - var config = Configuration.Default.WithDefaultLoader(); - var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + var fullQueryLink = $"http://imgur.com/search?q={ terms }"; + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); - var elems = document.QuerySelectorAll("a.image-list-link"); + var elems = document.QuerySelectorAll("a.image-list-link"); - if (!elems.Any()) - return; + if (!elems.Any()) + return; - var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement); + var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement); - if (img?.Source == null) - return; + if (img?.Source == null) + return; - var source = img.Source.Replace("b.", "."); + var source = img.Source.Replace("b.", "."); - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) - .WithUrl(fullQueryLink) - .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) - .WithDescription(source) - .WithImageUrl(source) - .WithTitle(Context.User.Mention); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl(fullQueryLink) + .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) + .WithDescription(source) + .WithImageUrl(source) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -150,34 +167,50 @@ namespace NadekoBot.Modules.Searches terms = terms?.Trim(); if (string.IsNullOrWhiteSpace(terms)) return; + try + { + var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") + .WithIconUrl("http://i.imgur.com/G46fm8J.png")) + .WithDescription(res.Link) + .WithImageUrl(res.Link) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + catch + { + _log.Warn("Falling back to Imgur"); + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + var fullQueryLink = $"http://imgur.com/search?q={ terms }"; + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); - var fullQueryLink = $"http://imgur.com/search?q={ terms }"; - var config = Configuration.Default.WithDefaultLoader(); - var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + var elems = document.QuerySelectorAll("a.image-list-link").ToList(); - var elems = document.QuerySelectorAll("a.image-list-link").ToList(); + if (!elems.Any()) + return; - if (!elems.Any()) - return; + var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement); - var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement); + if (img?.Source == null) + return; - if (img?.Source == null) - return; + var source = img.Source.Replace("b.", "."); - var source = img.Source.Replace("b.", "."); - - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) - .WithUrl(fullQueryLink) - .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) - .WithDescription(source) - .WithImageUrl(source) - .WithTitle(Context.User.Mention); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl(fullQueryLink) + .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) + .WithDescription(source) + .WithImageUrl(source) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -260,7 +293,7 @@ namespace NadekoBot.Modules.Searches .WithTitle(Context.User.Mention) .WithFooter(efb => efb.WithText(totalResults)); - var desc = await Task.WhenAll(results.Select(async res => + var desc = await Task.WhenAll(results.Select(async res => $"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n")) .ConfigureAwait(false); await Context.Channel.EmbedAsync(embed.WithDescription(String.Concat(desc))).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 7da7ad7b..f2934ba6 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -8,13 +8,19 @@ using System.Text.RegularExpressions; using Google.Apis.Urlshortener.v1; using Google.Apis.Urlshortener.v1.Data; using NLog; +using Google.Apis.Customsearch.v1; +using Google.Apis.Customsearch.v1.Data; namespace NadekoBot.Services.Impl { public class GoogleApiService : IGoogleApiService { + const string search_engine_id = "018084019232060951019:hs5piey28-e"; + private YouTubeService yt; private UrlshortenerService sh; + private CustomsearchService cs; + private Logger _log { get; } public GoogleApiService() @@ -22,13 +28,14 @@ namespace NadekoBot.Services.Impl var bcs = new BaseClientService.Initializer { ApplicationName = "Nadeko Bot", - ApiKey = NadekoBot.Credentials.GoogleApiKey + ApiKey = NadekoBot.Credentials.GoogleApiKey, }; _log = LogManager.GetCurrentClassLogger(); yt = new YouTubeService(bcs); sh = new UrlshortenerService(bcs); + cs = new CustomsearchService(bcs); } public async Task> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1) { @@ -150,7 +157,7 @@ namespace NadekoBot.Services.Impl return toReturn; } //todo AsyncEnumerable - public async Task> GetVideoDurationsAsync(IEnumerable videoIds) + public async Task> GetVideoDurationsAsync(IEnumerable videoIds) { var videoIdsList = videoIds as List ?? videoIds.ToList(); @@ -179,5 +186,34 @@ namespace NadekoBot.Services.Impl return toReturn; } + + public struct ImageResult + { + public Result.ImageData Image { get; } + public string Link { get; } + + public ImageResult(Result.ImageData image, string link) + { + this.Image = image; + this.Link = link; + } + } + + public async Task GetImageAsync(string query, int start = 0) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + var req = cs.Cse.List(query); + req.Cx = search_engine_id; + req.Num = 1; + req.Fields = "items(image(contextLink,thumbnailLink),link)"; + req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image; + req.Start = start; + + var search = await req.ExecuteAsync().ConfigureAwait(false); + + return new ImageResult(search.Items[0].Image, search.Items[0].Link); + } } }