A lot of work on searches module done
This commit is contained in:
@@ -190,22 +190,6 @@ namespace NadekoBot.Modules.NSFW
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> GetSafebooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var webpage = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> GetRule34ImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
|
171
src/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs
Normal file
171
src/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using ScaredFingers.UnitsConversion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class ConverterCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public ConverterCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
if (unitTables == null)
|
||||
{
|
||||
CultureInfo ci = new CultureInfo("en-US");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
unitTables = new List<UnitTable>();
|
||||
unitTables.Add(UnitTable.LengthTable);
|
||||
unitTables.Add(UnitTable.TemperatureTable);
|
||||
unitTables.Add(UnitTable.VolumeTable);
|
||||
unitTables.Add(UnitTable.WeightTable);
|
||||
reInitCurrencyConverterTable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "convert")
|
||||
.Description($"Convert quantities from>to. | `{Prefix}convert m>km 1000`")
|
||||
.Parameter("from-to", ParameterType.Required)
|
||||
.Parameter("quantity", ParameterType.Optional)
|
||||
.Do(ConvertFunc());
|
||||
cgb.CreateCommand(Module.Prefix + "convertlist")
|
||||
.Description("List of the convertable dimensions and currencies.")
|
||||
.Do(ConvertListFunc());
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> ConvertListFunc() =>
|
||||
async e =>
|
||||
{
|
||||
reInitCurrencyConverterTable();
|
||||
string msg = "";
|
||||
foreach (var tmpTable in unitTables)
|
||||
{
|
||||
int i = 1;
|
||||
while (tmpTable.IsKnownUnit(i))
|
||||
{
|
||||
msg += tmpTable.GetUnitName(i) + " (" + tmpTable.GetUnitSymbol(i) + "); ";
|
||||
i++;
|
||||
}
|
||||
msg += "\n";
|
||||
}
|
||||
foreach (var curr in exchangeRateProvider.Currencies)
|
||||
{
|
||||
msg += curr + "; ";
|
||||
}
|
||||
|
||||
await channel.SendMessageAsync(msg).ConfigureAwait(false);
|
||||
};
|
||||
|
||||
private Func<CommandEventArgs, Task> ConvertFunc() =>
|
||||
async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
|
||||
string from = e.GetArg("from-to").ToLowerInvariant().Split('>')[0];
|
||||
string to = e.GetArg("from-to").ToLowerInvariant().Split('>')[1];
|
||||
|
||||
float quantity = 1.0f;
|
||||
if (!float.TryParse(e.GetArg("quantity"), out quantity))
|
||||
{
|
||||
quantity = 1.0f;
|
||||
}
|
||||
|
||||
int fromCode, toCode = 0;
|
||||
UnitTable table = null;
|
||||
ResolveUnitCodes(from, to, out table, out fromCode, out toCode);
|
||||
|
||||
if (table != null)
|
||||
{
|
||||
Unit inUnit = new Unit(fromCode, quantity, table);
|
||||
Unit outUnit = inUnit.Convert(toCode);
|
||||
await channel.SendMessageAsync(inUnit.ToString() + " = " + outUnit.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CultureInfo ci = new CultureInfo("en-US");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
reInitCurrencyConverterTable();
|
||||
Unit inUnit = currTable.CreateUnit(quantity, from.ToUpperInvariant());
|
||||
Unit outUnit = inUnit.Convert(currTable.CurrencyCode(to.ToUpperInvariant()));
|
||||
await channel.SendMessageAsync(inUnit.ToString() + " = " + outUnit.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch //(Exception ex)
|
||||
{
|
||||
//Console.WriteLine(ex.ToString());
|
||||
await channel.SendMessageAsync("Bad input format, or sth went wrong... Try to list them with `" + Module.Prefix + "`convertlist").ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
|
||||
private void reInitCurrencyConverterTable()
|
||||
{
|
||||
if (lastChanged == null || lastChanged.DayOfYear != DateTime.Now.DayOfYear)
|
||||
{
|
||||
try
|
||||
{
|
||||
exchangeRateProvider = new WebExchangeRatesProvider();
|
||||
currTable = new CurrencyExchangeTable(exchangeRateProvider);
|
||||
lastChanged = DateTime.Now;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Error with the currency download.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveUnitCodes(string from, string to, out UnitTable table, out int fromCode, out int toCode)
|
||||
{
|
||||
foreach (var tmpTable in unitTables)
|
||||
{
|
||||
int f = LookupUnit(tmpTable, from);
|
||||
int t = LookupUnit(tmpTable, to);
|
||||
if (f > 0 && t > 0)
|
||||
{
|
||||
table = tmpTable;
|
||||
fromCode = f;
|
||||
toCode = t;
|
||||
return;
|
||||
}
|
||||
}
|
||||
table = null;
|
||||
fromCode = 0;
|
||||
toCode = 0;
|
||||
}
|
||||
|
||||
private int LookupUnit(UnitTable table, string lookup)
|
||||
{
|
||||
string wellformedLookup = lookup.ToLowerInvariant().Replace("°", "");
|
||||
int i = 1;
|
||||
while (table.IsKnownUnit(i))
|
||||
{
|
||||
if (wellformedLookup == table.GetUnitName(i).ToLowerInvariant().Replace("°", "") ||
|
||||
wellformedLookup == table.GetUnitPlural(i).ToLowerInvariant().Replace("°", "") ||
|
||||
wellformedLookup == table.GetUnitSymbol(i).ToLowerInvariant().Replace("°", ""))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static List<UnitTable> unitTables;
|
||||
|
||||
private static CurrencyExchangeRatesProvider exchangeRateProvider;
|
||||
|
||||
private static CurrencyExchangeTable currTable;
|
||||
|
||||
private static DateTime lastChanged;
|
||||
}
|
||||
}
|
85
src/NadekoBot/Modules/Searches/Commands/EvalCommand.cs
Normal file
85
src/NadekoBot/Modules/Searches/Commands/EvalCommand.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Discord.Commands;
|
||||
using Mathos.Parser;
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class CalcCommand : DiscordCommand
|
||||
{
|
||||
public CalcCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "calculate")
|
||||
.Alias(Module.Prefix + "calc")
|
||||
.Description($"Evaluate a mathematical expression. | `{Prefix}calc 1+1`")
|
||||
.Parameter("expression", ParameterType.Unparsed)
|
||||
.Do(EvalFunc());
|
||||
}
|
||||
|
||||
|
||||
private CustomParser parser = new CustomParser();
|
||||
private Func<CommandEventArgs, Task> EvalFunc() => async e =>
|
||||
{
|
||||
string expression = e.GetArg("expression")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string answer = Evaluate(expression);
|
||||
if (answer == null)
|
||||
{
|
||||
await channel.SendMessageAsync($"Expression {expression} failed to evaluate");
|
||||
return;
|
||||
}
|
||||
await channel.SendMessageAsync($"⚙ `{answer}`");
|
||||
};
|
||||
|
||||
private string Evaluate(string expression)
|
||||
{
|
||||
//check for factorial
|
||||
expression = Regex.Replace(expression, @"\d+!", x => x.Value + "0");
|
||||
try
|
||||
{
|
||||
string result = parser.Parse(expression).ToString();
|
||||
return result;
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return $"Overflow error on {expression}";
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return $"\"{expression}\" was not formatted correctly";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CustomParser : MathParser
|
||||
{
|
||||
public CustomParser() : base()
|
||||
{
|
||||
OperatorList.Add("!");
|
||||
OperatorAction.Add("!", (x, y) => Factorial(x));
|
||||
}
|
||||
|
||||
static decimal Factorial(decimal x)
|
||||
{
|
||||
decimal y = x - 1;
|
||||
while (y > 0)
|
||||
{
|
||||
x = x * y--;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
63
src/NadekoBot/Modules/Searches/Commands/IMDB/ImdbMovie.cs
Normal file
63
src/NadekoBot/Modules/Searches/Commands/IMDB/ImdbMovie.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using NadekoBot.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Web;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands.IMDB
|
||||
{
|
||||
public class ImdbMovie
|
||||
{
|
||||
public bool Status { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string OriginalTitle { get; set; }
|
||||
public string Year { get; set; }
|
||||
public string Rating { get; set; }
|
||||
public string Plot { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
//public ArrayList Directors { get; set; }
|
||||
//public ArrayList Writers { get; set; }
|
||||
//public ArrayList Cast { get; set; }
|
||||
//public ArrayList Producers { get; set; }
|
||||
//public ArrayList Musicians { get; set; }
|
||||
//public ArrayList Cinematographers { get; set; }
|
||||
//public ArrayList Editors { get; set; }
|
||||
//public string MpaaRating { get; set; }
|
||||
//public string ReleaseDate { get; set; }
|
||||
//public ArrayList PlotKeywords { get; set; }
|
||||
//public string PosterLarge { get; set; }
|
||||
//public string PosterFull { get; set; }
|
||||
//public string Runtime { get; set; }
|
||||
//public string Top250 { get; set; }
|
||||
//public string Oscars { get; set; }
|
||||
//public string Awards { get; set; }
|
||||
//public string Nominations { get; set; }
|
||||
//public string Storyline { get; set; }
|
||||
//public string Tagline { get; set; }
|
||||
//public string Votes { get; set; }
|
||||
//public ArrayList Languages { get; set; }
|
||||
//public ArrayList Countries { get; set; }
|
||||
//public Dictionary<string, string> ReleaseDates { get; set; }
|
||||
//public ArrayList MediaImages { get; set; }
|
||||
//public ArrayList RecommendedTitles { get; set; }
|
||||
public string ImdbURL { get; set; }
|
||||
|
||||
public Dictionary<string, string> Aka { get; set; }
|
||||
|
||||
public override string ToString() =>
|
||||
$@"`Title:` {HttpUtility.HtmlDecode(Title)} {(string.IsNullOrEmpty(OriginalTitle) ? "" : $"({OriginalTitle})")}
|
||||
`Year:` {Year}
|
||||
`Rating:` {Rating}
|
||||
`Genre:` {GenresAsString}
|
||||
`Link:` <{ImdbURL}>
|
||||
`Plot:` {System.Net.WebUtility.HtmlDecode(Plot.TrimTo(500))}
|
||||
`img:` " + Poster.ShortenUrl().Result;
|
||||
|
||||
//public string EnglishTitle => Aka.ContainsKey("USA") ? Aka["USA"] :
|
||||
// (Aka.ContainsKey("UK") ? Aka["UK"] :
|
||||
// (Aka.ContainsKey("(original title)") ? Aka["(original title)"] :
|
||||
// (Aka.ContainsKey("(original)") ? Aka["(original)"] : OriginalTitle)));
|
||||
public string GenresAsString =>
|
||||
string.Join(", ", Genres);
|
||||
}
|
||||
}
|
223
src/NadekoBot/Modules/Searches/Commands/IMDB/ImdbScraper.cs
Normal file
223
src/NadekoBot/Modules/Searches/Commands/IMDB/ImdbScraper.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/*******************************************************************************
|
||||
* Free ASP.net IMDb Scraper API for the new IMDb Template.
|
||||
* Author: Abhinay Rathore
|
||||
* Website: http://www.AbhinayRathore.com
|
||||
* Blog: http://web3o.blogspot.com
|
||||
* More Info: http://web3o.blogspot.com/2010/11/aspnetc-imdb-scraping-api.html
|
||||
|
||||
* Updated By: Gergo Torcsvari
|
||||
* Last Updated: Feb, 2016
|
||||
*******************************************************************************/
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands.IMDB
|
||||
{
|
||||
public static class ImdbScraper
|
||||
{
|
||||
//Search Engine URLs
|
||||
private static string GoogleSearch = "https://www.google.com/search?q=imdb+";
|
||||
private static string BingSearch = "http://www.bing.com/search?q=imdb+";
|
||||
private static string AskSearch = "http://www.ask.com/web?q=imdb+";
|
||||
//Constructor
|
||||
public static ImdbMovie ImdbScrape(string MovieName, bool GetExtraInfo = true)
|
||||
{
|
||||
ImdbMovie mov = new ImdbMovie();
|
||||
string imdbUrl = GetIMDbUrl(System.Uri.EscapeUriString(MovieName));
|
||||
mov.Status = false;
|
||||
if (!string.IsNullOrWhiteSpace(imdbUrl))
|
||||
{
|
||||
ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
|
||||
}
|
||||
|
||||
return mov;
|
||||
}
|
||||
|
||||
public static ImdbMovie ImdbScrapeFromId(string imdbId, bool GetExtraInfo = true)
|
||||
{
|
||||
ImdbMovie mov = new ImdbMovie();
|
||||
string imdbUrl = "http://www.imdb.com/title/" + imdbId + "/";
|
||||
mov.Status = false;
|
||||
ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
|
||||
return mov;
|
||||
}
|
||||
|
||||
public static string GetIMDBId(string MovieName)
|
||||
{
|
||||
string imdbUrl = GetIMDbUrl(System.Uri.EscapeUriString(MovieName));
|
||||
return match(@"http://www.imdb.com/title/(tt\d{7})", imdbUrl);
|
||||
}
|
||||
//Get IMDb URL from search results
|
||||
private static string GetIMDbUrl(string MovieName, string searchEngine = "google")
|
||||
{
|
||||
string url = GoogleSearch + MovieName; //default to Google search
|
||||
if (searchEngine.ToLower().Equals("bing")) url = BingSearch + MovieName;
|
||||
if (searchEngine.ToLower().Equals("ask")) url = AskSearch + MovieName;
|
||||
string html = GetUrlData(url);
|
||||
ArrayList imdbUrls = MatchAll(@"<a href=""(http://www.imdb.com/title/tt\d{7}/)"".*?>.*?</a>", html);
|
||||
if (imdbUrls.Count > 0)
|
||||
return (string)imdbUrls[0]; //return first IMDb result
|
||||
else if (searchEngine.ToLower().Equals("google")) //if Google search fails
|
||||
return GetIMDbUrl(MovieName, "bing"); //search using Bing
|
||||
else if (searchEngine.ToLower().Equals("bing")) //if Bing search fails
|
||||
return GetIMDbUrl(MovieName, "ask"); //search using Ask
|
||||
else //search fails
|
||||
return string.Empty;
|
||||
}
|
||||
//Parse IMDb page data
|
||||
private static void ParseIMDbPage(string imdbUrl, bool GetExtraInfo, ImdbMovie mov)
|
||||
{
|
||||
string html = GetUrlData(imdbUrl + "combined");
|
||||
mov.Id = match(@"<link rel=""canonical"" href=""http://www.imdb.com/title/(tt\d{7})/combined"" />", html);
|
||||
if (!string.IsNullOrEmpty(mov.Id))
|
||||
{
|
||||
mov.Status = true;
|
||||
mov.Title = match(@"<title>(IMDb \- )*(.*?) \(.*?</title>", html, 2);
|
||||
mov.OriginalTitle = match(@"title-extra"">(.*?)<", html);
|
||||
mov.Year = match(@"<title>.*?\(.*?(\d{4}).*?\).*?</title>", match(@"(<title>.*?</title>)", html));
|
||||
mov.Rating = match(@"<b>(\d.\d)/10</b>", html);
|
||||
mov.Genres = MatchAll(@"<a.*?>(.*?)</a>", match(@"Genre.?:(.*?)(</div>|See more)", html)).Cast<string>().ToList();
|
||||
mov.Plot = match(@"Plot:</h5>.*?<div class=""info-content"">(.*?)(<a|</div)", html);
|
||||
//mov.Directors = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Directed by</a></h5>(.*?)</table>", html));
|
||||
//mov.Writers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Writing credits</a></h5>(.*?)</table>", html));
|
||||
//mov.Producers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Produced by</a></h5>(.*?)</table>", html));
|
||||
//mov.Musicians = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Original Music by</a></h5>(.*?)</table>", html));
|
||||
//mov.Cinematographers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Cinematography by</a></h5>(.*?)</table>", html));
|
||||
//mov.Editors = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Film Editing by</a></h5>(.*?)</table>", html));
|
||||
//mov.Cast = matchAll(@"<td class=""nm""><a.*?href=""/name/.*?/"".*?>(.*?)</a>", match(@"<h3>Cast</h3>(.*?)</table>", html));
|
||||
//mov.PlotKeywords = matchAll(@"<a.*?>(.*?)</a>", match(@"Plot Keywords:</h5>.*?<div class=""info-content"">(.*?)</div", html));
|
||||
//mov.ReleaseDate = match(@"Release Date:</h5>.*?<div class=""info-content"">.*?(\d{1,2} (January|February|March|April|May|June|July|August|September|October|November|December) (19|20)\d{2})", html);
|
||||
//mov.Runtime = match(@"Runtime:</h5><div class=""info-content"">(\d{1,4}) min[\s]*.*?</div>", html);
|
||||
//mov.Top250 = match(@"Top 250: #(\d{1,3})<", html);
|
||||
//mov.Oscars = match(@"Won (\d+) Oscars?\.", html);
|
||||
//if (string.IsNullOrEmpty(mov.Oscars) && "Won Oscar.".Equals(match(@"(Won Oscar\.)", html))) mov.Oscars = "1";
|
||||
//mov.Awards = match(@"(\d{1,4}) wins", html);
|
||||
//mov.Nominations = match(@"(\d{1,4}) nominations", html);
|
||||
//mov.Tagline = match(@"Tagline:</h5>.*?<div class=""info-content"">(.*?)(<a|</div)", html);
|
||||
//mov.MpaaRating = match(@"MPAA</a>:</h5><div class=""info-content"">Rated (G|PG|PG-13|PG-14|R|NC-17|X) ", html);
|
||||
//mov.Votes = match(@">(\d+,?\d*) votes<", html);
|
||||
//mov.Languages = matchAll(@"<a.*?>(.*?)</a>", match(@"Language.?:(.*?)(</div>|>.?and )", html));
|
||||
//mov.Countries = matchAll(@"<a.*?>(.*?)</a>", match(@"Country:(.*?)(</div>|>.?and )", html));
|
||||
mov.Poster = match(@"<div class=""photo"">.*?<a name=""poster"".*?><img.*?src=""(.*?)"".*?</div>", html);
|
||||
if (!string.IsNullOrEmpty(mov.Poster) && mov.Poster.IndexOf("media-imdb.com") > 0)
|
||||
{
|
||||
mov.Poster = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY200.jpg");
|
||||
//mov.PosterLarge = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY500.jpg");
|
||||
//mov.PosterFull = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY0.jpg");
|
||||
}
|
||||
else
|
||||
{
|
||||
mov.Poster = string.Empty;
|
||||
//mov.PosterLarge = string.Empty;
|
||||
//mov.PosterFull = string.Empty;
|
||||
}
|
||||
mov.ImdbURL = "http://www.imdb.com/title/" + mov.Id + "/";
|
||||
if (GetExtraInfo)
|
||||
{
|
||||
string plotHtml = GetUrlData(imdbUrl + "plotsummary");
|
||||
//mov.Storyline = match(@"<p class=""plotpar"">(.*?)(<i>|</p>)", plotHtml);
|
||||
GetReleaseDatesAndAka(mov);
|
||||
//mov.MediaImages = getMediaImages(mov);
|
||||
//mov.RecommendedTitles = getRecommendedTitles(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Get all release dates and aka-s
|
||||
private static void GetReleaseDatesAndAka(ImdbMovie mov)
|
||||
{
|
||||
Dictionary<string, string> release = new Dictionary<string, string>();
|
||||
string releasehtml = GetUrlData("http://www.imdb.com/title/" + mov.Id + "/releaseinfo");
|
||||
foreach (string r in MatchAll(@"<tr class="".*?"">(.*?)</tr>", match(@"<table id=""release_dates"" class=""subpage_data spFirst"">\n*?(.*?)</table>", releasehtml)))
|
||||
{
|
||||
Match rd = new Regex(@"<td>(.*?)</td>\n*?.*?<td class=.*?>(.*?)</td>", RegexOptions.Multiline).Match(r);
|
||||
release[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
|
||||
}
|
||||
//mov.ReleaseDates = release;
|
||||
|
||||
Dictionary<string, string> aka = new Dictionary<string, string>();
|
||||
ArrayList list = MatchAll(@".*?<tr class="".*?"">(.*?)</tr>", match(@"<table id=""akas"" class=.*?>\n*?(.*?)</table>", releasehtml));
|
||||
foreach (string r in list)
|
||||
{
|
||||
Match rd = new Regex(@"\n*?.*?<td>(.*?)</td>\n*?.*?<td>(.*?)</td>", RegexOptions.Multiline).Match(r);
|
||||
aka[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
|
||||
}
|
||||
mov.Aka = aka;
|
||||
|
||||
|
||||
|
||||
}
|
||||
//Get all media images
|
||||
private static ArrayList GetMediaImages(ImdbMovie mov)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
string mediaurl = "http://www.imdb.com/title/" + mov.Id + "/mediaindex";
|
||||
string mediahtml = GetUrlData(mediaurl);
|
||||
int pagecount = MatchAll(@"<a href=""\?page=(.*?)"">", match(@"<span style=""padding: 0 1em;"">(.*?)</span>", mediahtml)).Count;
|
||||
for (int p = 1; p <= pagecount + 1; p++)
|
||||
{
|
||||
mediahtml = GetUrlData(mediaurl + "?page=" + p);
|
||||
foreach (Match m in new Regex(@"src=""(.*?)""", RegexOptions.Multiline).Matches(match(@"<div class=""thumb_list"" style=""font-size: 0px;"">(.*?)</div>", mediahtml)))
|
||||
{
|
||||
String image = m.Groups[1].Value;
|
||||
list.Add(Regex.Replace(image, @"_V1\..*?.jpg", "_V1._SY0.jpg"));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
//Get Recommended Titles
|
||||
private static ArrayList GetRecommendedTitles(ImdbMovie mov)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
string recUrl = "http://www.imdb.com/widget/recommendations/_ajax/get_more_recs?specs=p13nsims%3A" + mov.Id;
|
||||
string json = GetUrlData(recUrl);
|
||||
list = MatchAll(@"title=\\""(.*?)\\""", json);
|
||||
HashSet<String> set = new HashSet<string>();
|
||||
foreach (String rec in list) set.Add(rec);
|
||||
return new ArrayList(set.ToList());
|
||||
}
|
||||
/*******************************[ Helper Methods ]********************************/
|
||||
//Match single instance
|
||||
private static string match(string regex, string html, int i = 1)
|
||||
{
|
||||
return new Regex(regex, RegexOptions.Multiline).Match(html).Groups[i].Value.Trim();
|
||||
}
|
||||
//Match all instances and return as ArrayList
|
||||
private static ArrayList MatchAll(string regex, string html, int i = 1)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
foreach (Match m in new Regex(regex, RegexOptions.Multiline).Matches(html))
|
||||
list.Add(m.Groups[i].Value.Trim());
|
||||
return list;
|
||||
}
|
||||
//Strip HTML Tags
|
||||
private static string StripHTML(string inputString)
|
||||
{
|
||||
return Regex.Replace(inputString, @"<.*?>", string.Empty);
|
||||
}
|
||||
//Get URL Data
|
||||
private static string GetUrlData(string url)
|
||||
{
|
||||
WebClient client = new WebClient();
|
||||
Random r = new Random();
|
||||
//Random IP Address
|
||||
//client.Headers["X-Forwarded-For"] = r.Next(0, 255) + "." + r.Next(0, 255) + "." + r.Next(0, 255) + "." + r.Next(0, 255);
|
||||
//Random User-Agent
|
||||
client.Headers["User-Agent"] = "Mozilla/" + r.Next(3, 5) + ".0 (Windows NT " + r.Next(3, 5) + "." + r.Next(0, 2) + "; rv:37.0) Gecko/20100101 Firefox/" + r.Next(30, 37) + "." + r.Next(0, 5);
|
||||
Stream datastream = client.OpenRead(url);
|
||||
StreamReader reader = new StreamReader(datastream);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
//TODO: Coud be reader error must catch and drop!!!
|
||||
while (!reader.EndOfStream)
|
||||
sb.Append(reader.ReadLine());
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
383
src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs
Normal file
383
src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs
Normal file
@@ -0,0 +1,383 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class LoLCommands : DiscordCommand
|
||||
{
|
||||
|
||||
private class CachedChampion
|
||||
{
|
||||
public System.IO.Stream ImageStream { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
private class ChampionNameComparer : IEqualityComparer<JToken>
|
||||
{
|
||||
public bool Equals(JToken a, JToken b) => a["name"].ToString() == b["name"].ToString();
|
||||
|
||||
public int GetHashCode(JToken obj) =>
|
||||
obj["name"].GetHashCode();
|
||||
}
|
||||
|
||||
private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>();
|
||||
|
||||
private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer();
|
||||
public LoLCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
clearTimer.Interval = new TimeSpan(0, 10, 0).TotalMilliseconds;
|
||||
clearTimer.Start();
|
||||
clearTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
CachedChampionImages = CachedChampionImages
|
||||
.Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private readonly string[] trashTalk = { "Better ban your counters. You are going to carry the game anyway.",
|
||||
"Go with the flow. Don't think. Just ban one of these.",
|
||||
"DONT READ BELOW! Ban Urgot mid OP 100%. Im smurf Diamond 1.",
|
||||
"Ask your teammates what would they like to play, and ban that.",
|
||||
"If you consider playing teemo, do it. If you consider teemo, you deserve him.",
|
||||
"Doesn't matter what you ban really. Enemy will ban your main and you will lose." };
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class MatchupModel
|
||||
{
|
||||
public int Games { get; set; }
|
||||
public float WinRate { get; set; }
|
||||
[Newtonsoft.Json.JsonProperty("key")]
|
||||
public string Name { get; set; }
|
||||
public float StatScore { get; set; }
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "lolchamp")
|
||||
.Description($"Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. |`{Prefix}lolchamp Riven` or `{Prefix}lolchamp Annie sup`")
|
||||
.Parameter("champ", ParameterType.Required)
|
||||
.Parameter("position", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
//get role
|
||||
var role = ResolvePos(e.GetArg("position"));
|
||||
var resolvedRole = role;
|
||||
var name = e.GetArg("champ").Replace(" ", "").ToLower();
|
||||
CachedChampion champ = null;
|
||||
|
||||
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
|
||||
if (champ != null)
|
||||
{
|
||||
champ.ImageStream.Position = 0;
|
||||
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var allData = JArray.Parse(await Classes.http.GetStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}").ConfigureAwait(false));
|
||||
JToken data = null;
|
||||
if (role != null)
|
||||
{
|
||||
for (var i = 0; i < allData.Count; i++)
|
||||
{
|
||||
if (allData[i]["role"].ToString().Equals(role))
|
||||
{
|
||||
data = allData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data == null)
|
||||
{
|
||||
await channel.SendMessageAsync("💢 Data for that role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = allData[0];
|
||||
role = allData[0]["role"].ToString();
|
||||
resolvedRole = ResolvePos(role);
|
||||
}
|
||||
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
|
||||
if (champ != null)
|
||||
{
|
||||
champ.ImageStream.Position = 0;
|
||||
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//name = data["title"].ToString();
|
||||
// get all possible roles, and "select" the shown one
|
||||
var roles = new string[allData.Count];
|
||||
for (var i = 0; i < allData.Count; i++)
|
||||
{
|
||||
roles[i] = allData[i]["role"].ToString();
|
||||
if (roles[i] == role)
|
||||
roles[i] = ">" + roles[i] + "<";
|
||||
}
|
||||
var general = JArray.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/" +
|
||||
$"champs/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")
|
||||
.ConfigureAwait(false))
|
||||
.FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
||||
if (general == null)
|
||||
{
|
||||
Console.WriteLine("General is null.");
|
||||
return;
|
||||
}
|
||||
//get build data for this role
|
||||
var buildData = data["items"]["mostGames"]["items"];
|
||||
var items = new string[6];
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
items[i] = buildData[i]["id"].ToString();
|
||||
}
|
||||
|
||||
//get matchup data to show counters and countered champions
|
||||
var matchupDataIE = data["matchups"].ToObject<List<MatchupModel>>();
|
||||
|
||||
var matchupData = matchupDataIE.OrderBy(m => m.StatScore).ToArray();
|
||||
|
||||
var countered = new[] { matchupData[0].Name, matchupData[1].Name, matchupData[2].Name };
|
||||
var counters = new[] { matchupData[matchupData.Length - 1].Name, matchupData[matchupData.Length - 2].Name, matchupData[matchupData.Length - 3].Name };
|
||||
|
||||
//get runes data
|
||||
var runesJArray = data["runes"]["mostGames"]["runes"] as JArray;
|
||||
var runes = string.Join("\n", runesJArray.OrderBy(jt => int.Parse(jt["number"].ToString())).Select(jt => jt["number"].ToString() + "x" + jt["name"]));
|
||||
|
||||
// get masteries data
|
||||
|
||||
var masteries = (data["masteries"]["mostGames"]["masteries"] as JArray);
|
||||
|
||||
//get skill order data<API_KEY>
|
||||
|
||||
var orderArr = (data["skills"]["mostGames"]["order"] as JArray);
|
||||
|
||||
var img = Image.FromFile("data/lol/bg.png");
|
||||
using (var g = Graphics.FromImage(img))
|
||||
{
|
||||
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
||||
//g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
|
||||
const int margin = 5;
|
||||
const int imageSize = 75;
|
||||
var normalFont = new Font("Monaco", 8, FontStyle.Regular);
|
||||
var smallFont = new Font("Monaco", 7, FontStyle.Regular);
|
||||
//draw champ image
|
||||
var champName = data["key"].ToString().Replace(" ", "");
|
||||
|
||||
g.DrawImage(GetImage(champName), new Rectangle(margin, margin, imageSize, imageSize));
|
||||
//draw champ name
|
||||
if (champName == "MonkeyKing")
|
||||
champName = "Wukong";
|
||||
g.DrawString($"{champName}", new Font("Times New Roman", 24, FontStyle.Regular), Brushes.WhiteSmoke, margin + imageSize + margin, margin);
|
||||
//draw champ surname
|
||||
|
||||
//draw skill order
|
||||
if (orderArr.Count != 0)
|
||||
{
|
||||
float orderFormula = 120 / orderArr.Count;
|
||||
const float orderVerticalSpacing = 10;
|
||||
for (var i = 0; i < orderArr.Count; i++)
|
||||
{
|
||||
var orderX = margin + margin + imageSize + orderFormula * i + i;
|
||||
float orderY = margin + 35;
|
||||
var spellName = orderArr[i].ToString().ToLowerInvariant();
|
||||
|
||||
switch (spellName)
|
||||
{
|
||||
case "w":
|
||||
orderY += orderVerticalSpacing;
|
||||
break;
|
||||
case "e":
|
||||
orderY += orderVerticalSpacing * 2;
|
||||
break;
|
||||
case "r":
|
||||
orderY += orderVerticalSpacing * 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g.DrawString(spellName.ToUpperInvariant(), new Font("Monaco", 7), Brushes.LimeGreen, orderX, orderY);
|
||||
}
|
||||
}
|
||||
//draw roles
|
||||
g.DrawString("Roles: " + string.Join(", ", roles), normalFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin);
|
||||
|
||||
//draw average stats
|
||||
g.DrawString(
|
||||
$@" Average Stats
|
||||
|
||||
Kills: {general["kills"]} CS: {general["minionsKilled"]}
|
||||
Deaths: {general["deaths"]} Win: {general["winPercent"]}%
|
||||
Assists: {general["assists"]} Ban: {general["banRate"]}%
|
||||
", normalFont, Brushes.WhiteSmoke, img.Width - 150, margin);
|
||||
//draw masteries
|
||||
g.DrawString($"Masteries: {string.Join(" / ", masteries?.Select(jt => jt["total"]))}", normalFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin + 20);
|
||||
//draw runes
|
||||
g.DrawString($"{runes}", smallFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin + 40);
|
||||
//draw counters
|
||||
g.DrawString($"Best against", smallFont, Brushes.WhiteSmoke, margin, img.Height - imageSize + margin);
|
||||
var smallImgSize = 50;
|
||||
|
||||
for (var i = 0; i < counters.Length; i++)
|
||||
{
|
||||
g.DrawImage(GetImage(counters[i]),
|
||||
new Rectangle(i * (smallImgSize + margin) + margin, img.Height - smallImgSize - margin,
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
//draw countered by
|
||||
g.DrawString($"Worst against", smallFont, Brushes.WhiteSmoke, img.Width - 3 * (smallImgSize + margin), img.Height - imageSize + margin);
|
||||
|
||||
for (var i = 0; i < countered.Length; i++)
|
||||
{
|
||||
var j = countered.Length - i;
|
||||
g.DrawImage(GetImage(countered[i]),
|
||||
new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), img.Height - smallImgSize - margin,
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
//draw item build
|
||||
g.DrawString("Popular build", normalFont, Brushes.WhiteSmoke, img.Width - (3 * (smallImgSize + margin) + margin), 77);
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
var inverseI = 5 - i;
|
||||
var j = inverseI % 3 + 1;
|
||||
var k = inverseI / 3;
|
||||
g.DrawImage(GetImage(items[i], GetImageType.Item),
|
||||
new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), 92 + k * (smallImgSize + margin),
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
}
|
||||
var cachedChamp = new CachedChampion { AddedAt = DateTime.Now, ImageStream = img.ToStream(System.Drawing.Imaging.ImageFormat.Png), Name = name.ToLower() + "_" + resolvedRole };
|
||||
CachedChampionImages.Add(cachedChamp.Name, cachedChamp);
|
||||
await e.Channel.SendFile(data["title"] + "_stats.png", cachedChamp.ImageStream).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
await channel.SendMessageAsync("💢 Failed retreiving data for that champion.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "lolban")
|
||||
.Description($"Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time. | `{Prefix}lolban`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var showCount = 8;
|
||||
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
|
||||
try
|
||||
{
|
||||
var data = JObject.Parse(
|
||||
await Classes
|
||||
.SearchHelper
|
||||
.GetResponseStringAsync($"http://api.champion.gg/stats/champs/mostBanned?" +
|
||||
$"api_key={NadekoBot.Creds.LOLAPIKey}&page=1&" +
|
||||
$"limit={showCount}")
|
||||
.ConfigureAwait(false))["data"] as JArray;
|
||||
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"**Showing {showCount} top banned champions.**");
|
||||
sb.AppendLine($"`{trashTalk[new Random().Next(0, trashTalk.Length)]}`");
|
||||
for (var i = 0; i < dataList.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0 && i != 0)
|
||||
sb.AppendLine();
|
||||
sb.Append($"`{i + 1}.` **{dataList[i]["name"]}** ");
|
||||
//sb.AppendLine($" ({dataList[i]["general"]["banRate"]}%)");
|
||||
}
|
||||
|
||||
await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await channel.SendMessageAsync($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private enum GetImageType
|
||||
{
|
||||
Champion,
|
||||
Item
|
||||
}
|
||||
private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (imageType)
|
||||
{
|
||||
case GetImageType.Champion:
|
||||
return Image.FromFile($"data/lol/champions/{id}.png");
|
||||
case GetImageType.Item:
|
||||
default:
|
||||
return Image.FromFile($"data/lol/items/{id}.png");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Image.FromFile("data/lol/_ERROR.png");
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolvePos(string pos)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pos))
|
||||
return null;
|
||||
switch (pos.ToLowerInvariant())
|
||||
{
|
||||
case "m":
|
||||
case "mid":
|
||||
case "midorfeed":
|
||||
case "midd":
|
||||
case "middle":
|
||||
return "Middle";
|
||||
case "top":
|
||||
case "topp":
|
||||
case "t":
|
||||
case "toporfeed":
|
||||
return "Top";
|
||||
case "j":
|
||||
case "jun":
|
||||
case "jungl":
|
||||
case "jungle":
|
||||
return "Jungle";
|
||||
case "a":
|
||||
case "ad":
|
||||
case "adc":
|
||||
case "carry":
|
||||
case "ad carry":
|
||||
case "adcarry":
|
||||
case "c":
|
||||
return "ADC";
|
||||
case "s":
|
||||
case "sup":
|
||||
case "supp":
|
||||
case "support":
|
||||
return "Support";
|
||||
default:
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs
Normal file
46
src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class MemegenCommands : DiscordCommand
|
||||
{
|
||||
public MemegenCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "memelist")
|
||||
.Description($"Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `{Prefix}memelist`")
|
||||
.Do(async e =>
|
||||
{
|
||||
int i = 0;
|
||||
await channel.SendMessageAsync("`List Of Commands:`\n```xl\n" +
|
||||
string.Join("\n", JsonConvert.DeserializeObject<Dictionary<string, string>>(await http.GetStringAsync("http://memegen.link/templates/"))
|
||||
.Select(kvp => Path.GetFileName(kvp.Value))
|
||||
.GroupBy(item => (i++) / 4)
|
||||
.Select(ig => string.Concat(ig.Select(el => $"{el,-17}"))))
|
||||
+ $"\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "memegen")
|
||||
.Description($"Generates a meme from memelist with top and bottom text. | `{Prefix}memegen biw \"gets iced coffee\" \"in the winter\"`")
|
||||
.Parameter("meme", ParameterType.Required)
|
||||
.Parameter("toptext", ParameterType.Required)
|
||||
.Parameter("bottext", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var meme = e.GetArg("meme");
|
||||
var top = Uri.EscapeDataString(e.GetArg("toptext").Replace(' ', '-'));
|
||||
var bot = Uri.EscapeDataString(e.GetArg("bottext").Replace(' ', '-'));
|
||||
await channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
268
src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs
Normal file
268
src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class OsuCommands : DiscordCommand
|
||||
{
|
||||
public OsuCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "osu")
|
||||
.Description($"Shows osu stats for a player. | `{Prefix}osu Name` or `{Prefix}osu Name taiko`")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
return;
|
||||
|
||||
using (WebClient cl = new WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
cl.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
|
||||
cl.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.2; Win64; x64)");
|
||||
cl.DownloadDataAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ e.GetArg("usr") }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}"));
|
||||
cl.DownloadDataCompleted += async (s, cle) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendFile($"{e.GetArg("usr")}.png", new MemoryStream(cle.Result)).ConfigureAwait(false);
|
||||
await channel.SendMessageAsync($"`Profile Link:`https://osu.ppy.sh/u/{Uri.EscapeDataString(e.GetArg("usr"))}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("💢 Failed retrieving osu signature :\\").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu b")
|
||||
.Description($"Shows information about an osu beatmap. |`{Prefix}osu b` https://osu.ppy.sh/s/127712`")
|
||||
.Parameter("map", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await channel.SendMessageAsync("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("map")))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var mapId = ResolveMap(e.GetArg("map"));
|
||||
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&{mapId}";
|
||||
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0];
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}"), 2);
|
||||
var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss");
|
||||
sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}");
|
||||
sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}");
|
||||
await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("Something went wrong.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu top5")
|
||||
.Description($"Displays a user's top 5 plays. |`{Prefix}osu top5 Name`")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await channel.SendMessageAsync("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
{
|
||||
await channel.SendMessageAsync("💢 Please provide a username.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
var reqString = $"https://osu.ppy.sh/api/get_user_best?k={NadekoBot.Creds.OsuAPIKey}&u={Uri.EscapeDataString(e.GetArg("usr"))}&type=string&limit=5&m={m}";
|
||||
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||
var sb = new System.Text.StringBuilder($"`Top 5 plays for {e.GetArg("usr")}:`\n```xl" + Environment.NewLine);
|
||||
foreach (var item in obj)
|
||||
{
|
||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&b={item["beatmap_id"]}";
|
||||
var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0];
|
||||
var pp = Math.Round(Double.Parse($"{item["pp"]}"), 2);
|
||||
var acc = CalculateAcc(item, m);
|
||||
var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}"));
|
||||
if (mods != "+")
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | **{mods,-10}** | /b/{item["beatmap_id"]}");
|
||||
else
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | /b/{item["beatmap_id"]}");
|
||||
}
|
||||
sb.Append("```");
|
||||
await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("Something went wrong.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//https://osu.ppy.sh/wiki/Accuracy
|
||||
private static Double CalculateAcc(JToken play, int mode)
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["count300"]}") * 300;
|
||||
var totalHits = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countmiss"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["countmiss"]}") * 0 + Double.Parse($"{play["count100"]}") * 0.5 + Double.Parse($"{play["count300"]}") * 1;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
hitPoints *= 300;
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
var fruitsCaught = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
var totalFruits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countkatu"]}");
|
||||
return Math.Round(fruitsCaught / totalFruits * 100, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["countkatu"]}") * 200 + (Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}")) * 300;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["countkatu"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveMap(string mapLink)
|
||||
{
|
||||
Match s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
if (s.Success)
|
||||
{
|
||||
var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3);
|
||||
return $"s={mapId}";
|
||||
}
|
||||
else if (b.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("/b/") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3)}";
|
||||
}
|
||||
else if (p.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("?b=") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"s={mapLink}"; //just a default incase an ID number was provided by itself (non-url)?
|
||||
}
|
||||
}
|
||||
|
||||
private static int ResolveGameMode(string mode)
|
||||
{
|
||||
switch (mode.ToLower())
|
||||
{
|
||||
case "std":
|
||||
case "standard":
|
||||
return 0;
|
||||
case "taiko":
|
||||
return 1;
|
||||
case "ctb":
|
||||
case "catchthebeat":
|
||||
return 2;
|
||||
case "mania":
|
||||
case "osu!mania":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/ppy/osu-api/wiki#mods
|
||||
private static string ResolveMods(int mods)
|
||||
{
|
||||
var modString = $"+";
|
||||
|
||||
if (IsBitSet(mods, 0))
|
||||
modString += "NF";
|
||||
if (IsBitSet(mods, 1))
|
||||
modString += "EZ";
|
||||
if (IsBitSet(mods, 8))
|
||||
modString += "HT";
|
||||
|
||||
if (IsBitSet(mods, 3))
|
||||
modString += "HD";
|
||||
if (IsBitSet(mods, 4))
|
||||
modString += "HR";
|
||||
if (IsBitSet(mods, 6) && !IsBitSet(mods, 9))
|
||||
modString += "DT";
|
||||
if (IsBitSet(mods, 9))
|
||||
modString += "NC";
|
||||
if (IsBitSet(mods, 10))
|
||||
modString += "FL";
|
||||
|
||||
if (IsBitSet(mods, 5))
|
||||
modString += "SD";
|
||||
if (IsBitSet(mods, 14))
|
||||
modString += "PF";
|
||||
|
||||
if (IsBitSet(mods, 7))
|
||||
modString += "RX";
|
||||
if (IsBitSet(mods, 11))
|
||||
modString += "AT";
|
||||
if (IsBitSet(mods, 12))
|
||||
modString += "SO";
|
||||
return modString;
|
||||
}
|
||||
|
||||
private static bool IsBitSet(int mods, int pos)
|
||||
{
|
||||
return (mods & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
116
src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs
Normal file
116
src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class PokemonSearchCommands : DiscordCommand
|
||||
{
|
||||
private static Dictionary<string, SearchPokemon> pokemons;
|
||||
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities;
|
||||
|
||||
public PokemonSearchCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
pokemons = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemon>>(File.ReadAllText("data/pokemon/pokemon_list.json"));
|
||||
pokemonAbilities = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemonAbility>>(File.ReadAllText("data/pokemon/pokemon_abilities.json"));
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "pokemon")
|
||||
.Alias(Prefix + "poke")
|
||||
.Description($"Searches for a pokemon. | `{Prefix}poke Sylveon`")
|
||||
.Parameter("pokemon", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pok = e.GetArg("pokemon")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(pok))
|
||||
return;
|
||||
|
||||
foreach (var kvp in pokemons)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == pok.ToUpperInvariant())
|
||||
{
|
||||
await channel.SendMessageAsync($"`Stats for \"{kvp.Key}\" pokemon:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await channel.SendMessageAsync("`No pokemon found.`");
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "pokemonability")
|
||||
.Alias(Prefix + "pokeab")
|
||||
.Description($"Searches for a pokemon ability. | `{Prefix}pokeab \"water gun\"`")
|
||||
.Parameter("abil", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var ab = e.GetArg("abil")?.Trim().ToUpperInvariant().Replace(" ", "");
|
||||
if (string.IsNullOrWhiteSpace(ab))
|
||||
return;
|
||||
foreach (var kvp in pokemonAbilities)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == ab)
|
||||
{
|
||||
await channel.SendMessageAsync($"`Info for \"{kvp.Key}\" ability:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await channel.SendMessageAsync("`No ability found.`");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchPokemon
|
||||
{
|
||||
public class GenderRatioClass
|
||||
{
|
||||
public float M { get; set; }
|
||||
public float F { get; set; }
|
||||
}
|
||||
public class BaseStatsClass
|
||||
{
|
||||
public int HP { get; set; }
|
||||
public int ATK { get; set; }
|
||||
public int DEF { get; set; }
|
||||
public int SPA { get; set; }
|
||||
public int SPD { get; set; }
|
||||
public int SPE { get; set; }
|
||||
|
||||
public override string ToString() => $@"
|
||||
**HP:** {HP,-4} **ATK:** {ATK,-4} **DEF:** {DEF,-4}
|
||||
**SPA:** {SPA,-4} **SPD:** {SPD,-4} **SPE:** {SPE,-4}";
|
||||
}
|
||||
public int Id { get; set; }
|
||||
public string Species { get; set; }
|
||||
public string[] Types { get; set; }
|
||||
public GenderRatioClass GenderRatio { get; set; }
|
||||
public BaseStatsClass BaseStats { get; set; }
|
||||
public Dictionary<string, string> Abilities { get; set; }
|
||||
public float HeightM { get; set; }
|
||||
public float WeightKg { get; set; }
|
||||
public string Color { get; set; }
|
||||
public string[] Evos { get; set; }
|
||||
public string[] EggGroups { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` {Species}
|
||||
`Types:` {string.Join(", ", Types)}
|
||||
`Stats:` {BaseStats}
|
||||
`Height:` {HeightM,4}m `Weight:` {WeightKg}kg
|
||||
`Abilities:` {string.Join(", ", Abilities.Values)}";
|
||||
|
||||
}
|
||||
|
||||
public class SearchPokemonAbility
|
||||
{
|
||||
public string Desc { get; set; }
|
||||
public string Name { get; set; }
|
||||
public float Rating { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` : {Name}
|
||||
`Rating:` {Rating}
|
||||
`Description:` {Desc}";
|
||||
}
|
||||
}
|
17
src/NadekoBot/Modules/Searches/Commands/RedditCommand.cs
Normal file
17
src/NadekoBot/Modules/Searches/Commands/RedditCommand.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class RedditCommand : DiscordCommand
|
||||
{
|
||||
public RedditCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
344
src/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs
Normal file
344
src/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class StreamNotifications : DiscordCommand
|
||||
{
|
||||
|
||||
private readonly Timer checkTimer = new Timer
|
||||
{
|
||||
Interval = new TimeSpan(0, 0, 15).TotalMilliseconds,
|
||||
};
|
||||
|
||||
private ConcurrentDictionary<string, Tuple<bool, string>> cachedStatuses = new ConcurrentDictionary<string, Tuple<bool, string>>();
|
||||
|
||||
public StreamNotifications(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
checkTimer.Elapsed += async (s, e) =>
|
||||
{
|
||||
cachedStatuses.Clear();
|
||||
try
|
||||
{
|
||||
var streams = SpecificConfigurations.Default.AllConfigs.SelectMany(c => c.ObservingStreams);
|
||||
if (!streams.Any()) return;
|
||||
|
||||
foreach (var stream in streams)
|
||||
{
|
||||
Tuple<bool, string> data;
|
||||
try
|
||||
{
|
||||
data = await GetStreamStatus(stream).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.Item1 != stream.LastStatus)
|
||||
{
|
||||
stream.LastStatus = data.Item1;
|
||||
var server = NadekoBot.Client.GetServer(stream.ServerId);
|
||||
var channel = server?.GetChannel(stream.ChannelId);
|
||||
if (channel == null)
|
||||
continue;
|
||||
var msg = $"`{stream.Username}`'s stream is now " +
|
||||
$"**{(data.Item1 ? "ONLINE" : "OFFLINE")}** with " +
|
||||
$"**{data.Item2}** viewers.";
|
||||
if (stream.LastStatus)
|
||||
if (stream.Type == StreamNotificationConfig.StreamType.Hitbox)
|
||||
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.Twitch)
|
||||
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.Beam)
|
||||
msg += $"\n`Here is the Link:`【 http://www.beam.pro/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.YoutubeGaming)
|
||||
msg += $"\n`Here is the Link:`【 not implemented yet - {stream.Username} 】";
|
||||
await channel.SendMessage(msg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
};
|
||||
checkTimer.Start();
|
||||
}
|
||||
|
||||
private async Task<Tuple<bool, string>> GetStreamStatus(StreamNotificationConfig stream, bool checkCache = true)
|
||||
{
|
||||
bool isLive;
|
||||
string response;
|
||||
JObject data;
|
||||
Tuple<bool, string> result;
|
||||
switch (stream.Type)
|
||||
{
|
||||
case StreamNotificationConfig.StreamType.Hitbox:
|
||||
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username}";
|
||||
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||
return result;
|
||||
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = data["media_is_live"].ToString() == "1";
|
||||
result = new Tuple<bool, string>(isLive, data["media_views"].ToString());
|
||||
cachedStatuses.TryAdd(hitboxUrl, result);
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Twitch:
|
||||
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}";
|
||||
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||
return result;
|
||||
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = !string.IsNullOrWhiteSpace(data["stream"].ToString());
|
||||
result = new Tuple<bool, string>(isLive, isLive ? data["stream"]["viewers"].ToString() : "0");
|
||||
cachedStatuses.TryAdd(twitchUrl, result);
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Beam:
|
||||
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}";
|
||||
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
|
||||
return result;
|
||||
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = data["online"].ToObject<bool>() == true;
|
||||
result = new Tuple<bool, string>(isLive, data["viewersCurrent"].ToString());
|
||||
cachedStatuses.TryAdd(beamUrl, result);
|
||||
return result;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new Tuple<bool, string>(false, "0");
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "hitbox")
|
||||
.Alias(Module.Prefix + "hb")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}hitbox SomeStreamer`")
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Hitbox));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "twitch")
|
||||
.Alias(Module.Prefix + "tw")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}twitch SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Twitch));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "beam")
|
||||
.Alias(Module.Prefix + "bm")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}beam SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Beam));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkhitbox")
|
||||
.Alias(Module.Prefix + "chhb")
|
||||
.Description("Checks if a certain user is streaming on the hitbox platform." +
|
||||
$" | `{Prefix}chhb SomeStreamer`")
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Hitbox
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await channel.SendMessageAsync($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checktwitch")
|
||||
.Alias(Module.Prefix + "chtw")
|
||||
.Description("Checks if a certain user is streaming on the twitch platform." +
|
||||
$" | `{Prefix}chtw SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Twitch
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await channel.SendMessageAsync($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkbeam")
|
||||
.Alias(Module.Prefix + "chbm")
|
||||
.Description("Checks if a certain user is streaming on the beam platform." +
|
||||
$" | `{Prefix}chbm SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Beam
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await channel.SendMessageAsync($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "removestream")
|
||||
.Alias(Module.Prefix + "rms")
|
||||
.Description("Removes notifications of a certain streamer on this channel." +
|
||||
$" | `{Prefix}rms SomeGuy`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var username = e.GetArg("username")?.ToLower().Trim();
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
return;
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var toRemove = config.ObservingStreams
|
||||
.FirstOrDefault(snc => snc.ChannelId == e.Channel.Id &&
|
||||
snc.Username.ToLower().Trim() == username);
|
||||
if (toRemove == null)
|
||||
{
|
||||
await channel.SendMessageAsync(":anger: No such stream.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
config.ObservingStreams.Remove(toRemove);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await channel.SendMessageAsync($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "liststreams")
|
||||
.Alias(Module.Prefix + "ls")
|
||||
.Description("Lists all streams you are following on this server." +
|
||||
$" | `{Prefix}ls`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var streams = config.ObservingStreams.Where(snc =>
|
||||
snc.ServerId == e.Server.Id);
|
||||
|
||||
var streamsArray = streams as StreamNotificationConfig[] ?? streams.ToArray();
|
||||
|
||||
if (streamsArray.Length == 0)
|
||||
{
|
||||
await channel.SendMessageAsync("You are not following any streams on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var text = string.Join("\n", streamsArray.Select(snc =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return $"`{snc.Username}`'s stream on **{e.Server.GetChannel(e.Channel.Id).Name}** channel. 【`{snc.Type.ToString()}`】";
|
||||
}
|
||||
catch { }
|
||||
return "";
|
||||
}));
|
||||
|
||||
await channel.SendMessageAsync($"You are following **{streamsArray.Length}** streams on this server.\n\n" + text).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> TrackStream(StreamNotificationConfig.StreamType type) =>
|
||||
async e =>
|
||||
{
|
||||
var username = e.GetArg("username")?.ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
return;
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var stream = new StreamNotificationConfig
|
||||
{
|
||||
ServerId = e.Server.Id,
|
||||
ChannelId = e.Channel.Id,
|
||||
Username = username,
|
||||
Type = type,
|
||||
};
|
||||
var exists = config.ObservingStreams.Contains(stream);
|
||||
if (exists)
|
||||
{
|
||||
await channel.SendMessageAsync(":anger: I am already notifying that stream on this channel.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Tuple<bool, string> data;
|
||||
try
|
||||
{
|
||||
data = await GetStreamStatus(stream).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync(":anger: Stream probably doesn't exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var msg = $"Stream is currently **{(data.Item1 ? "ONLINE" : "OFFLINE")}** with **{data.Item2}** viewers";
|
||||
if (data.Item1)
|
||||
if (type == StreamNotificationConfig.StreamType.Hitbox)
|
||||
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.Twitch)
|
||||
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.Beam)
|
||||
msg += $"\n`Here is the Link:`【 https://beam.pro/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.YoutubeGaming)
|
||||
msg += $"\n`Here is the Link:` not implemented yet - {stream.Username}";
|
||||
stream.LastStatus = data.Item1;
|
||||
if (!exists)
|
||||
msg = $":ok: I will notify this channel when status changes.\n{msg}";
|
||||
await channel.SendMessageAsync(msg).ConfigureAwait(false);
|
||||
config.ObservingStreams.Add(stream);
|
||||
};
|
||||
}
|
||||
}
|
36
src/NadekoBot/Modules/Searches/Commands/WowJokes.cs
Normal file
36
src/NadekoBot/Modules/Searches/Commands/WowJokes.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class WowJokeCommand : DiscordCommand
|
||||
{
|
||||
|
||||
List<WoWJoke> jokes = new List<WoWJoke>();
|
||||
|
||||
public WowJokeCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "wowjoke")
|
||||
.Description($"Get one of Kwoth's penultimate WoW jokes. | `{Prefix}wowjoke`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!jokes.Any())
|
||||
{
|
||||
jokes = JsonConvert.DeserializeObject<List<WoWJoke>>(File.ReadAllText("data/wowjokes.json"));
|
||||
}
|
||||
await channel.SendMessageAsync(jokes[new Random().Next(0, jokes.Count)].ToString());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
584
src/NadekoBot/Modules/Searches/SearchesModule.cs
Normal file
584
src/NadekoBot/Modules/Searches/SearchesModule.cs
Normal file
@@ -0,0 +1,584 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Modules.Searches.Commands.IMDB;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using NadekoBot.Services;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using Discord.API;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.Searches
|
||||
{
|
||||
[Module("~", AppendSpace = false)]
|
||||
public class SearchesModule : DiscordModule
|
||||
{
|
||||
private readonly Random rng;
|
||||
|
||||
public SearchesModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client)
|
||||
{
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Weather(IMessage imsg, string city, string country)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
city = city.Replace(" ", "");
|
||||
country = city.Replace(" ", "");
|
||||
string response;
|
||||
using (var http = new HttpClient())
|
||||
response = await http.GetStringAsync($"http://api.lawlypopzz.xyz/nadekobot/weather/?city={city}&country={country}").ConfigureAwait(false);
|
||||
|
||||
var obj = JObject.Parse(response)["weather"];
|
||||
|
||||
await imsg.Channel.SendMessageAsync(
|
||||
$@"🌍 **Weather for** 【{obj["target"]}】
|
||||
📏 **Lat,Long:** ({obj["latitude"]}, {obj["longitude"]}) ☁ **Condition:** {obj["condition"]}
|
||||
😓 **Humidity:** {obj["humidity"]}% 💨 **Wind Speed:** {obj["windspeedk"]}km/h / {obj["windspeedm"]}mph
|
||||
🔆 **Temperature:** {obj["centigrade"]}°C / {obj["fahrenheit"]}°F 🔆 **Feels like:** {obj["feelscentigrade"]}°C / {obj["feelsfahrenheit"]}°F
|
||||
🌄 **Sunrise:** {obj["sunrise"]} 🌇 **Sunset:** {obj["sunset"]}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Youtube(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
|
||||
var link = await FindYoutubeUrlByKeywords(query).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("No results found for that query.");
|
||||
return;
|
||||
}
|
||||
var shortUrl = await link.ShortenUrl().ConfigureAwait(false);
|
||||
await imsg.Channel.SendMessageAsync(shortUrl).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Anime(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = (await GetAnimeData(query).ConfigureAwait(false)).ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Failed to find that anime.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await imsg.Channel.SendMessageAsync(result.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Manga(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = (await GetMangaData(query).ConfigureAwait(false)).ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Failed to find that manga.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await imsg.Channel.SendMessageAsync(result).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Imdb(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
string result;
|
||||
try
|
||||
{
|
||||
var movie = ImdbScraper.ImdbScrape(query, true);
|
||||
if (movie.Status) result = movie.ToString();
|
||||
else result = "Failed to find that movie.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Failed to find that movie.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await imsg.Channel.SendMessageAsync(result.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RandomCat(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync(JObject.Parse(
|
||||
await http.GetStringAsync("http://www.random.cat/meow").ConfigureAwait(false))["file"].ToString())
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RandomDog(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("http://random.dog/" + await http.GetStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task I(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(query)}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&fields=items%2Flink&key={NadekoBot.Credentials.GoogleApiKey}";
|
||||
var obj = JObject.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||
await imsg.Channel.SendMessageAsync(obj["items"][0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Something went wrong.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Ir(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(query)}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&start={ rng.Next(1, 50) }&fields=items%2Flink&key={NadekoBot.Credentials.GoogleApiKey}";
|
||||
var obj = JObject.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||
var items = obj["items"] as JArray;
|
||||
await imsg.Channel.SendMessageAsync(items[0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Something went wrong.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Lmgtfy(IMessage imsg, [Remainder] string ffs)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ffs))
|
||||
return;
|
||||
|
||||
await imsg.Channel.SendMessageAsync(await $"<http://lmgtfy.com/?q={ Uri.EscapeUriString(ffs) }>".ShortenUrl())
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Google(IMessage imsg, [Remainder] string terms)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
|
||||
terms = terms?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(terms))
|
||||
return;
|
||||
await imsg.Channel.SendMessageAsync($"https://google.com/search?q={ HttpUtility.UrlEncode(terms).Replace(' ', '+') }")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Hearthstone(IMessage imsg, [Remainder] string name)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
var arg = e.GetArg("name");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("💢 Please enter a card name to search for.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await imsg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||
string response = "";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||
response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}", headers)
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JArray.Parse(response);
|
||||
var images = new List<Image>();
|
||||
if (items == null)
|
||||
throw new KeyNotFoundException("Cannot find a card by that name");
|
||||
var cnt = 0;
|
||||
items.Shuffle();
|
||||
foreach (var item in items.TakeWhile(item => cnt++ < 4).Where(item => item.HasValues && item["img"] != null))
|
||||
{
|
||||
images.Add(
|
||||
Image.FromStream(await http.GetStreamAsync(item["img"].ToString()).ConfigureAwait(false)));
|
||||
}
|
||||
if (items.Count > 4)
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("⚠ Found over 4 images. Showing random 4.").ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendFile(arg + ".png", (await images.MergeAsync()).ToStream(System.Drawing.Imaging.ImageFormat.Png))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync($"💢 Error {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task UrbanDictionary(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var arg = query;
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("💢 Please enter a search term.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await imsg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||
var res = await http.GetStringAsync($"https://mashape-community-urban-dictionary.p.mashape.com/define?term={Uri.EscapeUriString(arg)}", headers).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JObject.Parse(res);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine($"`Term:` {items["list"][0]["word"].ToString()}");
|
||||
sb.AppendLine($"`Definition:` {items["list"][0]["definition"].ToString()}");
|
||||
sb.Append($"`Link:` <{await items["list"][0]["permalink"].ToString().ShortenUrl().ConfigureAwait(false)}>");
|
||||
await imsg.Channel.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("💢 Failed finding a definition for that term.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Hashtag(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var arg = query;
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("💢 Please enter a search term.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await imsg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||
string res = "";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||
res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(arg)}.json").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var items = JObject.Parse(res);
|
||||
var str = $@"`Hashtag:` {items["defs"]["def"]["hashtag"].ToString()}
|
||||
`Definition:` {items["defs"]["def"]["text"].ToString()}
|
||||
`Link:` <{await items["defs"]["def"]["uri"].ToString().ShortenUrl().ConfigureAwait(false)}>");
|
||||
await imsg.Channel.SendMessageAsync(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("💢 Failed finidng a definition for that tag.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Quote(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
|
||||
await imsg.Channel.SendMessageAsync(quote).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Catfact(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var response = await http.GetStringAsync("http://catfacts-api.appspot.com/api/facts").ConfigureAwait(false);
|
||||
if (response == null)
|
||||
return;
|
||||
await imsg.Channel.SendMessageAsync($"🐈 `{JObject.Parse(response)["facts"][0].ToString()}`").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Yomama(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var response = await http.GetStringAsync("http://api.yomomma.info/").ConfigureAwait(false);
|
||||
await imsg.Channel.SendMessageAsync("`" + JObject.Parse(response)["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Randjoke(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var response = await http.GetStringAsync("http://tambal.azurewebsites.net/joke/random").ConfigureAwait(false);
|
||||
await imsg.Channel.SendMessageAsync("`" + JObject.Parse(response)["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChuckNorris(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var response = await http.GetStringAsync("http://tambal.azurewebsites.net/joke/random").ConfigureAwait(false);
|
||||
await imsg.Channel.SendMessageAsync("`" + JObject.Parse(response)["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task MagicItem(IMessage imsg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
|
||||
var item = magicItems[rng.Next(0, magicItems.Count)].ToString();
|
||||
|
||||
await imsg.Channel.SendMessageAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Revav(IMessage imsg, [Remainder] string arg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
var usrStr = arg?.Trim().ToUpperInvariant();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(usrStr))
|
||||
return;
|
||||
|
||||
var usr = (await channel.Guild.GetUsersAsync()).Where(u=>u.Username.ToUpperInvariant() == usrStr).FirstOrDefault();
|
||||
|
||||
if (usr == null || string.IsNullOrWhiteSpace(usr.AvatarUrl))
|
||||
return;
|
||||
await imsg.Channel.SendMessageAsync($"https://images.google.com/searchbyimage?image_url={usr.AvatarUrl}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Revimg(IMessage imsg, [Remainder] string imageLink)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
imageLink = imageLink?.Trim() ?? "";
|
||||
|
||||
if (string.IsNullOrWhiteSpace(imageLink))
|
||||
return;
|
||||
await imsg.Channel.SendMessageAsync($"https://images.google.com/searchbyimage?image_url={imageLink}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Safebooru(IMessage imsg, [Remainder] string tag)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
tag = tag?.Trim() ?? "";
|
||||
var link = await GetSafebooruImageLink(tag).ConfigureAwait(false);
|
||||
if (link == null)
|
||||
await imsg.Channel.SendMessageAsync("`No results.`");
|
||||
else
|
||||
await imsg.Channel.SendMessageAsync(link).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Wiki(IMessage imsg, [Remainder] string query)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
query = query?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return;
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var result = await http.GetStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query));
|
||||
var data = JsonConvert.DeserializeObject<WikipediaApiModel>(result);
|
||||
if (data.Query.Pages[0].Missing)
|
||||
await imsg.Channel.SendMessageAsync("`That page could not be found.`");
|
||||
else
|
||||
await imsg.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Clr(IMessage imsg, [Remainder] string color)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var arg1 = e.GetArg("color")?.Trim()?.Replace("#", "");
|
||||
if (string.IsNullOrWhiteSpace(arg1))
|
||||
return;
|
||||
var img = new Bitmap(50, 50);
|
||||
|
||||
var red = Convert.ToInt32(arg1.Substring(0, 2), 16);
|
||||
var green = Convert.ToInt32(arg1.Substring(2, 2), 16);
|
||||
var blue = Convert.ToInt32(arg1.Substring(4, 2), 16);
|
||||
var brush = new SolidBrush(System.Drawing.Color.FromArgb(red, green, blue));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(img))
|
||||
{
|
||||
g.FillRectangle(brush, 0, 0, 50, 50);
|
||||
g.Flush();
|
||||
}
|
||||
|
||||
await imsg.Channel.SendFileAsync("arg1.png", img.ToStream());
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Videocall(IMessage imsg, [Remainder] string arg)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
try
|
||||
{
|
||||
var allUsrs = imsg.MentionedUsers.Append(imsg.Author);
|
||||
var allUsrsArray = allUsrs.ToArray();
|
||||
var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Name[0].ToString()));
|
||||
str += new Random().Next();
|
||||
foreach (var usr in allUsrsArray)
|
||||
{
|
||||
await (await (usr as IGuildUser).CreateDMChannelAsync()).SendMessageAsync(str).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Avatar(IMessage imsg, [Remainder] string mention)
|
||||
{
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
|
||||
var usr = imsg.MentionedUsers.FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await imsg.Channel.SendMessageAsync("Invalid user specified.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await imsg.Channel.SendMessageAsync(await usr.AvatarUrl.ShortenUrl()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<string> GetSafebooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var webpage = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> ValidateQuery(ITextChannel ch, string query)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(query.Trim())) return true;
|
||||
await ch.SendMessageAsync("Please specify search parameters.").ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
234
src/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs
Normal file
234
src/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2015 Ravi Bhavnani
|
||||
// License: Code Project Open License
|
||||
// http://www.codeproject.com/info/cpol10.aspx
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace NadekoBot.Modules.Translator.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Translates text using Google's online language tools.
|
||||
/// </summary>
|
||||
public class GoogleTranslator
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported languages.
|
||||
/// </summary>
|
||||
public static IEnumerable<string> Languages {
|
||||
get {
|
||||
GoogleTranslator.EnsureInitialized();
|
||||
return GoogleTranslator._languageModeMap.Keys.OrderBy(p => p);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
|
||||
/// <summary>
|
||||
/// Translates the specified source text.
|
||||
/// </summary>
|
||||
/// <param name="sourceText">The source text.</param>
|
||||
/// <param name="sourceLanguage">The source language.</param>
|
||||
/// <param name="targetLanguage">The target language.</param>
|
||||
/// <returns>The translation.</returns>
|
||||
public async Task<string> Translate
|
||||
(string sourceText,
|
||||
string sourceLanguage,
|
||||
string targetLanguage)
|
||||
{
|
||||
// Initialize
|
||||
DateTime tmStart = DateTime.Now;
|
||||
string text = string.Empty;
|
||||
|
||||
|
||||
// Download translation
|
||||
string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
||||
GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage),
|
||||
GoogleTranslator.LanguageEnumToIdentifier(targetLanguage),
|
||||
HttpUtility.UrlEncode(sourceText));
|
||||
using (HttpClient http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
||||
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return (string.Concat(JArray.Parse(text)[0].Select(x => x[0])));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Converts a language to its identifier.
|
||||
/// </summary>
|
||||
/// <param name="language">The language."</param>
|
||||
/// <returns>The identifier or <see cref="string.Empty"/> if none.</returns>
|
||||
private static string LanguageEnumToIdentifier
|
||||
(string language)
|
||||
{
|
||||
string mode = string.Empty;
|
||||
GoogleTranslator.EnsureInitialized();
|
||||
GoogleTranslator._languageModeMap.TryGetValue(language, out mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the translator has been initialized.
|
||||
/// </summary>
|
||||
public static void EnsureInitialized()
|
||||
{
|
||||
if (GoogleTranslator._languageModeMap == null)
|
||||
{
|
||||
GoogleTranslator._languageModeMap = new Dictionary<string, string>() {
|
||||
{ "afrikaans", "af"},
|
||||
{ "albanian", "sq"},
|
||||
{ "arabic", "ar"},
|
||||
{ "armenian", "hy"},
|
||||
{ "azerbaijani", "az"},
|
||||
{ "basque", "eu"},
|
||||
{ "belarusian", "be"},
|
||||
{ "bengali", "bn"},
|
||||
{ "bulgarian", "bg"},
|
||||
{ "catalan", "ca"},
|
||||
{ "chinese", "zh-CN"},
|
||||
{ "croatian", "hr"},
|
||||
{ "czech", "cs"},
|
||||
{ "danish", "da"},
|
||||
{ "dutch", "nl"},
|
||||
{ "english", "en"},
|
||||
{ "esperanto", "eo"},
|
||||
{ "estonian", "et"},
|
||||
{ "filipino", "tl"},
|
||||
{ "finnish", "fi"},
|
||||
{ "french", "fr"},
|
||||
{ "galician", "gl"},
|
||||
{ "german", "de"},
|
||||
{ "georgian", "ka"},
|
||||
{ "greek", "el"},
|
||||
{ "haitian Creole", "ht"},
|
||||
{ "hebrew", "iw"},
|
||||
{ "hindi", "hi"},
|
||||
{ "hungarian", "hu"},
|
||||
{ "icelandic", "is"},
|
||||
{ "indonesian", "id"},
|
||||
{ "irish", "ga"},
|
||||
{ "italian", "it"},
|
||||
{ "japanese", "ja"},
|
||||
{ "korean", "ko"},
|
||||
{ "lao", "lo"},
|
||||
{ "latin", "la"},
|
||||
{ "latvian", "lv"},
|
||||
{ "lithuanian", "lt"},
|
||||
{ "macedonian", "mk"},
|
||||
{ "malay", "ms"},
|
||||
{ "maltese", "mt"},
|
||||
{ "norwegian", "no"},
|
||||
{ "persian", "fa"},
|
||||
{ "polish", "pl"},
|
||||
{ "portuguese", "pt"},
|
||||
{ "romanian", "ro"},
|
||||
{ "russian", "ru"},
|
||||
{ "serbian", "sr"},
|
||||
{ "slovak", "sk"},
|
||||
{ "slovenian", "sl"},
|
||||
{ "spanish", "es"},
|
||||
{ "swahili", "sw"},
|
||||
{ "swedish", "sv"},
|
||||
{ "tamil", "ta"},
|
||||
{ "telugu", "te"},
|
||||
{ "thai", "th"},
|
||||
{ "turkish", "tr"},
|
||||
{ "ukrainian", "uk"},
|
||||
{ "urdu", "ur"},
|
||||
{ "vietnamese", "vi"},
|
||||
{ "welsh", "cy"},
|
||||
{ "yiddish", "yi"},
|
||||
|
||||
{ "af", "af"},
|
||||
{ "sq", "sq"},
|
||||
{ "ar", "ar"},
|
||||
{ "hy", "hy"},
|
||||
{ "az", "az"},
|
||||
{ "eu", "eu"},
|
||||
{ "be", "be"},
|
||||
{ "bn", "bn"},
|
||||
{ "bg", "bg"},
|
||||
{ "ca", "ca"},
|
||||
{ "zh-CN", "zh-CN"},
|
||||
{ "hr", "hr"},
|
||||
{ "cs", "cs"},
|
||||
{ "da", "da"},
|
||||
{ "nl", "nl"},
|
||||
{ "en", "en"},
|
||||
{ "eo", "eo"},
|
||||
{ "et", "et"},
|
||||
{ "tl", "tl"},
|
||||
{ "fi", "fi"},
|
||||
{ "fr", "fr"},
|
||||
{ "gl", "gl"},
|
||||
{ "de", "de"},
|
||||
{ "ka", "ka"},
|
||||
{ "el", "el"},
|
||||
{ "ht", "ht"},
|
||||
{ "iw", "iw"},
|
||||
{ "hi", "hi"},
|
||||
{ "hu", "hu"},
|
||||
{ "is", "is"},
|
||||
{ "id", "id"},
|
||||
{ "ga", "ga"},
|
||||
{ "it", "it"},
|
||||
{ "ja", "ja"},
|
||||
{ "ko", "ko"},
|
||||
{ "lo", "lo"},
|
||||
{ "la", "la"},
|
||||
{ "lv", "lv"},
|
||||
{ "lt", "lt"},
|
||||
{ "mk", "mk"},
|
||||
{ "ms", "ms"},
|
||||
{ "mt", "mt"},
|
||||
{ "no", "no"},
|
||||
{ "fa", "fa"},
|
||||
{ "pl", "pl"},
|
||||
{ "pt", "pt"},
|
||||
{ "ro", "ro"},
|
||||
{ "ru", "ru"},
|
||||
{ "sr", "sr"},
|
||||
{ "sk", "sk"},
|
||||
{ "sl", "sl"},
|
||||
{ "es", "es"},
|
||||
{ "sw", "sw"},
|
||||
{ "sv", "sv"},
|
||||
{ "ta", "ta"},
|
||||
{ "te", "te"},
|
||||
{ "th", "th"},
|
||||
{ "tr", "tr"},
|
||||
{ "uk", "uk"},
|
||||
{ "ur", "ur"},
|
||||
{ "vi", "vi"},
|
||||
{ "cy", "cy"},
|
||||
{ "yi", "yi"},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// The language to translation mode map.
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> _languageModeMap;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
45
src/NadekoBot/Modules/Translator/TranslateCommand.cs
Normal file
45
src/NadekoBot/Modules/Translator/TranslateCommand.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Translator.Helpers;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
class TranslateCommand : DiscordCommand
|
||||
{
|
||||
public TranslateCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "translate")
|
||||
.Alias(Module.Prefix + "trans")
|
||||
.Description($"Translates from>to text. From the given language to the destiation language. | `{Module.Prefix}trans en>fr Hello`")
|
||||
.Parameter("langs", ParameterType.Required)
|
||||
.Parameter("text", ParameterType.Unparsed)
|
||||
.Do(TranslateFunc());
|
||||
}
|
||||
private GoogleTranslator t = new GoogleTranslator();
|
||||
private Func<CommandEventArgs, Task> TranslateFunc() => async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
string from = e.GetArg("langs").ToLowerInvariant().Split('>')[0];
|
||||
string to = e.GetArg("langs").ToLowerInvariant().Split('>')[1];
|
||||
var text = e.GetArg("text")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
string translation = await t.Translate(text, from, to).ConfigureAwait(false);
|
||||
await channel.SendMessageAsync(translation).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
await channel.SendMessageAsync("Bad input format, or something went wrong...").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
27
src/NadekoBot/Modules/Translator/TranslatorModule.cs
Normal file
27
src/NadekoBot/Modules/Translator/TranslatorModule.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
internal class TranslatorModule : DiscordModule
|
||||
{
|
||||
public TranslatorModule()
|
||||
{
|
||||
commands.Add(new TranslateCommand(this));
|
||||
commands.Add(new ValidLanguagesCommand(this));
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Searches;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
50
src/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs
Normal file
50
src/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Translator.Helpers;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
class ValidLanguagesCommand : DiscordCommand
|
||||
{
|
||||
public ValidLanguagesCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "translangs")
|
||||
.Description($"List the valid languages for translation. | `{Prefix}translangs` or `{Prefix}translangs language`")
|
||||
.Parameter("search", ParameterType.Optional)
|
||||
.Do(ListLanguagesFunc());
|
||||
}
|
||||
private Func<CommandEventArgs, Task> ListLanguagesFunc() => async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
GoogleTranslator.EnsureInitialized();
|
||||
string s = e.GetArg("search");
|
||||
string ret = "";
|
||||
foreach (string key in GoogleTranslator._languageModeMap.Keys)
|
||||
{
|
||||
if (!s.Equals(""))
|
||||
{
|
||||
if (key.ToLower().Contains(s))
|
||||
{
|
||||
ret += " " + key + ";";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += " " + key + ";";
|
||||
}
|
||||
}
|
||||
await channel.SendMessageAsync(ret).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendMessageAsync("Bad input format, or sth went wrong...").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public UtilityModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[LocalizedCommand, LocalizedDescription, LocalizedSummary]
|
||||
|
Reference in New Issue
Block a user