diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs index cfbcb729..bf4374ad 100644 --- a/NadekoBot/Classes/Extensions.cs +++ b/NadekoBot/Classes/Extensions.cs @@ -8,6 +8,7 @@ using Discord; using NadekoBot.Modules; using System.IO; using System.Drawing; +using NadekoBot.Classes; namespace NadekoBot.Extensions { public static class Extensions @@ -152,7 +153,7 @@ namespace NadekoBot.Extensions { /// /// /// - public static async Task ShortenUrl(this string str) => await Searches.ShortenUrl(str); + public static async Task ShortenUrl(this string str) => await SearchHelper.ShortenUrl(str); /// /// Gets the program runtime diff --git a/NadekoBot/Classes/Music/SoundCloud.cs b/NadekoBot/Classes/Music/SoundCloud.cs index b8a95690..207e45e6 100644 --- a/NadekoBot/Classes/Music/SoundCloud.cs +++ b/NadekoBot/Classes/Music/SoundCloud.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Classes.Music { if (string.IsNullOrWhiteSpace(NadekoBot.creds.SoundCloudClientID)) throw new ArgumentNullException(nameof(NadekoBot.creds.SoundCloudClientID)); - var response = await Modules.Searches.GetResponseAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.creds.SoundCloudClientID}"); + var response = await SearchHelper.GetResponseAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.creds.SoundCloudClientID}"); var responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject(response); if (responseObj?.Kind != "track") diff --git a/NadekoBot/Classes/Music/StreamRequest.cs b/NadekoBot/Classes/Music/StreamRequest.cs index 1ee7692a..53fbd40d 100644 --- a/NadekoBot/Classes/Music/StreamRequest.cs +++ b/NadekoBot/Classes/Music/StreamRequest.cs @@ -78,7 +78,7 @@ namespace NadekoBot.Classes.Music { if (OnResolving != null) OnResolving(); - var links = await Searches.FindYoutubeUrlByKeywords(Query); + var links = await SearchHelper.FindYoutubeUrlByKeywords(Query); var allVideos = await YouTube.Default.GetAllVideosAsync(links); var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio); var video = videos diff --git a/NadekoBot/Classes/PermissionCheckers/NSWFPermissionChecker.cs b/NadekoBot/Classes/PermissionCheckers/NSWFPermissionChecker.cs new file mode 100644 index 00000000..6d22f09c --- /dev/null +++ b/NadekoBot/Classes/PermissionCheckers/NSWFPermissionChecker.cs @@ -0,0 +1,18 @@ +using Discord.Commands.Permissions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; + +namespace NadekoBot.Classes.PermissionCheckers { + class NSFWPermissionChecker : PermissionChecker { + public override bool CanRun(Command command, User user, Channel channel, out string error) { + error = string.Empty; + Console.WriteLine(command.Category); + return false; + } + } +} diff --git a/NadekoBot/Classes/PermissionCheckers/PermissionChecker.cs b/NadekoBot/Classes/PermissionCheckers/PermissionChecker.cs new file mode 100644 index 00000000..61fa4d7c --- /dev/null +++ b/NadekoBot/Classes/PermissionCheckers/PermissionChecker.cs @@ -0,0 +1,17 @@ +using Discord.Commands.Permissions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; + +namespace NadekoBot.Classes.PermissionCheckers { + abstract class PermissionChecker : IPermissionChecker where T : new() { + public static readonly T _instance = new T(); + public static T Instance => _instance; + + public abstract bool CanRun(Command command, User user, Channel channel, out string error); + } +} diff --git a/NadekoBot/Classes/SearchHelper.cs b/NadekoBot/Classes/SearchHelper.cs new file mode 100644 index 00000000..12197f55 --- /dev/null +++ b/NadekoBot/Classes/SearchHelper.cs @@ -0,0 +1,219 @@ +using NadekoBot.Extensions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace NadekoBot.Classes { + static class SearchHelper { + public static async Task GetResponseStream(string v) { + var wr = (HttpWebRequest)WebRequest.Create(v); + try { + return (await (wr).GetResponseAsync()).GetResponseStream(); + } catch (Exception ex) { + Console.WriteLine("error in getresponse stream " + ex); + return null; + } + } + + public static async Task GetResponseAsync(string v) => + await new StreamReader((await ((HttpWebRequest)WebRequest.Create(v)).GetResponseAsync()).GetResponseStream()).ReadToEndAsync(); + + public static async Task GetResponseAsync(string v, IEnumerable> headers) { + var wr = (HttpWebRequest)WebRequest.Create(v); + foreach (var header in headers) { + wr.Headers.Add(header.Item1, header.Item2); + } + return await new StreamReader((await wr.GetResponseAsync()).GetResponseStream()).ReadToEndAsync(); + } + + private static string token = ""; + public static async Task GetAnimeQueryResultLink(string query) { + try { + var cl = new RestSharp.RestClient("http://anilist.co/api"); + var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); + + RefreshAnilistToken(); + + rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query)); + rq.AddParameter("access_token", token); + + var smallObj = JArray.Parse(cl.Execute(rq).Content)[0]; + + rq = new RestSharp.RestRequest("anime/" + smallObj["id"]); + rq.AddParameter("access_token", token); + return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content)); + } catch (Exception) { + return null; + } + } + //todo kick out RestSharp and make it truly async + public static async Task GetMangaQueryResultLink(string query) { + try { + RefreshAnilistToken(); + + var cl = new RestSharp.RestClient("http://anilist.co/api"); + var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); + rq = new RestSharp.RestRequest("/manga/search/" + Uri.EscapeUriString(query)); + rq.AddParameter("access_token", token); + + var smallObj = JArray.Parse(cl.Execute(rq).Content)[0]; + + rq = new RestSharp.RestRequest("manga/" + smallObj["id"]); + rq.AddParameter("access_token", token); + return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content)); + } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + return null; + } + } + + private static void RefreshAnilistToken() { + try { + var cl = new RestSharp.RestClient("http://anilist.co/api"); + var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); + rq.AddParameter("grant_type", "client_credentials"); + rq.AddParameter("client_id", "kwoth-w0ki9"); + rq.AddParameter("client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"); + var exec = cl.Execute(rq); + + token = JObject.Parse(exec.Content)["access_token"].ToString(); + } catch (Exception ex) { + Console.WriteLine($"Failed refreshing anilist token:\n {ex}"); + } + } + + public static async Task ValidateQuery(Discord.Channel ch, string query) { + if (string.IsNullOrEmpty(query.Trim())) { + await ch.Send("Please specify search parameters."); + return false; + } + return true; + } + + public static async Task FindYoutubeUrlByKeywords(string v) { + if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { + Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); + return @"https://www.youtube.com/watch?v=dQw4w9WgXcQ"; + } + try { + //maybe it is already a youtube url, in which case we will just extract the id and prepend it with youtube.com?v= + var match = new Regex("(?:youtu\\.be\\/|v=)(?[\\da-zA-Z\\-_]*)").Match(v); + if (match.Length > 1) { + string str = $"http://www.youtube.com?v={ match.Groups["id"].Value }"; + return str; + } + + WebRequest wr = WebRequest.Create("https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q=" + Uri.EscapeDataString(v) + "&key=" + NadekoBot.GoogleAPIKey); + + var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); + + dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); + return "http://www.youtube.com/watch?v=" + obj.items[0].id.videoId.ToString(); + } catch (Exception ex) { + Console.WriteLine($"Error in findyoutubeurl: {ex.Message}"); + return string.Empty; + } + } + + public static async Task GetPlaylistIdByKeyword(string v) { + if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { + Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); + return string.Empty; + } + try { + WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q={Uri.EscapeDataString(v)}&type=playlist&key={NadekoBot.creds.GoogleAPIKey}"); + + var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); + + dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); + return obj.items[0].id.playlistId.ToString(); + } catch (Exception ex) { + Console.WriteLine($"Error in GetPlaylistId: {ex.Message}"); + return string.Empty; + } + } + + public static async Task> GetVideoIDs(string v) { + List toReturn = new List(); + if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { + Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); + return toReturn; + } + try { + + WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&maxResults={25}&playlistId={v}&key={ NadekoBot.creds.GoogleAPIKey }"); + + var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); + + dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); + + foreach (var item in obj.items) { + toReturn.Add("http://www.youtube.com/watch?v=" + item.contentDetails.videoId); + } + return toReturn; + } catch (Exception ex) { + Console.WriteLine($"Error in GetPlaylistId: {ex.Message}"); + return new List(); + } + } + + + public static async Task GetDanbooruImageLink(string tag) { + try { + var rng = new Random(); + + if (tag == "loli") //loli doesn't work for some reason atm + tag = "flat_chest"; + + var webpage = await GetResponseAsync($"http://danbooru.donmai.us/posts?page={ rng.Next(0, 30) }&tags={ tag.Replace(" ", "_") }"); + var matches = Regex.Matches(webpage, "data-large-file-url=\"(?.*?)\""); + + return await $"http://danbooru.donmai.us{ matches[rng.Next(0, matches.Count)].Groups["id"].Value }".ShortenUrl(); + } catch (Exception) { + return null; + } + } + + public static async Task GetGelbooruImageLink(string tag) { + try { + var rng = new Random(); + var url = $"http://gelbooru.com/index.php?page=post&s=list&pid={ rng.Next(0, 15) * 42 }&tags={ tag.Replace(" ", "_") }"; + var webpage = await GetResponseAsync(url); // first extract the post id and go to that posts page + var matches = Regex.Matches(webpage, "span id=\"s(?\\d*)\""); + var postLink = $"http://gelbooru.com/index.php?page=post&s=view&id={ matches[rng.Next(0, matches.Count)].Groups["id"].Value }"; + webpage = await GetResponseAsync(postLink); + //now extract the image from post page + var match = Regex.Match(webpage, "\"(?http://simg4.gelbooru.com//images.*?)\""); + return match.Groups["url"].Value; + } catch (Exception) { + return null; + } + } + + public static async Task ShortenUrl(string url) { + if (NadekoBot.GoogleAPIKey == null || NadekoBot.GoogleAPIKey == "") return url; + try { + var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + NadekoBot.GoogleAPIKey); + httpWebRequest.ContentType = "application/json"; + httpWebRequest.Method = "POST"; + + using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync())) { + string json = "{\"longUrl\":\"" + url + "\"}"; + streamWriter.Write(json); + } + + var httpResponse = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse; + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { + string responseText = await streamReader.ReadToEndAsync(); + string MATCH_PATTERN = @"""id"": ?""(?.+)"""; + return Regex.Match(responseText, MATCH_PATTERN).Groups["id"].Value; + } + } catch (Exception ex) { Console.WriteLine(ex.ToString()); return ""; } + } + } +} diff --git a/NadekoBot/Modules/Music.cs b/NadekoBot/Modules/Music.cs index f78f6c62..31f2c3e7 100644 --- a/NadekoBot/Modules/Music.cs +++ b/NadekoBot/Modules/Music.cs @@ -8,6 +8,7 @@ using System.Collections.Concurrent; using NadekoBot.Classes.Music; using Timer = System.Timers.Timer; using System.Threading.Tasks; +using NadekoBot.Classes; namespace NadekoBot.Modules { class Music : DiscordModule { @@ -172,7 +173,7 @@ namespace NadekoBot.Modules { await e.Send("💢 You need to be in the voice channel on this server."); return; } - var ids = await Searches.GetVideoIDs(await Searches.GetPlaylistIdByKeyword(e.GetArg("playlist"))); + var ids = await SearchHelper.GetVideoIDs(await SearchHelper.GetPlaylistIdByKeyword(e.GetArg("playlist"))); //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE var msg = await e.Send($"🎵 Attempting to queue **{ids.Count}** songs".SnPl(ids.Count)); foreach (var id in ids) { diff --git a/NadekoBot/Modules/NSFW.cs b/NadekoBot/Modules/NSFW.cs new file mode 100644 index 00000000..44ca9d25 --- /dev/null +++ b/NadekoBot/Modules/NSFW.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord.Modules; +using NadekoBot.Extensions; +using NadekoBot.Classes.PermissionCheckers; +using Discord.Commands; +using Newtonsoft.Json.Linq; +using NadekoBot.Classes; + +namespace NadekoBot.Modules { + class NSFW : DiscordModule { + + private Random _r = new Random(); + + public NSFW() : base() { + + } + + public override void Install(ModuleManager manager) { + manager.CreateCommands("", cgb => { + cgb.CreateCommand("~hentai") + .Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") + .Parameter("tag", ParameterType.Unparsed) + .Do(async e => { + string tag = e.GetArg("tag"); + if (tag == null) + tag = ""; + await e.Send(":heart: Gelbooru: " + await SearchHelper.GetGelbooruImageLink(tag)); + await e.Send(":heart: Danbooru: " + await SearchHelper.GetDanbooruImageLink(tag)); + }); + cgb.CreateCommand("~danbooru") + .Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") + .Parameter("tag", ParameterType.Unparsed) + .Do(async e => { + string tag = e.GetArg("tag"); + if (tag == null) + tag = ""; + await e.Send(await SearchHelper.GetDanbooruImageLink(tag)); + }); + cgb.CreateCommand("~gelbooru") + .Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") + .Parameter("tag", ParameterType.Unparsed) + .Do(async e => { + string tag = e.GetArg("tag"); + if (tag == null) + tag = ""; + await e.Send(await SearchHelper.GetGelbooruImageLink(tag)); + }); + cgb.CreateCommand("~cp") + .Description("We all know where this will lead you to.") + .Parameter("anything", ParameterType.Unparsed) + .Do(async e => { + await e.Send("http://i.imgur.com/MZkY1md.jpg"); + }); + cgb.CreateCommand("~boobs") + .Description("Real adult content.") + .Do(async e => { + try { + var obj = JArray.Parse(await SearchHelper.GetResponseAsync($"http://api.oboobs.ru/boobs/{_r.Next(0, 9304)}"))[0]; + await e.Send($"http://media.oboobs.ru/{ obj["preview"].ToString() }"); + } catch (Exception ex) { + await e.Send($"💢 {ex.Message}"); + } + }); + }); + } + } +} diff --git a/NadekoBot/Modules/Searches.cs b/NadekoBot/Modules/Searches.cs index 41e1b370..bb493797 100644 --- a/NadekoBot/Modules/Searches.cs +++ b/NadekoBot/Modules/Searches.cs @@ -9,6 +9,8 @@ using Newtonsoft.Json; using Discord.Commands; using NadekoBot.Extensions; using System.Collections.Generic; +using NadekoBot.Classes.PermissionCheckers; +using NadekoBot.Classes; namespace NadekoBot.Modules { class Searches : DiscordModule { @@ -29,9 +31,9 @@ namespace NadekoBot.Modules { .Parameter("query", ParameterType.Unparsed) .Description("Searches youtubes and shows the first result") .Do(async e => { - if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return; + if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")))) return; - var str = await ShortenUrl(await FindYoutubeUrlByKeywords(e.GetArg("query"))); + var str = await SearchHelper.ShortenUrl(await SearchHelper.FindYoutubeUrlByKeywords(e.GetArg("query"))); if (string.IsNullOrEmpty(str.Trim())) { await e.Send("Query failed"); return; @@ -44,9 +46,9 @@ namespace NadekoBot.Modules { .Parameter("query", ParameterType.Unparsed) .Description("Queries anilist for an anime and shows the first result.") .Do(async e => { - if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return; + if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")))) return; - var result = await GetAnimeQueryResultLink(e.GetArg("query")); + var result = await SearchHelper.GetAnimeQueryResultLink(e.GetArg("query")); if (result == null) { await e.Send("Failed to find that anime."); return; @@ -60,9 +62,9 @@ namespace NadekoBot.Modules { .Parameter("query", ParameterType.Unparsed) .Description("Queries anilist for a manga and shows the first result.") .Do(async e => { - if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return; + if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")))) return; - var result = await GetMangaQueryResultLink(e.GetArg("query")); + var result = await SearchHelper.GetMangaQueryResultLink(e.GetArg("query")); if (result == null) { await e.Send("Failed to find that anime."); return; @@ -90,7 +92,7 @@ namespace NadekoBot.Modules { return; try { var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&fields=items%2Flink&key={NadekoBot.creds.GoogleAPIKey}"; - var obj = JObject.Parse(await GetResponseAsync(reqString)); + var obj = JObject.Parse(await SearchHelper.GetResponseAsync(reqString)); await e.Send(obj["items"][0]["link"].ToString()); } catch (Exception ex) { await e.Send($"💢 {ex.Message}"); @@ -105,57 +107,12 @@ namespace NadekoBot.Modules { return; try { var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&start={ _r.Next(1, 150) }&fields=items%2Flink&key={NadekoBot.creds.GoogleAPIKey}"; - var obj = JObject.Parse(await GetResponseAsync(reqString)); + var obj = JObject.Parse(await SearchHelper.GetResponseAsync(reqString)); await e.Send(obj["items"][0]["link"].ToString()); } catch (Exception ex) { await e.Send($"💢 {ex.Message}"); } }); - - cgb.CreateCommand("~hentai") - .Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") - .Parameter("tag", ParameterType.Unparsed) - .Do(async e => { - string tag = e.GetArg("tag"); - if (tag == null) - tag = ""; - await e.Send(":heart: Gelbooru: " + await GetGelbooruImageLink(tag)); - await e.Send(":heart: Danbooru: " + await GetDanbooruImageLink(tag)); - }); - cgb.CreateCommand("~danbooru") - .Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") - .Parameter("tag", ParameterType.Unparsed) - .Do(async e => { - string tag = e.GetArg("tag"); - if (tag == null) - tag = ""; - await e.Send(await GetDanbooruImageLink(tag)); - }); - cgb.CreateCommand("~gelbooru") - .Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri") - .Parameter("tag", ParameterType.Unparsed) - .Do(async e => { - string tag = e.GetArg("tag"); - if (tag == null) - tag = ""; - await e.Send(await GetGelbooruImageLink(tag)); - }); - cgb.CreateCommand("~cp") - .Description("We all know where this will lead you to.") - .Parameter("anything", ParameterType.Unparsed) - .Do(async e => { - await e.Send("http://i.imgur.com/MZkY1md.jpg"); - }); - cgb.CreateCommand("~boobs") - .Description("Real adult content.") - .Do(async e => { - try { - var obj = JArray.Parse(await GetResponseAsync($"http://api.oboobs.ru/boobs/{_r.Next(0, 9304)}"))[0]; - await e.Send($"http://media.oboobs.ru/{ obj["preview"].ToString() }"); - } catch (Exception ex) { - await e.Send($"💢 {ex.Message}"); - } - }); cgb.CreateCommand("lmgtfy") .Alias("~lmgtfy") .Description("Google something for an idiot.") @@ -175,7 +132,7 @@ namespace NadekoBot.Modules { return; } await e.Channel.SendIsTyping(); - var res = await GetResponseAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}", + var res = await SearchHelper.GetResponseAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}", new Tuple[] { new Tuple("X-Mashape-Key", NadekoBot.creds.MashapeKey), }); @@ -192,7 +149,7 @@ namespace NadekoBot.Modules { if (!item.HasValues || item["img"] == null) continue; cnt++; - images.Add(System.Drawing.Bitmap.FromStream(await GetResponseStream(item["img"].ToString()))); + images.Add(System.Drawing.Bitmap.FromStream(await SearchHelper.GetResponseStream(item["img"].ToString()))); } if (items.Count > 4) { await e.Send("⚠ Found over 4 images. Showing random 4."); @@ -246,216 +203,5 @@ namespace NadekoBot.Modules { */ }); } - - public static async Task GetResponseStream(string v) { - var wr = (HttpWebRequest)WebRequest.Create(v); - try { - return (await (wr).GetResponseAsync()).GetResponseStream(); - } catch (Exception ex) { - Console.WriteLine("error in getresponse stream " + ex); - return null; - } - } - - public static async Task GetResponseAsync(string v) => - await new StreamReader((await ((HttpWebRequest)WebRequest.Create(v)).GetResponseAsync()).GetResponseStream()).ReadToEndAsync(); - - public static async Task GetResponseAsync(string v, IEnumerable> headers) { - var wr = (HttpWebRequest)WebRequest.Create(v); - foreach (var header in headers) { - wr.Headers.Add(header.Item1, header.Item2); - } - return await new StreamReader((await wr.GetResponseAsync()).GetResponseStream()).ReadToEndAsync(); - } - - private string token = ""; - private async Task GetAnimeQueryResultLink(string query) { - try { - var cl = new RestSharp.RestClient("http://anilist.co/api"); - var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); - - RefreshAnilistToken(); - - rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query)); - rq.AddParameter("access_token", token); - - var smallObj = JArray.Parse(cl.Execute(rq).Content)[0]; - - rq = new RestSharp.RestRequest("anime/" + smallObj["id"]); - rq.AddParameter("access_token", token); - return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content)); - } catch (Exception) { - return null; - } - } - //todo kick out RestSharp and make it truly async - private async Task GetMangaQueryResultLink(string query) { - try { - RefreshAnilistToken(); - - var cl = new RestSharp.RestClient("http://anilist.co/api"); - var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); - rq = new RestSharp.RestRequest("/manga/search/" + Uri.EscapeUriString(query)); - rq.AddParameter("access_token", token); - - var smallObj = JArray.Parse(cl.Execute(rq).Content)[0]; - - rq = new RestSharp.RestRequest("manga/" + smallObj["id"]); - rq.AddParameter("access_token", token); - return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content)); - } catch (Exception ex) { - Console.WriteLine(ex.ToString()); - return null; - } - } - - private void RefreshAnilistToken() { - try { - var cl = new RestSharp.RestClient("http://anilist.co/api"); - var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST); - rq.AddParameter("grant_type", "client_credentials"); - rq.AddParameter("client_id", "kwoth-w0ki9"); - rq.AddParameter("client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"); - var exec = cl.Execute(rq); - /* - Console.WriteLine($"Server gave me content: { exec.Content }\n{ exec.ResponseStatus } -> {exec.ErrorMessage} "); - Console.WriteLine($"Err exception: {exec.ErrorException}"); - Console.WriteLine($"Inner: {exec.ErrorException.InnerException}"); - */ - - token = JObject.Parse(exec.Content)["access_token"].ToString(); - } catch (Exception ex) { - Console.WriteLine($"Failed refreshing anilist token:\n {ex}"); - } - } - - private static async Task ValidateQuery(Discord.Channel ch, string query) { - if (string.IsNullOrEmpty(query.Trim())) { - await ch.Send("Please specify search parameters."); - return false; - } - return true; - } - - public static async Task FindYoutubeUrlByKeywords(string v) { - if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { - Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); - return @"https://www.youtube.com/watch?v=dQw4w9WgXcQ"; - } - try { - //maybe it is already a youtube url, in which case we will just extract the id and prepend it with youtube.com?v= - var match = new Regex("(?:youtu\\.be\\/|v=)(?[\\da-zA-Z\\-_]*)").Match(v); - if (match.Length > 1) { - string str = $"http://www.youtube.com?v={ match.Groups["id"].Value }"; - return str; - } - - WebRequest wr = WebRequest.Create("https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q=" + Uri.EscapeDataString(v) + "&key=" + NadekoBot.GoogleAPIKey); - - var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); - - dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); - return "http://www.youtube.com/watch?v=" + obj.items[0].id.videoId.ToString(); - } catch (Exception ex) { - Console.WriteLine($"Error in findyoutubeurl: {ex.Message}"); - return string.Empty; - } - } - - public static async Task GetPlaylistIdByKeyword(string v) { - if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { - Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); - return string.Empty; - } - try { - WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q={Uri.EscapeDataString(v)}&type=playlist&key={NadekoBot.creds.GoogleAPIKey}"); - - var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); - - dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); - return obj.items[0].id.playlistId.ToString(); - } catch (Exception ex) { - Console.WriteLine($"Error in GetPlaylistId: {ex.Message}"); - return string.Empty; - } - } - - public static async Task> GetVideoIDs(string v) { - List toReturn = new List(); - if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) { - Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`."); - return toReturn; - } - try { - - WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&maxResults={25}&playlistId={v}&key={ NadekoBot.creds.GoogleAPIKey }"); - - var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream()); - - dynamic obj = JObject.Parse(await sr.ReadToEndAsync()); - - foreach (var item in obj.items) { - toReturn.Add("http://www.youtube.com/watch?v=" + item.contentDetails.videoId); - } - return toReturn; - } catch (Exception ex) { - Console.WriteLine($"Error in GetPlaylistId: {ex.Message}"); - return new List(); - } - } - - - public async Task GetDanbooruImageLink(string tag) { - try { - var rng = new Random(); - - if (tag == "loli") //loli doesn't work for some reason atm - tag = "flat_chest"; - - var webpage = await GetResponseAsync($"http://danbooru.donmai.us/posts?page={ rng.Next(0, 30) }&tags={ tag.Replace(" ", "_") }"); - var matches = Regex.Matches(webpage, "data-large-file-url=\"(?.*?)\""); - - return await $"http://danbooru.donmai.us{ matches[rng.Next(0, matches.Count)].Groups["id"].Value }".ShortenUrl(); - } catch (Exception) { - return null; - } - } - - public async Task GetGelbooruImageLink(string tag) { - try { - var rng = new Random(); - var url = $"http://gelbooru.com/index.php?page=post&s=list&pid={ rng.Next(0, 15) * 42 }&tags={ tag.Replace(" ", "_") }"; - var webpage = await GetResponseAsync(url); // first extract the post id and go to that posts page - var matches = Regex.Matches(webpage, "span id=\"s(?\\d*)\""); - var postLink = $"http://gelbooru.com/index.php?page=post&s=view&id={ matches[rng.Next(0, matches.Count)].Groups["id"].Value }"; - webpage = await GetResponseAsync(postLink); - //now extract the image from post page - var match = Regex.Match(webpage, "\"(?http://simg4.gelbooru.com//images.*?)\""); - return match.Groups["url"].Value; - } catch (Exception) { - return null; - } - } - - public static async Task ShortenUrl(string url) { - if (NadekoBot.GoogleAPIKey == null || NadekoBot.GoogleAPIKey == "") return url; - try { - var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + NadekoBot.GoogleAPIKey); - httpWebRequest.ContentType = "application/json"; - httpWebRequest.Method = "POST"; - - using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync())) { - string json = "{\"longUrl\":\"" + url + "\"}"; - streamWriter.Write(json); - } - - var httpResponse = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse; - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { - string responseText = await streamReader.ReadToEndAsync(); - string MATCH_PATTERN = @"""id"": ?""(?.+)"""; - return Regex.Match(responseText, MATCH_PATTERN).Groups["id"].Value; - } - } catch (Exception ex) { Console.WriteLine(ex.ToString()); return ""; } - } } } diff --git a/NadekoBot/NadekoBot.cs b/NadekoBot/NadekoBot.cs index 0803f8cb..a5f03d62 100644 --- a/NadekoBot/NadekoBot.cs +++ b/NadekoBot/NadekoBot.cs @@ -95,6 +95,7 @@ namespace NadekoBot { modules.Add(new Searches(), "Searches", ModuleFilter.None); if (loadTrello) modules.Add(new Trello(), "Trello", ModuleFilter.None); + modules.Add(new NSFW(), "NSFW", ModuleFilter.None); //run the bot client.ExecuteAndWait(async () => { diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index 3b22dc87..90ce03c9 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -132,6 +132,9 @@ + + + @@ -164,6 +167,7 @@ +