Adding Initial API support, updating readme

This commit is contained in:
Runebaas 2017-10-02 21:57:48 +02:00
parent 6732506dae
commit 92015d8880
No known key found for this signature in database
GPG key ID: 2677AF508D0300D6
27 changed files with 78 additions and 33 deletions

View file

@ -0,0 +1,196 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Geekbot.net.Lib;
using Serilog;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
[Group("admin")]
public class AdminCmd : ModuleBase
{
private readonly IDatabase _redis;
private readonly DiscordSocketClient _client;
private readonly ILogger _logger;
private readonly IUserRepository _userRepository;
private readonly IErrorHandler _errorHandler;
public AdminCmd(IDatabase redis, DiscordSocketClient client, ILogger logger, IUserRepository userRepositry, IErrorHandler errorHandler)
{
_redis = redis;
_client = client;
_logger = logger;
_userRepository = userRepositry;
_errorHandler = errorHandler;
}
[RequireUserPermission(GuildPermission.Administrator)]
[Command("welcome", RunMode = RunMode.Async)]
[Summary("Set a Welcome Message (use '$user' to mention the new joined user).")]
public async Task SetWelcomeMessage([Remainder] [Summary("message")] string welcomeMessage)
{
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] { new HashEntry("WelcomeMsg", welcomeMessage) });
var formatedMessage = welcomeMessage.Replace("$user", Context.User.Mention);
await ReplyAsync("Welcome message has been changed\r\nHere is an example of how it would look:\r\n" +
formatedMessage);
}
[Command("youtubekey", RunMode = RunMode.Async)]
[Summary("Set the youtube api key")]
public async Task SetYoutubeKey([Summary("API Key")] string key)
{
var botOwner = Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner"))).Result;
if (!Context.User.Id.ToString().Equals(botOwner.Id.ToString()))
{
await ReplyAsync($"Sorry, only the botowner can do this ({botOwner.Username}#{botOwner.Discriminator})");
return;
}
_redis.StringSet("youtubeKey", key);
await ReplyAsync("Apikey has been set");
}
[Command("game", RunMode = RunMode.Async)]
[Summary("Set the game that the bot is playing")]
public async Task SetGame([Remainder] [Summary("Game")] string key)
{
var botOwner = Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner"))).Result;
if (!Context.User.Id.ToString().Equals(botOwner.Id.ToString()))
{
await ReplyAsync($"Sorry, only the botowner can do this ({botOwner.Username}#{botOwner.Discriminator})");
return;
}
_redis.StringSet("Game", key);
await _client.SetGameAsync(key);
_logger.Information($"[Geekbot] Changed game to {key}");
await ReplyAsync($"Now Playing {key}");
}
[Command("popuserrepo", RunMode = RunMode.Async)]
[Summary("Set the game that the bot is playing")]
public async Task popUserRepoCommand()
{
try
{
var botOwner = Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner"))).Result;
if (!Context.User.Id.ToString().Equals(botOwner.Id.ToString()))
{
await ReplyAsync(
$"Sorry, only the botowner can do this ({botOwner.Username}#{botOwner.Discriminator})");
return;
}
}
catch (Exception)
{
await ReplyAsync(
$"Sorry, only the botowner can do this");
return;
}
var success = 0;
var failed = 0;
try
{
_logger.Warning("[UserRepository] Populating User Repositry");
await ReplyAsync("Starting Population of User Repository");
foreach (var guild in _client.Guilds)
{
_logger.Information($"[UserRepository] Populating users from {guild.Name}");
foreach (var user in guild.Users)
{
var succeded = await _userRepository.Update(user);
var inc = succeded ? success++ : failed++;
}
}
_logger.Warning("[UserRepository] Finished Updating User Repositry");
await ReplyAsync($"Successfully Populated User Repository with {success} Users in {_client.Guilds.Count} Guilds (Failed: {failed})");
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "Couldn't complete User Repository, see console for more info");
}
}
[RequireUserPermission(GuildPermission.Administrator)]
[Command("modchannel", RunMode = RunMode.Async)]
[Summary("Set the game that the bot is playing")]
public async Task selectModChannel([Summary("ChannelId")] ulong channelId)
{
try
{
var channel = (ISocketMessageChannel)_client.GetChannel(channelId);
if (string.IsNullOrEmpty(channel.Name))
{
await ReplyAsync("I couldn't find that channel...");
return;
}
var sb = new StringBuilder();
sb.AppendLine("Successfully saved mod channel, you can now do the following");
sb.AppendLine("- `!admin showleave true` - send message to mod channel when someone leaves");
sb.AppendLine("- `!admin showdel true` - send message to mod channel when someone deletes a message");
await channel.SendMessageAsync(sb.ToString());
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] {new HashEntry("ModChannel", channel.Id.ToString())});
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to be valid");
}
}
[RequireUserPermission(GuildPermission.Administrator)]
[Command("showleave", RunMode = RunMode.Async)]
[Summary("Notify modchannel when someone leaves")]
public async Task showLeave([Summary("true/false")] bool enabled)
{
var modChannelId = (ulong)_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel");
try
{
var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId);
if (enabled)
{
await modChannel.SendMessageAsync("Saved - now sending messages here when someone leaves");
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] {new HashEntry("ShowLeave", true)});
}
else
{
await modChannel.SendMessageAsync("Saved - stopping sending messages here when someone leaves");
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] {new HashEntry("ShowLeave", false)});
}
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
}
}
[RequireUserPermission(GuildPermission.Administrator)]
[Command("showdel", RunMode = RunMode.Async)]
[Summary("Notify modchannel when someone leaves")]
public async Task showDelete([Summary("true/false")] bool enabled)
{
var modChannelId = (ulong)_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel");
try
{
var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId);
if (enabled)
{
await modChannel.SendMessageAsync("Saved - now sending messages here when someone deletes a message");
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] {new HashEntry("ShowDelete", true)});
}
else
{
await modChannel.SendMessageAsync("Saved - stopping sending messages here when someone deletes a message");
_redis.HashSet($"{Context.Guild.Id}:Settings", new HashEntry[] {new HashEntry("ShowDelete", false)});
}
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
}
}
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Discord.Commands;
using Newtonsoft.Json;
namespace Geekbot.net.Commands
{
public class Cat : ModuleBase
{
[Command("cat", RunMode = RunMode.Async)]
[Summary("Return a random image of a cat.")]
public async Task Say()
{
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://random.cat");
var response = await client.GetAsync("/meow.php");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
var catFile = JsonConvert.DeserializeObject<CatResponse>(stringResponse);
await ReplyAsync(catFile.file);
}
catch (HttpRequestException e)
{
await ReplyAsync($"Seems like the dog cought the cat (error occured)\r\n{e.Message}");
}
}
}
}
public class CatResponse
{
public string file { get; set; }
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Geekbot.net.Lib;
using Geekbot.net.Lib.Media;
using Serilog;
namespace Geekbot.net.Commands
{
public class CheckEm : ModuleBase
{
private readonly ICheckEmImageProvider checkEmImages;
private readonly Random rnd;
private readonly ILogger logger;
private readonly IErrorHandler errorHandler;
public CheckEm(Random RandomClient, ICheckEmImageProvider checkEmImages, ILogger logger, IErrorHandler errorHandler)
{
this.rnd = RandomClient;
this.checkEmImages = checkEmImages;
this.logger = logger;
this.errorHandler = errorHandler;
}
[Command("checkem", RunMode = RunMode.Async)]
[Summary("Check for dubs")]
public async Task MuhDubs()
{
try
{
var number = rnd.Next(10000000, 99999999);
var dubtriqua = "";
var ns = GetIntArray(number);
if (ns[7] == ns[6])
{
dubtriqua = "DUBS";
if (ns[6] == ns[5])
{
dubtriqua = "TRIPS";
if (ns[5] == ns[4])
dubtriqua = "QUADS";
}
}
var sb = new StringBuilder();
sb.AppendLine($"Check em {Context.User.Mention}");
sb.AppendLine($"**{number}**");
if (!string.IsNullOrEmpty(dubtriqua))
sb.AppendLine($":tada: {dubtriqua} :tada:");
sb.AppendLine(checkEmImages.GetRandomCheckEmPic());
await ReplyAsync(sb.ToString());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context);
}
}
private int[] GetIntArray(int num)
{
var listOfInts = new List<int>();
while (num > 0)
{
listOfInts.Add(num % 10);
num = num / 10;
}
listOfInts.Reverse();
return listOfInts.ToArray();
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Choose : ModuleBase
{
private readonly Random rnd;
public Choose(Random RandomClient)
{
rnd = RandomClient;
}
[Command("choose", RunMode = RunMode.Async)]
[Summary("Seperate options with a semicolon.")]
public async Task Command([Remainder] [Summary("option1;option2")] string choices)
{
var choicesArray = choices.Split(';');
var choice = rnd.Next(choicesArray.Length);
await ReplyAsync($"I choose **{choicesArray[choice]}**");
}
}
}

View file

@ -0,0 +1,125 @@
using System;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
using Serilog;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class Counters : ModuleBase
{
private readonly IDatabase redis;
private readonly ILogger logger;
private readonly IErrorHandler errorHandler;
public Counters(IDatabase redis, ILogger logger, IErrorHandler errorHandler)
{
this.redis = redis;
this.logger = logger;
this.errorHandler = errorHandler;
}
[Command("good", RunMode = RunMode.Async)]
[Summary("Increase Someones Karma")]
public async Task Good([Summary("@someone")] IUser user)
{
try
{
var lastKarmaFromRedis = redis.HashGet($"{Context.Guild.Id}:KarmaTimeout", Context.User.Id.ToString());
var lastKarma = ConvertToDateTimeOffset(lastKarmaFromRedis.ToString());
if (user.Id == Context.User.Id)
{
await ReplyAsync($"Sorry {Context.User.Username}, but you can't lower your own karma");
}
else if (TimeoutFinished(lastKarma))
{
await ReplyAsync(
$"Sorry {Context.User.Username}, but you have to wait {GetTimeLeft(lastKarma)} before you can give karma again...");
}
else
{
var newKarma = redis.HashIncrement($"{Context.Guild.Id}:Karma", user.Id.ToString());
redis.HashSet($"{Context.Guild.Id}:KarmaTimeout",
new HashEntry[] {new HashEntry(Context.User.Id.ToString(), DateTimeOffset.Now.ToString("u"))});
var eb = new EmbedBuilder();
eb.WithAuthor(new EmbedAuthorBuilder()
.WithIconUrl(user.GetAvatarUrl())
.WithName(user.Username));
eb.WithColor(new Color(138, 219, 146));
eb.Title = "Karma Increased";
eb.AddInlineField("By", Context.User.Username);
eb.AddInlineField("amount", "+1");
eb.AddInlineField("Current Karma", newKarma);
await ReplyAsync("", false, eb.Build());
}
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context);
}
}
[Command("bad", RunMode = RunMode.Async)]
[Summary("Decrease Someones Karma")]
public async Task Bad([Summary("@someone")] IUser user)
{
try
{
var lastKarmaFromRedis = redis.HashGet($"{Context.Guild.Id}:KarmaTimeout", Context.User.Id.ToString());
var lastKarma = ConvertToDateTimeOffset(lastKarmaFromRedis.ToString());
if (user.Id == Context.User.Id)
{
await ReplyAsync($"Sorry {Context.User.Username}, but you can't lower your own karma");
}
else if (TimeoutFinished(lastKarma))
{
await ReplyAsync(
$"Sorry {Context.User.Username}, but you have to wait {GetTimeLeft(lastKarma)} before you can take karma again...");
}
else
{
var newKarma = redis.HashDecrement($"{Context.Guild.Id}:Karma", user.Id.ToString());
redis.HashSet($"{Context.Guild.Id}:KarmaTimeout",
new HashEntry[] {new HashEntry(Context.User.Id.ToString(), DateTimeOffset.Now.ToString())});
var eb = new EmbedBuilder();
eb.WithAuthor(new EmbedAuthorBuilder()
.WithIconUrl(user.GetAvatarUrl())
.WithName(user.Username));
eb.WithColor(new Color(138, 219, 146));
eb.Title = "Karma Decreased";
eb.AddInlineField("By", Context.User.Username);
eb.AddInlineField("amount", "-1");
eb.AddInlineField("Current Karma", newKarma);
await ReplyAsync("", false, eb.Build());
}
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context);
}
}
private DateTimeOffset ConvertToDateTimeOffset(string dateTimeOffsetString)
{
if(string.IsNullOrEmpty(dateTimeOffsetString)) return DateTimeOffset.Now.Subtract(new TimeSpan(7, 18, 0, 0));
return DateTimeOffset.Parse(dateTimeOffsetString);
}
private bool TimeoutFinished(DateTimeOffset lastKarma)
{
return lastKarma.AddMinutes(3) > DateTimeOffset.Now;
}
private string GetTimeLeft(DateTimeOffset lastKarma)
{
var dt = lastKarma.AddMinutes(3).Subtract(DateTimeOffset.Now);
return $"{dt.Minutes} Minutes and {dt.Seconds} Seconds";
}
}
}

View file

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Dice : ModuleBase
{
private readonly Random rnd;
public Dice(Random RandomClient)
{
rnd = RandomClient;
}
[Command("dice", RunMode = RunMode.Async)]
[Summary("Roll a dice.")]
public async Task RollCommand([Remainder] [Summary("diceType")] string diceType = "1d20")
{
var splitedDices = diceType.Split("+");
var dices = new List<DiceTypeDto>();
var mod = 0;
foreach (var i in splitedDices)
{
var dice = toDice(i);
if (dice.sides != 0 && dice.times != 0)
{
dices.Add(dice);
}
else if (dice.mod != 0)
{
if (mod != 0)
{
await ReplyAsync("You can only have one mod");
return;
}
mod = dice.mod;
}
}
if (!dices.Any())
{
await ReplyAsync(
"That is not a valid dice, examples are: 1d20, 1d6, 2d6, 1d6+2, 1d6+2d8+1d20+6, etc...");
return;
}
var rep = new StringBuilder();
rep.AppendLine($":game_die: {Context.User.Mention}");
rep.Append("**Result:** ");
var resultStrings = new List<string>();
var total = 0;
var extraText = "";
foreach (var dice in dices)
{
var results = new List<int>();
for (var i = 0; i < dice.times; i++)
{
var roll = rnd.Next(1, dice.sides);
total += roll;
results.Add(roll);
if (roll == dice.sides)
{
extraText = "**Critical Hit!**";
}
if (roll == 1)
{
extraText = "**Critical Fail!**";
}
}
resultStrings.Add($"{dice.diceType} ({string.Join(",", results)})");
}
rep.Append(string.Join(" + ", resultStrings));
if (mod != 0)
{
rep.Append($" + {mod}");
total += mod;
}
rep.AppendLine();
rep.AppendLine($"**Total:** {total}");
if (extraText != "")
{
rep.AppendLine(extraText);
}
await ReplyAsync(rep.ToString());
}
private DiceTypeDto toDice(string dice)
{
var diceParts = dice.Split('d');
if (diceParts.Length == 2
&& int.TryParse(diceParts[0], out int times)
&& int.TryParse(diceParts[1], out int max))
{
return new DiceTypeDto()
{
diceType = dice,
times = times,
sides = max
};
}
if (dice.Length == 1
&& int.TryParse(diceParts[0], out int mod))
{
return new DiceTypeDto()
{
mod = mod
};
}
return new DiceTypeDto();
}
}
class DiceTypeDto
{
public string diceType { get; set; }
public int times { get; set; }
public int sides { get; set; }
public int mod { get; set; }
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Discord.Commands;
using Newtonsoft.Json;
namespace Geekbot.net.Commands
{
public class Dog : ModuleBase
{
[Command("dog", RunMode = RunMode.Async)]
[Summary("Return a random image of a dog.")]
public async Task Say()
{
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://random.dog");
var response = await client.GetAsync("/woof.json");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
var dogFile = JsonConvert.DeserializeObject<DogResponse>(stringResponse);
await ReplyAsync(dogFile.url);
}
catch (HttpRequestException e)
{
await ReplyAsync($"Seems like the dog got lost (error occured)\r\n{e.Message}");
}
}
}
}
public class DogResponse
{
public string url { get; set; }
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class EightBall : ModuleBase
{
private readonly Random rnd;
public EightBall(Random RandomClient)
{
rnd = RandomClient;
}
[Command("8ball", RunMode = RunMode.Async)]
[Summary("Ask 8Ball a Question.")]
public async Task Ball([Remainder] [Summary("Question")] string echo)
{
var replies = new List<string>
{
"It is certain",
"It is decidedly so",
"Without a doubt",
"Yes, definitely",
"You may rely on it",
"As I see it, yes",
"Most likely",
"Outlook good",
"Yes",
"Signs point to yes",
"Reply hazy try again",
"Ask again later",
"Better not tell you now",
"Cannot predict now",
"Concentrate and ask again",
"Don't count on it",
"My reply is no",
"My sources say no",
"Outlook not so good",
"Very doubtful"
};
var answer = rnd.Next(replies.Count);
await ReplyAsync(replies[answer]);
}
}
}

View file

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Discord.Commands;
using Geekbot.net.Lib.Media;
namespace Geekbot.net.Commands
{
public class Fortune : ModuleBase
{
private readonly IFortunesProvider fortunes;
public Fortune(IFortunesProvider fortunes)
{
this.fortunes = fortunes;
}
[Command("fortune", RunMode = RunMode.Async)]
[Summary("Get a random fortune")]
public async Task GetAFortune()
{
await ReplyAsync(fortunes.GetRandomFortune());
}
}
}

View file

@ -0,0 +1,17 @@
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Google : ModuleBase
{
[Command("google", RunMode = RunMode.Async)]
[Summary("Google Something.")]
public async Task Eyes([Remainder, Summary("SearchText")] string searchText)
{
var url = $"http://lmgtfy.com/?q={searchText.Replace(' ', '+')}";
await ReplyAsync($"Please click here :unamused:\r\n{url}");
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class GuildInfo : ModuleBase
{
private readonly IDatabase redis;
public GuildInfo(IDatabase redis)
{
this.redis = redis;
}
[Command("serverstats", RunMode = RunMode.Async)]
[Summary("Show some info about the bot.")]
public async Task getInfo()
{
var eb = new EmbedBuilder();
eb.WithAuthor(new EmbedAuthorBuilder()
.WithIconUrl(Context.Guild.IconUrl)
.WithName(Context.Guild.Name));
eb.WithColor(new Color(110, 204, 147));
var created = Context.Guild.CreatedAt;
var age = Math.Floor((DateTime.Now - created).TotalDays);
var messages = redis.HashGet($"{Context.Guild.Id}:Messages", 0.ToString());
var level = LevelCalc.GetLevelAtExperience((int) messages);
eb.AddField("Server Age", $"{created.Day}/{created.Month}/{created.Year} ({age} days)");
eb.AddInlineField("Level", level)
.AddInlineField("Messages", messages);
await ReplyAsync("", false, eb.Build());
}
public static string FirstCharToUpper(string input)
{
if (string.IsNullOrEmpty(input))
throw new ArgumentException("ARGH!");
return input.First().ToString().ToUpper() + input.Substring(1);
}
}
}

View file

@ -0,0 +1,48 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Help : ModuleBase
{
private readonly CommandService commands;
public Help(CommandService commands)
{
this.commands = commands;
}
[Command("help", RunMode = RunMode.Async)]
[Summary("List all Commands")]
public async Task GetHelp()
{
var sb = new StringBuilder();
sb.AppendLine("```");
sb.AppendLine("**Geekbot Command list**");
sb.AppendLine("");
sb.AppendLine(tp("Name", 15) + tp("Parameters", 19) + "Description");
foreach (var cmd in commands.Commands)
{
var param = string.Join(", !", cmd.Aliases);
if (!param.Contains("admin"))
if (cmd.Parameters.Any())
sb.AppendLine(tp(param, 15) +
tp(string.Join(" ", cmd.Parameters.Select(e => e.Summary)), 19) +
cmd.Summary);
else
sb.AppendLine(tp(param, 34) + cmd.Summary);
}
sb.AppendLine("```");
var dm = await Context.User.GetOrCreateDMChannelAsync();
await dm.SendMessageAsync(sb.ToString());
}
// Table Padding, short function name because of many usages
private string tp(string text, int shouldHave)
{
return text.PadRight(shouldHave);
}
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class Info : ModuleBase
{
private readonly IDatabase _redis;
private readonly IErrorHandler _errorHandler;
public Info(IDatabase redis, IErrorHandler errorHandler)
{
_redis = redis;
_errorHandler = errorHandler;
}
[Command("info", RunMode = RunMode.Async)]
[Summary("Get Information about the bot")]
public async Task BotInfo()
{
try
{
var eb = new EmbedBuilder();
eb.WithTitle("Geekbot V3.3");
var botOwner = Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner"))).Result;
var uptime = (DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime));
eb.AddInlineField("Bot Name", Context.Client.CurrentUser.Username)
.AddInlineField("Servers", Context.Client.GetGuildsAsync().Result.Count)
.AddInlineField("Uptime", $"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S")
.AddInlineField("Bot Owner", $"{botOwner.Username}#{botOwner.Discriminator}")
.AddInlineField("Website", "https://geekbot.pizzaandcoffee.rocks/");
await ReplyAsync("", false, eb.Build());
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context);
}
}
}
}

View file

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Discord.Commands;
using Geekbot.net.Lib.Media;
namespace Geekbot.net.Commands
{
public class Panda : ModuleBase
{
private readonly IPandaProvider pandaImages;
public Panda(IPandaProvider pandaImages)
{
this.pandaImages = pandaImages;
}
[Command("panda", RunMode = RunMode.Async)]
[Summary("Get a random panda")]
public async Task PandaCommand()
{
await ReplyAsync(pandaImages.GetRandomPanda());
}
}
}

View file

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Ping : ModuleBase
{
[Command("👀", RunMode = RunMode.Async)]
[Summary("Look at the bot.")]
public async Task Eyes()
{
await ReplyAsync("S... Stop looking at me... baka!");
}
}
}

View file

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
using Newtonsoft.Json;
using Serilog;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
[Group("quote")]
public class Quote : ModuleBase
{
private readonly IDatabase redis;
private readonly ILogger logger;
private readonly IErrorHandler errorHandler;
public Quote(IDatabase redis, ILogger logger, IErrorHandler errorHandler)
{
this.redis = redis;
this.logger = logger;
this.errorHandler = errorHandler;
}
[Command()]
[Summary("Return a random quoute from the database")]
public async Task getRandomQuote()
{
var randomQuote = redis.SetRandomMember($"{Context.Guild.Id}:Quotes");
try
{
var quote = JsonConvert.DeserializeObject<QuoteObject>(randomQuote);
var embed = quoteBuilder(quote);
await ReplyAsync("", false, embed.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return");
}
}
[Command("save")]
[Summary("Save a quote from the last sent message by @user")]
public async Task saveQuote([Summary("@user")] IUser user)
{
try
{
var lastMessage = await getLastMessageByUser(user);
var quote = createQuoteObject(lastMessage);
var quoteStore = JsonConvert.SerializeObject(quote);
redis.SetAdd($"{Context.Guild.Id}:Quotes", quoteStore);
var embed = quoteBuilder(quote);
await ReplyAsync("**Quote Added**", false, embed.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context, "I counldn't find a quote from that user :disappointed:");
}
}
[Command("save")]
[Summary("Save a quote from a message id")]
public async Task saveQuote([Summary("messageId")] ulong messageId)
{
try
{
var message = await Context.Channel.GetMessageAsync(messageId);
var quote = createQuoteObject(message);
var quoteStore = JsonConvert.SerializeObject(quote);
redis.SetAdd($"{Context.Guild.Id}:Quotes", quoteStore);
var embed = quoteBuilder(quote);
await ReplyAsync("**Quote Added**", false, embed.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context, "I couldn't find a message with that id :disappointed:");
}
}
[Command("make")]
[Summary("Create a quote from the last sent message by @user")]
public async Task returnSpecifiedQuote([Summary("@user")] IUser user)
{
try
{
var lastMessage = await getLastMessageByUser(user);
var quote = createQuoteObject(lastMessage);
var embed = quoteBuilder(quote);
await ReplyAsync("", false, embed.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context, "I counldn't find a quote from that user :disappointed:");
}
}
[Command("make")]
[Summary("Create a quote from a message id")]
public async Task returnSpecifiedQuote([Summary("messageId")] ulong messageId)
{
try
{
var message = await Context.Channel.GetMessageAsync(messageId);
var quote = createQuoteObject(message);
var embed = quoteBuilder(quote);
await ReplyAsync("", false, embed.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context, "I couldn't find a message with that id :disappointed:");
}
}
private async Task<IMessage> getLastMessageByUser(IUser user)
{
Task<IEnumerable<IMessage>> list = Context.Channel.GetMessagesAsync().Flatten();
await list;
return list.Result
.First(msg => msg.Author.Id == user.Id
&& msg.Embeds.Count == 0
&& msg.Id != Context.Message.Id
&& !msg.Content.ToLower().StartsWith("!"));
}
private EmbedBuilder quoteBuilder(QuoteObject quote)
{
var user = Context.Client.GetUserAsync(quote.userId).Result;
var eb = new EmbedBuilder();
eb.WithColor(new Color(143, 167, 232));
eb.Title = $"{user.Username} @ {quote.time.Day}.{quote.time.Month}.{quote.time.Year}";
eb.Description = quote.quote;
eb.ThumbnailUrl = user.GetAvatarUrl();
if (quote.image != null)
{
eb.ImageUrl = quote.image;
}
return eb;
}
private QuoteObject createQuoteObject(IMessage message)
{
string image;
try
{
image = message.Attachments.First().Url;
}
catch (Exception)
{
image = null;
}
return new QuoteObject()
{
userId = message.Author.Id,
time = message.Timestamp.DateTime,
quote = message.Content,
image = image
};
}
}
public class QuoteObject {
public ulong userId { get; set; }
public string quote { get; set; }
public DateTime time { get; set; }
public string image { get; set; }
}
}

View file

@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class Roll : ModuleBase
{
private readonly IDatabase redis;
private readonly Random rnd;
public Roll(IDatabase redis, Random RandomClient)
{
this.redis = redis;
rnd = RandomClient;
}
[Command("roll", RunMode = RunMode.Async)]
[Summary("Roll a number between 1 and 100.")]
public async Task RollCommand([Remainder] [Summary("stuff...")] string stuff = "nothing")
{
var number = rnd.Next(1, 100);
var guess = 1000;
int.TryParse(stuff, out guess);
if (guess <= 100 && guess > 0)
{
await ReplyAsync($"{Context.Message.Author.Mention} you rolled {number}, your guess was {guess}");
if (guess == number)
{
await ReplyAsync($"Congratulations {Context.User.Username}, your guess was correct!");
redis.HashIncrement($"{Context.Guild.Id}:Rolls", Context.User.Id.ToString());
}
}
else
{
await ReplyAsync(Context.Message.Author.Mention + ", you rolled " + number);
}
}
}
}

View file

@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
namespace Geekbot.net.Commands
{
public class Say : ModuleBase
{
[RequireUserPermission(GuildPermission.Administrator)]
[Command("say", RunMode = RunMode.Async)]
[Summary("Say Something.")]
public async Task Echo([Remainder] [Summary("What?")] string echo)
{
await Context.Message.DeleteAsync();
await ReplyAsync(echo);
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class Ship : ModuleBase
{
private readonly IDatabase redis;
private readonly Random rnd;
public Ship(IDatabase redis, Random RandomClient)
{
this.redis = redis;
rnd = RandomClient;
}
[Command("Ship", RunMode = RunMode.Async)]
[Summary("Ask the Shipping meter")]
public async Task Command([Summary("@User1")] IUser user1, [Summary("@User2")] IUser user2)
{
// Create a String
var dbstring = "";
if (user1.Id > user2.Id)
dbstring = $"{user1.Id}-{user2.Id}";
else
dbstring = $"{user2.Id}-{user1.Id}";
var dbval = redis.HashGet($"{Context.Guild.Id}:Ships", dbstring);
var shippingRate = 0;
if (dbval.IsNullOrEmpty)
{
shippingRate = rnd.Next(1, 100);
redis.HashSet($"{Context.Guild.Id}:Ships", dbstring, shippingRate);
}
else
{
shippingRate = int.Parse(dbval.ToString());
}
var reply = ":heartpulse: **Matchmaking** :heartpulse:\r\n";
reply = reply + $":two_hearts: {user1.Mention} :heart: {user2.Mention} :two_hearts:\r\n";
reply = reply + $"0% [{BlockCounter(shippingRate)}] 100% - {DeterminateSuccess(shippingRate)}";
await ReplyAsync(reply);
}
private string DeterminateSuccess(int rate)
{
if (rate < 20)
return "Not gonna happen";
if (rate >= 20 && rate < 40)
return "Not such a good idea";
if (rate >= 40 && rate < 60)
return "There might be a chance";
if (rate >= 60 && rate < 80)
return "Almost a match, but could work";
if (rate >= 80)
return "It's a match";
return "a";
}
private string BlockCounter(int rate)
{
var amount = Math.Floor(decimal.Floor(rate / 10));
Console.WriteLine(amount);
var blocks = "";
for (var i = 1; i <= 10; i++)
if (i <= amount)
{
blocks = blocks + ":white_medium_small_square:";
if (i == amount)
blocks = blocks + $" {rate}% ";
}
else
{
blocks = blocks + ":black_medium_small_square:";
}
return blocks;
}
}
}

View file

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
using Serilog;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class UserInfo : ModuleBase
{
private readonly IDatabase redis;
private readonly IErrorHandler errorHandler;
private readonly ILogger logger;
private readonly IUserRepository userRepository;
public UserInfo(IDatabase redis, IErrorHandler errorHandler, ILogger logger, IUserRepository userRepository)
{
this.redis = redis;
this.errorHandler = errorHandler;
this.logger = logger;
this.userRepository = userRepository;
}
[Command("stats", RunMode = RunMode.Async)]
[Summary("Get information about this user")]
public async Task User([Summary("@someone")] IUser user = null)
{
try
{
var userInfo = user ?? Context.Message.Author;
var userGuildInfo = (IGuildUser) userInfo;
var createdAt = userInfo.CreatedAt;
var joinedAt = userGuildInfo.JoinedAt.Value;
var age = Math.Floor((DateTime.Now - createdAt).TotalDays);
var joinedDayAgo = Math.Floor((DateTime.Now - joinedAt).TotalDays);
var messages = (int) redis.HashGet($"{Context.Guild.Id}:Messages", userInfo.Id.ToString());
var guildMessages = (int) redis.HashGet($"{Context.Guild.Id}:Messages", 0.ToString());
var level = LevelCalc.GetLevelAtExperience(messages);
var percent = Math.Round((double) (100 * messages) / guildMessages, 2);
var eb = new EmbedBuilder();
eb.WithAuthor(new EmbedAuthorBuilder()
.WithIconUrl(userInfo.GetAvatarUrl())
.WithName(userInfo.Username));
eb.WithColor(new Color(221, 255, 119));
var karma = redis.HashGet($"{Context.Guild.Id}:Karma", userInfo.Id);
var correctRolls = redis.HashGet($"{Context.Guild.Id}:Rolls", userInfo.Id.ToString());
eb.AddInlineField("Discordian Since", $"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} days)")
.AddInlineField("Joined Server", $"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} days)")
.AddInlineField("Karma", karma.ToString() ?? "0")
.AddInlineField("Level", level)
.AddInlineField("Messages Sent", messages)
.AddInlineField("Server Total", $"{percent}%");
if (!correctRolls.IsNullOrEmpty)
eb.AddInlineField("Guessed Rolls", correctRolls);
await ReplyAsync("", false, eb.Build());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context);
}
}
[Command("rank", RunMode = RunMode.Async)]
[Summary("get user top 10")]
public async Task Rank()
{
try
{
var messageList = redis.HashGetAll($"{Context.Guild.Id}:Messages");
var sortedList = messageList.OrderByDescending(e => e.Value).ToList();
var guildMessages = (int) sortedList.First().Value;
sortedList.RemoveAt(0);
var highscoreUsers = new Dictionary<RankUserPolyfill, int>();
var listLimiter = 1;
var failedToRetrieveUser = false;
foreach (var user in sortedList)
{
if (listLimiter > 10) break;
try
{
var guildUser = userRepository.Get((ulong)user.Name);
if (guildUser.Username != null)
{
highscoreUsers.Add(new RankUserPolyfill()
{
Username = guildUser.Username,
Discriminator = guildUser.Discriminator
}, (int) user.Value);
}
else
{
highscoreUsers.Add(new RankUserPolyfill()
{
Id = user.Name
}, (int) user.Value);
failedToRetrieveUser = true;
}
listLimiter++;
}
catch (Exception e)
{
logger.Warning(e, $"Could not retrieve user {user.Name}");
}
}
var highScore = new StringBuilder();
if (failedToRetrieveUser) highScore.AppendLine(":warning: I couldn't get all userdata, sorry! (bugfix coming soon:tm:)\n");
highScore.AppendLine($":bar_chart: **Highscore for {Context.Guild.Name}**");
var highscorePlace = 1;
foreach (var user in highscoreUsers)
{
var percent = Math.Round((double) (100 * user.Value) / guildMessages, 2);
if (user.Key.Username != null)
{
highScore.AppendLine(
$"{NumerToEmoji(highscorePlace)} **{user.Key.Username}#{user.Key.Discriminator}** - {percent}% of total - {user.Value} messages");
}
else
{
highScore.AppendLine(
$"{NumerToEmoji(highscorePlace)} **{user.Key.Id}** - {percent}% of total - {user.Value} messages");
}
highscorePlace++;
}
await ReplyAsync(highScore.ToString());
}
catch (Exception e)
{
errorHandler.HandleCommandException(e, Context);
}
}
private string NumerToEmoji(int number)
{
var emojis = new string[] {":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":keycap_ten:"};
try
{
return emojis[number - 1];
}
catch (Exception e)
{
logger.Warning(e, $"Can't provide emoji number {number}");
return ":zero:";
}
}
}
class RankUserPolyfill
{
public string Username { get; set; }
public string Discriminator { get; set; }
public string Id { get; set; }
}
}

View file

@ -0,0 +1,59 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using StackExchange.Redis;
namespace Geekbot.net.Commands
{
public class Youtube : ModuleBase
{
private readonly IDatabase redis;
public Youtube(IDatabase redis)
{
this.redis = redis;
}
[Command("yt", RunMode = RunMode.Async)]
[Summary("Search for something on youtube.")]
public async Task Yt([Remainder] [Summary("Title")] string searchQuery)
{
var key = redis.StringGet("youtubeKey");
if (key.IsNullOrEmpty)
{
await ReplyAsync("No youtube key set, please tell my senpai to set one");
return;
}
try
{
var youtubeService = new YouTubeService(new BaseClientService.Initializer
{
ApiKey = key.ToString(),
ApplicationName = GetType().ToString()
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = searchQuery;
searchListRequest.MaxResults = 2;
var searchListResponse = await searchListRequest.ExecuteAsync();
var result = searchListResponse.Items[0];
await ReplyAsync(
$"\"{result.Snippet.Title}\" from \"{result.Snippet.ChannelTitle}\" https://youtu.be/{result.Id.VideoId}");
}
catch (Exception e)
{
await ReplyAsync("Something went wrong... informing my senpai...");
var botOwner = Context.Guild.GetUserAsync(ulong.Parse(redis.StringGet("botOwner"))).Result;
var dm = await botOwner.GetOrCreateDMChannelAsync();
await dm.SendMessageAsync(
$"Something went wrong while getting a video from youtube:\r\n```\r\n{e.Message}\r\n```");
}
}
}
}

116
Geekbot.net/Commands/mal.cs Normal file
View file

@ -0,0 +1,116 @@
using System;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.net.Lib;
namespace Geekbot.net.Commands
{
public class mal : ModuleBase
{
private readonly IMalClient _malClient;
private readonly IErrorHandler _errorHandler;
public mal(IMalClient malClient, IErrorHandler errorHandler)
{
_malClient = malClient;
_errorHandler = errorHandler;
}
[Command("anime", RunMode = RunMode.Async)]
[Summary("Show Info about an Anime.")]
public async Task searchAnime([Remainder, Summary("AnimeName")] string animeName)
{
try
{
if (_malClient.isLoggedIn())
{
var anime = await _malClient.getAnime(animeName);
if (anime != null)
{
var eb = new EmbedBuilder();
var description = System.Web.HttpUtility.HtmlDecode(anime.Synopsis)
.Replace("<br />", "")
.Replace("[i]", "*")
.Replace("[/i]", "*");
eb.Title = anime.Title;
eb.Description = description;
eb.ImageUrl = anime.Image;
eb.AddInlineField("Premiered", $"{anime.StartDate}");
eb.AddInlineField("Ended", anime.EndDate == "0000-00-00" ? "???" : anime.EndDate);
eb.AddInlineField("Status", anime.Status);
eb.AddInlineField("Episodes", anime.Episodes);
eb.AddInlineField("MAL Score", anime.Score);
eb.AddInlineField("Type", anime.Type);
eb.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.Id}");
await ReplyAsync("", false, eb.Build());
}
else
{
await ReplyAsync("No anime found with that name...");
}
}
else
{
await ReplyAsync(
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
}
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "Something went wrong...");
}
}
[Command("manga", RunMode = RunMode.Async)]
[Summary("Show Info about a Manga.")]
public async Task searchManga([Remainder, Summary("MangaName")] string mangaName)
{
try
{
if (_malClient.isLoggedIn())
{
var manga = await _malClient.getManga(mangaName);
if (manga != null)
{
var eb = new EmbedBuilder();
var description = System.Web.HttpUtility.HtmlDecode(manga.Synopsis)
.Replace("<br />", "")
.Replace("[i]", "*")
.Replace("[/i]", "*");
eb.Title = manga.Title;
eb.Description = description;
eb.ImageUrl = manga.Image;
eb.AddInlineField("Premiered", $"{manga.StartDate}");
eb.AddInlineField("Ended", manga.EndDate == "0000-00-00" ? "???" : manga.EndDate);
eb.AddInlineField("Status", manga.Status);
eb.AddInlineField("Volumes", manga.Volumes);
eb.AddInlineField("Chapters", manga.Chapters);
eb.AddInlineField("MAL Score", manga.Score);
eb.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.Id}");
await ReplyAsync("", false, eb.Build());
}
else
{
await ReplyAsync("No manga found with that name...");
}
}
else
{
await ReplyAsync(
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
}
}
catch (Exception e)
{
_errorHandler.HandleCommandException(e, Context, "Something went wrong...");
}
}
}
}