Compare commits
1 commit
master
...
context-ha
Author | SHA1 | Date | |
---|---|---|---|
70d92706e2 |
360 changed files with 5393 additions and 14204 deletions
38
.deploy.yml
38
.deploy.yml
|
@ -1,38 +0,0 @@
|
||||||
---
|
|
||||||
- name: Geekbot Deploy
|
|
||||||
hosts: all
|
|
||||||
remote_user: geekbot
|
|
||||||
vars:
|
|
||||||
ansible_port: 65432
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
tasks:
|
|
||||||
- name: Login to Gitlab Docker Registry
|
|
||||||
'community.docker.docker_login':
|
|
||||||
registry_url: "{{ lookup('env', 'CI_REGISTRY') }}"
|
|
||||||
username: "{{ lookup('env', 'CI_REGISTRY_USER') }}"
|
|
||||||
password: "{{ lookup('env', 'CI_REGISTRY_PASSWORD') }}"
|
|
||||||
reauthorize: yes
|
|
||||||
- name: Replace Prod Container
|
|
||||||
'community.docker.docker_container':
|
|
||||||
name: GeekbotProd
|
|
||||||
image: "{{ lookup('env', 'IMAGE_TAG') }}"
|
|
||||||
recreate: yes
|
|
||||||
pull: yes
|
|
||||||
restart_policy: always
|
|
||||||
keep_volumes: no
|
|
||||||
ports:
|
|
||||||
- "12995:12995"
|
|
||||||
env:
|
|
||||||
GEEKBOT_DB_HOST: "{{ lookup('env', 'GEEKBOT_DB_HOST') }}"
|
|
||||||
GEEKBOT_DB_USER: "{{ lookup('env', 'GEEKBOT_DB_USER') }}"
|
|
||||||
GEEKBOT_DB_PASSWORD: "{{ lookup('env', 'GEEKBOT_DB_PASSWORD') }}"
|
|
||||||
GEEKBOT_DB_PORT: "{{ lookup('env', 'GEEKBOT_DB_PORT') }}"
|
|
||||||
GEEKBOT_DB_DATABASE: "{{ lookup('env', 'GEEKBOT_DB_DATABASE') }}"
|
|
||||||
GEEKBOT_DB_REQUIRE_SSL: "true"
|
|
||||||
GEEKBOT_DB_TRUST_CERT: "true"
|
|
||||||
GEEKBOT_SUMOLOGIC: "{{ lookup('env', 'GEEKBOT_SUMOLOCIG') }}"
|
|
||||||
GEEKBOT_SENTRY: "{{ lookup('env', 'GEEKBOT_SENTRY') }}"
|
|
||||||
GEEKBOT_DB_REDSHIFT_COMPAT: "true"
|
|
||||||
- name: Cleanup Old Container
|
|
||||||
'community.docker.docker_prune':
|
|
||||||
images: yes
|
|
16
.gitignore
vendored
16
.gitignore
vendored
|
@ -1,10 +1,12 @@
|
||||||
/*/**/bin
|
Geekbot.net/bin
|
||||||
/*/**/obj
|
Geekbot.net/obj
|
||||||
src/Bot/tmp/
|
Geekbot.net/tmp/
|
||||||
src/Bot/Logs/*
|
Tests/bin
|
||||||
!/src/Bot/Logs/.keep
|
Tests/obj
|
||||||
|
Backup/
|
||||||
.vs/
|
.vs/
|
||||||
|
UpgradeLog.htm
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
Geekbot.net.sln.DotSettings.user
|
Geekbot.net/Logs/*
|
||||||
app
|
!/Geekbot.net/Logs/.keep
|
||||||
|
|
|
@ -1,69 +1,54 @@
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
- docker
|
|
||||||
- deploy
|
- deploy
|
||||||
- ops
|
|
||||||
|
|
||||||
variables:
|
before_script:
|
||||||
VERSION: 4.4.0-V$CI_COMMIT_SHORT_SHA
|
- set -e
|
||||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
- set -u
|
||||||
|
- set -o pipefail
|
||||||
|
|
||||||
Build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
image: mcr.microsoft.com/dotnet/sdk:6.0
|
image: microsoft/dotnet:2.0.3-sdk-stretch
|
||||||
|
variables:
|
||||||
|
NUGET_PACKAGES: "${CI_PROJECT_DIR}/.nugetcache"
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .nugetcache
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 1h
|
expire_in: 1h
|
||||||
paths:
|
paths:
|
||||||
- app
|
- Geekbot.net/Binaries/
|
||||||
script:
|
script:
|
||||||
- dotnet restore
|
- dotnet restore
|
||||||
- dotnet test tests
|
- dotnet test Tests
|
||||||
- dotnet publish --version-suffix "$VERSION" -r linux-x64 -c Release -p:DebugType=embedded --no-self-contained -o ./app ./src/Startup/
|
- dotnet publish --configuration Release -o Binaries ./
|
||||||
|
|
||||||
Package:
|
deploy:
|
||||||
stage: docker
|
|
||||||
image: docker
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
services:
|
|
||||||
- docker:stable-dind
|
|
||||||
script:
|
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
|
||||||
- docker build -t $IMAGE_TAG .
|
|
||||||
- docker push $IMAGE_TAG
|
|
||||||
|
|
||||||
Deploy:
|
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: quay.io/ansible/ansible-runner:stable-2.12-latest
|
image: instrumentisto/rsync-ssh
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
variables:
|
dependencies:
|
||||||
ANSIBLE_NOCOWS: 1
|
- build
|
||||||
|
environment:
|
||||||
|
name: Production
|
||||||
|
url: https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054
|
||||||
before_script:
|
before_script:
|
||||||
- mkdir /root/.ssh
|
- eval $(ssh-agent -s)
|
||||||
- cp $SSH_PRIVATE_KEY /root/.ssh/id_ed25519
|
- mkdir -p ~/.ssh
|
||||||
- cp $SSH_PUBLIC_KEY /root/.ssh/id_ed25519.pub
|
- '[[ -f /.dockerenv ]] && echo -e "Host *\n StrictHostKeyChecking no" > ~/.ssh/config'
|
||||||
- chmod -R 600 /root/.ssh
|
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
|
||||||
- ssh-keyscan -p 65432 $PROD_IP > /root/.ssh/known_hosts
|
- chmod 700 ~/.ssh
|
||||||
script:
|
script:
|
||||||
- ansible-galaxy collection install -r ansible-requirements.yml
|
- rsync -rav -e "ssh -p 65432" ./Geekbot.net/Binaries/* www-data@31.220.42.224:$DEPPATH
|
||||||
- ansible-playbook -i $PROD_IP, .deploy.yml
|
- ssh -p 65432 www-data@31.220.42.224 "sudo systemctl restart geekbot.service"
|
||||||
|
|
||||||
Sentry:
|
mirror:
|
||||||
stage: ops
|
stage: deploy
|
||||||
image: getsentry/sentry-cli
|
image: bravissimolabs/alpine-git:latest
|
||||||
allow_failure: true
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
script:
|
|
||||||
- sentry-cli releases new -p geekbot $VERSION
|
|
||||||
- sentry-cli releases set-commits --auto $VERSION
|
|
||||||
- sentry-cli releases deploys $VERSION new -e Production
|
|
||||||
|
|
||||||
Github Mirror:
|
|
||||||
stage: ops
|
|
||||||
image: runebaas/rsync-ssh-git
|
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
script:
|
script:
|
||||||
- git push https://runebaas:$TOKEN@github.com/pizzaandcoffee/Geekbot.net.git origin/master:master -f
|
- git push https://runebaas:$TOKEN@github.com/pizzaandcoffee/Geekbot.net.git origin/master:master -f
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0
|
|
||||||
|
|
||||||
COPY ./app /app/
|
|
||||||
|
|
||||||
EXPOSE 12995/tcp
|
|
||||||
WORKDIR /app
|
|
||||||
ENTRYPOINT ./Geekbot
|
|
|
@ -3,19 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 2013
|
||||||
VisualStudioVersion = 12.0.0.0
|
VisualStudioVersion = 12.0.0.0
|
||||||
MinimumVisualStudioVersion = 10.0.0.1
|
MinimumVisualStudioVersion = 10.0.0.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geekbot.net", "Geekbot.net/Geekbot.net.csproj", "{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{47671723-52A9-4668-BBC5-2BA76AE3B288}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}"
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{0A63D5DC-6325-4F53-8ED2-9843239B76CC}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot", "src\Bot\Bot.csproj", "{DBF79896-9F7F-443D-B336-155E276DFF16}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands", "src\Commands\Commands.csproj", "{7C771DFE-912A-4276-B0A6-047E09603F1E}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interactions", "src\Interactions\Interactions.csproj", "{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startup", "src\Startup\Startup.csproj", "{A691B018-4B19-4A7A-A0F6-DBB17641254F}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -23,34 +13,14 @@ Global
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
|
||||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">200</s:Int64>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
159
Geekbot.net/Commands/Admin.cs
Normal file
159
Geekbot.net/Commands/Admin.cs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("admin")]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
public class Admin : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Admin(IDatabase redis, DiscordSocketClient client, IErrorHandler errorHandler,
|
||||||
|
ITranslationHandler translationHandler)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_client = client;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_translation = translationHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("welcome", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[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[] {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("modchannel", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Set a channel for moderation purposes")]
|
||||||
|
public async Task selectModChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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[] {new HashEntry("ModChannel", channel.Id.ToString())});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to be valid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("showleave", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Notify modchannel when someone leaves")]
|
||||||
|
public async Task showLeave([Summary("true/false")] bool enabled)
|
||||||
|
{
|
||||||
|
var modChannelId = ulong.Parse(_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[] {new HashEntry("ShowLeave", true)});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await modChannel.SendMessageAsync("Saved - stopping sending messages here when someone leaves");
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ShowLeave", false)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context,
|
||||||
|
"Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("showdel", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Notify modchannel when someone deletes a message")]
|
||||||
|
public async Task showDelete([Summary("true/false")] bool enabled)
|
||||||
|
{
|
||||||
|
var modChannelId = ulong.Parse(_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[] {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[] {new HashEntry("ShowDelete", false)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context,
|
||||||
|
"Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("setlang", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Change the bots language")]
|
||||||
|
public async Task setLanguage([Summary("language")] string languageRaw)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var language = languageRaw.ToUpper();
|
||||||
|
var success = _translation.SetLanguage(Context.Guild.Id, language);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
var trans = _translation.GetDict(Context);
|
||||||
|
await ReplyAsync(trans["NewLanguageSet"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync(
|
||||||
|
$"That doesn't seem to be a supported language\r\nSupported Languages are {string.Join(", ", _translation.GetSupportedLanguages())}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("lang", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Change the bots language")]
|
||||||
|
public async Task getLanguage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var trans = _translation.GetDict(Context);
|
||||||
|
await ReplyAsync(trans["GetLanguage"]);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,12 +2,11 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class AvatarGetter : TransactionModuleBase
|
public class AvatarGetter : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -17,18 +16,19 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("avatar", RunMode = RunMode.Async)]
|
[Command("avatar", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("Get someones avatar")]
|
[Summary("Get someones avatar")]
|
||||||
public async Task GetAvatar([Remainder, Summary("@someone")] IUser user = null)
|
public async Task getAvatar([Remainder] [Summary("user")] IUser user = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
user ??= Context.User;
|
if (user == null) user = Context.User;
|
||||||
var url = user.GetAvatarUrl(ImageFormat.Auto, 1024);
|
var url = user.GetAvatarUrl().Replace("128", "1024");
|
||||||
await ReplyAsync(url);
|
await ReplyAsync(url);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
71
Geekbot.net/Commands/BattleTag.cs
Normal file
71
Geekbot.net/Commands/BattleTag.cs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("battletag")]
|
||||||
|
public class BattleTag : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public BattleTag(IErrorHandler errorHandler, IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
[Summary("Get your battletag")]
|
||||||
|
public async Task BattleTagCmd()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tag = _userRepository.getUserSetting(Context.User.Id, "BattleTag");
|
||||||
|
if (!string.IsNullOrEmpty(tag))
|
||||||
|
await ReplyAsync($"Your BattleTag is {tag}");
|
||||||
|
else
|
||||||
|
await ReplyAsync("You haven't set your BattleTag, set it with `!battletag user#1234`");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
[Summary("Save your battletag")]
|
||||||
|
public async Task BattleTagCmd([Summary("Battletag")] string tag)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isValidTag(tag))
|
||||||
|
{
|
||||||
|
_userRepository.saveUserSetting(Context.User.Id, "BattleTag", tag);
|
||||||
|
await ReplyAsync("Saved!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyAsync("That doesn't seem to be a valid battletag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool isValidTag(string tag)
|
||||||
|
{
|
||||||
|
var splited = tag.Split("#");
|
||||||
|
if (splited.Length != 2) return false;
|
||||||
|
if (!int.TryParse(splited[1], out var discriminator)) return false;
|
||||||
|
if (splited[1].Length == 4 || splited[1].Length == 5) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
Geekbot.net/Commands/Cat.cs
Normal file
58
Geekbot.net/Commands/Cat.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Cat : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Cat(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cat", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Return a random image of a cat.")]
|
||||||
|
public async Task Say()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.ImageUrl = catFile.file;
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
await ReplyAsync($"Seems like the dog cought the cat (error occured)\r\n{e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CatResponse
|
||||||
|
{
|
||||||
|
public string file { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
Geekbot.net/Commands/Changelog.cs
Normal file
89
Geekbot.net/Commands/Changelog.cs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Changelog : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Changelog(IErrorHandler errorHandler, DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("changelog", RunMode = RunMode.Async)]
|
||||||
|
[Alias("updates")]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Show the latest 5 updates")]
|
||||||
|
public async Task getChangelog()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
client.BaseAddress = new Uri("https://api.github.com");
|
||||||
|
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent",
|
||||||
|
"http://developer.github.com/v3/#user-agent-required");
|
||||||
|
var response = await client.GetAsync("/repos/pizzaandcoffee/geekbot.net/commits");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
var commits = JsonConvert.DeserializeObject<List<Commit>>(stringResponse);
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.WithColor(new Color(143, 165, 102));
|
||||||
|
eb.WithAuthor(new EmbedAuthorBuilder
|
||||||
|
{
|
||||||
|
IconUrl = _client.CurrentUser.GetAvatarUrl(),
|
||||||
|
Name = "Latest Updates",
|
||||||
|
Url = "https://geekbot.pizzaandcoffee.rocks/updates"
|
||||||
|
});
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var commit in commits.Take(10))
|
||||||
|
sb.AppendLine($"- {commit.commit.message} ({commit.commit.author.date:yyyy-MM-dd})");
|
||||||
|
eb.Description = sb.ToString();
|
||||||
|
eb.WithFooter(new EmbedFooterBuilder
|
||||||
|
{
|
||||||
|
Text = $"List generated from github commits on {DateTime.Now:yyyy-MM-dd}"
|
||||||
|
});
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Commit
|
||||||
|
{
|
||||||
|
public string sha { get; set; }
|
||||||
|
public CommitInfo commit { get; set; }
|
||||||
|
public Uri html_url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommitInfo
|
||||||
|
{
|
||||||
|
public commitAuthor author { get; set; }
|
||||||
|
public string message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class commitAuthor
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public string email { get; set; }
|
||||||
|
public DateTimeOffset date { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
Geekbot.net/Commands/CheckEm.cs
Normal file
74
Geekbot.net/Commands/CheckEm.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class CheckEm : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IMediaProvider _checkEmImages;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly Random _rnd;
|
||||||
|
|
||||||
|
public CheckEm(Random RandomClient, IMediaProvider mediaProvider, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_rnd = RandomClient;
|
||||||
|
_checkEmImages = mediaProvider;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("checkem", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[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.getCheckem());
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
Geekbot.net/Commands/Choose.cs
Normal file
40
Geekbot.net/Commands/Choose.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Choose : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly Random _rnd;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Choose(Random RandomClient, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_rnd = RandomClient;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_translation = translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("choose", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Let the bot choose for you, seperate options with a semicolon.")]
|
||||||
|
public async Task Command([Remainder] [Summary("option1;option2")]
|
||||||
|
string choices)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var transDict = _translation.GetDict(Context);
|
||||||
|
var choicesArray = choices.Split(';');
|
||||||
|
var choice = _rnd.Next(choicesArray.Length);
|
||||||
|
await ReplyAsync(string.Format(transDict["Choice"], choicesArray[choice]));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
Geekbot.net/Commands/ContextHandler.cs
Normal file
97
Geekbot.net/Commands/ContextHandler.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class ContextHandler : IContextHandler
|
||||||
|
{
|
||||||
|
private Dictionary<ulong, ContextStore> _store;
|
||||||
|
private readonly IDiscordClient _client;
|
||||||
|
private readonly CommandService _commandService;
|
||||||
|
private readonly IServiceProvider _servicesProvider;
|
||||||
|
|
||||||
|
public ContextHandler(IDiscordClient client, CommandService commandService, IServiceProvider servicesProvider)
|
||||||
|
{
|
||||||
|
_store = new Dictionary<ulong, ContextStore>();
|
||||||
|
_commandService = commandService;
|
||||||
|
_servicesProvider = servicesProvider;
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContextReference HasContext(IUserMessage message)
|
||||||
|
{
|
||||||
|
if (_store.ContainsKey(message.Author.Id)) return ContextReference.User;
|
||||||
|
|
||||||
|
if (_store.ContainsKey(message.Channel.Id)) return ContextReference.Channel;
|
||||||
|
|
||||||
|
return ContextReference.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveContext(ContextReference type, ICommandContext context, string commandName)
|
||||||
|
{
|
||||||
|
var contextStore = new ContextStore()
|
||||||
|
{
|
||||||
|
CommandName = commandName
|
||||||
|
};
|
||||||
|
var id = GetId(type, context.Message);
|
||||||
|
_store.Add(id, contextStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ExecuteOnContext(ContextReference type, IUserMessage message)
|
||||||
|
{
|
||||||
|
var id = GetId(type, message);
|
||||||
|
var obj = _store[id];
|
||||||
|
var context = new CommandContext(_client, message);
|
||||||
|
var rest = await _commandService.ExecuteAsync(context, $"{obj.CommandSearch} {context.Message?.Content}", _servicesProvider);
|
||||||
|
if (!rest.IsSuccess)
|
||||||
|
{
|
||||||
|
await context.Channel.SendMessageAsync(rest.ErrorReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearContext(ulong id)
|
||||||
|
{
|
||||||
|
_store.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong GetId(ContextReference type, IUserMessage message)
|
||||||
|
{
|
||||||
|
if (type == ContextReference.Channel)
|
||||||
|
{
|
||||||
|
return message.Author.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == ContextReference.User)
|
||||||
|
{
|
||||||
|
return message.Author.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("No Context Object Found");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ContextStore
|
||||||
|
{
|
||||||
|
public string CommandName { get; set; }
|
||||||
|
public string CommandSearch => $"{CommandName} ctx";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ContextReference
|
||||||
|
{
|
||||||
|
User,
|
||||||
|
Channel,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IContextHandler
|
||||||
|
{
|
||||||
|
ContextReference HasContext(IUserMessage message);
|
||||||
|
void SaveContext(ContextReference type, ICommandContext context, string commandName);
|
||||||
|
void ExecuteOnContext(ContextReference type, IUserMessage message);
|
||||||
|
void ClearContext(ulong id);
|
||||||
|
}
|
||||||
|
}
|
130
Geekbot.net/Commands/Dice.cs
Normal file
130
Geekbot.net/Commands/Dice.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Dice : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly Random _rnd;
|
||||||
|
|
||||||
|
public Dice(Random RandomClient)
|
||||||
|
{
|
||||||
|
_rnd = RandomClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("dice", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dices.Any(d => d.times > 20))
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't throw more than 20 dices");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dices.Any(d => d.sides > 120))
|
||||||
|
{
|
||||||
|
await ReplyAsync("A dice can't have more than 120 sides");
|
||||||
|
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 var times)
|
||||||
|
&& int.TryParse(diceParts[1], out var max))
|
||||||
|
return new DiceTypeDto
|
||||||
|
{
|
||||||
|
diceType = dice,
|
||||||
|
times = times,
|
||||||
|
sides = max
|
||||||
|
};
|
||||||
|
if (dice.Length == 1
|
||||||
|
&& int.TryParse(diceParts[0], out var mod))
|
||||||
|
return new DiceTypeDto
|
||||||
|
{
|
||||||
|
mod = mod
|
||||||
|
};
|
||||||
|
return new DiceTypeDto();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DiceTypeDto
|
||||||
|
{
|
||||||
|
public string diceType { get; set; }
|
||||||
|
public int times { get; set; }
|
||||||
|
public int sides { get; set; }
|
||||||
|
public int mod { get; set; }
|
||||||
|
}
|
||||||
|
}
|
58
Geekbot.net/Commands/Dog.cs
Normal file
58
Geekbot.net/Commands/Dog.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Dog : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Dog(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("dog", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Return a random image of a dog.")]
|
||||||
|
public async Task Say()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.ImageUrl = dogFile.url;
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
await ReplyAsync($"Seems like the dog got lost (error occured)\r\n{e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DogResponse
|
||||||
|
{
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
Geekbot.net/Commands/EightBall.cs
Normal file
60
Geekbot.net/Commands/EightBall.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class EightBall : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly Random _rnd;
|
||||||
|
|
||||||
|
public EightBall(Random RandomClient, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_rnd = RandomClient;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("8ball", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Ask 8Ball a Question.")]
|
||||||
|
public async Task Ball([Remainder] [Summary("Question")] string echo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,29 @@
|
||||||
using Discord.Commands;
|
using System;
|
||||||
using Geekbot.Core;
|
using System.Threading.Tasks;
|
||||||
using Geekbot.Core.Converters;
|
using Discord.Commands;
|
||||||
using Geekbot.Core.ErrorHandling;
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Emojify : TransactionModuleBase
|
public class Emojify : ModuleBase
|
||||||
{
|
{
|
||||||
|
private readonly IEmojiConverter _emojiConverter;
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
public Emojify(IErrorHandler errorHandler)
|
public Emojify(IErrorHandler errorHandler, IEmojiConverter emojiConverter)
|
||||||
{
|
{
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
|
_emojiConverter = emojiConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("emojify", RunMode = RunMode.Async)]
|
[Command("emojify", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("Emojify text")]
|
[Summary("Emojify text")]
|
||||||
public async Task Dflt([Remainder] [Summary("text")] string text)
|
public async Task Dflt([Remainder] [Summary("text")] string text)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var emojis = EmojiConverter.TextToEmoji(text);
|
var emojis = _emojiConverter.textToEmoji(text);
|
||||||
if (emojis.Length > 1999)
|
if (emojis.Length > 1999)
|
||||||
{
|
{
|
||||||
await ReplyAsync("I can't take that much at once!");
|
await ReplyAsync("I can't take that much at once!");
|
||||||
|
@ -29,18 +32,10 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
|
|
||||||
await ReplyAsync($"{Context.User.Username}#{Context.User.Discriminator} said:");
|
await ReplyAsync($"{Context.User.Username}#{Context.User.Discriminator} said:");
|
||||||
await ReplyAsync(emojis);
|
await ReplyAsync(emojis);
|
||||||
try
|
|
||||||
{
|
|
||||||
await Context.Message.DeleteAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// bot may not have enough permission, doesn't matter if it fails
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core.Media;
|
using Geekbot.net.Lib.Media;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Fortune : TransactionModuleBase
|
public class Fortune : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IFortunesProvider _fortunes;
|
private readonly IFortunesProvider _fortunes;
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ namespace Geekbot.Bot.Commands.Randomness
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("fortune", RunMode = RunMode.Async)]
|
[Command("fortune", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random fortune")]
|
[Summary("Get a random fortune")]
|
||||||
public async Task GetAFortune()
|
public async Task GetAFortune()
|
||||||
{
|
{
|
41
Geekbot.net/Commands/Gdq.cs
Normal file
41
Geekbot.net/Commands/Gdq.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Gdq : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Gdq(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("gdq", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
[Summary("Get a quote from the GDQ donation generator.")]
|
||||||
|
public async Task getQuote()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new WebClient())
|
||||||
|
{
|
||||||
|
var url = new Uri("http://taskinoz.com/gdq/api/");
|
||||||
|
var response = client.DownloadString(url);
|
||||||
|
|
||||||
|
await ReplyAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
Geekbot.net/Commands/Google.cs
Normal file
102
Geekbot.net/Commands/Google.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.Net;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Google : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Google(IErrorHandler errorHandler, IDatabase redis)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_redis = redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("google", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Google Something.")]
|
||||||
|
public async Task askGoogle([Remainder, Summary("SearchText")] string searchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new WebClient())
|
||||||
|
{
|
||||||
|
var apiKey = _redis.StringGet("googleGraphKey");
|
||||||
|
if (!apiKey.HasValue)
|
||||||
|
{
|
||||||
|
await ReplyAsync("No Google API key has been set, please contact my owner");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = new Uri($"https://kgsearch.googleapis.com/v1/entities:search?languages=en&limit=1&query={searchText}&key={apiKey}");
|
||||||
|
var responseString = client.DownloadString(url);
|
||||||
|
var response = Utf8Json.JsonSerializer.Deserialize<GoogleKGApiResponse>(responseString);
|
||||||
|
|
||||||
|
if (!response.itemListElement.Any())
|
||||||
|
{
|
||||||
|
await ReplyAsync("No results were found...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = response.itemListElement.First().result;
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.Title = data.name;
|
||||||
|
if(!string.IsNullOrEmpty(data.description)) eb.WithDescription(data.description);
|
||||||
|
if(!string.IsNullOrEmpty(data.detailedDescription?.url)) eb.WithUrl(data.detailedDescription.url);
|
||||||
|
if(!string.IsNullOrEmpty(data.detailedDescription?.articleBody)) eb.AddField("Details", data.detailedDescription.articleBody);
|
||||||
|
if(!string.IsNullOrEmpty(data.image?.contentUrl)) eb.WithThumbnailUrl(data.image.contentUrl);
|
||||||
|
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GoogleKGApiResponse
|
||||||
|
{
|
||||||
|
public List<GoogleKGApiElement> itemListElement { get; set; }
|
||||||
|
|
||||||
|
public class GoogleKGApiElement
|
||||||
|
{
|
||||||
|
public GoogleKGApiResult result { get; set; }
|
||||||
|
public double resultScore { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GoogleKGApiResult
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public string description { get; set; }
|
||||||
|
public GoogleKGApiImage image { get; set; }
|
||||||
|
public GoogleKGApiDetailed detailedDescription { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GoogleKGApiImage
|
||||||
|
{
|
||||||
|
public string contentUrl { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GoogleKGApiDetailed
|
||||||
|
{
|
||||||
|
public string articleBody { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string license { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,32 +3,28 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Bot.CommandPreconditions;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core;
|
using StackExchange.Redis;
|
||||||
using Geekbot.Core.Database;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.Levels;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.User
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class GuildInfo : TransactionModuleBase
|
public class GuildInfo : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
private readonly ILevelCalc _levelCalc;
|
private readonly ILevelCalc _levelCalc;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
public GuildInfo(DatabaseContext database, ILevelCalc levelCalc, IErrorHandler errorHandler)
|
public GuildInfo(IDatabase redis, ILevelCalc levelCalc, IErrorHandler errorHandler)
|
||||||
{
|
{
|
||||||
_database = database;
|
_redis = redis;
|
||||||
_levelCalc = levelCalc;
|
_levelCalc = levelCalc;
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("serverstats", RunMode = RunMode.Async)]
|
[Command("serverstats", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Statistics)]
|
||||||
[Summary("Show some info about the bot.")]
|
[Summary("Show some info about the bot.")]
|
||||||
[DisableInDirectMessage]
|
public async Task getInfo()
|
||||||
public async Task GetInfo()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -41,10 +37,8 @@ namespace Geekbot.Bot.Commands.User
|
||||||
var created = Context.Guild.CreatedAt;
|
var created = Context.Guild.CreatedAt;
|
||||||
var age = Math.Floor((DateTime.Now - created).TotalDays);
|
var age = Math.Floor((DateTime.Now - created).TotalDays);
|
||||||
|
|
||||||
var messages = _database.Messages
|
var messages = _redis.HashGet($"{Context.Guild.Id}:Messages", 0.ToString());
|
||||||
.Where(e => e.GuildId == Context.Guild.Id.AsLong())
|
var level = _levelCalc.GetLevel((int) messages);
|
||||||
.Sum(e => e.MessageCount);
|
|
||||||
var level = _levelCalc.GetLevel(messages);
|
|
||||||
|
|
||||||
eb.AddField("Server Age", $"{created.Day}/{created.Month}/{created.Year} ({age} days)");
|
eb.AddField("Server Age", $"{created.Day}/{created.Month}/{created.Year} ({age} days)");
|
||||||
eb.AddInlineField("Level", level)
|
eb.AddInlineField("Level", level)
|
||||||
|
@ -54,8 +48,15 @@ namespace Geekbot.Bot.Commands.User
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FirstCharToUpper(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
throw new ArgumentException("ARGH!");
|
||||||
|
return input.First().ToString().ToUpper() + input.Substring(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Help : TransactionModuleBase
|
public class Help : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -18,6 +16,7 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("help", RunMode = RunMode.Async)]
|
[Command("help", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("List all Commands")]
|
[Summary("List all Commands")]
|
||||||
public async Task GetHelp()
|
public async Task GetHelp()
|
||||||
{
|
{
|
||||||
|
@ -27,13 +26,12 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
|
|
||||||
sb.AppendLine("For a list of all commands, please visit the following page");
|
sb.AppendLine("For a list of all commands, please visit the following page");
|
||||||
sb.AppendLine("https://geekbot.pizzaandcoffee.rocks/commands");
|
sb.AppendLine("https://geekbot.pizzaandcoffee.rocks/commands");
|
||||||
var dm = await Context.User.CreateDMChannelAsync(RequestOptions.Default);
|
var dm = await Context.User.GetOrCreateDMChannelAsync();
|
||||||
await dm.SendMessageAsync(sb.ToString());
|
await dm.SendMessageAsync(sb.ToString());
|
||||||
await Context.Message.AddReactionAsync(new Emoji("✅"));
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,26 +5,28 @@ using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core.ErrorHandling;
|
using StackExchange.Redis;
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Info : TransactionModuleBase
|
public class Info : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly CommandService _commands;
|
private readonly CommandService _commands;
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
public Info(IErrorHandler errorHandler, DiscordSocketClient client, CommandService commands)
|
public Info(IDatabase redis, IErrorHandler errorHandler, DiscordSocketClient client, CommandService commands)
|
||||||
{
|
{
|
||||||
|
_redis = redis;
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
_client = client;
|
_client = client;
|
||||||
_commands = commands;
|
_commands = commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("info", RunMode = RunMode.Async)]
|
[Command("info", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("Get Information about the bot")]
|
[Summary("Get Information about the bot")]
|
||||||
public async Task BotInfo()
|
public async Task BotInfo()
|
||||||
{
|
{
|
||||||
|
@ -32,30 +34,31 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
{
|
{
|
||||||
var eb = new EmbedBuilder();
|
var eb = new EmbedBuilder();
|
||||||
|
|
||||||
var appInfo = await _client.GetApplicationInfoAsync();
|
|
||||||
|
|
||||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||||
.WithIconUrl(appInfo.IconUrl)
|
.WithIconUrl(_client.CurrentUser.GetAvatarUrl())
|
||||||
.WithName($"{Constants.Name} V{Constants.BotVersion()}"));
|
.WithName($"{Constants.Name} V{Constants.BotVersion}"));
|
||||||
|
var botOwner = await Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner")));
|
||||||
var uptime = DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime);
|
var uptime = DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime);
|
||||||
|
|
||||||
eb.AddInlineField("Bot Name", _client.CurrentUser.Username);
|
eb.AddInlineField("Bot Name", _client.CurrentUser.Username);
|
||||||
eb.AddInlineField("Bot Owner", $"{appInfo.Owner.Username}#{appInfo.Owner.Discriminator}");
|
eb.AddInlineField("Bot Owner", $"{botOwner.Username}#{botOwner.Discriminator}");
|
||||||
eb.AddInlineField("Library", $"Discord.NET {Constants.LibraryVersion()}");
|
eb.AddInlineField("Library", "Discord.NET V1.0.2");
|
||||||
eb.AddInlineField("Uptime", $"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S");
|
eb.AddInlineField("Uptime", $"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S");
|
||||||
eb.AddInlineField("Servers", Context.Client.GetGuildsAsync().Result.Count);
|
eb.AddInlineField("Servers", Context.Client.GetGuildsAsync().Result.Count);
|
||||||
eb.AddInlineField("Total Commands", _commands.Commands.Count());
|
eb.AddInlineField("Total Commands", _commands.Commands.Count());
|
||||||
|
|
||||||
eb.AddField("Website", "https://geekbot.pizzaandcoffee.rocks/");
|
eb.AddField("Website", "https://geekbot.pizzaandcoffee.rocks/");
|
||||||
|
|
||||||
await ReplyAsync("", false, eb.Build());
|
await ReplyAsync("", false, eb.Build());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("uptime", RunMode = RunMode.Async)]
|
[Command("uptime", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("Get the Bot Uptime")]
|
[Summary("Get the Bot Uptime")]
|
||||||
public async Task BotUptime()
|
public async Task BotUptime()
|
||||||
{
|
{
|
||||||
|
@ -66,7 +69,7 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
129
Geekbot.net/Commands/Karma.cs
Normal file
129
Geekbot.net/Commands/Karma.cs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Karma : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Karma(IDatabase redis, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_translation = translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("good", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Karma)]
|
||||||
|
[Summary("Increase Someones Karma")]
|
||||||
|
public async Task Good([Summary("@someone")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var transDict = _translation.GetDict(Context);
|
||||||
|
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(string.Format(transDict["CannotChangeOwn"], Context.User.Username));
|
||||||
|
}
|
||||||
|
else if (TimeoutFinished(lastKarma))
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["WaitUntill"], Context.User.Username,
|
||||||
|
GetTimeLeft(lastKarma)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newKarma = _redis.HashIncrement($"{Context.Guild.Id}:Karma", user.Id.ToString());
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:KarmaTimeout",
|
||||||
|
new[] {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 = transDict["Increased"];
|
||||||
|
eb.AddInlineField(transDict["By"], Context.User.Username);
|
||||||
|
eb.AddInlineField(transDict["Amount"], "+1");
|
||||||
|
eb.AddInlineField(transDict["Current"], newKarma);
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("bad", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Karma)]
|
||||||
|
[Summary("Decrease Someones Karma")]
|
||||||
|
public async Task Bad([Summary("@someone")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var transDict = _translation.GetDict(Context);
|
||||||
|
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(string.Format(transDict["CannotChangeOwn"], Context.User.Username));
|
||||||
|
}
|
||||||
|
else if (TimeoutFinished(lastKarma))
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["WaitUntill"], Context.User.Username,
|
||||||
|
GetTimeLeft(lastKarma)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newKarma = _redis.HashDecrement($"{Context.Guild.Id}:Karma", user.Id.ToString());
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:KarmaTimeout",
|
||||||
|
new[] {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 = transDict["Decreased"];
|
||||||
|
eb.AddInlineField(transDict["By"], Context.User.Username);
|
||||||
|
eb.AddInlineField(transDict["Amount"], "-1");
|
||||||
|
eb.AddInlineField(transDict["Current"], 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
Geekbot.net/Commands/MagicTheGathering.cs
Normal file
88
Geekbot.net/Commands/MagicTheGathering.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using MtgApiManager.Lib.Service;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Magicthegathering : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Magicthegathering(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("mtg", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
[Summary("Find a Magic The Gathering Card.")]
|
||||||
|
public async Task getCard([Remainder] [Summary("name")] string cardName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var service = new CardService();
|
||||||
|
var result = service.Where(x => x.Name, cardName);
|
||||||
|
|
||||||
|
var card = result.All().Value.FirstOrDefault();
|
||||||
|
if (card == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("I couldn't find that card...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.Title = card.Name;
|
||||||
|
eb.Description = card.Type;
|
||||||
|
|
||||||
|
if (card.Colors != null) eb.WithColor(GetColor(card.Colors));
|
||||||
|
|
||||||
|
if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", card.Text);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor);
|
||||||
|
if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName);
|
||||||
|
if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power);
|
||||||
|
if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty);
|
||||||
|
if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", card.ManaCost);
|
||||||
|
if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity);
|
||||||
|
|
||||||
|
if (card.Legalities != null)
|
||||||
|
eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format)));
|
||||||
|
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color GetColor(IEnumerable<string> colors)
|
||||||
|
{
|
||||||
|
var color = colors.FirstOrDefault();
|
||||||
|
switch (color)
|
||||||
|
{
|
||||||
|
case "Black":
|
||||||
|
return new Color(177, 171, 170);
|
||||||
|
case "White":
|
||||||
|
return new Color(255, 252, 214);
|
||||||
|
case "Blue":
|
||||||
|
return new Color(156, 189, 204);
|
||||||
|
case "Red":
|
||||||
|
return new Color(204, 156, 140);
|
||||||
|
case "Green":
|
||||||
|
return new Color(147, 181, 159);
|
||||||
|
default:
|
||||||
|
return new Color(255, 252, 214);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
Geekbot.net/Commands/Mod.cs
Normal file
87
Geekbot.net/Commands/Mod.cs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("mod")]
|
||||||
|
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
public class Mod : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public Mod(IUserRepository userRepositry, IErrorHandler errorHandler, IDatabase redis,
|
||||||
|
DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
_userRepository = userRepositry;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_redis = redis;
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("namehistory", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("See past usernames of an user")]
|
||||||
|
public async Task usernameHistory([Summary("@user")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userRepo = _userRepository.Get(user.Id);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine($":bust_in_silhouette: {user.Username} has been known as:");
|
||||||
|
foreach (var name in userRepo.UsedNames) sb.AppendLine($"- `{name}`");
|
||||||
|
await ReplyAsync(sb.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context,
|
||||||
|
$"I don't have enough permissions to give {user.Username} that role");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("kick", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Ban a user")]
|
||||||
|
public async Task kick([Summary("@user")] IUser userNormal,
|
||||||
|
[Summary("reason")] [Remainder] string reason = "none")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = (IGuildUser) userNormal;
|
||||||
|
if (reason == "none") reason = "No reason provided";
|
||||||
|
await user.GetOrCreateDMChannelAsync().Result.SendMessageAsync(
|
||||||
|
$"You have been kicked from {Context.Guild.Name} for the following reason: \"{reason}\"");
|
||||||
|
await user.KickAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var modChannelId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel"));
|
||||||
|
var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId);
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.Title = ":x: User Kicked";
|
||||||
|
eb.AddInlineField("User", user.Username);
|
||||||
|
eb.AddInlineField("By Mod", Context.User.Username);
|
||||||
|
eb.AddField("Reason", reason);
|
||||||
|
await modChannel.SendMessageAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await ReplyAsync($"{user.Username} was kicked for the following reason: \"{reason}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context, "I don't have enough permissions to kick someone");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
Geekbot.net/Commands/Overwatch.cs
Normal file
131
Geekbot.net/Commands/Overwatch.cs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using OverwatchAPI;
|
||||||
|
using OverwatchAPI.Config;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("ow")]
|
||||||
|
public class Overwatch : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public Overwatch(IErrorHandler errorHandler, IDatabase redis, IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("profile", RunMode = RunMode.Async)]
|
||||||
|
[Summary("Get someones overwatch profile. EU on PC only. Default battletag is your own (if set).")]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
public async Task owProfile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tag = _userRepository.getUserSetting(Context.User.Id, "BattleTag");
|
||||||
|
if (string.IsNullOrEmpty(tag))
|
||||||
|
{
|
||||||
|
await ReplyAsync("You have no battle Tag saved, use `!battletag`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profile = await createProfile(tag);
|
||||||
|
if (profile == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("That player doesn't seem to exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("", false, profile.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("profile", RunMode = RunMode.Async)]
|
||||||
|
[Summary("Get someones overwatch profile. EU on PC only. Default battletag is your own (if set).")]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
public async Task owProfile([Summary("BattleTag")] string tag)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!BattleTag.isValidTag(tag))
|
||||||
|
{
|
||||||
|
await ReplyAsync("That doesn't seem to be a valid battletag...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profile = await createProfile(tag);
|
||||||
|
if (profile == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("That player doesn't seem to exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("", false, profile.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("profile", RunMode = RunMode.Async)]
|
||||||
|
[Summary("Get someones overwatch profile. EU on PC only.")]
|
||||||
|
[Remarks(CommandCategories.Games)]
|
||||||
|
public async Task owProfile([Summary("@someone")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tag = _userRepository.getUserSetting(user.Id, "BattleTag");
|
||||||
|
if (string.IsNullOrEmpty(tag))
|
||||||
|
{
|
||||||
|
await ReplyAsync("This user didn't set a battletag");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profile = await createProfile(tag);
|
||||||
|
if (profile == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("That player doesn't seem to exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("", false, profile.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<EmbedBuilder> createProfile(string battletag)
|
||||||
|
{
|
||||||
|
var owConfig = new OverwatchConfig.Builder().WithRegions(Region.Eu).WithPlatforms(Platform.Pc);
|
||||||
|
using (var owClient = new OverwatchClient(owConfig))
|
||||||
|
{
|
||||||
|
var player = await owClient.GetPlayerAsync(battletag);
|
||||||
|
if (player.Username == null) return null;
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||||
|
.WithIconUrl(player.ProfilePortraitUrl)
|
||||||
|
.WithName(player.Username));
|
||||||
|
eb.Url = player.ProfileUrl;
|
||||||
|
eb.AddInlineField("Level", player.PlayerLevel);
|
||||||
|
eb.AddInlineField("Current Rank",
|
||||||
|
player.CompetitiveRank > 0 ? player.CompetitiveRank.ToString() : "Unranked");
|
||||||
|
|
||||||
|
return eb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
Geekbot.net/Commands/Owner.cs
Normal file
117
Geekbot.net/Commands/Owner.cs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
using System;
|
||||||
|
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("owner")]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
public class Owner : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public Owner(IDatabase redis, DiscordSocketClient client, IGeekbotLogger logger, IUserRepository userRepositry,
|
||||||
|
IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_client = client;
|
||||||
|
_logger = logger;
|
||||||
|
_userRepository = userRepositry;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("youtubekey", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[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)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[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)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Populate user cache")]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Ping : TransactionModuleBase
|
public class Ping : ModuleBase
|
||||||
{
|
{
|
||||||
[Command("👀", RunMode = RunMode.Async)]
|
[Command("👀", RunMode = RunMode.Async)]
|
||||||
[Summary("Look at the bot.")]
|
[Summary("Look at the bot.")]
|
||||||
|
[Remarks(CommandCategories.Fun)]
|
||||||
public async Task Eyes()
|
public async Task Eyes()
|
||||||
{
|
{
|
||||||
await ReplyAsync("S... Stop looking at me... baka!");
|
await ReplyAsync("S... Stop looking at me... baka!");
|
|
@ -3,14 +3,12 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Geekbot.Core;
|
using Geekbot.net.Lib;
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using PokeAPI;
|
using PokeAPI;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Games
|
namespace Geekbot.net.Commands
|
||||||
{
|
{
|
||||||
public class Pokedex : TransactionModuleBase
|
public class Pokedex : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -20,8 +18,9 @@ namespace Geekbot.Bot.Commands.Games
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("pokedex", RunMode = RunMode.Async)]
|
[Command("pokedex", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("A Pokedex Tool")]
|
[Summary("A Pokedex Tool")]
|
||||||
public async Task GetPokemon([Summary("pokemon-name")] string pokemonName)
|
public async Task GetPokemon([Summary("pokemonName")] string pokemonName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -37,38 +36,38 @@ namespace Geekbot.Bot.Commands.Games
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var embed = await PokemonEmbedBuilder(pokemon);
|
var embed = await pokemonEmbedBuilder(pokemon);
|
||||||
await ReplyAsync("", false, embed.Build());
|
await ReplyAsync("", false, embed.Build());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<EmbedBuilder> PokemonEmbedBuilder(Pokemon pokemon)
|
private async Task<EmbedBuilder> pokemonEmbedBuilder(Pokemon pokemon)
|
||||||
{
|
{
|
||||||
var eb = new EmbedBuilder();
|
var eb = new EmbedBuilder();
|
||||||
var species = await DataFetcher.GetApiObject<PokemonSpecies>(pokemon.ID);
|
var species = await DataFetcher.GetApiObject<PokemonSpecies>(pokemon.ID);
|
||||||
eb.Title = $"#{pokemon.ID} {ToUpper(pokemon.Name)}";
|
eb.Title = $"#{pokemon.ID} {toUpper(pokemon.Name)}";
|
||||||
eb.Description = species.FlavorTexts[1].FlavorText;
|
eb.Description = species.FlavorTexts[1].FlavorText;
|
||||||
eb.ThumbnailUrl = pokemon.Sprites.FrontMale ?? pokemon.Sprites.FrontFemale;
|
eb.ThumbnailUrl = pokemon.Sprites.FrontMale ?? pokemon.Sprites.FrontFemale;
|
||||||
eb.AddInlineField(GetSingularOrPlural(pokemon.Types.Length, "Type"),
|
eb.AddInlineField(getSingularOrPlural(pokemon.Types.Length, "Type"),
|
||||||
string.Join(", ", pokemon.Types.Select(t => ToUpper(t.Type.Name))));
|
string.Join(", ", pokemon.Types.Select(t => toUpper(t.Type.Name))));
|
||||||
eb.AddInlineField(GetSingularOrPlural(pokemon.Abilities.Length, "Ability"),
|
eb.AddInlineField(getSingularOrPlural(pokemon.Abilities.Length, "Ability"),
|
||||||
string.Join(", ", pokemon.Abilities.Select(t => ToUpper(t.Ability.Name))));
|
string.Join(", ", pokemon.Abilities.Select(t => toUpper(t.Ability.Name))));
|
||||||
eb.AddInlineField("Height", pokemon.Height);
|
eb.AddInlineField("Height", pokemon.Height);
|
||||||
eb.AddInlineField("Weight", pokemon.Mass);
|
eb.AddInlineField("Weight", pokemon.Mass);
|
||||||
return eb;
|
return eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSingularOrPlural(int lenght, string word)
|
private string getSingularOrPlural(int lenght, string word)
|
||||||
{
|
{
|
||||||
if (lenght == 1) return word;
|
if (lenght == 1) return word;
|
||||||
return word.EndsWith("y") ? $"{word.Remove(word.Length - 1)}ies" : $"{word}s";
|
return word.EndsWith("y") ? $"{word.Remove(word.Length - 1)}ies" : $"{word}s";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ToUpper(string s)
|
private string toUpper(string s)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(s)) return string.Empty;
|
if (string.IsNullOrEmpty(s)) return string.Empty;
|
||||||
return char.ToUpper(s[0]) + s.Substring(1);
|
return char.ToUpper(s[0]) + s.Substring(1);
|
191
Geekbot.net/Commands/Poll.cs
Normal file
191
Geekbot.net/Commands/Poll.cs
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
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 Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("poll")]
|
||||||
|
public class Poll : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IEmojiConverter _emojiConverter;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public Poll(IErrorHandler errorHandler, IDatabase redis, IEmojiConverter emojiConverter,
|
||||||
|
IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_redis = redis;
|
||||||
|
_emojiConverter = emojiConverter;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Check status of the current poll")]
|
||||||
|
public async Task Dflt()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentPoll = GetCurrentPoll();
|
||||||
|
if (currentPoll.Question == null || currentPoll.IsFinshed)
|
||||||
|
{
|
||||||
|
await ReplyAsync(
|
||||||
|
"There is no poll in this channel ongoing at the moment\r\nYou can create one with `!poll create question;option1;option2;option3`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("There is a poll running at the moment");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("create", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Create a poll")]
|
||||||
|
public async Task Create([Remainder] [Summary("question;option1;option2")]
|
||||||
|
string rawPollString)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentPoll = GetCurrentPoll();
|
||||||
|
if (currentPoll.Question != null && !currentPoll.IsFinshed)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You have not finished you last poll yet. To finish it use `!poll end`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pollList = rawPollString.Split(';').ToList();
|
||||||
|
if (pollList.Count <= 2)
|
||||||
|
{
|
||||||
|
await ReplyAsync(
|
||||||
|
"You need a question with atleast 2 options, a valid creation would look like this `question;option1;option2`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.Title = $"Poll by {Context.User.Username}";
|
||||||
|
var question = pollList[0];
|
||||||
|
eb.Description = question;
|
||||||
|
pollList.RemoveAt(0);
|
||||||
|
var i = 1;
|
||||||
|
pollList.ForEach(option =>
|
||||||
|
{
|
||||||
|
eb.AddInlineField($"Option {_emojiConverter.numberToEmoji(i)}", option);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
var pollMessage = await ReplyAsync("", false, eb.Build());
|
||||||
|
i = 1;
|
||||||
|
pollList.ForEach(option =>
|
||||||
|
{
|
||||||
|
pollMessage.AddReactionAsync(new Emoji(_emojiConverter.numberToEmoji(i)));
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
var poll = new PollData
|
||||||
|
{
|
||||||
|
Creator = Context.User.Id,
|
||||||
|
MessageId = pollMessage.Id,
|
||||||
|
IsFinshed = false,
|
||||||
|
Question = question,
|
||||||
|
Options = pollList
|
||||||
|
};
|
||||||
|
var pollJson = JsonConvert.SerializeObject(poll);
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:Polls", new[] {new HashEntry(Context.Channel.Id, pollJson)});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("end", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("End the current poll")]
|
||||||
|
public async Task End()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentPoll = GetCurrentPoll();
|
||||||
|
if (currentPoll.Question == null || currentPoll.IsFinshed)
|
||||||
|
{
|
||||||
|
await ReplyAsync("There is no ongoing poll at the moment");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = await getPollResults(currentPoll);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine("**Poll Results**");
|
||||||
|
sb.AppendLine(currentPoll.Question);
|
||||||
|
foreach (var result in results) sb.AppendLine($"{result.VoteCount} - {result.Option}");
|
||||||
|
await ReplyAsync(sb.ToString());
|
||||||
|
currentPoll.IsFinshed = true;
|
||||||
|
var pollJson = JsonConvert.SerializeObject(currentPoll);
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:Polls", new[] {new HashEntry(Context.Channel.Id, pollJson)});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PollData GetCurrentPoll()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentPoll = _redis.HashGet($"{Context.Guild.Id}:Polls", Context.Channel.Id);
|
||||||
|
return JsonConvert.DeserializeObject<PollData>(currentPoll.ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new PollData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<PollResult>> getPollResults(PollData poll)
|
||||||
|
{
|
||||||
|
var message = (IUserMessage) await Context.Channel.GetMessageAsync(poll.MessageId);
|
||||||
|
var results = new List<PollResult>();
|
||||||
|
foreach (var r in message.Reactions)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var option = int.Parse(r.Key.Name.ToCharArray()[0].ToString());
|
||||||
|
var result = new PollResult
|
||||||
|
{
|
||||||
|
Option = poll.Options[option - 1],
|
||||||
|
VoteCount = r.Value.ReactionCount
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
results.Sort((x, y) => y.VoteCount.CompareTo(x.VoteCount));
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PollData
|
||||||
|
{
|
||||||
|
public ulong Creator { get; set; }
|
||||||
|
public ulong MessageId { get; set; }
|
||||||
|
public bool IsFinshed { get; set; }
|
||||||
|
public string Question { get; set; }
|
||||||
|
public List<string> Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PollResult
|
||||||
|
{
|
||||||
|
public string Option { get; set; }
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
231
Geekbot.net/Commands/Quote.cs
Normal file
231
Geekbot.net/Commands/Quote.cs
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("quote")]
|
||||||
|
public class Quote : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Quote(IDatabase redis, IErrorHandler errorHandler, Random random)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[Summary("Return a random quoute from the database")]
|
||||||
|
public async Task getRandomQuote()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var randomQuotes = _redis.SetMembers($"{Context.Guild.Id}:Quotes");
|
||||||
|
var randomNumber = new Random().Next(randomQuotes.Length - 1);
|
||||||
|
var randomQuote = randomQuotes[randomNumber];
|
||||||
|
var quote = JsonConvert.DeserializeObject<QuoteObject>(randomQuote);
|
||||||
|
var embed = quoteBuilder(quote, randomNumber + 1);
|
||||||
|
await ReplyAsync("", false, embed.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("save")]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[Summary("Save a quote from the last sent message by @user")]
|
||||||
|
public async Task saveQuote([Summary("@user")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (user.Id == Context.Message.Author.Id)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't save your own quotes...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.IsBot)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't save quotes by a bot...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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")]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[Summary("Save a quote from a message id")]
|
||||||
|
public async Task saveQuote([Summary("messageId")] ulong messageId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||||
|
if (message.Author.Id == Context.Message.Author.Id)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't save your own quotes...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Author.IsBot)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't save quotes by a bot...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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")]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[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")]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[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:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("remove")]
|
||||||
|
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
[Remarks(CommandCategories.Quotes)]
|
||||||
|
[Summary("Remove a quote (required mod permissions)")]
|
||||||
|
public async Task removeQuote([Summary("quoteId")] int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var quotes = _redis.SetMembers($"{Context.Guild.Id}:Quotes");
|
||||||
|
var success = _redis.SetRemove($"{Context.Guild.Id}:Quotes", quotes[id - 1]);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
var quote = JsonConvert.DeserializeObject<QuoteObject>(quotes[id - 1]);
|
||||||
|
var embed = quoteBuilder(quote);
|
||||||
|
await ReplyAsync($"**Removed #{id}**", false, embed.Build());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyAsync($"I couldn't find a quote with that id :disappointed:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context,
|
||||||
|
"I couldn't find a quote with that id :disappointed:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IMessage> getLastMessageByUser(IUser user)
|
||||||
|
{
|
||||||
|
var 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, int id = 0)
|
||||||
|
{
|
||||||
|
var user = Context.Client.GetUserAsync(quote.userId).Result;
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.WithColor(new Color(143, 167, 232));
|
||||||
|
eb.Title = id == 0 ? "" : $"#{id} | ";
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
58
Geekbot.net/Commands/RandomAnimals.cs
Normal file
58
Geekbot.net/Commands/RandomAnimals.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.Media;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class RandomAnimals : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IMediaProvider _mediaProvider;
|
||||||
|
|
||||||
|
public RandomAnimals(IMediaProvider mediaProvider)
|
||||||
|
{
|
||||||
|
_mediaProvider = mediaProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("panda", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Get a random panda image")]
|
||||||
|
public async Task panda()
|
||||||
|
{
|
||||||
|
await ReplyAsync(_mediaProvider.getPanda());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("croissant", RunMode = RunMode.Async)]
|
||||||
|
[Alias("gipfeli")]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Get a random croissant image")]
|
||||||
|
public async Task croissant()
|
||||||
|
{
|
||||||
|
await ReplyAsync(_mediaProvider.getCrossant());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("pumpkin", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Get a random pumpkin image")]
|
||||||
|
public async Task pumpkin()
|
||||||
|
{
|
||||||
|
await ReplyAsync(_mediaProvider.getPumpkin());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("squirrel", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Get a random squirrel image")]
|
||||||
|
public async Task squirrel()
|
||||||
|
{
|
||||||
|
await ReplyAsync(_mediaProvider.getSquirrel());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("turtle", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Get a random turtle image")]
|
||||||
|
public async Task turtle()
|
||||||
|
{
|
||||||
|
await ReplyAsync(_mediaProvider.getTurtle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
145
Geekbot.net/Commands/Rank.cs
Normal file
145
Geekbot.net/Commands/Rank.cs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Rank : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IEmojiConverter _emojiConverter;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
public Rank(IDatabase redis, IErrorHandler errorHandler, IGeekbotLogger logger, IUserRepository userRepository,
|
||||||
|
IEmojiConverter emojiConverter, DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_logger = logger;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
_emojiConverter = emojiConverter;
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("rank", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Statistics)]
|
||||||
|
[Summary("get user top 10 in messages or karma")]
|
||||||
|
public async Task RankCmd([Summary("type")] string typeUnformated = "messages",
|
||||||
|
[Summary("amount")] int amount = 10)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var type = typeUnformated.ToCharArray().First().ToString().ToUpper() + typeUnformated.Substring(1);
|
||||||
|
|
||||||
|
if (!type.Equals("Messages") && !type.Equals("Karma") && !type.Equals("Rolls"))
|
||||||
|
{
|
||||||
|
await ReplyAsync("Valid types are '`messages`' '`karma`', '`rolls`'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
if (amount > 20)
|
||||||
|
{
|
||||||
|
replyBuilder.AppendLine(":warning: Limiting to 20");
|
||||||
|
amount = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageList = _redis.HashGetAll($"{Context.Guild.Id}:{type}");
|
||||||
|
var sortedList = messageList.OrderByDescending(e => e.Value).ToList();
|
||||||
|
var guildMessages = (int) sortedList.First().Value;
|
||||||
|
sortedList.Remove(sortedList.Single(e => e.Name.ToString().Equals(_client.CurrentUser.Id.ToString())));
|
||||||
|
if (type == "Messages") sortedList.RemoveAt(0);
|
||||||
|
|
||||||
|
var highscoreUsers = new Dictionary<RankUserPolyfill, int>();
|
||||||
|
var listLimiter = 1;
|
||||||
|
var failedToRetrieveUser = false;
|
||||||
|
foreach (var user in sortedList)
|
||||||
|
{
|
||||||
|
if (listLimiter > amount) 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("Geekbot", $"Could not retrieve user {user.Name}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedToRetrieveUser) replyBuilder.AppendLine(":warning: Couldn't get all userdata\n");
|
||||||
|
replyBuilder.AppendLine($":bar_chart: **{type} Highscore for {Context.Guild.Name}**");
|
||||||
|
var highscorePlace = 1;
|
||||||
|
foreach (var user in highscoreUsers)
|
||||||
|
{
|
||||||
|
replyBuilder.Append(highscorePlace < 11
|
||||||
|
? $"{_emojiConverter.numberToEmoji(highscorePlace)} "
|
||||||
|
: $"`{highscorePlace}.` ");
|
||||||
|
|
||||||
|
replyBuilder.Append(user.Key.Username != null
|
||||||
|
? $"**{user.Key.Username}#{user.Key.Discriminator}**"
|
||||||
|
: $"**{user.Key.Id}**");
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "Messages":
|
||||||
|
var percent = Math.Round((double) (100 * user.Value) / guildMessages, 2);
|
||||||
|
replyBuilder.Append($" - {percent}% of total - {user.Value} messages");
|
||||||
|
break;
|
||||||
|
case "Karma":
|
||||||
|
replyBuilder.Append($" - {user.Value} Karma");
|
||||||
|
break;
|
||||||
|
case "Rolls":
|
||||||
|
replyBuilder.Append($" - {user.Value} Guessed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyBuilder.Append("\n");
|
||||||
|
|
||||||
|
highscorePlace++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync(replyBuilder.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class RankUserPolyfill
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Discriminator { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
146
Geekbot.net/Commands/Role.cs
Normal file
146
Geekbot.net/Commands/Role.cs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.Net;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("role")]
|
||||||
|
public class Role : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Role(IErrorHandler errorHandler, IDatabase redis)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_redis = redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Get a list of all available roles.")]
|
||||||
|
public async Task getAllRoles()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var roles = _redis.HashGetAll($"{Context.Guild.Id}:RoleWhitelist");
|
||||||
|
if (roles.Length == 0)
|
||||||
|
{
|
||||||
|
await ReplyAsync("There are no roles configured for this server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"**Self Service Roles on {Context.Guild.Name}**");
|
||||||
|
sb.AppendLine("To get a role, use `!role name`");
|
||||||
|
foreach (var role in roles) sb.AppendLine($"- {role.Name}");
|
||||||
|
await ReplyAsync(sb.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Get a role by mentioning it.")]
|
||||||
|
public async Task giveRole([Summary("roleNickname")] string roleNameRaw)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var roleName = roleNameRaw.ToLower();
|
||||||
|
if (_redis.HashExists($"{Context.Guild.Id}:RoleWhitelist", roleName))
|
||||||
|
{
|
||||||
|
var guildUser = (IGuildUser) Context.User;
|
||||||
|
var roleId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:RoleWhitelist", roleName));
|
||||||
|
var role = Context.Guild.Roles.First(r => r.Id == roleId);
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("That role doesn't seem to exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guildUser.RoleIds.Contains(roleId))
|
||||||
|
{
|
||||||
|
await guildUser.RemoveRoleAsync(role);
|
||||||
|
await ReplyAsync($"Removed you from {role.Name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await guildUser.AddRoleAsync(role);
|
||||||
|
await ReplyAsync($"Added you to {role.Name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("That role doesn't seem to exist");
|
||||||
|
}
|
||||||
|
catch (HttpException e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleHttpException(e, Context);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("add", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Add a role to the whitelist.")]
|
||||||
|
public async Task addRole([Summary("@role")] IRole role, [Summary("alias")] string roleName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (role.IsManaged)
|
||||||
|
{
|
||||||
|
await ReplyAsync("You can't add a role that is managed by discord");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role.Permissions.ManageRoles
|
||||||
|
|| role.Permissions.Administrator
|
||||||
|
|| role.Permissions.ManageGuild
|
||||||
|
|| role.Permissions.BanMembers
|
||||||
|
|| role.Permissions.KickMembers)
|
||||||
|
{
|
||||||
|
await ReplyAsync(
|
||||||
|
"Woah, i don't think you want to add that role to self service as it contains some dangerous permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:RoleWhitelist",
|
||||||
|
new[] {new HashEntry(roleName.ToLower(), role.Id.ToString())});
|
||||||
|
await ReplyAsync($"Added {role.Name} to the whitelist");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("remove", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Remove a role from the whitelist.")]
|
||||||
|
public async Task removeRole([Summary("roleNickname")] string roleName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_redis.HashDelete($"{Context.Guild.Id}:RoleWhitelist", roleName);
|
||||||
|
await ReplyAsync($"Removed {roleName} from the whitelist");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
Geekbot.net/Commands/Roll.cs
Normal file
64
Geekbot.net/Commands/Roll.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Roll : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly Random _rnd;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Roll(IDatabase redis, Random RandomClient, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_rnd = RandomClient;
|
||||||
|
_translation = translation;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("roll", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Fun)]
|
||||||
|
[Summary("Guess which number the bot will roll (1-100")]
|
||||||
|
public async Task RollCommand([Remainder] [Summary("guess")] string stuff = "noGuess")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var number = _rnd.Next(1, 100);
|
||||||
|
var guess = 1000;
|
||||||
|
int.TryParse(stuff, out guess);
|
||||||
|
var transDict = _translation.GetDict(Context);
|
||||||
|
if (guess <= 100 && guess > 0)
|
||||||
|
{
|
||||||
|
var prevRoll = _redis.HashGet($"{Context.Guild.Id}:RollsPrevious", Context.Message.Author.Id);
|
||||||
|
if (!prevRoll.IsNullOrEmpty && prevRoll.ToString() == guess.ToString())
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["NoPrevGuess"], Context.Message.Author.Mention));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:RollsPrevious",
|
||||||
|
new[] {new HashEntry(Context.Message.Author.Id, guess)});
|
||||||
|
await ReplyAsync(string.Format(transDict["Rolled"], Context.Message.Author.Mention, number, guess));
|
||||||
|
if (guess == number)
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["Gratz"], Context.Message.Author));
|
||||||
|
_redis.HashIncrement($"{Context.Guild.Id}:Rolls", Context.User.Id.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["RolledNoGuess"], Context.Message.Author.Mention, number));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
Geekbot.net/Commands/Say.cs
Normal file
66
Geekbot.net/Commands/Say.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
[Group("say")]
|
||||||
|
public class Say : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IContextHandler _contextHandler;
|
||||||
|
|
||||||
|
public Say(IErrorHandler errorHandler, IContextHandler contextHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_contextHandler = contextHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("record", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Say Something.")]
|
||||||
|
public async Task recordEcho()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_contextHandler.SaveContext(ContextReference.User, Context, "say");
|
||||||
|
await ReplyAsync("Recording...");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("ctx", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Say Something.")]
|
||||||
|
public async Task recordEcho([Remainder] [Summary("What?")] string echo)
|
||||||
|
{
|
||||||
|
Console.WriteLine("actually got here...");
|
||||||
|
_contextHandler.ClearContext(Context.User.Id);
|
||||||
|
await Context.Channel.SendMessageAsync(echo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("ss", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Say Something.")]
|
||||||
|
public async Task Echo([Remainder] [Summary("What?")] string echo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Context.Message.DeleteAsync();
|
||||||
|
await ReplyAsync(echo);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
Geekbot.net/Commands/Ship.cs
Normal file
94
Geekbot.net/Commands/Ship.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Ship : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly Random _rnd;
|
||||||
|
|
||||||
|
public Ship(IDatabase redis, Random randomClient, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_rnd = randomClient;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("Ship", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Fun)]
|
||||||
|
[Summary("Ask the Shipping meter")]
|
||||||
|
public async Task Command([Summary("@User1")] IUser user1, [Summary("@User2")] IUser user2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
Geekbot.net/Commands/Slap.cs
Normal file
72
Geekbot.net/Commands/Slap.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Slap : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly Random _random;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Slap(IErrorHandler errorHandler, Random random, IDatabase redis)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_random = random;
|
||||||
|
_redis = redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("slap", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Fun)]
|
||||||
|
[Summary("slap someone")]
|
||||||
|
public async Task Slapper([Summary("@user")] IUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (user.Id == Context.User.Id)
|
||||||
|
{
|
||||||
|
await ReplyAsync("Why would you slap yourself?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var things = new List<string>()
|
||||||
|
{
|
||||||
|
"thing",
|
||||||
|
"rubber chicken",
|
||||||
|
"leek stick",
|
||||||
|
"large trout",
|
||||||
|
"flat hand",
|
||||||
|
"strip of bacon",
|
||||||
|
"feather",
|
||||||
|
"piece of pizza",
|
||||||
|
"moldy banana",
|
||||||
|
"sharp retort",
|
||||||
|
"printed version of wikipedia",
|
||||||
|
"panda paw",
|
||||||
|
"spiked sledgehammer",
|
||||||
|
"monstertruck",
|
||||||
|
"dirty toilet brush",
|
||||||
|
"sleeping seagull",
|
||||||
|
"sunflower",
|
||||||
|
"mousepad",
|
||||||
|
"lolipop",
|
||||||
|
"bottle of rum"
|
||||||
|
};
|
||||||
|
|
||||||
|
_redis.HashIncrement($"{Context.Guild.Id}:SlapsRecieved", user.Id.ToString());
|
||||||
|
_redis.HashIncrement($"{Context.Guild.Id}:SlapsGiven", Context.User.Id.ToString());
|
||||||
|
|
||||||
|
await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[_random.Next(things.Count - 1)]}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
Geekbot.net/Commands/Stats.cs
Normal file
72
Geekbot.net/Commands/Stats.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Stats : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly ILevelCalc _levelCalc;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Stats(IDatabase redis, IErrorHandler errorHandler, ILevelCalc levelCalc)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_levelCalc = levelCalc;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("stats", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Statistics)]
|
||||||
|
[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.GetLevel(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.ToString());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
Geekbot.net/Commands/UrbanDictionary.cs
Normal file
87
Geekbot.net/Commands/UrbanDictionary.cs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class UrbanDictionary : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public UrbanDictionary(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("urban", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[Summary("Lookup something on urban dictionary")]
|
||||||
|
public async Task urbanDefine([Remainder] [Summary("word")] string word)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
client.BaseAddress = new Uri("https://api.urbandictionary.com");
|
||||||
|
var response = await client.GetAsync($"/v0/define?term={word}");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
var definitions = JsonConvert.DeserializeObject<UrbanResponse>(stringResponse);
|
||||||
|
if (definitions.list.Count == 0)
|
||||||
|
{
|
||||||
|
await ReplyAsync("That word hasn't been defined...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var definition = definitions.list.First(e => !string.IsNullOrWhiteSpace(e.example));
|
||||||
|
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.WithAuthor(new EmbedAuthorBuilder
|
||||||
|
{
|
||||||
|
Name = definition.word,
|
||||||
|
Url = definition.permalink
|
||||||
|
});
|
||||||
|
eb.WithColor(new Color(239, 255, 0));
|
||||||
|
eb.Description = definition.definition;
|
||||||
|
eb.AddField("Example", definition.example ?? "(no example given...)");
|
||||||
|
eb.AddInlineField("Upvotes", definition.thumbs_up);
|
||||||
|
eb.AddInlineField("Downvotes", definition.thumbs_down);
|
||||||
|
if (definitions.tags.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.tags));
|
||||||
|
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UrbanResponse
|
||||||
|
{
|
||||||
|
public string[] tags { get; set; }
|
||||||
|
public string result_type { get; set; }
|
||||||
|
public List<UrbanListItem> list { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UrbanListItem
|
||||||
|
{
|
||||||
|
public string definition { get; set; }
|
||||||
|
public string permalink { get; set; }
|
||||||
|
public string thumbs_up { get; set; }
|
||||||
|
public string author { get; set; }
|
||||||
|
public string word { get; set; }
|
||||||
|
public string defid { get; set; }
|
||||||
|
public string current_vote { get; set; }
|
||||||
|
public string example { get; set; }
|
||||||
|
public string thumbs_down { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
Geekbot.net/Commands/Voice.cs
Normal file
102
Geekbot.net/Commands/Voice.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Voice : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IAudioUtils _audioUtils;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Voice(IErrorHandler errorHandler, IAudioUtils audioUtils)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_audioUtils = audioUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("join")]
|
||||||
|
public async Task JoinChannel()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the audio channel
|
||||||
|
var channel = (Context.User as IGuildUser)?.VoiceChannel;
|
||||||
|
if (channel == null)
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync(
|
||||||
|
"User must be in a voice channel, or a voice channel must be passed as an argument.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the next step with transmitting audio, you would want to pass this Audio Client in to a service.
|
||||||
|
var audioClient = await channel.ConnectAsync();
|
||||||
|
_audioUtils.StoreAudioClient(Context.Guild.Id, audioClient);
|
||||||
|
await ReplyAsync($"Connected to {channel.Name}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("disconnect")]
|
||||||
|
public async Task DisconnectChannel()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id);
|
||||||
|
if (audioClient == null)
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync("I'm not in a voice channel at the moment");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await audioClient.StopAsync();
|
||||||
|
await ReplyAsync("Disconnected from channel!");
|
||||||
|
_audioUtils.Cleanup(Context.Guild.Id);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
_audioUtils.Cleanup(Context.Guild.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("ytplay")]
|
||||||
|
public async Task ytplay(string url)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!url.Contains("youtube"))
|
||||||
|
{
|
||||||
|
await ReplyAsync("I can only play youtube videos");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id);
|
||||||
|
if (audioClient == null)
|
||||||
|
{
|
||||||
|
await ReplyAsync("I'm not in a voice channel at the moment");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = await Context.Channel.SendMessageAsync("Just a second, i'm still a bit slow at this");
|
||||||
|
var ffmpeg = _audioUtils.CreateStreamFromYoutube(url, Context.Guild.Id);
|
||||||
|
var output = ffmpeg.StandardOutput.BaseStream;
|
||||||
|
await message.ModifyAsync(msg => msg.Content = "**Playing!** Please note that this feature is experimental");
|
||||||
|
var discord = audioClient.CreatePCMStream(Discord.Audio.AudioApplication.Mixed);
|
||||||
|
await output.CopyToAsync(discord);
|
||||||
|
await discord.FlushAsync();
|
||||||
|
_audioUtils.Cleanup(Context.Guild.Id);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
_audioUtils.Cleanup(Context.Guild.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
Geekbot.net/Commands/Youtube.cs
Normal file
59
Geekbot.net/Commands/Youtube.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Google.Apis.Services;
|
||||||
|
using Google.Apis.YouTube.v3;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class Youtube : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Youtube(IDatabase redis, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("yt", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[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)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
Geekbot.net/Commands/mal.cs
Normal file
119
Geekbot.net/Commands/mal.cs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands
|
||||||
|
{
|
||||||
|
public class mal : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IMalClient _malClient;
|
||||||
|
|
||||||
|
public mal(IMalClient malClient, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_malClient = malClient;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("anime", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[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 = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("manga", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
|
[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 = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
Geekbot.net/Geekbot.net.csproj
Executable file
73
Geekbot.net/Geekbot.net.csproj
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<ApplicationIcon>derp.ico</ApplicationIcon>
|
||||||
|
<Version>1.1.0</Version>
|
||||||
|
<Company>Pizza and Coffee Studios</Company>
|
||||||
|
<Authors>Pizza and Coffee Studios</Authors>
|
||||||
|
<Description>A Discord bot</Description>
|
||||||
|
<RepositoryUrl>https://github.com/pizzaandcoffee/Geekbot.net</RepositoryUrl>
|
||||||
|
<NoWarn>NU1701</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Discord.Net">
|
||||||
|
<Version>1.0.2</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.29.1.991" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
|
||||||
|
<PackageReference Include="MtgApiManager.Lib" Version="1.0.0.2" />
|
||||||
|
<PackageReference Include="MyAnimeListSharp" Version="1.3.4" />
|
||||||
|
<PackageReference Include="Nancy" Version="2.0.0-clinteastwood" />
|
||||||
|
<PackageReference Include="Nancy.Hosting.Self" Version="2.0.0-clinteastwood" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||||
|
<PackageReference Include="Overwatch.Net" Version="3.0.0" />
|
||||||
|
<PackageReference Include="PokeApi.NET" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.6.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1-dev-00757" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Literate" Version="3.0.1-dev-00044" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.1-dev-00771" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.SumoLogic" Version="2.3.0" />
|
||||||
|
<PackageReference Include="SharpRaven" Version="2.2.0" />
|
||||||
|
<PackageReference Include="StackExchange.Redis">
|
||||||
|
<Version>1.2.6</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="System.Net.Http" Version="4.3.3" />
|
||||||
|
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Runtime.Serialization.Json">
|
||||||
|
<Version>4.3.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="System.Runtime.Serialization.Primitives">
|
||||||
|
<Version>4.3.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Utf8Json" Version="1.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Storage\checkEmPics">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\croissant">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\fortunes">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\pandas">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\pumpkin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\squirrel">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\Translations.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\turtles">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
196
Geekbot.net/Handlers.cs
Normal file
196
Geekbot.net/Handlers.cs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net
|
||||||
|
{
|
||||||
|
public class Handlers
|
||||||
|
{
|
||||||
|
private readonly IDiscordClient _client;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IServiceProvider _servicesProvider;
|
||||||
|
private readonly CommandService _commands;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly IContextHandler _contextHandler;
|
||||||
|
|
||||||
|
public Handlers(IDiscordClient client, IGeekbotLogger logger, IDatabase redis, IServiceProvider servicesProvider, CommandService commands, IUserRepository userRepository, IContextHandler contextHandler)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_logger = logger;
|
||||||
|
_redis = redis;
|
||||||
|
_servicesProvider = servicesProvider;
|
||||||
|
_commands = commands;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
_contextHandler = contextHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Incoming Messages
|
||||||
|
//
|
||||||
|
|
||||||
|
public Task RunCommand(SocketMessage messageParam)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask;
|
||||||
|
if (message.Author.IsBot) return Task.CompletedTask;
|
||||||
|
var argPos = 0;
|
||||||
|
var lowCaseMsg = message.ToString().ToLower();
|
||||||
|
if (lowCaseMsg.Equals("ping") || lowCaseMsg.StartsWith("ping "))
|
||||||
|
{
|
||||||
|
message.Channel.SendMessageAsync("pong");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
if (lowCaseMsg.StartsWith("hui"))
|
||||||
|
{
|
||||||
|
message.Channel.SendMessageAsync("hui!!!");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contextType = _contextHandler.HasContext(message);
|
||||||
|
if (contextType != ContextReference.None)
|
||||||
|
{
|
||||||
|
_contextHandler.ExecuteOnContext(contextType, message);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
if (!(message.HasCharPrefix('!', ref argPos) ||
|
||||||
|
message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return Task.CompletedTask;
|
||||||
|
var context = new CommandContext(_client, message);
|
||||||
|
var commandExec = _commands.ExecuteAsync(context, argPos, _servicesProvider);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Failed to run commands", e);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateStats(SocketMessage message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (message == null) return Task.CompletedTask;
|
||||||
|
if (message.Channel.Name.StartsWith('@'))
|
||||||
|
{
|
||||||
|
_logger.Information("Message", "DM-Channel - {message.Channel.Name} - {message.Content}");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
var channel = (SocketGuildChannel) message.Channel;
|
||||||
|
|
||||||
|
_redis.HashIncrementAsync($"{channel.Guild.Id}:Messages", message.Author.Id.ToString());
|
||||||
|
_redis.HashIncrementAsync($"{channel.Guild.Id}:Messages", 0.ToString());
|
||||||
|
|
||||||
|
if (message.Author.IsBot) return Task.CompletedTask;
|
||||||
|
_logger.Information("Message", message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||||
|
// _logger.Information($"[Message] {channel.Guild.Name} ({channel.Guild.Id}) - {message.Channel} ({message.Channel.Id}) - {message.Author.Username}#{message.Author.Discriminator} ({message.Author.Id}) - {message.Content}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Message", "Could not process message stats", e);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// User Stuff
|
||||||
|
//
|
||||||
|
|
||||||
|
public Task UserJoined(SocketGuildUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!user.IsBot)
|
||||||
|
{
|
||||||
|
var message = _redis.HashGet($"{user.Guild.Id}:Settings", "WelcomeMsg");
|
||||||
|
if (!message.IsNullOrEmpty)
|
||||||
|
{
|
||||||
|
message = message.ToString().Replace("$user", user.Mention);
|
||||||
|
user.Guild.DefaultChannel.SendMessageAsync(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_userRepository.Update(user);
|
||||||
|
_logger.Information("Geekbot", $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Failed to send welcome message", e);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UserUpdated(SocketUser oldUser, SocketUser newUser)
|
||||||
|
{
|
||||||
|
_userRepository.Update(newUser);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UserLeft(SocketGuildUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sendLeftEnabled = _redis.HashGet($"{user.Guild.Id}:Settings", "ShowLeave");
|
||||||
|
if (sendLeftEnabled.ToString() == "1")
|
||||||
|
{
|
||||||
|
var modChannel = ulong.Parse(_redis.HashGet($"{user.Guild.Id}:Settings", "ModChannel"));
|
||||||
|
if (!string.IsNullOrEmpty(modChannel.ToString()))
|
||||||
|
{
|
||||||
|
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(modChannel);
|
||||||
|
await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Failed to send leave message", e);
|
||||||
|
}
|
||||||
|
_logger.Information("Geekbot", $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Message Stuff
|
||||||
|
//
|
||||||
|
|
||||||
|
public async Task MessageDeleted(Cacheable<IMessage, ulong> message, ISocketMessageChannel channel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var guild = ((IGuildChannel) channel).Guild;
|
||||||
|
var sendLeftEnabled = _redis.HashGet($"{guild.Id}:Settings", "ShowDelete");
|
||||||
|
if (sendLeftEnabled.ToString() == "1")
|
||||||
|
{
|
||||||
|
var modChannel = ulong.Parse(_redis.HashGet($"{guild.Id}:Settings", "ModChannel"));
|
||||||
|
if (!string.IsNullOrEmpty(modChannel.ToString()) && modChannel != channel.Id)
|
||||||
|
{
|
||||||
|
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(modChannel);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
if (message.Value != null)
|
||||||
|
{
|
||||||
|
sb.AppendLine(
|
||||||
|
$"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>");
|
||||||
|
sb.AppendLine(message.Value.Content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine("Someone deleted a message, the message was not cached...");
|
||||||
|
}
|
||||||
|
await modChannelSocket.SendMessageAsync(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Failed to send delete message...", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
Geekbot.net/Lib/AudioClientCache.cs
Normal file
106
Geekbot.net/Lib/AudioClientCache.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Discord.Audio;
|
||||||
|
using Discord.Net;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class AudioUtils : IAudioUtils
|
||||||
|
{
|
||||||
|
private string _tempFolderPath;
|
||||||
|
private Dictionary<ulong, IAudioClient> _audioClients;
|
||||||
|
|
||||||
|
public AudioUtils()
|
||||||
|
{
|
||||||
|
_audioClients = new Dictionary<ulong, IAudioClient>();
|
||||||
|
_tempFolderPath = Path.GetFullPath("./tmp/");
|
||||||
|
if (Directory.Exists(_tempFolderPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(_tempFolderPath, true);
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(_tempFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAudioClient GetAudioClient(ulong guildId)
|
||||||
|
{
|
||||||
|
return _audioClients[guildId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StoreAudioClient(ulong guildId, IAudioClient client)
|
||||||
|
{
|
||||||
|
_audioClients[guildId] = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process CreateStreamFromFile(string path)
|
||||||
|
{
|
||||||
|
var ffmpeg = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "ffmpeg",
|
||||||
|
Arguments = $"-i {path} -ac 2 -f s16le -ar 48000 pipe:1",
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
};
|
||||||
|
return Process.Start(ffmpeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process CreateStreamFromYoutube(string url, ulong guildId)
|
||||||
|
{
|
||||||
|
var ytdlMediaUrl = GetYoutubeMediaUrl(url);
|
||||||
|
DownloadMediaUrl(ytdlMediaUrl, guildId);
|
||||||
|
return CreateStreamFromFile($"{_tempFolderPath}{guildId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cleanup(ulong guildId)
|
||||||
|
{
|
||||||
|
File.Delete($"{_tempFolderPath}{guildId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetYoutubeMediaUrl(string url)
|
||||||
|
{
|
||||||
|
var ytdl = new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
FileName = "youtube-dl",
|
||||||
|
Arguments = $"-f bestaudio -g {url}",
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = true
|
||||||
|
};
|
||||||
|
var output = Process.Start(ytdl).StandardOutput.ReadToEnd();
|
||||||
|
if (string.IsNullOrWhiteSpace(output))
|
||||||
|
{
|
||||||
|
throw new Exception("Could not get Youtube Media URL");
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DownloadMediaUrl(string url, ulong guildId)
|
||||||
|
{
|
||||||
|
using (var web = new WebClient())
|
||||||
|
{
|
||||||
|
web.DownloadFile(url, $"{_tempFolderPath}{guildId}");
|
||||||
|
}
|
||||||
|
// var ffmpeg = new ProcessStartInfo
|
||||||
|
// {
|
||||||
|
// FileName = "ffmpeg",
|
||||||
|
// Arguments = $"-i \"{_tempFolderPath}{guildId}\" -c:a mp3 -b:a 256k {_tempFolderPath}{guildId}.mp3",
|
||||||
|
// UseShellExecute = false,
|
||||||
|
// RedirectStandardOutput = true,
|
||||||
|
// };
|
||||||
|
// Process.Start(ffmpeg).WaitForExit();
|
||||||
|
// File.Delete($"{_tempFolderPath}{guildId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAudioUtils
|
||||||
|
{
|
||||||
|
IAudioClient GetAudioClient(ulong guildId);
|
||||||
|
void StoreAudioClient(ulong guildId, IAudioClient client);
|
||||||
|
Process CreateStreamFromFile(string path);
|
||||||
|
Process CreateStreamFromYoutube(string url, ulong guildId);
|
||||||
|
void Cleanup(ulong guildId);
|
||||||
|
}
|
||||||
|
}
|
15
Geekbot.net/Lib/CommandCategories.cs
Normal file
15
Geekbot.net/Lib/CommandCategories.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class CommandCategories
|
||||||
|
{
|
||||||
|
public const string Randomness = "Randomness";
|
||||||
|
public const string Karma = "Karma";
|
||||||
|
public const string Quotes = "Quotes";
|
||||||
|
public const string Fun = "Fun";
|
||||||
|
public const string Statistics = "Statistics";
|
||||||
|
public const string Helpers = "Helpers";
|
||||||
|
public const string Games = "Games";
|
||||||
|
public const string Admin = "Admin";
|
||||||
|
public const string Uncategorized = "Uncategorized";
|
||||||
|
}
|
||||||
|
}
|
9
Geekbot.net/Lib/Constants.cs
Normal file
9
Geekbot.net/Lib/Constants.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class Constants
|
||||||
|
{
|
||||||
|
public const string Name = "Geekbot";
|
||||||
|
public const double BotVersion = 3.5;
|
||||||
|
public const double ApiVersion = 1;
|
||||||
|
}
|
||||||
|
}
|
99
Geekbot.net/Lib/EmojiConverter.cs
Normal file
99
Geekbot.net/Lib/EmojiConverter.cs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class EmojiConverter : IEmojiConverter
|
||||||
|
{
|
||||||
|
public string numberToEmoji(int number)
|
||||||
|
{
|
||||||
|
if (number == 10)
|
||||||
|
{
|
||||||
|
return "🔟";
|
||||||
|
}
|
||||||
|
var emojiMap = new string[]
|
||||||
|
{
|
||||||
|
":zero:",
|
||||||
|
":one:",
|
||||||
|
":two:",
|
||||||
|
":three:",
|
||||||
|
":four:",
|
||||||
|
":five:",
|
||||||
|
":six:",
|
||||||
|
":seven:",
|
||||||
|
":eight:",
|
||||||
|
":nine:",
|
||||||
|
};
|
||||||
|
var numbers = number.ToString().ToCharArray();
|
||||||
|
var returnString = new StringBuilder();
|
||||||
|
foreach (var n in numbers)
|
||||||
|
{
|
||||||
|
returnString.Append(emojiMap[int.Parse(n.ToString())]);
|
||||||
|
}
|
||||||
|
return returnString.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string textToEmoji(string text)
|
||||||
|
{
|
||||||
|
var emojiMap = new Hashtable
|
||||||
|
{
|
||||||
|
['A'] = ":regional_indicator_a:",
|
||||||
|
['B'] = ":b:",
|
||||||
|
['C'] = ":regional_indicator_c:",
|
||||||
|
['D'] = ":regional_indicator_d:",
|
||||||
|
['E'] = ":regional_indicator_e:",
|
||||||
|
['F'] = ":regional_indicator_f:",
|
||||||
|
['G'] = ":regional_indicator_g:",
|
||||||
|
['H'] = ":regional_indicator_h:",
|
||||||
|
['I'] = ":regional_indicator_i:",
|
||||||
|
['J'] = ":regional_indicator_j:",
|
||||||
|
['K'] = ":regional_indicator_k:",
|
||||||
|
['L'] = ":regional_indicator_l:",
|
||||||
|
['M'] = ":regional_indicator_m:",
|
||||||
|
['N'] = ":regional_indicator_n:",
|
||||||
|
['O'] = ":regional_indicator_o:",
|
||||||
|
['P'] = ":regional_indicator_p:",
|
||||||
|
['Q'] = ":regional_indicator_q:",
|
||||||
|
['R'] = ":regional_indicator_r:",
|
||||||
|
['S'] = ":regional_indicator_s:",
|
||||||
|
['T'] = ":regional_indicator_t:",
|
||||||
|
['U'] = ":regional_indicator_u:",
|
||||||
|
['V'] = ":regional_indicator_v:",
|
||||||
|
['W'] = ":regional_indicator_w:",
|
||||||
|
['X'] = ":regional_indicator_x:",
|
||||||
|
['Y'] = ":regional_indicator_y:",
|
||||||
|
['Z'] = ":regional_indicator_z:",
|
||||||
|
['!'] = ":exclamation:",
|
||||||
|
['?'] = ":question:",
|
||||||
|
['#'] = ":hash:",
|
||||||
|
['*'] = ":star2:",
|
||||||
|
['+'] = ":heavy_plus_sign:",
|
||||||
|
['0'] = ":zero:",
|
||||||
|
['1'] = ":one:",
|
||||||
|
['2'] = ":two:",
|
||||||
|
['3'] = ":three:",
|
||||||
|
['4'] = ":four:",
|
||||||
|
['5'] = ":five:",
|
||||||
|
['6'] = ":six:",
|
||||||
|
['7'] = ":seven:",
|
||||||
|
['8'] = ":eight:",
|
||||||
|
['9'] = ":nine:",
|
||||||
|
[' '] = " "
|
||||||
|
};
|
||||||
|
var letters = text.ToUpper().ToCharArray();
|
||||||
|
var returnString = new StringBuilder();
|
||||||
|
foreach (var n in letters)
|
||||||
|
{
|
||||||
|
var emoji = emojiMap[n] ?? n;
|
||||||
|
returnString.Append(emoji);
|
||||||
|
}
|
||||||
|
return returnString.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IEmojiConverter
|
||||||
|
{
|
||||||
|
string numberToEmoji(int number);
|
||||||
|
string textToEmoji(string text);
|
||||||
|
}
|
||||||
|
}
|
92
Geekbot.net/Lib/ErrorHandler.cs
Normal file
92
Geekbot.net/Lib/ErrorHandler.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.Net;
|
||||||
|
using Nancy.Extensions;
|
||||||
|
using Serilog;
|
||||||
|
using SharpRaven;
|
||||||
|
using SharpRaven.Data;
|
||||||
|
using SharpRaven.Utilities;
|
||||||
|
using Utf8Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class ErrorHandler : IErrorHandler
|
||||||
|
{
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
private readonly IRavenClient _raven;
|
||||||
|
|
||||||
|
public ErrorHandler(IGeekbotLogger logger, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_translation = translation;
|
||||||
|
|
||||||
|
var sentryDsn = Environment.GetEnvironmentVariable("SENTRY");
|
||||||
|
if (!string.IsNullOrEmpty(sentryDsn))
|
||||||
|
{
|
||||||
|
_raven = new RavenClient(sentryDsn);
|
||||||
|
_logger.Information("Geekbot", $"Command Errors will be logged to Sentry: {sentryDsn}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_raven = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleCommandException(Exception e, ICommandContext Context, string errorMessage = "def")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var errorString = errorMessage == "def" ? _translation.GetString(Context.Guild.Id, "errorHandler", "SomethingWentWrong") : errorMessage;
|
||||||
|
var errorObj = SimpleConextConverter.ConvertContext(Context);
|
||||||
|
_logger.Error("Geekbot", "An error ocured", e, errorObj);
|
||||||
|
if (!string.IsNullOrEmpty(errorMessage))
|
||||||
|
{
|
||||||
|
Context.Channel.SendMessageAsync(errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Message.Contains("50013")) return;
|
||||||
|
if (e.Message.Contains("50007")) return;
|
||||||
|
if (_raven == null) return;
|
||||||
|
|
||||||
|
var sentryEvent = new SentryEvent(e)
|
||||||
|
{
|
||||||
|
Tags =
|
||||||
|
{
|
||||||
|
["discord_server"] = errorObj.Guild.Name,
|
||||||
|
["discord_user"] = errorObj.User.Name
|
||||||
|
},
|
||||||
|
Message = errorObj.Message.Content,
|
||||||
|
Extra = errorObj
|
||||||
|
};
|
||||||
|
_raven.Capture(sentryEvent);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Errorception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void HandleHttpException(HttpException e, ICommandContext Context)
|
||||||
|
{
|
||||||
|
var errorStrings = _translation.GetDict(Context, "httpErrors");
|
||||||
|
switch(e.HttpCode)
|
||||||
|
{
|
||||||
|
case HttpStatusCode.Forbidden:
|
||||||
|
await Context.Channel.SendMessageAsync(errorStrings["403"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IErrorHandler
|
||||||
|
{
|
||||||
|
void HandleCommandException(Exception e, ICommandContext Context, string errorMessage = "def");
|
||||||
|
void HandleHttpException(HttpException e, ICommandContext Context);
|
||||||
|
}
|
||||||
|
}
|
80
Geekbot.net/Lib/GeekbotLogger.cs
Normal file
80
Geekbot.net/Lib/GeekbotLogger.cs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Serilog;
|
||||||
|
using Utf8Json;
|
||||||
|
using Utf8Json.Formatters;
|
||||||
|
using Utf8Json.Resolvers;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class GeekbotLogger : IGeekbotLogger
|
||||||
|
{
|
||||||
|
private readonly ILogger _serilog;
|
||||||
|
public GeekbotLogger()
|
||||||
|
{
|
||||||
|
_serilog = LoggerFactory.createLogger();
|
||||||
|
//JsonSerializer.SetDefaultResolver(StandardResolver.AllowPrivateExcludeNullSnakeCase);
|
||||||
|
Information("Geekbot", "Using GeekbotLogger");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Debug(string source, string message, object extra = null)
|
||||||
|
{
|
||||||
|
HandleLogObject("Debug", source, message, null, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Information(string source, string message, object extra = null)
|
||||||
|
{
|
||||||
|
HandleLogObject("Information", source, message, null, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Warning(string source, string message, Exception stackTrace = null, object extra = null)
|
||||||
|
{
|
||||||
|
HandleLogObject("Warning", source, message, stackTrace, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Error(string source, string message, Exception stackTrace, object extra = null)
|
||||||
|
{
|
||||||
|
HandleLogObject("Error", source, message, stackTrace, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task HandleLogObject(string type, string source, string message, Exception stackTrace = null, object extra = null)
|
||||||
|
{
|
||||||
|
var logJson = CreateLogObject(type, source, message, null, extra);
|
||||||
|
// fuck serilog
|
||||||
|
_serilog.Information(logJson + "}");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateLogObject(string type, string source, string message, Exception stackTrace = null, object extra = null)
|
||||||
|
{
|
||||||
|
var logObject = new GeekbotLoggerObject()
|
||||||
|
{
|
||||||
|
Timestamp = DateTime.Now,
|
||||||
|
Type = type,
|
||||||
|
Source = source,
|
||||||
|
Message = message,
|
||||||
|
StackTrace = stackTrace,
|
||||||
|
Extra = extra
|
||||||
|
};
|
||||||
|
return JsonSerializer.ToJsonString(logObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GeekbotLoggerObject
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public string Source { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public Exception StackTrace { get; set; }
|
||||||
|
public object Extra { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IGeekbotLogger
|
||||||
|
{
|
||||||
|
void Debug(string source, string message, object extra = null);
|
||||||
|
void Information(string source, string message, object extra = null);
|
||||||
|
void Warning(string source, string message, Exception stackTrace = null, object extra = null);
|
||||||
|
void Error(string source, string message, Exception stackTrace, object extra = null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Geekbot.Core.Levels
|
namespace Geekbot.net.Lib
|
||||||
{
|
{
|
||||||
public class LevelCalc : ILevelCalc
|
public class LevelCalc : ILevelCalc
|
||||||
{
|
{
|
||||||
private readonly int[] _levels;
|
private int[] _levels;
|
||||||
|
|
||||||
public LevelCalc()
|
public LevelCalc()
|
||||||
{
|
{
|
||||||
|
@ -20,9 +20,20 @@ namespace Geekbot.Core.Levels
|
||||||
_levels = levels.ToArray();
|
_levels = levels.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetLevel(int? messages)
|
public int GetLevel(int messages)
|
||||||
{
|
{
|
||||||
return 1 + _levels.TakeWhile(level => !(level > messages)).Count();
|
var returnVal = 1;
|
||||||
|
foreach (var level in _levels)
|
||||||
|
{
|
||||||
|
if (level > messages) break;
|
||||||
|
returnVal++;
|
||||||
|
}
|
||||||
|
return returnVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface ILevelCalc
|
||||||
|
{
|
||||||
|
int GetLevel(int experience);
|
||||||
|
}
|
||||||
}
|
}
|
28
Geekbot.net/Lib/LoggerFactory.cs
Normal file
28
Geekbot.net/Lib/LoggerFactory.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Formatting.Json;
|
||||||
|
using Serilog.Sinks.SumoLogic;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class LoggerFactory
|
||||||
|
{
|
||||||
|
public static ILogger createLogger()
|
||||||
|
{
|
||||||
|
var loggerCreation = new LoggerConfiguration();
|
||||||
|
var template = "{Message}{NewLine}";
|
||||||
|
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GEEKBOT_SUMO")))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Logging Geekbot Logs to Sumologic");
|
||||||
|
loggerCreation.WriteTo.SumoLogic(Environment.GetEnvironmentVariable("GEEKBOT_SUMO"),
|
||||||
|
outputTemplate: template);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loggerCreation.WriteTo.LiterateConsole(outputTemplate: template);
|
||||||
|
loggerCreation.WriteTo.RollingFile("Logs/geekbot-{Date}.txt", shared: true, outputTemplate: template);
|
||||||
|
}
|
||||||
|
return loggerCreation.CreateLogger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
Geekbot.net/Lib/MalClient.cs
Normal file
78
Geekbot.net/Lib/MalClient.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MyAnimeListSharp.Auth;
|
||||||
|
using MyAnimeListSharp.Core;
|
||||||
|
using MyAnimeListSharp.Facade.Async;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class MalClient : IMalClient
|
||||||
|
{
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private ICredentialContext _credentials;
|
||||||
|
private AnimeSearchMethodsAsync _animeSearch;
|
||||||
|
private MangaSearchMethodsAsync _mangaSearch;
|
||||||
|
|
||||||
|
public MalClient(IDatabase redis, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_logger = logger;
|
||||||
|
reloadClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool reloadClient()
|
||||||
|
{
|
||||||
|
var malCredentials = _redis.HashGetAll("malCredentials");
|
||||||
|
if (malCredentials.Length != 0)
|
||||||
|
{
|
||||||
|
_credentials = new CredentialContext();
|
||||||
|
foreach (var c in malCredentials)
|
||||||
|
{
|
||||||
|
switch (c.Name)
|
||||||
|
{
|
||||||
|
case "Username":
|
||||||
|
_credentials.UserName = c.Value;
|
||||||
|
break;
|
||||||
|
case "Password":
|
||||||
|
_credentials.Password = c.Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_animeSearch = new AnimeSearchMethodsAsync(_credentials);
|
||||||
|
_mangaSearch = new MangaSearchMethodsAsync(_credentials);
|
||||||
|
_logger.Debug("Geekbot", "Logged in to MAL");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_logger.Debug("Geekbot", "No MAL Credentials Set!");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool isLoggedIn()
|
||||||
|
{
|
||||||
|
return _credentials != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AnimeEntry> getAnime(string query)
|
||||||
|
{
|
||||||
|
var response = await _animeSearch.SearchDeserializedAsync(query);
|
||||||
|
return response.Entries.Count == 0 ? null : response.Entries[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MangaEntry> getManga(string query)
|
||||||
|
{
|
||||||
|
var response = await _mangaSearch.SearchDeserializedAsync(query);
|
||||||
|
return response.Entries.Count == 0 ? null : response.Entries[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IMalClient
|
||||||
|
{
|
||||||
|
bool reloadClient();
|
||||||
|
bool isLoggedIn();
|
||||||
|
Task<AnimeEntry> getAnime(string query);
|
||||||
|
Task<MangaEntry> getManga(string query);
|
||||||
|
}
|
||||||
|
}
|
40
Geekbot.net/Lib/Media/FortunesProvider.cs
Normal file
40
Geekbot.net/Lib/Media/FortunesProvider.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Media
|
||||||
|
{
|
||||||
|
internal class FortunesProvider : IFortunesProvider
|
||||||
|
{
|
||||||
|
private readonly string[] fortuneArray;
|
||||||
|
private readonly Random rnd;
|
||||||
|
private readonly int totalFortunes;
|
||||||
|
|
||||||
|
public FortunesProvider(Random rnd, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
var path = Path.GetFullPath("./Storage/fortunes");
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var rawFortunes = File.ReadAllText(path);
|
||||||
|
fortuneArray = rawFortunes.Split("%");
|
||||||
|
totalFortunes = fortuneArray.Length;
|
||||||
|
this.rnd = rnd;
|
||||||
|
logger.Debug("Geekbot", "Loaded {totalFortunes} Fortunes");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Information("Geekbot", $"Fortunes File not found at {path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetRandomFortune()
|
||||||
|
{
|
||||||
|
return fortuneArray[rnd.Next(0, totalFortunes)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IFortunesProvider
|
||||||
|
{
|
||||||
|
string GetRandomFortune();
|
||||||
|
}
|
||||||
|
}
|
117
Geekbot.net/Lib/Media/MediaProvider.cs
Normal file
117
Geekbot.net/Lib/Media/MediaProvider.cs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Media
|
||||||
|
{
|
||||||
|
public class MediaProvider : IMediaProvider
|
||||||
|
{
|
||||||
|
private readonly Random _random;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private string[] _checkemImages;
|
||||||
|
private string[] _pandaImages;
|
||||||
|
private string[] _croissantImages;
|
||||||
|
private string[] _squirrelImages;
|
||||||
|
private string[] _pumpkinImages;
|
||||||
|
private string[] _turtlesImages;
|
||||||
|
|
||||||
|
public MediaProvider(Random rnd, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
_random = rnd;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
logger.Information("Geekbot", "Loading Media Files");
|
||||||
|
|
||||||
|
LoadCheckem();
|
||||||
|
LoadPandas();
|
||||||
|
BakeCroissants();
|
||||||
|
LoadSquirrels();
|
||||||
|
LoadPumpkins();
|
||||||
|
LoadTurtles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadCheckem()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/checkEmPics"));
|
||||||
|
_checkemImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_checkemImages.Length} CheckEm Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPandas()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pandas"));
|
||||||
|
_pandaImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_pandaImages.Length} Panda Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BakeCroissants()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/croissant"));
|
||||||
|
_croissantImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_croissantImages.Length} Croissant Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSquirrels()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/squirrel"));
|
||||||
|
_squirrelImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_squirrelImages.Length} Squirrel Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPumpkins()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pumpkin"));
|
||||||
|
_pumpkinImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_pumpkinImages.Length} Pumpkin Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTurtles()
|
||||||
|
{
|
||||||
|
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/turtles"));
|
||||||
|
_turtlesImages = rawLinks.Split("\n");
|
||||||
|
_logger.Debug("Geekbot", $"Loaded {_turtlesImages.Length} Turtle Images");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getCheckem()
|
||||||
|
{
|
||||||
|
return _checkemImages[_random.Next(0, _checkemImages.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getPanda()
|
||||||
|
{
|
||||||
|
return _pandaImages[_random.Next(0, _pandaImages.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getCrossant()
|
||||||
|
{
|
||||||
|
return _croissantImages[_random.Next(0, _croissantImages.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getSquirrel()
|
||||||
|
{
|
||||||
|
return _squirrelImages[_random.Next(0, _squirrelImages.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getPumpkin()
|
||||||
|
{
|
||||||
|
return _pumpkinImages[_random.Next(0, _pumpkinImages.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getTurtle()
|
||||||
|
{
|
||||||
|
return _turtlesImages[_random.Next(0, _turtlesImages.Length)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IMediaProvider
|
||||||
|
{
|
||||||
|
string getCheckem();
|
||||||
|
string getPanda();
|
||||||
|
string getCrossant();
|
||||||
|
string getSquirrel();
|
||||||
|
string getPumpkin();
|
||||||
|
string getTurtle();
|
||||||
|
}
|
||||||
|
}
|
97
Geekbot.net/Lib/SimpleConextConverter.cs
Normal file
97
Geekbot.net/Lib/SimpleConextConverter.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class SimpleConextConverter
|
||||||
|
{
|
||||||
|
public static MessageDto ConvertContext(ICommandContext context)
|
||||||
|
{
|
||||||
|
return new MessageDto()
|
||||||
|
{
|
||||||
|
Message = new MessageDto.MessageContent()
|
||||||
|
{
|
||||||
|
Content = context.Message.Content,
|
||||||
|
Id = context.Message.Id.ToString(),
|
||||||
|
Attachments = context.Message.Attachments.Count,
|
||||||
|
ChannelMentions = context.Message.MentionedChannelIds.Count,
|
||||||
|
UserMentions = context.Message.MentionedUserIds.Count,
|
||||||
|
RoleMentions = context.Message.MentionedRoleIds.Count
|
||||||
|
},
|
||||||
|
User = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = context.User.Id.ToString(),
|
||||||
|
Name = $"{context.User.Username}#{context.User.Discriminator}"
|
||||||
|
},
|
||||||
|
Guild = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = context.Guild.Id.ToString(),
|
||||||
|
Name = context.Guild.Name
|
||||||
|
},
|
||||||
|
Channel = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = context.Channel.Id.ToString(),
|
||||||
|
Name = context.Channel.Name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static MessageDto ConvertSocketMessage(SocketMessage message)
|
||||||
|
{
|
||||||
|
var channel = (SocketGuildChannel) message.Channel;
|
||||||
|
return new MessageDto()
|
||||||
|
{
|
||||||
|
Message = new MessageDto.MessageContent()
|
||||||
|
{
|
||||||
|
Content = message.Content,
|
||||||
|
Id = message.Id.ToString(),
|
||||||
|
Attachments = message.Attachments.Count,
|
||||||
|
ChannelMentions = message.MentionedChannels.Count,
|
||||||
|
UserMentions = message.MentionedUsers.Count,
|
||||||
|
RoleMentions = message.MentionedRoles.Count
|
||||||
|
},
|
||||||
|
User = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = message.Author.Id.ToString(),
|
||||||
|
Name = $"{message.Author.Username}#{message.Author.Discriminator}"
|
||||||
|
},
|
||||||
|
Guild = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = channel.Guild.Id.ToString(),
|
||||||
|
Name = channel.Guild.Name
|
||||||
|
},
|
||||||
|
Channel = new MessageDto.IdAndName()
|
||||||
|
{
|
||||||
|
Id = channel.Id.ToString(),
|
||||||
|
Name = channel.Name
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class MessageDto
|
||||||
|
{
|
||||||
|
public MessageContent Message { get; set; }
|
||||||
|
public IdAndName User { get; set; }
|
||||||
|
public IdAndName Guild { get; set; }
|
||||||
|
public IdAndName Channel { get; set; }
|
||||||
|
|
||||||
|
public class MessageContent
|
||||||
|
{
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
public int Attachments { get; set; }
|
||||||
|
public int ChannelMentions { get; set; }
|
||||||
|
public int UserMentions { get; set; }
|
||||||
|
public int RoleMentions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdAndName
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
164
Geekbot.net/Lib/TranslationHandler.cs
Normal file
164
Geekbot.net/Lib/TranslationHandler.cs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class TranslationHandler : ITranslationHandler
|
||||||
|
{
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private Dictionary<string, Dictionary<string, Dictionary<string, string>>> _translations;
|
||||||
|
private Dictionary<ulong, string> _serverLanguages;
|
||||||
|
private List<string> _supportedLanguages;
|
||||||
|
|
||||||
|
public TranslationHandler(IReadOnlyCollection<SocketGuild> clientGuilds, IDatabase redis, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_redis = redis;
|
||||||
|
_logger.Information("Geekbot", "Loading Translations");
|
||||||
|
LoadTranslations();
|
||||||
|
LoadServerLanguages(clientGuilds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTranslations()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var translationFile = File.ReadAllText(Path.GetFullPath("./Storage/Translations.json"));
|
||||||
|
var rawTranslations = Utf8Json.JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(translationFile);
|
||||||
|
var sortedPerLanguage = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
|
||||||
|
foreach (var command in rawTranslations)
|
||||||
|
{
|
||||||
|
foreach (var str in command.Value)
|
||||||
|
{
|
||||||
|
foreach (var lang in str.Value)
|
||||||
|
{
|
||||||
|
if (!sortedPerLanguage.ContainsKey(lang.Key))
|
||||||
|
{
|
||||||
|
var commandDict = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
var strDict = new Dictionary<string, string>();
|
||||||
|
strDict.Add(str.Key, lang.Value);
|
||||||
|
commandDict.Add(command.Key, strDict);
|
||||||
|
sortedPerLanguage.Add(lang.Key, commandDict);
|
||||||
|
}
|
||||||
|
if (!sortedPerLanguage[lang.Key].ContainsKey(command.Key))
|
||||||
|
{
|
||||||
|
var strDict = new Dictionary<string, string>();
|
||||||
|
strDict.Add(str.Key, lang.Value);
|
||||||
|
sortedPerLanguage[lang.Key].Add(command.Key, strDict);
|
||||||
|
}
|
||||||
|
if (!sortedPerLanguage[lang.Key][command.Key].ContainsKey(str.Key))
|
||||||
|
{
|
||||||
|
sortedPerLanguage[lang.Key][command.Key].Add(str.Key, lang.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_translations = sortedPerLanguage;
|
||||||
|
|
||||||
|
_supportedLanguages = new List<string>();
|
||||||
|
foreach (var lang in sortedPerLanguage)
|
||||||
|
{
|
||||||
|
_supportedLanguages.Add(lang.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Failed to load Translations", e);
|
||||||
|
Environment.Exit(110);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadServerLanguages(IReadOnlyCollection<SocketGuild> clientGuilds)
|
||||||
|
{
|
||||||
|
_serverLanguages = new Dictionary<ulong, string>();
|
||||||
|
foreach (var guild in clientGuilds)
|
||||||
|
{
|
||||||
|
var language = _redis.HashGet($"{guild.Id}:Settings", "Language");
|
||||||
|
if (string.IsNullOrEmpty(language) || !_supportedLanguages.Contains(language))
|
||||||
|
{
|
||||||
|
_serverLanguages[guild.Id] = "EN";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_serverLanguages[guild.Id] = language.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetString(ulong guildId, string command, string stringName)
|
||||||
|
{
|
||||||
|
var translation = _translations[_serverLanguages[guildId]][command][stringName];
|
||||||
|
if (!string.IsNullOrWhiteSpace(translation)) return translation;
|
||||||
|
translation = _translations[command][stringName]["EN"];
|
||||||
|
if (string.IsNullOrWhiteSpace(translation))
|
||||||
|
{
|
||||||
|
_logger.Warning("Geekbot", $"No translation found for {command} - {stringName}");
|
||||||
|
}
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, string> GetDict(ICommandContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var command = context.Message.Content.Split(' ').First().TrimStart('!').ToLower();
|
||||||
|
return _translations[_serverLanguages[context.Guild.Id]][command];
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "lol nope", e);
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, string> GetDict(ICommandContext context, string command)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _translations[_serverLanguages[context.Guild.Id]][command];
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "lol nope", e);
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetLanguage(ulong guildId, string language)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_supportedLanguages.Contains(language)) return false;
|
||||||
|
_redis.HashSet($"{guildId}:Settings", new HashEntry[]{ new HashEntry("Language", language), });
|
||||||
|
_serverLanguages[guildId] = language;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error("Geekbot", "Error while changing language", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GetSupportedLanguages()
|
||||||
|
{
|
||||||
|
return _supportedLanguages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ITranslationHandler
|
||||||
|
{
|
||||||
|
string GetString(ulong guildId, string command, string stringName);
|
||||||
|
Dictionary<string, string> GetDict(ICommandContext context);
|
||||||
|
Dictionary<string, string> GetDict(ICommandContext context, string command);
|
||||||
|
bool SetLanguage(ulong guildId, string language);
|
||||||
|
List<string> GetSupportedLanguages();
|
||||||
|
}
|
||||||
|
}
|
146
Geekbot.net/Lib/UserRepository.cs
Normal file
146
Geekbot.net/Lib/UserRepository.cs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using Utf8Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public class UserRepository : IUserRepository
|
||||||
|
{
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
public UserRepository(IDatabase redis, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> Update(SocketUser user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var savedUser = Get(user.Id);
|
||||||
|
savedUser.Id = user.Id;
|
||||||
|
savedUser.Username = user.Username;
|
||||||
|
savedUser.Discriminator = user.Discriminator;
|
||||||
|
savedUser.AvatarUrl = user.GetAvatarUrl() ?? "0";
|
||||||
|
savedUser.IsBot = user.IsBot;
|
||||||
|
savedUser.Joined = user.CreatedAt;
|
||||||
|
if(savedUser.UsedNames == null) savedUser.UsedNames = new List<string>();
|
||||||
|
if (!savedUser.UsedNames.Contains(user.Username))
|
||||||
|
{
|
||||||
|
savedUser.UsedNames.Add(user.Username);
|
||||||
|
}
|
||||||
|
Store(savedUser);
|
||||||
|
|
||||||
|
_logger.Information("UserRepository", "Updated User", savedUser);
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning("UserRepository", $"Failed to update user: {user.Username}#{user.Discriminator} ({user.Id})", e);
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Store(UserRepositoryUser user)
|
||||||
|
{
|
||||||
|
_redis.HashSetAsync($"Users:{user.Id.ToString()}", new HashEntry[]
|
||||||
|
{
|
||||||
|
new HashEntry("Id", user.Id.ToString()),
|
||||||
|
new HashEntry("Username", user.Username),
|
||||||
|
new HashEntry("Discriminator", user.Discriminator),
|
||||||
|
new HashEntry("AvatarUrl", user.AvatarUrl),
|
||||||
|
new HashEntry("IsBot", user.IsBot),
|
||||||
|
new HashEntry("Joined", user.Joined.ToString()),
|
||||||
|
new HashEntry("UsedNames", JsonSerializer.Serialize(user.UsedNames)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRepositoryUser Get(ulong userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = _redis.HashGetAll($"Users:{userId.ToString()}");
|
||||||
|
for (int i = 1; i < 11; i++)
|
||||||
|
{
|
||||||
|
if (user.Length != 0) break;
|
||||||
|
user = _redis.HashGetAll($"Users:{(userId + (ulong) i).ToString()}");
|
||||||
|
|
||||||
|
}
|
||||||
|
var dto = new UserRepositoryUser();
|
||||||
|
foreach (var a in user.ToDictionary())
|
||||||
|
{
|
||||||
|
switch (a.Key)
|
||||||
|
{
|
||||||
|
case "Id":
|
||||||
|
dto.Id = ulong.Parse(a.Value);
|
||||||
|
break;
|
||||||
|
case "Username":
|
||||||
|
dto.Username = a.Value.ToString();
|
||||||
|
break;
|
||||||
|
case "Discriminator":
|
||||||
|
dto.Discriminator = a.Value.ToString();
|
||||||
|
break;
|
||||||
|
case "AvatarUrl":
|
||||||
|
dto.AvatarUrl = (a.Value != "0") ? a.Value.ToString() : null;
|
||||||
|
break;
|
||||||
|
case "IsBot":
|
||||||
|
dto.IsBot = a.Value == 1;
|
||||||
|
break;
|
||||||
|
case "Joined":
|
||||||
|
dto.Joined = DateTimeOffset.Parse(a.Value.ToString());
|
||||||
|
break;
|
||||||
|
case "UsedNames":
|
||||||
|
dto.UsedNames = JsonSerializer.Deserialize<List<string>>(a.Value.ToString()) ?? new List<string>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning("UserRepository", "Failed to get {userId} from repository", e);
|
||||||
|
return new UserRepositoryUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getUserSetting(ulong userId, string setting)
|
||||||
|
{
|
||||||
|
return _redis.HashGet($"Users:{userId}", setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool saveUserSetting(ulong userId, string setting, string value)
|
||||||
|
{
|
||||||
|
_redis.HashSet($"Users:{userId}", new HashEntry[]
|
||||||
|
{
|
||||||
|
new HashEntry(setting, value)
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserRepositoryUser
|
||||||
|
{
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Discriminator { get; set; }
|
||||||
|
public string AvatarUrl { get; set; }
|
||||||
|
public bool IsBot { get; set; }
|
||||||
|
public DateTimeOffset Joined { get; set; }
|
||||||
|
public List<string> UsedNames { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IUserRepository
|
||||||
|
{
|
||||||
|
Task<bool> Update(SocketUser user);
|
||||||
|
UserRepositoryUser Get(ulong userId);
|
||||||
|
string getUserSetting(ulong userId, string setting);
|
||||||
|
bool saveUserSetting(ulong userId, string setting, string value);
|
||||||
|
}
|
||||||
|
}
|
0
Geekbot.net/Logs/.keep
Executable file
0
Geekbot.net/Logs/.keep
Executable file
243
Geekbot.net/Program.cs
Executable file
243
Geekbot.net/Program.cs
Executable file
|
@ -0,0 +1,243 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.Media;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Nancy.Hosting.Self;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private DiscordSocketClient client;
|
||||||
|
private CommandService commands;
|
||||||
|
private IDatabase redis;
|
||||||
|
private IServiceCollection services;
|
||||||
|
private IServiceProvider servicesProvider;
|
||||||
|
private RedisValue token;
|
||||||
|
private IGeekbotLogger logger;
|
||||||
|
private IUserRepository userRepository;
|
||||||
|
private string[] args;
|
||||||
|
private bool firstStart = false;
|
||||||
|
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var logo = new StringBuilder();
|
||||||
|
logo.AppendLine(@" ____ _____ _____ _ ______ ___ _____");
|
||||||
|
logo.AppendLine(@" / ___| ____| ____| |/ / __ ) / _ \\_ _|");
|
||||||
|
logo.AppendLine(@"| | _| _| | _| | ' /| _ \| | | || |");
|
||||||
|
logo.AppendLine(@"| |_| | |___| |___| . \| |_) | |_| || |");
|
||||||
|
logo.AppendLine(@" \____|_____|_____|_|\_\____/ \___/ |_|");
|
||||||
|
logo.AppendLine("=========================================");
|
||||||
|
Console.WriteLine(logo.ToString());
|
||||||
|
var logger = new GeekbotLogger();
|
||||||
|
logger.Information("Geekbot", "Starting...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
new Program().MainAsync(args, logger).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Geekbot", "RIP", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MainAsync(string[] args, IGeekbotLogger logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.args = args;
|
||||||
|
logger.Information("Geekbot", "Initing Stuff");
|
||||||
|
|
||||||
|
client = new DiscordSocketClient(new DiscordSocketConfig
|
||||||
|
{
|
||||||
|
LogLevel = LogSeverity.Verbose,
|
||||||
|
MessageCacheSize = 1000
|
||||||
|
});
|
||||||
|
client.Log += DiscordLogger;
|
||||||
|
commands = new CommandService();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var redisMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1:6379");
|
||||||
|
redis = redisMultiplexer.GetDatabase(6);
|
||||||
|
logger.Information("Redis", $"Connected to db {redis.Database}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Redis", "Redis Connection Failed", e);
|
||||||
|
Environment.Exit(102);
|
||||||
|
}
|
||||||
|
|
||||||
|
token = redis.StringGet("discordToken");
|
||||||
|
if (token.IsNullOrEmpty)
|
||||||
|
{
|
||||||
|
Console.Write("Your bot Token: ");
|
||||||
|
var newToken = Console.ReadLine();
|
||||||
|
redis.StringSet("discordToken", newToken);
|
||||||
|
redis.StringSet("Game", "Ping Pong");
|
||||||
|
token = newToken;
|
||||||
|
firstStart = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
services = new ServiceCollection();
|
||||||
|
|
||||||
|
userRepository = new UserRepository(redis, logger);
|
||||||
|
var randomClient = new Random();
|
||||||
|
var fortunes = new FortunesProvider(randomClient, logger);
|
||||||
|
var mediaProvider = new MediaProvider(randomClient, logger);
|
||||||
|
var malClient = new MalClient(redis, logger);
|
||||||
|
var levelCalc = new LevelCalc();
|
||||||
|
var emojiConverter = new EmojiConverter();
|
||||||
|
var audioUtils = new AudioUtils();
|
||||||
|
|
||||||
|
services.AddSingleton(redis);
|
||||||
|
services.AddSingleton<IGeekbotLogger>(logger);
|
||||||
|
services.AddSingleton<IUserRepository>(userRepository);
|
||||||
|
services.AddSingleton<ILevelCalc>(levelCalc);
|
||||||
|
services.AddSingleton<IEmojiConverter>(emojiConverter);
|
||||||
|
services.AddSingleton<IAudioUtils>(audioUtils);
|
||||||
|
services.AddSingleton(randomClient);
|
||||||
|
services.AddSingleton<IFortunesProvider>(fortunes);
|
||||||
|
services.AddSingleton<IMediaProvider>(mediaProvider);
|
||||||
|
services.AddSingleton<IMalClient>(malClient);
|
||||||
|
|
||||||
|
logger.Information("Geekbot", "Connecting to Discord");
|
||||||
|
|
||||||
|
await Login();
|
||||||
|
|
||||||
|
await Task.Delay(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Login()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client.LoginAsync(TokenType.Bot, token);
|
||||||
|
await client.StartAsync();
|
||||||
|
var isConneted = await isConnected();
|
||||||
|
if (isConneted)
|
||||||
|
{
|
||||||
|
await client.SetGameAsync(redis.StringGet("Game"));
|
||||||
|
logger.Information("Geekbot", $"Now Connected as {client.CurrentUser.Username} to {client.Guilds.Count} Servers");
|
||||||
|
|
||||||
|
logger.Information("Geekbot", "Registering Stuff");
|
||||||
|
var translationHandler = new TranslationHandler(client.Guilds, redis, logger);
|
||||||
|
var errorHandler = new ErrorHandler(logger, translationHandler);
|
||||||
|
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
|
||||||
|
var contextHandler = new ContextHandler(client, commands, servicesProvider);
|
||||||
|
services.AddSingleton(commands);
|
||||||
|
services.AddSingleton<IContextHandler>(contextHandler);
|
||||||
|
services.AddSingleton<IErrorHandler>(errorHandler);
|
||||||
|
services.AddSingleton<ITranslationHandler>(translationHandler);
|
||||||
|
services.AddSingleton<DiscordSocketClient>(client);
|
||||||
|
servicesProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
var handlers = new Handlers(client, logger, redis, servicesProvider, commands, userRepository, contextHandler);
|
||||||
|
|
||||||
|
client.MessageReceived += handlers.RunCommand;
|
||||||
|
client.MessageReceived += handlers.UpdateStats;
|
||||||
|
client.MessageDeleted += handlers.MessageDeleted;
|
||||||
|
client.UserJoined += handlers.UserJoined;
|
||||||
|
client.UserUpdated += handlers.UserUpdated;
|
||||||
|
client.UserLeft += handlers.UserLeft;
|
||||||
|
|
||||||
|
if (firstStart || args.Contains("--reset"))
|
||||||
|
{
|
||||||
|
logger.Information("Geekbot", "Finishing setup");
|
||||||
|
await FinishSetup();
|
||||||
|
logger.Information("Geekbot", "Setup finished");
|
||||||
|
}
|
||||||
|
if (!args.Contains("--disable-api"))
|
||||||
|
{
|
||||||
|
startWebApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Information("Geekbot", "Done and ready for use");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Discord", "Could not connect...", e);
|
||||||
|
Environment.Exit(103);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> isConnected()
|
||||||
|
{
|
||||||
|
while (!client.ConnectionState.Equals(ConnectionState.Connected))
|
||||||
|
await Task.Delay(25);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startWebApi()
|
||||||
|
{
|
||||||
|
logger.Information("API", "Starting Webserver");
|
||||||
|
var webApiUrl = new Uri("http://localhost:12995");
|
||||||
|
new NancyHost(webApiUrl).Start();
|
||||||
|
logger.Information("API", $"Webserver now running on {webApiUrl}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Task> FinishSetup()
|
||||||
|
{
|
||||||
|
var appInfo = await client.GetApplicationInfoAsync();
|
||||||
|
logger.Information("Setup", $"Just a moment while i setup everything {appInfo.Owner.Username}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
redis.StringSet("botOwner", appInfo.Owner.Id);
|
||||||
|
var req = HttpWebRequest.Create(appInfo.IconUrl);
|
||||||
|
using (var stream = req.GetResponse().GetResponseStream())
|
||||||
|
{
|
||||||
|
await client.CurrentUser.ModifyAsync(User =>
|
||||||
|
{
|
||||||
|
User.Avatar = new Image(stream);
|
||||||
|
User.Username = appInfo.Name.ToString();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
logger.Information("Setup", "Everything done, enjoy!");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Warning("Setup", "Oha, it seems like something went wrong while running the setup, geekbot will work never the less though", e);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task DiscordLogger(LogMessage message)
|
||||||
|
{
|
||||||
|
var logMessage = $"[{message.Source}] {message.Message}";
|
||||||
|
switch (message.Severity)
|
||||||
|
{
|
||||||
|
case LogSeverity.Verbose:
|
||||||
|
case LogSeverity.Debug:
|
||||||
|
logger.Debug(message.Source, message.Message);
|
||||||
|
break;
|
||||||
|
case LogSeverity.Info:
|
||||||
|
logger.Information(message.Source, message.Message);
|
||||||
|
break;
|
||||||
|
case LogSeverity.Critical:
|
||||||
|
case LogSeverity.Error:
|
||||||
|
case LogSeverity.Warning:
|
||||||
|
if (logMessage.Contains("VOICE_STATE_UPDATE")) break;
|
||||||
|
logger.Error(message.Source, message.Message, message.Exception);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.Information(message.Source, $"{logMessage} --- {message.Severity}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
Geekbot.net/Storage/Translations.json
Normal file
100
Geekbot.net/Storage/Translations.json
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
{
|
||||||
|
"admin": {
|
||||||
|
"NewLanguageSet": {
|
||||||
|
"EN": "I will reply in english from now on",
|
||||||
|
"CHDE": "I werd ab jetzt uf schwiizerdüütsch antworte, äuuä"
|
||||||
|
},
|
||||||
|
"GetLanguage": {
|
||||||
|
"EN": "I'm talking english",
|
||||||
|
"CHDE": "I red schwiizerdüütsch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"errorHandler": {
|
||||||
|
"SomethingWentWrong": {
|
||||||
|
"EN": "Something went wrong :confused:",
|
||||||
|
"CHDE": "Öppis isch schief gange :confused:"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"httpErrors": {
|
||||||
|
"403": {
|
||||||
|
"EN": "Seems like i don't have enough permission to that :confused:",
|
||||||
|
"CHDE": "Gseht danach us das ich nid gnueg recht han zum das mache :confused:"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": {
|
||||||
|
"Choice": {
|
||||||
|
"EN": "I Choose **{0}**",
|
||||||
|
"CHDE": "I nimme **{0}**"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"good": {
|
||||||
|
"CannotChangeOwn": {
|
||||||
|
"EN": "Sorry {0}, but you can't give yourself karma",
|
||||||
|
"CHDE": "Sorry {0}, aber du chasch dr selber kei karma geh"
|
||||||
|
},
|
||||||
|
"WaitUntill": {
|
||||||
|
"EN": "Sorry {0}, but you have to wait {1} before you can give karma again...",
|
||||||
|
"CHDE": "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch geh..."
|
||||||
|
},
|
||||||
|
"Increased": {
|
||||||
|
"EN": "Karma gained",
|
||||||
|
"CHDE": "Karma becho"
|
||||||
|
},
|
||||||
|
"By": {
|
||||||
|
"EN": "By",
|
||||||
|
"CHDE": "Vo"
|
||||||
|
},
|
||||||
|
"Amount": {
|
||||||
|
"EN": "Amount",
|
||||||
|
"CHDE": "Mengi"
|
||||||
|
},
|
||||||
|
"Current": {
|
||||||
|
"EN": "Current",
|
||||||
|
"CHDE": "Jetzt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bad": {
|
||||||
|
"CannotChangeOwn": {
|
||||||
|
"EN": "Sorry {0}, but you can't lower your own karma",
|
||||||
|
"CHDE": "Sorry {0}, aber du chasch dr din eigete karma nid weg neh"
|
||||||
|
},
|
||||||
|
"WaitUntill": {
|
||||||
|
"EN": "Sorry {0}, but you have to wait {1} before you can lower karma again...",
|
||||||
|
"CHDE": "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch senke..."
|
||||||
|
},
|
||||||
|
"Decreased": {
|
||||||
|
"EN": "Karma lowered",
|
||||||
|
"CHDE": "Karma gsenkt"
|
||||||
|
},
|
||||||
|
"By": {
|
||||||
|
"EN": "By",
|
||||||
|
"CHDE": "Vo"
|
||||||
|
},
|
||||||
|
"Amount": {
|
||||||
|
"EN": "Amount",
|
||||||
|
"CHDE": "Mengi"
|
||||||
|
},
|
||||||
|
"Current": {
|
||||||
|
"EN": "Current",
|
||||||
|
"CHDE": "Jetzt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roll": {
|
||||||
|
"Rolled": {
|
||||||
|
"EN": "{0}, you rolled {1}, your guess was {2}",
|
||||||
|
"CHDE": "{0}, du hesch {1} grollt und hesch {2} grate"
|
||||||
|
},
|
||||||
|
"Gratz": {
|
||||||
|
"EN": "Congratulations {0}, your guess was correct!",
|
||||||
|
"CHDE": "Gratuliere {0}, du hesch richtig grate!"
|
||||||
|
},
|
||||||
|
"RolledNoGuess": {
|
||||||
|
"EN": "{0}, you rolled {1}",
|
||||||
|
"CHDE": "{0}, du hesch {1} grollt"
|
||||||
|
},
|
||||||
|
"NoPrevGuess": {
|
||||||
|
"EN": ":red_circle: {0}, you can't guess the same number again",
|
||||||
|
"CHDE": ":red_circle: {0}, du chasch nid nomol es gliche rate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
Geekbot.net/Storage/checkEmPics
Normal file
122
Geekbot.net/Storage/checkEmPics
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
http://s19.postimg.org/pcq2kwzoj/4cb.png
|
||||||
|
http://s19.postimg.org/cvetk0f4z/5_Dim_Dy6p.jpg
|
||||||
|
http://s19.postimg.org/5hzfl1v37/1310151998600.jpg
|
||||||
|
http://s19.postimg.org/53y3lgazn/1324181141954.jpg
|
||||||
|
http://s19.postimg.org/724rjg3hf/1392512742365.png
|
||||||
|
http://s19.postimg.org/3rgejkdk3/1393501296733.png
|
||||||
|
http://s19.postimg.org/a6ffg8k9v/1401667341503.jpg
|
||||||
|
http://s19.postimg.org/qiph5yylf/1419231572452.jpg
|
||||||
|
http://s19.postimg.org/fqwi4m8ir/1427600681401.png
|
||||||
|
http://s19.postimg.org/4c00zzw6b/1447813628974.png
|
||||||
|
http://s19.postimg.org/uuio8puw3/b5_3q_ycaaavxtf.jpg
|
||||||
|
http://s19.postimg.org/bghu913fn/check_em_by_boyboy99100_d57xp3y.png
|
||||||
|
http://s19.postimg.org/s1pgooujn/l_Hkppjs.jpg
|
||||||
|
http://s19.postimg.org/m08itft0j/checkem.jpg
|
||||||
|
https://old.postimg.org/image/6vx33rb1b/
|
||||||
|
https://old.postimg.org/image/wxiaz1mov/
|
||||||
|
https://old.postimg.org/image/azqfizx27/
|
||||||
|
https://old.postimg.org/image/6iy2kbiu7/
|
||||||
|
https://old.postimg.org/image/k8slt45y7/
|
||||||
|
https://old.postimg.org/image/t7ruxmplr/
|
||||||
|
https://old.postimg.org/image/ssbzqvean/
|
||||||
|
https://old.postimg.org/image/kbchfy9lr/
|
||||||
|
https://old.postimg.org/image/dl0lk9btr/
|
||||||
|
https://old.postimg.org/image/e5k80oufz/
|
||||||
|
https://old.postimg.org/image/er005baqn/
|
||||||
|
https://old.postimg.org/image/bfk2uzcin/
|
||||||
|
https://old.postimg.org/image/556fp0jkv/
|
||||||
|
https://old.postimg.org/image/i0efbryu7/
|
||||||
|
https://old.postimg.org/image/943n7u87z/
|
||||||
|
https://old.postimg.org/image/xn5op5cm7/
|
||||||
|
https://old.postimg.org/image/3l5p4d0kf/
|
||||||
|
https://old.postimg.org/image/5boq5ui3j/
|
||||||
|
https://old.postimg.org/image/ru082bqcf/
|
||||||
|
https://old.postimg.org/image/ytea1oqan/
|
||||||
|
https://old.postimg.org/image/vu7dekgtb/
|
||||||
|
https://old.postimg.org/image/hl7qwi2an/
|
||||||
|
https://old.postimg.org/image/5aescfg9r/
|
||||||
|
https://old.postimg.org/image/9gzmrrfvj/
|
||||||
|
https://old.postimg.org/image/50bv6tr1b/
|
||||||
|
https://old.postimg.org/image/afkl7silb/
|
||||||
|
https://old.postimg.org/image/nrdsgzllr/
|
||||||
|
https://old.postimg.org/image/s32e5zsin/
|
||||||
|
https://old.postimg.org/image/5sej60v8f/
|
||||||
|
https://old.postimg.org/image/lgfqctau7/
|
||||||
|
https://old.postimg.org/image/tn7q4e0wv/
|
||||||
|
https://old.postimg.org/image/8612arz1b/
|
||||||
|
https://old.postimg.org/image/w5tf52mn3/
|
||||||
|
https://old.postimg.org/image/zdxwi48wv/
|
||||||
|
https://old.postimg.org/image/lphwghd0f/
|
||||||
|
https://old.postimg.org/image/uzu0k0nq7/
|
||||||
|
https://old.postimg.org/image/3vqzsxjbz/
|
||||||
|
https://old.postimg.org/image/5d7uqqyov/
|
||||||
|
https://old.postimg.org/image/dntnyku8v/
|
||||||
|
https://old.postimg.org/image/dsxf891jz/
|
||||||
|
https://old.postimg.org/image/3nyrioizj/
|
||||||
|
https://old.postimg.org/image/6zx2bzaqn/
|
||||||
|
https://old.postimg.org/image/wu6v1raqn/
|
||||||
|
https://old.postimg.org/image/hb9f4n2fz/
|
||||||
|
https://old.postimg.org/image/p7yhqm3a7/
|
||||||
|
https://old.postimg.org/image/oelvxzx9b/
|
||||||
|
https://old.postimg.org/image/vcq03xvdr/
|
||||||
|
https://old.postimg.org/image/b08t1yqlb/
|
||||||
|
https://old.postimg.org/image/6yrpwayan/
|
||||||
|
https://old.postimg.org/image/btleukwm7/
|
||||||
|
https://old.postimg.org/image/62ztuldzz/
|
||||||
|
https://old.postimg.org/image/w3iq9pxr3/
|
||||||
|
https://old.postimg.org/image/byp6493xb/
|
||||||
|
https://old.postimg.org/image/xp2lf9xcv/
|
||||||
|
https://old.postimg.org/image/j9p9u49pb/
|
||||||
|
https://old.postimg.org/image/hvxmytafz/
|
||||||
|
https://old.postimg.org/image/5eqzbnfa7/
|
||||||
|
https://old.postimg.org/image/do2uq290f/
|
||||||
|
https://old.postimg.org/image/54o261q1r/
|
||||||
|
https://old.postimg.org/image/94qm4jr4v/
|
||||||
|
https://old.postimg.org/image/lee88y0pr/
|
||||||
|
https://old.postimg.org/image/bncb58cv3/
|
||||||
|
https://old.postimg.org/image/5246j7me7/
|
||||||
|
https://old.postimg.org/image/4uby8ym1r/
|
||||||
|
https://old.postimg.org/image/qn996tj4v/
|
||||||
|
https://old.postimg.org/image/c1dn4twyn/
|
||||||
|
https://old.postimg.org/image/6rd9ra23j/
|
||||||
|
https://lehcark14.files.wordpress.com/2008/08/botan16.jpg
|
||||||
|
http://i.imgur.com/p9vALew.jpg
|
||||||
|
http://i.imgur.com/4a9l2Rm.png
|
||||||
|
http://i.imgur.com/RNtixMQ.jpg
|
||||||
|
https://pbs.twimg.com/media/Cro9aIGUEAAkXCP.jpg
|
||||||
|
http://s16.postimg.org/empvloimd/Check_em_Guts.png
|
||||||
|
https://s18.postimg.io/qgbhe7u09/1424491645996.gif
|
||||||
|
http://s19.postimg.org/hhemlt7xf/3eb.jpg
|
||||||
|
http://s19.postimg.org/cwsg6vo83/8aa.png
|
||||||
|
http://s19.postimg.org/rh9j1pj6r/28mohl4.png
|
||||||
|
http://s19.postimg.org/zba4n3qzn/86d.jpg
|
||||||
|
http://s19.postimg.org/cb3hart5v/2016_09_16_08_58_45.png
|
||||||
|
http://s19.postimg.org/m9ofx92lf/bb1.jpg
|
||||||
|
http://s19.postimg.org/maydqo4f7/e8b.jpg
|
||||||
|
http://s19.postimg.org/yqzoy5n4z/fbe.png
|
||||||
|
http://s19.postimg.org/xd822unvn/giphy.gif
|
||||||
|
http://s19.postimg.org/c4udlf9er/l_TU3eup.jpg
|
||||||
|
https://66.media.tumblr.com/cc893a0ee40d73d083da3df4bdaf45cc/tumblr_mx8psiFduG1t1g1k8o1_500.gif
|
||||||
|
http://i.imgur.com/swbXHSy.gif
|
||||||
|
http://img1.reactor.cc/pics/post/full/Anime-Touhou-Project-Yakumo-Yukari-%D0%A0%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F-1303807.jpeg
|
||||||
|
http://i.imgur.com/ftGLHE0.png
|
||||||
|
http://i.imgur.com/JELDhKQ.png
|
||||||
|
http://imgur.com/yBJound
|
||||||
|
http://i.imgur.com/f7gAVPJ.png
|
||||||
|
http://i.imgur.com/HxWyo2Z.jpg
|
||||||
|
http://i.imgur.com/8Eb9CxQ.png
|
||||||
|
http://i.imgur.com/kOECcjz.png
|
||||||
|
http://i.imgur.com/MJLu7oJ.jpg
|
||||||
|
http://i.imgur.com/itG3rPM.jpg
|
||||||
|
http://i.imgur.com/G83Go9t.jpg
|
||||||
|
http://i.imgur.com/jI2dBnU.jpg
|
||||||
|
http://i.imgur.com/FtALzg0.jpg
|
||||||
|
http://i.imgur.com/GwZpJEv.gif
|
||||||
|
http://i.imgur.com/TYGRD3B.gif
|
||||||
|
http://i.imgur.com/P6TxLS3.png
|
||||||
|
http://i.imgur.com/phTVTdn.jpg
|
||||||
|
http://i.imgur.com/thhR6UE.jpg
|
||||||
|
http://i.imgur.com/KbROufx.jpg
|
||||||
|
http://i.imgur.com/sQqWbcm.jpg
|
||||||
|
http://i.imgur.com/YYpis53.png
|
||||||
|
http://i.imgur.com/kwaRd54.gif
|
17
Geekbot.net/Storage/croissant
Normal file
17
Geekbot.net/Storage/croissant
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
https://i2.wp.com/epicureandculture.com/wp-content/uploads/2014/12/shutterstock_172040546.jpg
|
||||||
|
http://www.bakespace.com/images/large/5d79070cf21b2f33c3a1dd4336cb27d2.jpeg
|
||||||
|
http://food.fnr.sndimg.com/content/dam/images/food/fullset/2015/5/7/1/SD1B43_croissants-recipe_s4x3.jpg.rend.hgtvcom.616.462.suffix/1431052139248.jpeg
|
||||||
|
http://img.taste.com.au/u-Bwjfm_/taste/2016/11/mini-croissants-with-3-fillings-14692-1.jpeg
|
||||||
|
https://media.newyorker.com/photos/590974702179605b11ad8096/16:9/w_1200,h_630,c_limit/Gopnik-TheMurkyMeaningsofStraightenedOutCroissants.jpg
|
||||||
|
http://bt.static-redmouse.ch/sites/bielertagblatt.ch/files/styles/bt_article_showroom_landscape/hash/84/c9/84c9aed08415265911ec05c46d25d3ef.jpg?itok=hP5PnHaT
|
||||||
|
https://www.dermann.at/wp-content/uploads/Schokocroissant_HPBild_1400x900px.jpeg
|
||||||
|
https://www.bettybossi.ch/static/rezepte/x/bb_bkxx060101_0360a_x.jpg
|
||||||
|
http://www.engel-beck.ch/uploads/pics/tete-de-moine-gipfel-.jpg
|
||||||
|
https://storage.cpstatic.ch/storage/og_image/laugengipfel--425319.jpg
|
||||||
|
https://www.backhaus-kutzer.de/fileadmin/templates/Resources/Public/img/produkte/suesses-gebaeck/Milchhoernchen.png
|
||||||
|
https://www.kuechengoetter.de/uploads/media/1000x524/00/36390-vanillekipferl-0.jpg?v=1-0
|
||||||
|
https://c1.staticflickr.com/3/2835/10874180753_2b2916e3ce_b.jpg
|
||||||
|
http://www.mistercool.ch/wp-content/uploads/2017/02/Gipfel-mit-Cerealien-7168.png
|
||||||
|
https://scontent-sea1-1.cdninstagram.com/t51.2885-15/s480x480/e35/c40.0.999.999/15099604_105396696611384_2866237281000226816_n.jpg?ig_cache_key=MTM4MzQxOTU1MDc5NjUxNzcwMA%3D%3D.2.c
|
||||||
|
http://www.lecrobag.de/wp-content/uploads/2014/03/Wurst_2014_l.jpg
|
||||||
|
https://www.thecookierookie.com/wp-content/uploads/2017/02/sheet-pan-chocolate-croissants-collage1.jpeg
|
|
@ -4,9 +4,8 @@ https://nationalzoo.si.edu/sites/default/files/styles/slide_1400x700/public/supp
|
||||||
https://media4.s-nbcnews.com/j/newscms/2016_36/1685951/ss-160826-twip-05_8cf6d4cb83758449fd400c7c3d71aa1f.nbcnews-ux-2880-1000.jpg
|
https://media4.s-nbcnews.com/j/newscms/2016_36/1685951/ss-160826-twip-05_8cf6d4cb83758449fd400c7c3d71aa1f.nbcnews-ux-2880-1000.jpg
|
||||||
https://ichef-1.bbci.co.uk/news/660/cpsprodpb/169F6/production/_91026629_gettyimages-519508400.jpg
|
https://ichef-1.bbci.co.uk/news/660/cpsprodpb/169F6/production/_91026629_gettyimages-519508400.jpg
|
||||||
https://cdn.history.com/sites/2/2017/03/GettyImages-157278376.jpg
|
https://cdn.history.com/sites/2/2017/03/GettyImages-157278376.jpg
|
||||||
|
https://www.pandasinternational.org/wptemp/wp-content/uploads/2012/10/slider1.jpg
|
||||||
https://tctechcrunch2011.files.wordpress.com/2015/11/panda.jpg
|
https://tctechcrunch2011.files.wordpress.com/2015/11/panda.jpg
|
||||||
http://www.nationalgeographic.com/content/dam/magazine/rights-exempt/2016/08/departments/panda-mania-12.jpg
|
http://www.nationalgeographic.com/content/dam/magazine/rights-exempt/2016/08/departments/panda-mania-12.jpg
|
||||||
http://animals.sandiegozoo.org/sites/default/files/2016-09/panda1_10.jpg
|
http://animals.sandiegozoo.org/sites/default/files/2016-09/panda1_10.jpg
|
||||||
http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Mammals/A-G/giant-panda-eating.adapt.945.1.jpg
|
http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Mammals/A-G/giant-panda-eating.adapt.945.1.jpg
|
||||||
https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/10/08/15/Hong-Kong-pandas.jpg
|
|
||||||
https://3sn4dm1qd6i72l8a4r2ig7fl-wpengine.netdna-ssl.com/wp-content/uploads/2016/11/panda_lunlun_ZA_2083-b.jpg
|
|
23
Geekbot.net/Storage/pumpkin
Normal file
23
Geekbot.net/Storage/pumpkin
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
https://i.pinimg.com/736x/0a/a7/8a/0aa78af25e114836e1a42585fb7b09ed--funny-pumpkins-pumkin-carving.jpg
|
||||||
|
http://wdy.h-cdn.co/assets/16/31/980x1470/gallery-1470321728-shot-two-021.jpg
|
||||||
|
https://i.pinimg.com/736x/6c/62/bf/6c62bfa73a19ffd9fc6f2d720d5e9764--cool-pumpkin-carving-carving-pumpkins.jpg
|
||||||
|
http://images6.fanpop.com/image/photos/38900000/Jack-o-Lantern-halloween-38991566-500-415.jpg
|
||||||
|
http://ghk.h-cdn.co/assets/15/37/1441834730-pumpkin-carve-2.jpg
|
||||||
|
http://diy.sndimg.com/content/dam/images/diy/fullset/2011/7/26/1/iStock-10761186_halloween-pumpkin-in-garden_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420851319631.jpeg
|
||||||
|
http://ghk.h-cdn.co/assets/cm/15/11/54ffe537af882-snail-pumpkin-de.jpg
|
||||||
|
https://www.digsdigs.com/photos/2009/10/100-halloween-pumpkin-carving-ideas-12.jpg
|
||||||
|
http://diy.sndimg.com/content/dam/images/diy/fullset/2010/6/4/0/CI-Kyle-Nishioka_big-teeth-Jack-O-Lantern_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420699522718.jpeg
|
||||||
|
https://twistedsifter.files.wordpress.com/2011/10/most-amazing-pumpkin-carving-ray-villafane-10.jpg?w=521&h=739
|
||||||
|
https://i.pinimg.com/736x/09/c4/b1/09c4b187b266c1f65332294f66009944--funny-pumpkins-halloween-pumpkins.jpg
|
||||||
|
http://www.evilmilk.com/pictures/The_Pumpkin_Man.jpg
|
||||||
|
http://cache.lovethispic.com/uploaded_images/blogs/13-Funny-Pumpkin-Carvings-5773-9.JPG
|
||||||
|
http://ihappyhalloweenpictures.com/wp-content/uploads/2016/10/funny-halloween-pumpkin.jpg
|
||||||
|
http://www.smallhomelove.com/wp-content/uploads/2012/08/leg-eating-pumpkin.jpg
|
||||||
|
https://cdn.shopify.com/s/files/1/0773/6789/articles/Halloween_Feature_8ff7a7c4-2cb3-4584-a85f-5d4d1e6ca26e.jpg?v=1476211360
|
||||||
|
http://4vector.com/i/free-vector-pumpkin-boy-color-version-clip-art_107714_Pumpkin_Boy_Color_Version_clip_art_hight.png
|
||||||
|
https://i.pinimg.com/736x/59/8a/0f/598a0fbf789631b76c1ffd4443194d8e--halloween-pumpkins-fall-halloween.jpg
|
||||||
|
https://i.pinimg.com/originals/8f/86/f9/8f86f95457467872b371ba697d341961.jpg
|
||||||
|
http://nerdist.com/wp-content/uploads/2015/08/taleshalloween1.jpg
|
||||||
|
http://www.designbolts.com/wp-content/uploads/2014/09/Scary-Pumpkin_Grin_stencil-Ideas.jpg
|
||||||
|
http://vignette2.wikia.nocookie.net/scoobydoo/images/7/75/Pumpkin_monsters_%28Witch%27s_Ghost%29.png/revision/latest?cb=20140520070213
|
||||||
|
https://taholtorf.files.wordpress.com/2013/10/36307-1920x1280.jpg
|
45
Geekbot.net/Storage/squirrel
Normal file
45
Geekbot.net/Storage/squirrel
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
http://orig14.deviantart.net/6016/f/2010/035/c/b/first_squirrel_assassin_by_shotokanteddy.jpg
|
||||||
|
https://thumbs-prod.si-cdn.com/eoEYA_2Hau4795uKoecUZZgz-3w=/800x600/filters:no_upscale()/https://public-media.smithsonianmag.com/filer/52/f9/52f93262-c29b-4a4f-b031-0c7ad145ed5f/42-33051942.jpg
|
||||||
|
http://images5.fanpop.com/image/photos/30700000/Squirrel-squirrels-30710732-400-300.jpg
|
||||||
|
https://www.lovethegarden.com/sites/default/files/files/Red%20%26%20Grey%20Squirrel%20picture%20side%20by%20side-LR.jpg
|
||||||
|
http://i.dailymail.co.uk/i/pix/2016/02/24/16/158F7E7C000005DC-3462228-image-a-65_1456331226865.jpg
|
||||||
|
http://2.bp.blogspot.com/-egfnMhUb8tg/T_dAIu1m6cI/AAAAAAAAPPU/v4x9q4WqWl8/s640/cute-squirrel-hey-watcha-thinkin-about.jpg
|
||||||
|
https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Squirrel_posing.jpg/287px-Squirrel_posing.jpg
|
||||||
|
https://i.pinimg.com/736x/51/db/9b/51db9bad4a87d445d321923c7d56b501--red-squirrel-animal-kingdom.jpg
|
||||||
|
https://metrouk2.files.wordpress.com/2016/10/ad_223291521.jpg?w=620&h=949&crop=1
|
||||||
|
http://www.redsquirrelsunited.org.uk/wp-content/uploads/2016/07/layer-slider.jpg
|
||||||
|
http://images.mentalfloss.com/sites/default/files/squirrel-hero.jpg?resize=1100x740
|
||||||
|
https://i.pinimg.com/736x/ce/9c/59/ce9c5990b193046400d98724595cdaf3--red-squirrel-chipmunks.jpg
|
||||||
|
https://www.brooklynpaper.com/assets/photos/40/30/dtg-squirrel-attacks-prospect-park-patrons-2017-07-28-bk01_z.jpg
|
||||||
|
http://www.freakingnews.com/pictures/16000/Squirrel-Shark-16467.jpg
|
||||||
|
http://img09.deviantart.net/5c1c/i/2013/138/0/6/barbarian_squirel_by_coucoucmoa-d64r9m4.jpg
|
||||||
|
https://i.pinimg.com/736x/b4/5c/0d/b45c0d00b1a57e9f84f27f13cb019001--baby-squirrel-red-squirrel.jpg
|
||||||
|
https://i.pinimg.com/736x/0f/75/87/0f7587bb613ab524763afe8c9a532e5c--cute-squirrel-squirrels.jpg
|
||||||
|
http://cdn.images.express.co.uk/img/dynamic/128/590x/Grey-squirrel-828838.jpg
|
||||||
|
http://www.lovethispic.com/uploaded_images/79964-Squirrel-Smelling-A-Flower.jpg
|
||||||
|
https://i.pinimg.com/736x/23/d5/f9/23d5f9868f7d76c79c49bef53ae08f7f--squirrel-funny-red-squirrel.jpg
|
||||||
|
http://stories.barkpost.com/wp-content/uploads/2016/01/squirrel-3-copy.jpg
|
||||||
|
https://i.ytimg.com/vi/pzUs0DdzK3Y/hqdefault.jpg
|
||||||
|
https://www.askideas.com/media/41/I-Swear-It-Wasnt-Me-Funny-Squirrel-Meme-Picture-For-Facebook.jpg
|
||||||
|
https://i.pinimg.com/736x/2d/54/d8/2d54d8d2a9b3ab9d3e78544b75afd88e--funny-animal-pictures-humorous-pictures.jpg
|
||||||
|
http://www.funny-animalpictures.com/media/content/items/images/funnysquirrels0012_O.jpg
|
||||||
|
http://funny-pics.co/wp-content/uploads/funny-squirrel-and-coffee-picture.jpg
|
||||||
|
https://pbs.twimg.com/media/Bi4Ij6CIgAAgEdZ.jpg
|
||||||
|
http://www.funnyjunksite.com/pictures/wp-content/uploads/2015/06/Funny-Superman-Squirrels.jpg
|
||||||
|
https://i.pinimg.com/736x/bf/35/00/bf3500104f8394909d116259d1f0575e--funny-squirrel-squirrel-girl.jpg
|
||||||
|
http://quotespill.com/wp-content/uploads/2017/07/Squirrel-Meme-Draw-me-like-one-of-your-french-squirrrels-min.jpg
|
||||||
|
https://i.pinimg.com/736x/e2/16/bb/e216bba53f80fc8e0111d371e9850159--funny-squirrels-cute-squirrel.jpg
|
||||||
|
https://i.pinimg.com/736x/52/43/c9/5243c93377245be1f686218c266d775c--funny-squirrel-baby-squirrel.jpg
|
||||||
|
https://i.pinimg.com/736x/0c/be/1d/0cbe1da8ad2c0cf3882a806b6fd88965--cute-pictures-funny-animal-pictures.jpg
|
||||||
|
https://i.pinimg.com/736x/e5/08/67/e508670aa00ca3c896eccb81c4f6e2a8--funny-squirrel-baby-squirrel.jpg
|
||||||
|
https://i.pinimg.com/736x/1c/7d/4f/1c7d4f067a10066aad802ce5ac468d71--group-boards-a-squirrel.jpg
|
||||||
|
http://funny-pics.co/wp-content/uploads/funny-squirrel-on-a-branch.jpg
|
||||||
|
http://loldamn.com/wp-content/uploads/2016/06/funny-squirrel-playing-water-bending.jpg
|
||||||
|
https://cdn.trendhunterstatic.com/thumbs/squirrel-photography.jpeg
|
||||||
|
https://i.pinimg.com/736x/d6/42/12/d64212cc6221916db4173962bf6c131a--cute-squirrel-baby-squirrel.jpg
|
||||||
|
https://i.pinimg.com/236x/10/13/58/101358f2afc2c7d6b6a668046e7b8382--funny-animal-pictures-funny-animals.jpg
|
||||||
|
https://i.pinimg.com/736x/da/0d/fe/da0dfe93bb26887795f906e8fa97d68e--secret-squirrel-cute-squirrel.jpg
|
||||||
|
http://2.bp.blogspot.com/-HLieBqEuQoM/UDkRmeyzB5I/AAAAAAAABHs/RtsEynn5t6Y/s1600/hd-squirrel-wallpaper-with-a-brown-squirrel-eating-watermelon-wallpapers-backgrounds-pictures-photos.jpg
|
||||||
|
http://www.city-data.com/forum/members/brenda-starz-328928-albums-brenda-s-funny-squirrel-comment-pic-s-pic5075-punk-squirrels.jpg
|
||||||
|
http://img15.deviantart.net/9c50/i/2011/213/c/9/just_taking_it_easy_by_lou_in_canada-d42do3d.jpg
|
||||||
|
http://3.bp.blogspot.com/-AwsSk76R2Is/USQa3-dszKI/AAAAAAAABUQ/KF_F8HbtP1U/w1200-h630-p-k-no-nu/crazySquirrel.jpg
|
|
@ -1,20 +1,21 @@
|
||||||
https://i.guim.co.uk/img/media/6b9be13031738e642f93f9271f3592044726a9b1/0_0_2863_1610/2863.jpg?w=640&h=360&q=55&auto=format&usm=12&fit=max&s=85f3b33cc158b5aa120c143dae1916ed
|
https://i.guim.co.uk/img/media/6b9be13031738e642f93f9271f3592044726a9b1/0_0_2863_1610/2863.jpg?w=640&h=360&q=55&auto=format&usm=12&fit=max&s=85f3b33cc158b5aa120c143dae1916ed
|
||||||
http://cf.ltkcdn.net/small-pets/images/std/212089-676x450-Turtle-feeding-on-leaf.jpg
|
http://cf.ltkcdn.net/small-pets/images/std/212089-676x450-Turtle-feeding-on-leaf.jpg
|
||||||
|
https://static1.squarespace.com/static/5369465be4b0507a1fd05af0/53767a6be4b0ad0822345e52/57e40ba4893fc031e05a018f/1498243318058/solvin.jpg?format=1500w
|
||||||
https://c402277.ssl.cf1.rackcdn.com/photos/419/images/story_full_width/HI_287338Hero.jpg?1433950119
|
https://c402277.ssl.cf1.rackcdn.com/photos/419/images/story_full_width/HI_287338Hero.jpg?1433950119
|
||||||
https://www.cdc.gov/salmonella/agbeni-08-17/images/turtle.jpg
|
https://www.cdc.gov/salmonella/agbeni-08-17/images/turtle.jpg
|
||||||
https://cdn.arstechnica.net/wp-content/uploads/2017/08/GettyImages-524757168.jpg
|
https://cdn.arstechnica.net/wp-content/uploads/2017/08/GettyImages-524757168.jpg
|
||||||
http://pmdvod.nationalgeographic.com/NG_Video/595/319/4504517_098_05_TOS_thumbnail_640x360_636296259676.jpg
|
http://pmdvod.nationalgeographic.com/NG_Video/595/319/4504517_098_05_TOS_thumbnail_640x360_636296259676.jpg
|
||||||
|
http://cdn1.arkive.org/media/7D/7D46329A-6ED2-4F08-909E-7B596417994A/Presentation.Large/Big-headed-turtle-close-up.jpg
|
||||||
http://s7d2.scene7.com/is/image/PetSmart/ARTHMB-CleaningYourTortoiseOrTurtlesHabitat-20160818?$AR1104$
|
http://s7d2.scene7.com/is/image/PetSmart/ARTHMB-CleaningYourTortoiseOrTurtlesHabitat-20160818?$AR1104$
|
||||||
https://fthmb.tqn.com/9VGWzK_GWlvrjxtdFPX6EJxOq24=/960x0/filters:no_upscale()/133605352-56a2bce53df78cf7727960db.jpg
|
https://fthmb.tqn.com/9VGWzK_GWlvrjxtdFPX6EJxOq24=/960x0/filters:no_upscale()/133605352-56a2bce53df78cf7727960db.jpg
|
||||||
|
https://i.imgur.com/46QmzgF.jpg
|
||||||
https://www.wildgratitude.com/wp-content/uploads/2015/07/turtle-spirit-animal1.jpg
|
https://www.wildgratitude.com/wp-content/uploads/2015/07/turtle-spirit-animal1.jpg
|
||||||
http://www.backwaterreptiles.com/images/turtles/red-eared-slider-turtle-for-sale.jpg
|
http://www.backwaterreptiles.com/images/turtles/red-eared-slider-turtle-for-sale.jpg
|
||||||
|
https://i.pinimg.com/736x/f1/f4/13/f1f413d6d07912be6080c08b186630ac--happy-turtle-funny-stuff.jpg
|
||||||
|
http://www.dupageforest.org/uploadedImages/Content/District_News/Nature_Stories/2016/Snapping%20Turtle%20Scott%20Plantier%20STP4793.jpg
|
||||||
http://turtlebackzoo.com/wp-content/uploads/2016/07/exhibit-headers_0008_SOUTH-AMERICA-600x400.jpg
|
http://turtlebackzoo.com/wp-content/uploads/2016/07/exhibit-headers_0008_SOUTH-AMERICA-600x400.jpg
|
||||||
|
https://i.ytimg.com/vi/_YfYHFM3Das/maxresdefault.jpg
|
||||||
https://i.pinimg.com/736x/dd/4e/7f/dd4e7f2f921ac28b1d5a59174d477131--cute-baby-sea-turtles-adorable-turtles.jpg
|
https://i.pinimg.com/736x/dd/4e/7f/dd4e7f2f921ac28b1d5a59174d477131--cute-baby-sea-turtles-adorable-turtles.jpg
|
||||||
http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Reptiles/A-G/green-sea-turtle-closeup-underwater.adapt.945.1.jpg
|
http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Reptiles/A-G/green-sea-turtle-closeup-underwater.adapt.945.1.jpg
|
||||||
|
https://i.ytimg.com/vi/p4Jj9QZFJvw/hqdefault.jpg
|
||||||
https://fthmb.tqn.com/nirxHkH3jBAe74ife6fJJu6k6q8=/2121x1414/filters:fill(auto,1)/Red-eared-sliders-GettyImages-617946009-58fae8835f9b581d59a5bab6.jpg
|
https://fthmb.tqn.com/nirxHkH3jBAe74ife6fJJu6k6q8=/2121x1414/filters:fill(auto,1)/Red-eared-sliders-GettyImages-617946009-58fae8835f9b581d59a5bab6.jpg
|
||||||
http://assets.worldwildlife.org/photos/167/images/original/MID_225023-circle-hawksbill-turtle.jpg?1345565600
|
|
||||||
https://seaturtles.org/wp-content/uploads/2013/11/GRN-honuAnitaWintner2.jpg
|
|
||||||
https://images2.minutemediacdn.com/image/upload/c_crop,h_2549,w_4536,x_0,y_237/v1560186367/shape/mentalfloss/istock-687398754.jpg?itok=QsiF5yHP
|
|
||||||
https://c402277.ssl.cf1.rackcdn.com/photos/13028/images/story_full_width/seaturtle_spring2017.jpg?1485359391
|
|
||||||
https://i2.wp.com/rangerrick.org/wp-content/uploads/2018/03/Turtle-Tale-RR-Jr-June-July-2017.jpg?fit=1156%2C650&ssl=1
|
|
||||||
https://boyslifeorg.files.wordpress.com/2019/07/greenseaturtle.jpg
|
|
77
Geekbot.net/WebApi/HelpController.cs
Normal file
77
Geekbot.net/WebApi/HelpController.cs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Nancy;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.WebApi
|
||||||
|
{
|
||||||
|
public class HelpController : NancyModule
|
||||||
|
{
|
||||||
|
public HelpController()
|
||||||
|
{
|
||||||
|
Get("/v1/commands", args =>
|
||||||
|
{
|
||||||
|
var commands = getCommands().Result;
|
||||||
|
|
||||||
|
var commandList = new List<CommandDto>();
|
||||||
|
foreach (var cmd in commands.Commands)
|
||||||
|
{
|
||||||
|
var cmdParamsObj = new List<CommandParamDto>();
|
||||||
|
foreach (var cmdParam in cmd.Parameters)
|
||||||
|
{
|
||||||
|
var singleParamObj = new CommandParamDto()
|
||||||
|
{
|
||||||
|
Summary = cmdParam.Summary,
|
||||||
|
Default = cmdParam?.DefaultValue?.ToString() ?? null,
|
||||||
|
Type = cmdParam?.Type?.ToString()
|
||||||
|
};
|
||||||
|
cmdParamsObj.Add(singleParamObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
var param = string.Join(", !", cmd.Aliases);
|
||||||
|
var cmdObj = new CommandDto()
|
||||||
|
{
|
||||||
|
Name = cmd.Name,
|
||||||
|
Summary = cmd.Summary,
|
||||||
|
Category = cmd.Remarks ?? CommandCategories.Uncategorized,
|
||||||
|
IsAdminCommand = (param.Contains("admin")),
|
||||||
|
Aliases = cmd.Aliases.ToArray(),
|
||||||
|
Params = cmdParamsObj
|
||||||
|
};
|
||||||
|
commandList.Add(cmdObj);
|
||||||
|
}
|
||||||
|
return Response.AsJson(commandList);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<CommandService> getCommands()
|
||||||
|
{
|
||||||
|
var commands = new CommandService();
|
||||||
|
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public string Summary { get; set; }
|
||||||
|
public bool IsAdminCommand { get; set; }
|
||||||
|
public Array Aliases { get; set; }
|
||||||
|
public List<CommandParamDto> Params { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandParamDto
|
||||||
|
{
|
||||||
|
public string Summary { get; set; }
|
||||||
|
public string Default { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
29
Geekbot.net/WebApi/StatusController.cs
Normal file
29
Geekbot.net/WebApi/StatusController.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using Nancy;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
|
||||||
|
namespace Geekbot.net.WebApi
|
||||||
|
{
|
||||||
|
public class StatusController : NancyModule
|
||||||
|
{
|
||||||
|
public StatusController()
|
||||||
|
{
|
||||||
|
Get("/", args =>
|
||||||
|
{
|
||||||
|
var responseBody = new ApiStatusDto()
|
||||||
|
{
|
||||||
|
GeekbotVersion = Constants.BotVersion.ToString(),
|
||||||
|
ApiVersion = Constants.ApiVersion.ToString(),
|
||||||
|
Status = "Online"
|
||||||
|
};
|
||||||
|
return Response.AsJson(responseBody);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiStatusDto
|
||||||
|
{
|
||||||
|
public string GeekbotVersion { get; set; }
|
||||||
|
public string ApiVersion { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
Geekbot.net/WebApi/WebConfig.cs
Normal file
23
Geekbot.net/WebApi/WebConfig.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Nancy;
|
||||||
|
using Nancy.Bootstrapper;
|
||||||
|
using Nancy.TinyIoc;
|
||||||
|
|
||||||
|
namespace Geekbot.net.WebApi
|
||||||
|
{
|
||||||
|
public class WebConfig : DefaultNancyBootstrapper
|
||||||
|
{
|
||||||
|
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
//CORS Enable
|
||||||
|
pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
|
||||||
|
{
|
||||||
|
ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
|
||||||
|
.WithHeader("Access-Control-Allow-Methods", "GET")
|
||||||
|
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type")
|
||||||
|
.WithHeader("Last-Modified", Process.GetCurrentProcess().StartTime.ToString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 361 KiB |
75
Tests/Lib/EmojiConverter.test.cs
Normal file
75
Tests/Lib/EmojiConverter.test.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Tests.Lib
|
||||||
|
{
|
||||||
|
public class EmojiConverter_test
|
||||||
|
{
|
||||||
|
public static IEnumerable<object[]> NumberToEmojiTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
":two:"
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
10,
|
||||||
|
"🔟"
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
15,
|
||||||
|
":one::five:"
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
null,
|
||||||
|
":zero:"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Theory, MemberData(nameof(NumberToEmojiTestData))]
|
||||||
|
public async Task NumberToEmoji(int number, string expectedResult)
|
||||||
|
{
|
||||||
|
var emojiConverter = new EmojiConverter();
|
||||||
|
var result = emojiConverter.numberToEmoji(number);
|
||||||
|
Assert.Equal(result, expectedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> textToEmojiTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
":regional_indicator_t::regional_indicator_e::regional_indicator_s::regional_indicator_t:"
|
||||||
|
};
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
"Best3+?",
|
||||||
|
":b::regional_indicator_e::regional_indicator_s::regional_indicator_t::three::heavy_plus_sign::question:"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Theory, MemberData(nameof(textToEmojiTestData))]
|
||||||
|
public async Task TextToEmoji(string text, string expectedResult)
|
||||||
|
{
|
||||||
|
var emojiConverter = new EmojiConverter();
|
||||||
|
var result = emojiConverter.textToEmoji(text);
|
||||||
|
Assert.Equal(result, expectedResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
Tests/Lib/LevelCalc.test.cs
Normal file
49
Tests/Lib/LevelCalc.test.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Tests.Lib
|
||||||
|
{
|
||||||
|
public class LevelCalc_test
|
||||||
|
{
|
||||||
|
public static IEnumerable<object[]> LevelCalcTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
500,
|
||||||
|
13
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
41659,
|
||||||
|
55
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
4000000,
|
||||||
|
101
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Theory, MemberData(nameof(LevelCalcTestData))]
|
||||||
|
public async Task GetLevel(int messages, int expectedResult)
|
||||||
|
{
|
||||||
|
var levelCalc = new LevelCalc();
|
||||||
|
var result = levelCalc.GetLevel(messages);
|
||||||
|
Assert.Equal(result, expectedResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Tests/Tests.csproj
Normal file
16
Tests/Tests.csproj
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<NoWarn>NU1701</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.3.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||||
|
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Geekbot.net\Geekbot.net.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -1,3 +0,0 @@
|
||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
version: 2.7.0
|
|
27
readme.md
27
readme.md
|
@ -1,28 +1,37 @@
|
||||||
[![pipeline status](https://gitlab.com/dbgit/open/geekbot/badges/master/pipeline.svg)](https://gitlab.com/dbgit/open/geekbot/commits/master)
|
[![pipeline status](https://git.boerlage.me/open/Geekbot.net/badges/master/pipeline.svg)](https://git.boerlage.me/open/Geekbot.net/commits/master)
|
||||||
|
|
||||||
# [Geekbot.net](https://geekbot.pizzaandcoffee.rocks/)
|
# [Geekbot.net](https://geekbot.pizzaandcoffee.rocks/)
|
||||||
|
|
||||||
A General Purpose Discord Bot written in C#
|
A General Purpose Discord Bot written in DotNet Core.
|
||||||
|
|
||||||
You can invite Geekbot to your server with [this link](https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054)
|
You can invite Geekbot to your server with [this link](https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054)
|
||||||
|
|
||||||
## Technologies
|
## Technologies
|
||||||
|
|
||||||
* .NET 5
|
* DotNet Core 2
|
||||||
* PostgreSQL
|
* Redis
|
||||||
* Discord.net
|
* Discord.net
|
||||||
|
* ffmpeg
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
You can start geekbot with: `dotnet run`
|
Make sure redis is running
|
||||||
|
|
||||||
On your first run geekbot will ask for your bot token.
|
Run these commands
|
||||||
|
|
||||||
You might need to pass some additional configuration (e.g. database credentials), these can be passed as commandline arguments or environment variables.
|
* `dotnet restore`
|
||||||
|
* `dotnet run`
|
||||||
|
|
||||||
For a list of commandline arguments and environment variables use `dotnet run -- -h`
|
On your first run geekbot will ask for your bot token, everything else is taken care of.
|
||||||
|
|
||||||
All Environment Variables must be prefixed with `GEEKBOT_`
|
### Launch Parameters
|
||||||
|
|
||||||
|
| Parameter | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `--verbose` | Show more log information |
|
||||||
|
| `--disable-api` | Disables the webapi on startup |
|
||||||
|
| `--reset` | Resets certain parts of the bot |
|
||||||
|
| `--migrate` | Migrates the database from V3.1 to the new format from V3.2<br> (make sure to backup before running this) |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
|
||||||
<RootNamespace>Geekbot.Bot</RootNamespace>
|
|
||||||
<AssemblyName>Geekbot.Bot</AssemblyName>
|
|
||||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
|
||||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.0-DEV</Version>
|
|
||||||
<NoWarn>NU1701</NoWarn>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
|
||||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.45.0.1929" />
|
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.36" />
|
|
||||||
<PackageReference Include="JikanDotNet" Version="1.6.0" />
|
|
||||||
<PackageReference Include="MtgApiManager.Lib" Version="1.2.2" />
|
|
||||||
<PackageReference Include="PokeApi.NET" Version="1.1.2" />
|
|
||||||
<PackageReference Include="Sentry" Version="3.11.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Storage\*">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Commands\Commands.csproj" />
|
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -1,127 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using Geekbot.Bot.Handlers;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.Database;
|
|
||||||
using Geekbot.Core.GlobalSettings;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using Geekbot.Core.Logger;
|
|
||||||
using Geekbot.Core.Logger.Adapters;
|
|
||||||
using Geekbot.Core.ReactionListener;
|
|
||||||
using Geekbot.Core.UserRepository;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot;
|
|
||||||
|
|
||||||
public class BotStartup
|
|
||||||
{
|
|
||||||
private readonly IServiceCollection _serviceCollection;
|
|
||||||
private readonly GeekbotLogger _logger;
|
|
||||||
private readonly RunParameters _runParameters;
|
|
||||||
private readonly IGlobalSettings _globalSettings;
|
|
||||||
private DiscordSocketClient _client;
|
|
||||||
|
|
||||||
public BotStartup(IServiceCollection serviceCollection, GeekbotLogger logger, RunParameters runParameters, IGlobalSettings globalSettings)
|
|
||||||
{
|
|
||||||
_serviceCollection = serviceCollection;
|
|
||||||
_logger = logger;
|
|
||||||
_runParameters = runParameters;
|
|
||||||
_globalSettings = globalSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Start()
|
|
||||||
{
|
|
||||||
_logger.Information(LogSource.Geekbot, "Connecting to Discord");
|
|
||||||
SetupDiscordClient();
|
|
||||||
await Login();
|
|
||||||
await _client.SetGameAsync(_globalSettings.GetKey("Game"));
|
|
||||||
_logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers");
|
|
||||||
|
|
||||||
_logger.Information(LogSource.Geekbot, "Registering Gateway Handlers");
|
|
||||||
await RegisterHandlers();
|
|
||||||
|
|
||||||
_logger.Information(LogSource.Geekbot, "Done and ready for use");
|
|
||||||
await Task.Delay(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupDiscordClient()
|
|
||||||
{
|
|
||||||
_client = new DiscordSocketClient(new DiscordSocketConfig
|
|
||||||
{
|
|
||||||
GatewayIntents = GatewayIntents.DirectMessageReactions |
|
|
||||||
GatewayIntents.DirectMessages |
|
|
||||||
GatewayIntents.GuildMessageReactions |
|
|
||||||
GatewayIntents.GuildMessages |
|
|
||||||
GatewayIntents.GuildWebhooks |
|
|
||||||
GatewayIntents.GuildIntegrations |
|
|
||||||
GatewayIntents.GuildEmojis |
|
|
||||||
GatewayIntents.GuildBans |
|
|
||||||
GatewayIntents.Guilds |
|
|
||||||
GatewayIntents.GuildMembers,
|
|
||||||
LogLevel = LogSeverity.Verbose,
|
|
||||||
MessageCacheSize = 1000,
|
|
||||||
});
|
|
||||||
|
|
||||||
var discordLogger = new DiscordLogger(_logger);
|
|
||||||
_client.Log += discordLogger.Log;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Login()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var token = await GetToken();
|
|
||||||
await _client.LoginAsync(TokenType.Bot, token);
|
|
||||||
await _client.StartAsync();
|
|
||||||
while (!_client.ConnectionState.Equals(ConnectionState.Connected)) await Task.Delay(25);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.Error(LogSource.Geekbot, "Could not connect to Discord", e);
|
|
||||||
Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetToken()
|
|
||||||
{
|
|
||||||
var token = _runParameters.Token ?? _globalSettings.GetKey("DiscordToken");
|
|
||||||
if (string.IsNullOrEmpty(token))
|
|
||||||
{
|
|
||||||
Console.Write("Your bot Token: ");
|
|
||||||
var newToken = Console.ReadLine();
|
|
||||||
await _globalSettings.SetKey("DiscordToken", newToken);
|
|
||||||
await _globalSettings.SetKey("Game", "Ping Pong");
|
|
||||||
token = newToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RegisterHandlers()
|
|
||||||
{
|
|
||||||
var applicationInfo = await _client.GetApplicationInfoAsync();
|
|
||||||
|
|
||||||
_serviceCollection.AddSingleton<DiscordSocketClient>(_client);
|
|
||||||
var serviceProvider = _serviceCollection.BuildServiceProvider();
|
|
||||||
|
|
||||||
var commands = new CommandService();
|
|
||||||
await commands.AddModulesAsync(Assembly.GetAssembly(typeof(BotStartup)), serviceProvider);
|
|
||||||
|
|
||||||
var commandHandler = new CommandHandler(_client, _logger, serviceProvider, commands, applicationInfo, serviceProvider.GetService<IGuildSettingsManager>());
|
|
||||||
var userHandler = new UserHandler(serviceProvider.GetService<IUserRepository>(), _logger, serviceProvider.GetService<DatabaseContext>(), _client);
|
|
||||||
var reactionHandler = new ReactionHandler(serviceProvider.GetService<IReactionListener>());
|
|
||||||
var statsHandler = new StatsHandler(_logger, serviceProvider.GetService<DatabaseContext>());
|
|
||||||
var messageDeletedHandler = new MessageDeletedHandler(serviceProvider.GetService<DatabaseContext>(), _logger, _client);
|
|
||||||
|
|
||||||
_client.MessageReceived += commandHandler.RunCommand;
|
|
||||||
_client.MessageDeleted += messageDeletedHandler.HandleMessageDeleted;
|
|
||||||
_client.UserJoined += userHandler.Joined;
|
|
||||||
_client.UserUpdated += userHandler.Updated;
|
|
||||||
_client.UserLeft += userHandler.Left;
|
|
||||||
_client.ReactionAdded += reactionHandler.Added;
|
|
||||||
_client.ReactionRemoved += reactionHandler.Removed;
|
|
||||||
if (!_runParameters.InMemory) _client.MessageReceived += statsHandler.UpdateStats;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.Commands;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.CommandPreconditions
|
|
||||||
{
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
|
||||||
public class DisableInDirectMessageAttribute : PreconditionAttribute
|
|
||||||
{
|
|
||||||
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
|
|
||||||
{
|
|
||||||
var result = context.Guild.Id != 0 ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Command unavailable in Direct Messaging");
|
|
||||||
return Task.FromResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,253 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Resources;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using Geekbot.Bot.CommandPreconditions;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using Localization = Geekbot.Core.Localization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Admin
|
|
||||||
{
|
|
||||||
[Group("admin")]
|
|
||||||
[RequireUserPermission(GuildPermission.Administrator)]
|
|
||||||
[DisableInDirectMessage]
|
|
||||||
public class Admin : GeekbotCommandBase
|
|
||||||
{
|
|
||||||
private readonly DiscordSocketClient _client;
|
|
||||||
|
|
||||||
public Admin(DiscordSocketClient client, IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager)
|
|
||||||
{
|
|
||||||
_client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
[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)
|
|
||||||
{
|
|
||||||
GuildSettings.WelcomeMessage = welcomeMessage;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
|
|
||||||
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("welcomechannel", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Set a channel for the welcome messages (by default it uses the top most channel)")]
|
|
||||||
public async Task SelectWelcomeChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var m = await channel.SendMessageAsync("...");
|
|
||||||
|
|
||||||
GuildSettings.WelcomeChannel = channel.Id.AsLong();
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
|
|
||||||
await m.DeleteAsync();
|
|
||||||
|
|
||||||
await ReplyAsync("Successfully saved the welcome channel");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("modchannel", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Set a channel for moderation purposes")]
|
|
||||||
public async Task SelectModChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var m = await channel.SendMessageAsync("verifying...");
|
|
||||||
|
|
||||||
GuildSettings.ModChannel = channel.Id.AsLong();
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("Successfully saved mod channel, you can now do the following");
|
|
||||||
sb.AppendLine("- `!admin showleave` - send message to mod channel when someone leaves");
|
|
||||||
sb.AppendLine("- `!admin showdel` - send message to mod channel when someone deletes a message");
|
|
||||||
await m.ModifyAsync(e => e.Content = sb.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("showleave", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Toggle - notify modchannel when someone leaves")]
|
|
||||||
public async Task ShowLeave()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var modChannel = await GetModChannel(GuildSettings.ModChannel.AsUlong());
|
|
||||||
if (modChannel == null) return;
|
|
||||||
|
|
||||||
GuildSettings.ShowLeave = !GuildSettings.ShowLeave;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
await modChannel.SendMessageAsync(GuildSettings.ShowLeave
|
|
||||||
? "Saved - now sending messages here when someone leaves"
|
|
||||||
: "Saved - stopping sending messages here when someone leaves"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("showdel", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Toggle - notify modchannel when someone deletes a message")]
|
|
||||||
public async Task ShowDelete()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var modChannel = await GetModChannel(GuildSettings.ModChannel.AsUlong());
|
|
||||||
if (modChannel == null) return;
|
|
||||||
|
|
||||||
GuildSettings.ShowDelete = !GuildSettings.ShowDelete;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
await modChannel.SendMessageAsync(GuildSettings.ShowDelete
|
|
||||||
? "Saved - now sending messages here when someone deletes a message"
|
|
||||||
: "Saved - stopping sending messages here when someone deletes a message"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("setlang", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Change the bots language")]
|
|
||||||
public async Task SetLanguage([Summary("language")] string language)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var availableLanguages = new List<string>();
|
|
||||||
availableLanguages.Add("en-GB"); // default
|
|
||||||
availableLanguages.AddRange(GetAvailableCultures().Select(culture => culture.Name));
|
|
||||||
if (availableLanguages.Contains(language))
|
|
||||||
{
|
|
||||||
GuildSettings.Language = language;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language.ToLower() == "chde" ? "de-CH" : language);
|
|
||||||
|
|
||||||
await ReplyAsync(Localization.Admin.NewLanguageSet);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReplyAsync($"That doesn't seem to be a supported language\nSupported Languages are {string.Join(", ", availableLanguages)}");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("wiki", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Change the wikipedia instance (use lang code in xx.wikipedia.org)")]
|
|
||||||
public async Task SetWikiLanguage([Summary("language")] string languageRaw)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var language = languageRaw.ToLower();
|
|
||||||
GuildSettings.WikiLang = language;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
|
|
||||||
await ReplyAsync($"Now using the {language} wikipedia");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("ping", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Enable the ping reply.")]
|
|
||||||
public async Task TogglePing()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
|
||||||
GuildSettings.Ping = !GuildSettings.Ping;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
await ReplyAsync(GuildSettings.Ping ? "i will reply to ping now" : "No more pongs...");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("hui", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Enable the ping reply.")]
|
|
||||||
public async Task ToggleHui()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// var guild = _guildSettingsManager.GetSettings(Context.Guild.Id);
|
|
||||||
GuildSettings.Hui = !GuildSettings.Hui;
|
|
||||||
await GuildSettingsManager.UpdateSettings(GuildSettings);
|
|
||||||
await ReplyAsync(GuildSettings.Hui ? "i will reply to hui now" : "No more hui's...");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<ISocketMessageChannel> GetModChannel(ulong channelId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (channelId == ulong.MinValue) throw new Exception();
|
|
||||||
var modChannel = (ISocketMessageChannel) _client.GetChannel(channelId);
|
|
||||||
if (modChannel == null) throw new Exception();
|
|
||||||
return modChannel;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await ReplyAsync("Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<CultureInfo> GetAvailableCultures()
|
|
||||||
{
|
|
||||||
var result = new List<CultureInfo>();
|
|
||||||
var rm = new ResourceManager(typeof(Localization.Admin));
|
|
||||||
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
|
|
||||||
foreach (var culture in cultures)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work
|
|
||||||
|
|
||||||
var rs = rm.GetResourceSet(culture, true, false);
|
|
||||||
if (rs != null)
|
|
||||||
{
|
|
||||||
result.Add(culture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (CultureNotFoundException)
|
|
||||||
{
|
|
||||||
//NOP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.GlobalSettings;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using Geekbot.Core.Logger;
|
|
||||||
using Geekbot.Core.UserRepository;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Admin.Owner
|
|
||||||
{
|
|
||||||
[Group("owner")]
|
|
||||||
[RequireOwner]
|
|
||||||
public class Owner : GeekbotCommandBase
|
|
||||||
{
|
|
||||||
private readonly DiscordSocketClient _client;
|
|
||||||
private readonly IGlobalSettings _globalSettings;
|
|
||||||
private readonly IGeekbotLogger _logger;
|
|
||||||
private readonly IUserRepository _userRepository;
|
|
||||||
|
|
||||||
public Owner(DiscordSocketClient client, IGeekbotLogger logger, IUserRepository userRepositry, IErrorHandler errorHandler, IGlobalSettings globalSettings,
|
|
||||||
IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager)
|
|
||||||
{
|
|
||||||
_client = client;
|
|
||||||
_logger = logger;
|
|
||||||
_userRepository = userRepositry;
|
|
||||||
_globalSettings = globalSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("youtubekey", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Set the youtube api key")]
|
|
||||||
public async Task SetYoutubeKey([Summary("API-Key")] string key)
|
|
||||||
{
|
|
||||||
await _globalSettings.SetKey("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)
|
|
||||||
{
|
|
||||||
await _globalSettings.SetKey("Game", key);
|
|
||||||
await _client.SetGameAsync(key);
|
|
||||||
_logger.Information(LogSource.Geekbot, $"Changed game to {key}");
|
|
||||||
await ReplyAsync($"Now Playing {key}");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("popuserrepo", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Populate user cache")]
|
|
||||||
public async Task PopUserRepoCommand()
|
|
||||||
{
|
|
||||||
var success = 0;
|
|
||||||
var failed = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Warning(LogSource.UserRepository, "Populating User Repositry");
|
|
||||||
await ReplyAsync("Starting Population of User Repository");
|
|
||||||
foreach (var guild in _client.Guilds)
|
|
||||||
{
|
|
||||||
_logger.Information(LogSource.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(LogSource.UserRepository, "Finished Updating User Repositry");
|
|
||||||
await ReplyAsync(
|
|
||||||
$"Successfully Populated User Repository with {success} Users in {_client.Guilds.Count} Guilds (Failed: {failed})");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context,
|
|
||||||
"Couldn't complete User Repository, see console for more info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("refreshuser", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Refresh a user in the user cache")]
|
|
||||||
public async Task PopUserRepoCommand([Summary("@someone")] IUser user)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _userRepository.Update(user as SocketUser);
|
|
||||||
await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("refreshuser", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Refresh a user in the user cache")]
|
|
||||||
public async Task PopUserRepoCommand([Summary("user-id")] ulong userId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var user = _client.GetUser(userId);
|
|
||||||
await _userRepository.Update(user);
|
|
||||||
await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("error", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Throw an error un purpose")]
|
|
||||||
public async Task PurposefulError()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
throw new Exception("Error Generated by !owner error");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.Net;
|
|
||||||
using Geekbot.Bot.CommandPreconditions;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.Database;
|
|
||||||
using Geekbot.Core.Database.Models;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using Geekbot.Core.ReactionListener;
|
|
||||||
using Localization = Geekbot.Core.Localization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Admin
|
|
||||||
{
|
|
||||||
[Group("role")]
|
|
||||||
[DisableInDirectMessage]
|
|
||||||
public class Role : GeekbotCommandBase
|
|
||||||
{
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
private readonly IReactionListener _reactionListener;
|
|
||||||
|
|
||||||
public Role(DatabaseContext database, IErrorHandler errorHandler, IReactionListener reactionListener, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager)
|
|
||||||
{
|
|
||||||
_database = database;
|
|
||||||
_reactionListener = reactionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(RunMode = RunMode.Async)]
|
|
||||||
[Summary("Get a list of all available roles.")]
|
|
||||||
public async Task GetAllRoles()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var roles = _database.RoleSelfService.Where(g => g.GuildId.Equals(Context.Guild.Id.AsLong())).ToList();
|
|
||||||
if (roles.Count == 0)
|
|
||||||
{
|
|
||||||
await ReplyAsync(Localization.Role.NoRolesConfigured);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine(string.Format(Localization.Role.ListHeader, Context.Guild.Name));
|
|
||||||
sb.AppendLine(Localization.Role.ListInstruction);
|
|
||||||
foreach (var role in roles) sb.AppendLine($"- {role.WhiteListName}");
|
|
||||||
await ReplyAsync(sb.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(RunMode = RunMode.Async)]
|
|
||||||
[Summary("Get a role by mentioning it.")]
|
|
||||||
public async Task GiveRole([Summary("role-nickname")] string roleNameRaw)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var roleName = roleNameRaw.ToLower();
|
|
||||||
var roleFromDb = _database.RoleSelfService.FirstOrDefault(e =>
|
|
||||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName));
|
|
||||||
if (roleFromDb != null)
|
|
||||||
{
|
|
||||||
var guildUser = (IGuildUser) Context.User;
|
|
||||||
var role = Context.Guild.Roles.First(r => r.Id == roleFromDb.RoleId.AsUlong());
|
|
||||||
if (role == null)
|
|
||||||
{
|
|
||||||
await ReplyAsync(Localization.Role.RoleNotFound);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (guildUser.RoleIds.Contains(role.Id))
|
|
||||||
{
|
|
||||||
await guildUser.RemoveRoleAsync(role);
|
|
||||||
await ReplyAsync(string.Format(Localization.Role.RemovedUserFromRole, role.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await guildUser.AddRoleAsync(role);
|
|
||||||
await ReplyAsync(string.Format(Localization.Role.AddedUserFromRole, role.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReplyAsync(Localization.Role.RoleNotFound);
|
|
||||||
}
|
|
||||||
catch (HttpException e)
|
|
||||||
{
|
|
||||||
if (e.HttpCode == HttpStatusCode.Forbidden)
|
|
||||||
{
|
|
||||||
await ReplyAsync(Localization.Internal.Http403);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
|
||||||
[Command("add", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Add a role to the whitelist.")]
|
|
||||||
public async Task AddRole([Summary("@role")] IRole role, [Summary("alias")] string roleName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (role.IsManaged)
|
|
||||||
{
|
|
||||||
await ReplyAsync(Localization.Role.CannotAddManagedRole);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role.Permissions.ManageRoles
|
|
||||||
|| role.Permissions.Administrator
|
|
||||||
|| role.Permissions.ManageGuild
|
|
||||||
|| role.Permissions.BanMembers
|
|
||||||
|| role.Permissions.KickMembers)
|
|
||||||
{
|
|
||||||
await ReplyAsync(Localization.Role.CannotAddDangerousRole);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_database.RoleSelfService.Add(new RoleSelfServiceModel
|
|
||||||
{
|
|
||||||
GuildId = Context.Guild.Id.AsLong(),
|
|
||||||
RoleId = role.Id.AsLong(),
|
|
||||||
WhiteListName = roleName
|
|
||||||
});
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
await ReplyAsync(string.Format(Localization.Role.AddedRoleToWhitelist, role.Name));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
|
||||||
[Command("remove", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Remove a role from the whitelist.")]
|
|
||||||
public async Task RemoveRole([Summary("role-nickname")] string roleName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var roleFromDb = _database.RoleSelfService.FirstOrDefault(e =>
|
|
||||||
e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName));
|
|
||||||
if (roleFromDb != null)
|
|
||||||
{
|
|
||||||
_database.RoleSelfService.Remove(roleFromDb);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
await ReplyAsync(string.Format(Localization.Role.RemovedRoleFromWhitelist, roleName));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReplyAsync(Localization.Role.RoleNotFound);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
|
||||||
[Summary("Give a role by clicking on an emoji")]
|
|
||||||
[Command("listen", RunMode = RunMode.Async)]
|
|
||||||
public async Task AddListener([Summary("message-ID")] string messageIdStr, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var messageId = ulong.Parse(messageIdStr);
|
|
||||||
var message = (IUserMessage) await Context.Channel.GetMessageAsync(messageId);
|
|
||||||
var emote = _reactionListener.ConvertStringToEmote(emoji);
|
|
||||||
|
|
||||||
await message.AddReactionAsync(emote);
|
|
||||||
await _reactionListener.AddRoleToListener(messageId, Context.Guild.Id, emoji, role);
|
|
||||||
await Context.Message.DeleteAsync();
|
|
||||||
}
|
|
||||||
catch (HttpException)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendMessageAsync("Custom emojis from other servers are not supported");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.Database;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using Geekbot.Core.KvInMemoryStore;
|
|
||||||
using Geekbot.Core.RandomNumberGenerator;
|
|
||||||
using Sentry;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Games.Roll
|
|
||||||
{
|
|
||||||
public class Roll : GeekbotCommandBase
|
|
||||||
{
|
|
||||||
private readonly IKvInMemoryStore _kvInMemoryStore;
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
|
||||||
|
|
||||||
public Roll(IKvInMemoryStore kvInMemoryStore, IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager)
|
|
||||||
: base(errorHandler, guildSettingsManager)
|
|
||||||
{
|
|
||||||
_kvInMemoryStore = kvInMemoryStore;
|
|
||||||
_database = database;
|
|
||||||
_randomNumberGenerator = randomNumberGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("roll", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Guess which number the bot will roll (1-100")]
|
|
||||||
public async Task RollCommand([Remainder] [Summary("guess")] string stuff = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var res = await new Geekbot.Commands.Roll.Roll(_kvInMemoryStore, _database, _randomNumberGenerator)
|
|
||||||
.RunFromGateway(
|
|
||||||
Context.Guild.Id,
|
|
||||||
Context.User.Id,
|
|
||||||
Context.User.Username,
|
|
||||||
stuff ?? "0"
|
|
||||||
);
|
|
||||||
await ReplyAsync(res);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
Transaction.Status = SpanStatus.InternalError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
|
||||||
{
|
|
||||||
public class LolMmr : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
|
|
||||||
public LolMmr(IErrorHandler errorHandler)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("mmr", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Get the League of Legends MMR for a specified summoner")]
|
|
||||||
public async Task GetMmr([Remainder] [Summary("summoner")] string summonerName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LolMmrDto data;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var name = HttpUtility.UrlEncode(summonerName.ToLower());
|
|
||||||
var httpClient = HttpAbstractions.CreateDefaultClient();
|
|
||||||
// setting the user agent in accordance with the whatismymmr.com api rules
|
|
||||||
httpClient.DefaultRequestHeaders.Remove("User-Agent");
|
|
||||||
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Linux:rocks.pizzaandcoffee.geekbot:v0.0.0");
|
|
||||||
data = await HttpAbstractions.Get<LolMmrDto>(new Uri($"https://euw.whatismymmr.com/api/v1/summoner?name={name}"), httpClient);
|
|
||||||
}
|
|
||||||
catch (HttpRequestException e)
|
|
||||||
{
|
|
||||||
if (e.StatusCode != HttpStatusCode.NotFound) throw e;
|
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync("Player not found");
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine($"**MMR for {summonerName}**");
|
|
||||||
sb.AppendLine($"Normal: {data.Normal?.Avg ?? 0}");
|
|
||||||
sb.AppendLine($"Ranked: {data.Ranked?.Avg ?? 0}");
|
|
||||||
sb.AppendLine($"ARAM: {data.ARAM?.Avg ?? 0}");
|
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
|
||||||
{
|
|
||||||
public class LolMmrDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("ranked")]
|
|
||||||
public LolMrrInfoDto Ranked { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("normal")]
|
|
||||||
public LolMrrInfoDto Normal { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("aram")]
|
|
||||||
public LolMrrInfoDto ARAM { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
|
||||||
{
|
|
||||||
public class LolMrrInfoDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("avg")]
|
|
||||||
public decimal? Avg { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.Converters;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using MtgApiManager.Lib.Service;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
|
||||||
{
|
|
||||||
public class MagicTheGathering : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
private readonly IMtgManaConverter _manaConverter;
|
|
||||||
|
|
||||||
public MagicTheGathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
_manaConverter = manaConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("mtg", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Find a Magic The Gathering Card.")]
|
|
||||||
public async Task GetCard([Remainder] [Summary("card-name")] string cardName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = await Context.Channel.SendMessageAsync($":mag: Looking up \"{cardName}\", please wait...");
|
|
||||||
|
|
||||||
var service = new CardService();
|
|
||||||
var result = service
|
|
||||||
.Where(x => x.Name, cardName)
|
|
||||||
// fewer cards less risk of deserialization problems, don't need more than one anyways...
|
|
||||||
.Where(x => x.PageSize, 1);
|
|
||||||
|
|
||||||
var cards = await result.AllAsync();
|
|
||||||
if (!cards.IsSuccess)
|
|
||||||
{
|
|
||||||
await message.ModifyAsync(properties => properties.Content = $":warning: The Gatherer reacted in an unexpected way: {cards.Exception.Message}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var card = cards.Value.FirstOrDefault();
|
|
||||||
|
|
||||||
if (card == null)
|
|
||||||
{
|
|
||||||
await message.ModifyAsync(properties => properties.Content = ":red_circle: I couldn't find a card with that name...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder
|
|
||||||
{
|
|
||||||
Title = card.Name,
|
|
||||||
Description = card.Type
|
|
||||||
};
|
|
||||||
|
|
||||||
if (card.Colors != null) eb.WithColor(GetColor(card.Colors));
|
|
||||||
|
|
||||||
if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", _manaConverter.ConvertMana(card.Text));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor);
|
|
||||||
if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName);
|
|
||||||
if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power);
|
|
||||||
if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty);
|
|
||||||
if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", _manaConverter.ConvertMana(card.ManaCost));
|
|
||||||
if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity);
|
|
||||||
|
|
||||||
if (card.Legalities != null && card.Legalities.Count > 0)
|
|
||||||
eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format)));
|
|
||||||
|
|
||||||
await message.ModifyAsync(properties =>
|
|
||||||
{
|
|
||||||
properties.Content = string.Empty;
|
|
||||||
properties.Embed = eb.Build();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color GetColor(IEnumerable<string> colors)
|
|
||||||
{
|
|
||||||
var color = colors.FirstOrDefault();
|
|
||||||
return color switch
|
|
||||||
{
|
|
||||||
"Black" => new Color(203, 194, 191),
|
|
||||||
"White" => new Color(255, 251, 213),
|
|
||||||
"Blue" => new Color(170, 224, 250),
|
|
||||||
"Red" => new Color(250, 170, 143),
|
|
||||||
"Green" => new Color(155, 211, 174),
|
|
||||||
_ => new Color(204, 194, 212)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.GuildSettingsManager;
|
|
||||||
using JikanDotNet;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
|
||||||
{
|
|
||||||
public class Mal : GeekbotCommandBase
|
|
||||||
{
|
|
||||||
private readonly IJikan _client;
|
|
||||||
|
|
||||||
public Mal(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager)
|
|
||||||
{
|
|
||||||
_client = new Jikan();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("anime", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Show Info about an Anime.")]
|
|
||||||
public async Task SearchAnime([Remainder] [Summary("anime-name")] string animeName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var results = await _client.SearchAnime(animeName);
|
|
||||||
var anime = results.Results.FirstOrDefault();
|
|
||||||
if (anime != null)
|
|
||||||
{
|
|
||||||
var eb = new EmbedBuilder
|
|
||||||
{
|
|
||||||
Title = anime.Title,
|
|
||||||
Description = anime.Description,
|
|
||||||
ImageUrl = anime.ImageURL
|
|
||||||
};
|
|
||||||
|
|
||||||
eb.AddInlineField("Premiere", FormatDate(anime.StartDate))
|
|
||||||
.AddInlineField("Ended", anime.Airing ? "-" : FormatDate(anime.EndDate))
|
|
||||||
.AddInlineField("Episodes", anime.Episodes)
|
|
||||||
.AddInlineField("MAL Score", anime.Score)
|
|
||||||
.AddInlineField("Type", anime.Type)
|
|
||||||
.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.MalId}");
|
|
||||||
|
|
||||||
await ReplyAsync("", false, eb.Build());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ReplyAsync("No anime found with that name...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("manga", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Show Info about a Manga.")]
|
|
||||||
public async Task SearchManga([Remainder] [Summary("manga-name")] string mangaName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var results = await _client.SearchManga(mangaName);
|
|
||||||
var manga = results.Results.FirstOrDefault();
|
|
||||||
if (manga != null)
|
|
||||||
{
|
|
||||||
var eb = new EmbedBuilder
|
|
||||||
{
|
|
||||||
Title = manga.Title,
|
|
||||||
Description = manga.Description,
|
|
||||||
ImageUrl = manga.ImageURL
|
|
||||||
};
|
|
||||||
|
|
||||||
eb.AddInlineField("Premiere", FormatDate(manga.StartDate))
|
|
||||||
.AddInlineField("Ended", manga.Publishing ? "-" : FormatDate(manga.EndDate))
|
|
||||||
.AddInlineField("Volumes", manga.Volumes)
|
|
||||||
.AddInlineField("Chapters", manga.Chapters)
|
|
||||||
.AddInlineField("MAL Score", manga.Score)
|
|
||||||
.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.MalId}");
|
|
||||||
|
|
||||||
await ReplyAsync("", false, eb.Build());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ReplyAsync("No manga found with that name...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await ErrorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatDate(DateTime? dateTime)
|
|
||||||
{
|
|
||||||
if (!dateTime.HasValue)
|
|
||||||
{
|
|
||||||
return DateTime.MinValue.ToString("d", Thread.CurrentThread.CurrentUICulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dateTime.Value.ToString("d", Thread.CurrentThread.CurrentUICulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
|
||||||
{
|
|
||||||
public class UrbanDictionary : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
|
|
||||||
public UrbanDictionary(IErrorHandler errorHandler)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("urban", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Lookup something on urban dictionary")]
|
|
||||||
public async Task UrbanDefine([Remainder] [Summary("word")] string word)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var eb = await Geekbot.Commands.UrbanDictionary.UrbanDictionary.Run(word);
|
|
||||||
if (eb == null)
|
|
||||||
{
|
|
||||||
await ReplyAsync("That word hasn't been defined...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReplyAsync(string.Empty, false, eb.ToDiscordNetEmbed().Build());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.Database;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.WikipediaClient;
|
|
||||||
using Geekbot.Core.WikipediaClient.Page;
|
|
||||||
using HtmlAgilityPack;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
|
||||||
{
|
|
||||||
public class Wikipedia : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
private readonly IWikipediaClient _wikipediaClient;
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
|
|
||||||
public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, DatabaseContext database)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
_wikipediaClient = wikipediaClient;
|
|
||||||
_database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("wiki", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Get an article from wikipedia.")]
|
|
||||||
public async Task GetPreview([Remainder] [Summary("article")] string articleName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var wikiLang = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(Context.Guild.Id.AsLong()))?.WikiLang;
|
|
||||||
if (string.IsNullOrEmpty(wikiLang))
|
|
||||||
{
|
|
||||||
wikiLang = "en";
|
|
||||||
}
|
|
||||||
var article = await _wikipediaClient.GetPreview(articleName.Replace(" ", "_"), wikiLang);
|
|
||||||
|
|
||||||
if (article.Type != PageTypes.Standard)
|
|
||||||
{
|
|
||||||
switch (article.Type)
|
|
||||||
{
|
|
||||||
case PageTypes.Disambiguation:
|
|
||||||
await ReplyAsync($"**__Disambiguation__**\r\n{DisambiguationExtractor(article.ExtractHtml)}");
|
|
||||||
break;
|
|
||||||
case PageTypes.MainPage:
|
|
||||||
await ReplyAsync("The main page is not supported");
|
|
||||||
break;
|
|
||||||
case PageTypes.NoExtract:
|
|
||||||
await ReplyAsync($"This page has no summary, here is the link: {article.ContentUrls.Desktop.Page}");
|
|
||||||
break;
|
|
||||||
case PageTypes.Standard:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
await ReplyAsync($"This page type is currently not supported, here is the link: {article.ContentUrls.Desktop.Page}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eb = new EmbedBuilder
|
|
||||||
{
|
|
||||||
Title = article.Title,
|
|
||||||
Description = article.Description,
|
|
||||||
ImageUrl = article.Thumbnail?.Source.ToString(),
|
|
||||||
Url = article.ContentUrls.Desktop.Page.ToString(),
|
|
||||||
Color = new Color(246,246,246),
|
|
||||||
Timestamp = article.Timestamp,
|
|
||||||
Footer = new EmbedFooterBuilder
|
|
||||||
{
|
|
||||||
Text = "Last Edit",
|
|
||||||
IconUrl = "http://icons.iconarchive.com/icons/sykonist/popular-sites/256/Wikipedia-icon.png"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
eb.AddField("Description", article.Extract);
|
|
||||||
if (article.Coordinates != null) eb.AddField("Coordinates", $"{article.Coordinates.Lat} Lat {article.Coordinates.Lon} Lon");
|
|
||||||
await ReplyAsync("", false, eb.Build());
|
|
||||||
}
|
|
||||||
catch (HttpRequestException)
|
|
||||||
{
|
|
||||||
await ReplyAsync("I couldn't find that article");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DisambiguationExtractor(string extractHtml)
|
|
||||||
{
|
|
||||||
var doc = new HtmlDocument();
|
|
||||||
doc.LoadHtml(extractHtml);
|
|
||||||
var nodes = doc.DocumentNode.SelectNodes("//li");
|
|
||||||
if (nodes == null) return "(List is to long to show)";
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var node in nodes)
|
|
||||||
{
|
|
||||||
var split = node.InnerText.Split(',');
|
|
||||||
var title = split.First();
|
|
||||||
var desc = string.Join(",", split.Skip(1));
|
|
||||||
sb.AppendLine($"• **{title}** -{desc}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
// using Geekbot.Core.ErrorHandling;
|
|
||||||
// using Geekbot.Core.GlobalSettings;
|
|
||||||
// using Google.Apis.Services;
|
|
||||||
// using Google.Apis.YouTube.v3;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
|
||||||
{
|
|
||||||
public class Youtube : TransactionModuleBase
|
|
||||||
{
|
|
||||||
// private readonly IGlobalSettings _globalSettings;
|
|
||||||
// private readonly IErrorHandler _errorHandler;
|
|
||||||
|
|
||||||
// public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
|
|
||||||
// {
|
|
||||||
// _globalSettings = globalSettings;
|
|
||||||
// _errorHandler = errorHandler;
|
|
||||||
// }
|
|
||||||
|
|
||||||
[Command("yt", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Search for something on youtube.")]
|
|
||||||
public async Task Yt([Remainder] [Summary("title")] string searchQuery)
|
|
||||||
{
|
|
||||||
await ReplyAsync("The youtube command is temporarily disabled");
|
|
||||||
|
|
||||||
// var key = _globalSettings.GetKey("YoutubeKey");
|
|
||||||
// if (string.IsNullOrEmpty(key))
|
|
||||||
// {
|
|
||||||
// await ReplyAsync("No youtube key set, please tell my senpai to set one");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var youtubeService = new YouTubeService(new BaseClientService.Initializer
|
|
||||||
// {
|
|
||||||
// ApiKey = key,
|
|
||||||
// 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 _errorHandler.HandleCommandException(e, Context);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.RandomNumberGenerator;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness
|
|
||||||
{
|
|
||||||
public class BenedictCumberbatchNameGenerator : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
|
||||||
|
|
||||||
public BenedictCumberbatchNameGenerator(IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
_randomNumberGenerator = randomNumberGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("bdcb", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Benedict Cumberbatch Name Generator")]
|
|
||||||
public async Task GetQuote()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var firstnameList = new List<string>
|
|
||||||
{
|
|
||||||
"Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bombadil", "Boilerdang", "Bandicoot", "Fragglerock", "Muffintop", "Congleton", "Blubberdick", "Buffalo", "Benadryl",
|
|
||||||
"Butterfree", "Burberry", "Whippersnatch", "Buttermilk", "Beezlebub", "Budapest", "Boilerdang", "Blubberwhale", "Bumberstump", "Bulbasaur", "Cogglesnatch", "Liverswort",
|
|
||||||
"Bodybuild", "Johnnycash", "Bendydick", "Burgerking", "Bonaparte", "Bunsenburner", "Billiardball", "Bukkake", "Baseballmitt", "Blubberbutt", "Baseballbat", "Rumblesack",
|
|
||||||
"Barister", "Danglerack", "Rinkydink", "Bombadil", "Honkytonk", "Billyray", "Bumbleshack", "Snorkeldink", "Beetlejuice", "Bedlington", "Bandicoot", "Boobytrap", "Blenderdick",
|
|
||||||
"Bentobox", "Pallettown", "Wimbledon", "Buttercup", "Blasphemy", "Syphilis", "Snorkeldink", "Brandenburg", "Barbituate", "Snozzlebert", "Tiddleywomp", "Bouillabaisse",
|
|
||||||
"Wellington", "Benetton", "Bendandsnap", "Timothy", "Brewery", "Bentobox", "Brandybuck", "Benjamin", "Buckminster", "Bourgeoisie", "Bakery", "Oscarbait", "Buckyball",
|
|
||||||
"Bourgeoisie", "Burlington", "Buckingham", "Barnoldswick", "Bumblesniff", "Butercup", "Bubblebath", "Fiddlestick", "Bulbasaur", "Bumblebee", "Bettyboop", "Botany", "Cadbury",
|
|
||||||
"Brendadirk", "Buckingham", "Barnabus", "Barnacle", "Billybong", "Botany", "Benddadick", "Benderchick"
|
|
||||||
};
|
|
||||||
|
|
||||||
var lastnameList = new List<string>
|
|
||||||
{
|
|
||||||
"Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch", "Humperdinck", "Rivendell", "Cuttlefish", "Lingerie", "Vegemite", "Ampersand", "Cumberbund", "Candycrush",
|
|
||||||
"Clombyclomp", "Cragglethatch", "Nottinghill", "Cabbagepatch", "Camouflage", "Creamsicle", "Curdlemilk", "Upperclass", "Frumblesnatch", "Crumplehorn", "Talisman", "Candlestick",
|
|
||||||
"Chesterfield", "Bumbersplat", "Scratchnsniff", "Snugglesnatch", "Charizard", "Carrotstick", "Cumbercooch", "Crackerjack", "Crucifix", "Cuckatoo", "Cockletit", "Collywog",
|
|
||||||
"Capncrunch", "Covergirl", "Cumbersnatch", "Countryside", "Coggleswort", "Splishnsplash", "Copperwire", "Animorph", "Curdledmilk", "Cheddarcheese", "Cottagecheese", "Crumplehorn",
|
|
||||||
"Snickersbar", "Banglesnatch", "Stinkyrash", "Cameltoe", "Chickenbroth", "Concubine", "Candygram", "Moldyspore", "Chuckecheese", "Cankersore", "Crimpysnitch", "Wafflesmack",
|
|
||||||
"Chowderpants", "Toodlesnoot", "Clavichord", "Cuckooclock", "Oxfordshire", "Cumbersome", "Chickenstrips", "Battleship", "Commonwealth", "Cunningsnatch", "Custardbath",
|
|
||||||
"Kryptonite", "Curdlesnoot", "Cummerbund", "Coochyrash", "Crackerdong", "Crackerdong", "Curdledong", "Crackersprout", "Crumplebutt", "Colonist", "Coochierash", "Anglerfish",
|
|
||||||
"Cumbersniff", "Charmander", "Scratch-n-sniff", "Cumberbitch", "Pumpkinpatch", "Cramplesnutch", "Lumberjack", "Bonaparte", "Cul-de-sac", "Cankersore", "Cucumbercatch", "Contradict"
|
|
||||||
};
|
|
||||||
|
|
||||||
var lastname = lastnameList[_randomNumberGenerator.Next(0, lastnameList.Count - 1)];
|
|
||||||
var firstname = firstnameList[_randomNumberGenerator.Next(0, firstnameList.Count - 1)];
|
|
||||||
|
|
||||||
await ReplyAsync($"{firstname} {lastname}");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
|
||||||
{
|
|
||||||
public class Cat : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
|
|
||||||
public Cat(IErrorHandler errorHandler)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("cat", RunMode = RunMode.Async)]
|
|
||||||
[Summary("Return a random image of a cat.")]
|
|
||||||
public async Task Say()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await HttpAbstractions.Get<CatResponseDto>(new Uri("https://aws.random.cat/meow"));
|
|
||||||
var eb = new EmbedBuilder
|
|
||||||
{
|
|
||||||
ImageUrl = response.File
|
|
||||||
};
|
|
||||||
await ReplyAsync("", false, eb.Build());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
|
||||||
{
|
|
||||||
internal class CatResponseDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("file")]
|
|
||||||
public string File { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
|
||||||
{
|
|
||||||
internal class ChuckNorrisJokeResponseDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("value")]
|
|
||||||
public string Value { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Geekbot.Core;
|
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
|
||||||
{
|
|
||||||
public class ChuckNorrisJokes : TransactionModuleBase
|
|
||||||
{
|
|
||||||
private readonly IErrorHandler _errorHandler;
|
|
||||||
|
|
||||||
public ChuckNorrisJokes(IErrorHandler errorHandler)
|
|
||||||
{
|
|
||||||
_errorHandler = errorHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command("chuck", RunMode = RunMode.Async)]
|
|
||||||
[Summary("A random chuck norris joke")]
|
|
||||||
public async Task Say()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await HttpAbstractions.Get<ChuckNorrisJokeResponseDto>(new Uri("https://api.chucknorris.io/jokes/random"));
|
|
||||||
await ReplyAsync(response.Value);
|
|
||||||
}
|
|
||||||
catch (HttpRequestException)
|
|
||||||
{
|
|
||||||
await ReplyAsync("Api down...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue