Compare commits
2 commits
master
...
3.7-backup
Author | SHA1 | Date | |
---|---|---|---|
8cff234bc6 | |||
948c48909e |
404 changed files with 5921 additions and 13671 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
|
|
18
.gitignore
vendored
18
.gitignore
vendored
|
@ -1,10 +1,16 @@
|
||||||
/*/**/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/Logs/*
|
||||||
|
!/Geekbot.net/Logs/.keep
|
||||||
Geekbot.net.sln.DotSettings.user
|
Geekbot.net.sln.DotSettings.user
|
||||||
app
|
Geekbot.net/temp/
|
||||||
|
WikipediaApi/bin/
|
||||||
|
WikipediaApi/obj/
|
||||||
|
|
|
@ -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 --version-suffix ${CI_COMMIT_SHA:0:8} --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,11 @@ 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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{0A63D5DC-6325-4F53-8ED2-9843239B76CC}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WikipediaApi", "WikipediaApi\WikipediaApi.csproj", "{1084D499-EF94-4834-9E6A-B2AD81B60078}"
|
||||||
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 +15,18 @@ 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
|
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1084D499-EF94-4834-9E6A-B2AD81B60078}.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>
|
|
196
Geekbot.net/Commands/Admin/Admin.cs
Normal file
196
Geekbot.net/Commands/Admin/Admin.cs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Localization;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Admin
|
||||||
|
{
|
||||||
|
[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("wiki", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[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();
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("WikiLang", language) });
|
||||||
|
|
||||||
|
await ReplyAsync($"Now using the {language} wikipedia");
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("ping", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Enable the ping reply.")]
|
||||||
|
public async Task TogglePing()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool.TryParse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ping"), out var current);
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ping", current ? "false" : "true") });
|
||||||
|
await ReplyAsync(!current ? "i will reply to ping now" : "No more pongs...");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
90
Geekbot.net/Commands/Admin/Mod.cs
Normal file
90
Geekbot.net/Commands/Admin/Mod.cs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Admin
|
||||||
|
{
|
||||||
|
[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 do that");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
Geekbot.net/Commands/Admin/Owner.cs
Normal file
94
Geekbot.net/Commands/Admin/Owner.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Admin
|
||||||
|
{
|
||||||
|
[Group("owner")]
|
||||||
|
[RequireOwner]
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
_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)
|
||||||
|
{
|
||||||
|
_redis.StringSet("Game", key);
|
||||||
|
await _client.SetGameAsync(key);
|
||||||
|
_logger.Information(LogSource.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()
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context,
|
||||||
|
"Couldn't complete User Repository, see console for more info");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("error", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Throw an error un purpose")]
|
||||||
|
public void PurposefulError()
|
||||||
|
{
|
||||||
|
var e = new Exception("Error Generated by !owner error");
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
193
Geekbot.net/Commands/Admin/Role.cs
Normal file
193
Geekbot.net/Commands/Admin/Role.cs
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
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 Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.ReactionListener;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Admin
|
||||||
|
{
|
||||||
|
[Group("role")]
|
||||||
|
public class Role : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly IReactionListener _reactionListener;
|
||||||
|
|
||||||
|
public Role(IErrorHandler errorHandler, IDatabase redis, IReactionListener reactionListener)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_redis = redis;
|
||||||
|
_reactionListener = reactionListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
[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.ManageRoles)]
|
||||||
|
[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.ManageRoles)]
|
||||||
|
[Command("remove", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Remove a role from the whitelist.")]
|
||||||
|
public async Task RemoveRole([Summary("roleNickname")] string roleName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var success = _redis.HashDelete($"{Context.Guild.Id}:RoleWhitelist", roleName.ToLower());
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
await ReplyAsync($"Removed {roleName} from the whitelist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyAsync("There is not whitelisted role with that name...");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
[Remarks(CommandCategories.Admin)]
|
||||||
|
[Summary("Give a role by clicking on an emoji")]
|
||||||
|
[Command("listen", RunMode = RunMode.Async)]
|
||||||
|
public async Task AddListener([Summary("messageID")] string messageId, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = (IUserMessage) await Context.Channel.GetMessageAsync(ulong.Parse(messageId));
|
||||||
|
IEmote emote;
|
||||||
|
if (!emoji.StartsWith('<'))
|
||||||
|
{
|
||||||
|
var emo = new Emoji(emoji);
|
||||||
|
emote = emo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emote = Emote.Parse(emoji);
|
||||||
|
}
|
||||||
|
await message.AddReactionAsync(emote);
|
||||||
|
await _reactionListener.AddRoleToListener(messageId, emote, role);
|
||||||
|
await Context.Message.DeleteAsync();
|
||||||
|
}
|
||||||
|
catch (HttpException e)
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync("Custom emojis from other servers are not supported");
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync("Something went wrong... please try again on a new message");
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
Geekbot.net/Commands/Admin/Say.cs
Normal file
36
Geekbot.net/Commands/Admin/Say.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Admin
|
||||||
|
{
|
||||||
|
public class Say : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public Say(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[Command("say", 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
Geekbot.net/Commands/Audio/Voice.cs
Normal file
101
Geekbot.net/Commands/Audio/Voice.cs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib.Audio;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Audio
|
||||||
|
{
|
||||||
|
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("You must be in a voice channel.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
Geekbot.net/Commands/Games/BattleTag.cs
Normal file
72
Geekbot.net/Commands/Games/BattleTag.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Games
|
||||||
|
{
|
||||||
|
[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;
|
||||||
|
return splited[1].Length == 4 || splited[1].Length == 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
Geekbot.net/Commands/Games/Overwatch.cs
Normal file
132
Geekbot.net/Commands/Games/Overwatch.cs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
using OverwatchAPI;
|
||||||
|
using OverwatchAPI.Config;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Games
|
||||||
|
{
|
||||||
|
[Group("ow")]
|
||||||
|
public class Overwatch : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public Overwatch(IErrorHandler errorHandler, 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().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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,14 +3,14 @@ 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.net.Lib.ErrorHandling;
|
||||||
using Geekbot.Core.Extensions;
|
using Geekbot.net.Lib.Extensions;
|
||||||
using PokeAPI;
|
using PokeAPI;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Games
|
namespace Geekbot.net.Commands.Games
|
||||||
{
|
{
|
||||||
public class Pokedex : TransactionModuleBase
|
public class Pokedex : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -20,8 +20,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
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,7 @@ namespace Geekbot.Bot.Commands.Games
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
Geekbot.net/Commands/Games/Roll.cs
Normal file
67
Geekbot.net/Commands/Games/Roll.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Localization;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Games
|
||||||
|
{
|
||||||
|
public class Roll : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Roll(IDatabase redis, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_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 = new Random().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}:RollsPrevious2", Context.Message.Author.Id).ToString()?.Split('|');
|
||||||
|
if (prevRoll?.Length == 2)
|
||||||
|
{
|
||||||
|
if (prevRoll[0] == guess.ToString() && DateTime.Parse(prevRoll[1]) > DateTime.Now.AddDays(-1))
|
||||||
|
{
|
||||||
|
await ReplyAsync(string.Format(transDict["NoPrevGuess"], Context.Message.Author.Mention));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_redis.HashSet($"{Context.Guild.Id}:RollsPrevious2",
|
||||||
|
new[] {new HashEntry(Context.Message.Author.Id, $"{guess}|{DateTime.Now}")});
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
Geekbot.net/Commands/Integrations/Google/Google.cs
Normal file
68
Geekbot.net/Commands/Integrations/Google/Google.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
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 = JsonConvert.DeserializeObject<GoogleKgApiResponseDto>(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.DetailedDtoDescription?.Url)) eb.WithUrl(data.DetailedDtoDescription.Url);
|
||||||
|
if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.ArticleBody)) eb.AddField("Details", data.DetailedDtoDescription.ArticleBody);
|
||||||
|
if(!string.IsNullOrEmpty(data.Image?.ContentUrl)) eb.WithThumbnailUrl(data.Image.ContentUrl);
|
||||||
|
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
public class GoogleKgApiDetailedDto
|
||||||
|
{
|
||||||
|
public string ArticleBody { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string License { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
public class GoogleKgApiElementDto
|
||||||
|
{
|
||||||
|
public GoogleKgApiResultDto Result { get; set; }
|
||||||
|
public double ResultScore { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
public class GoogleKgApiImageDto
|
||||||
|
{
|
||||||
|
public string ContentUrl { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
public class GoogleKgApiResponseDto
|
||||||
|
{
|
||||||
|
public List<GoogleKgApiElementDto> ItemListElement { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Geekbot.net.Commands.Integrations.Google
|
||||||
|
{
|
||||||
|
public class GoogleKgApiResultDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public GoogleKgApiImageDto Image { get; set; }
|
||||||
|
public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; }
|
||||||
|
}
|
||||||
|
}
|
93
Geekbot.net/Commands/Integrations/MagicTheGathering.cs
Normal file
93
Geekbot.net/Commands/Integrations/MagicTheGathering.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.Converters;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using MtgApiManager.Lib.Service;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations
|
||||||
|
{
|
||||||
|
public class Magicthegathering : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IMtgManaConverter _manaConverter;
|
||||||
|
|
||||||
|
public Magicthegathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_manaConverter = manaConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
[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", _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)
|
||||||
|
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(203, 194, 191);
|
||||||
|
case "White":
|
||||||
|
return new Color(255, 251, 213);
|
||||||
|
case "Blue":
|
||||||
|
return new Color(170, 224, 250);
|
||||||
|
case "Red":
|
||||||
|
return new Color(250, 170, 143);
|
||||||
|
case "Green":
|
||||||
|
return new Color(155, 211, 174);
|
||||||
|
default:
|
||||||
|
return new Color(204, 194, 212);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
Geekbot.net/Commands/Integrations/Mal.cs
Normal file
122
Geekbot.net/Commands/Integrations/Mal.cs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.Clients;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||||
|
{
|
||||||
|
internal class UrbanListItemDto
|
||||||
|
{
|
||||||
|
public string Definition { get; set; }
|
||||||
|
public string Permalink { get; set; }
|
||||||
|
public string ThumbsUp { get; set; }
|
||||||
|
public string Word { get; set; }
|
||||||
|
public string Example { get; set; }
|
||||||
|
public string ThumbsDown { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||||
|
{
|
||||||
|
internal class UrbanResponseDto
|
||||||
|
{
|
||||||
|
public string[] Tags { get; set; }
|
||||||
|
public List<UrbanListItemDto> List { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||||
|
{
|
||||||
|
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<UrbanResponseDto>(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));
|
||||||
|
if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = definition.Definition;
|
||||||
|
if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", definition.Example ?? "(no example given...)");
|
||||||
|
if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp);
|
||||||
|
if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown);
|
||||||
|
if (definitions.Tags.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags));
|
||||||
|
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,36 +5,36 @@ using System.Text;
|
||||||
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.Database;
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
using Geekbot.Core.ErrorHandling;
|
|
||||||
using Geekbot.Core.Extensions;
|
|
||||||
using Geekbot.Core.WikipediaClient;
|
|
||||||
using Geekbot.Core.WikipediaClient.Page;
|
|
||||||
using HtmlAgilityPack;
|
using HtmlAgilityPack;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using WikipediaApi;
|
||||||
|
using WikipediaApi.Page;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Integrations
|
namespace Geekbot.net.Commands.Integrations
|
||||||
{
|
{
|
||||||
public class Wikipedia : TransactionModuleBase
|
public class Wikipedia : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
private readonly IWikipediaClient _wikipediaClient;
|
private readonly IWikipediaClient _wikipediaClient;
|
||||||
private readonly DatabaseContext _database;
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, DatabaseContext database)
|
public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, IDatabase redis)
|
||||||
{
|
{
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
_wikipediaClient = wikipediaClient;
|
_wikipediaClient = wikipediaClient;
|
||||||
_database = database;
|
_redis = redis;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("wiki", RunMode = RunMode.Async)]
|
[Command("wiki", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Helpers)]
|
||||||
[Summary("Get an article from wikipedia.")]
|
[Summary("Get an article from wikipedia.")]
|
||||||
public async Task GetPreview([Remainder] [Summary("article")] string articleName)
|
public async Task GetPreview([Remainder] [Summary("Article")] string articleName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var wikiLang = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(Context.Guild.Id.AsLong()))?.WikiLang;
|
var wikiLang = _redis.HashGet($"{Context.Guild.Id}:Settings", "WikiLang").ToString();
|
||||||
if (string.IsNullOrEmpty(wikiLang))
|
if (string.IsNullOrEmpty(wikiLang))
|
||||||
{
|
{
|
||||||
wikiLang = "en";
|
wikiLang = "en";
|
||||||
|
@ -88,7 +88,7 @@ namespace Geekbot.Bot.Commands.Integrations
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
60
Geekbot.net/Commands/Integrations/Youtube.cs
Normal file
60
Geekbot.net/Commands/Integrations/Youtube.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Google.Apis.Services;
|
||||||
|
using Google.Apis.YouTube.v3;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Integrations
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
Geekbot.net/Commands/Randomness/Cat/Cat.cs
Normal file
54
Geekbot.net/Commands/Randomness/Cat/Cat.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Cat
|
||||||
|
{
|
||||||
|
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("https://aws.random.cat");
|
||||||
|
var response = await client.GetAsync("/meow");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
var catFile = JsonConvert.DeserializeObject<CatResponseDto>(stringResponse);
|
||||||
|
var eb = new EmbedBuilder();
|
||||||
|
eb.ImageUrl = catFile.File;
|
||||||
|
await ReplyAsync("", false, eb.Build());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await ReplyAsync("Seems like the dog cought the cat (error occured)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Geekbot.net/Commands/Randomness/Cat/CatResponseDto.cs
Normal file
7
Geekbot.net/Commands/Randomness/Cat/CatResponseDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Cat
|
||||||
|
{
|
||||||
|
internal class CatResponseDto
|
||||||
|
{
|
||||||
|
public string File { get; set; }
|
||||||
|
}
|
||||||
|
}
|
73
Geekbot.net/Commands/Randomness/CheckEm.cs
Normal file
73
Geekbot.net/Commands/Randomness/CheckEm.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Media;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness
|
||||||
|
{
|
||||||
|
public class CheckEm : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IMediaProvider _checkEmImages;
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public CheckEm(IMediaProvider mediaProvider, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_checkEmImages = mediaProvider;
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("checkem", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("Check for dubs")]
|
||||||
|
public async Task MuhDubs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var number = new Random().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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Chuck
|
||||||
|
{
|
||||||
|
internal class ChuckNorrisJokeResponseDto
|
||||||
|
{
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
53
Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokes.cs
Normal file
53
Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokes.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Chuck
|
||||||
|
{
|
||||||
|
public class ChuckNorrisJokes : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public ChuckNorrisJokes(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("chuck", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("A random chuck norris joke")]
|
||||||
|
public async Task Say()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Accept.Clear();
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||||
|
var response = await client.GetAsync("https://api.chucknorris.io/jokes/random");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
var data = JsonConvert.DeserializeObject<ChuckNorrisJokeResponseDto>(stringResponse);
|
||||||
|
await ReplyAsync(data.Value);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException)
|
||||||
|
{
|
||||||
|
await ReplyAsync("Api down...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Dad
|
||||||
|
{
|
||||||
|
internal class DadJokeResponseDto
|
||||||
|
{
|
||||||
|
public string Joke { get; set; }
|
||||||
|
}
|
||||||
|
}
|
53
Geekbot.net/Commands/Randomness/Dad/DadJokes.cs
Normal file
53
Geekbot.net/Commands/Randomness/Dad/DadJokes.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Dad
|
||||||
|
{
|
||||||
|
public class DadJokes : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public DadJokes(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("dad", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
|
[Summary("A random dad joke")]
|
||||||
|
public async Task Say()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Accept.Clear();
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||||
|
var response = await client.GetAsync("https://icanhazdadjoke.com/");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
var data = JsonConvert.DeserializeObject<DadJokeResponseDto>(stringResponse);
|
||||||
|
await ReplyAsync(data.Joke);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException)
|
||||||
|
{
|
||||||
|
await ReplyAsync("Api down...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
Geekbot.net/Commands/Randomness/Dog/Dog.cs
Normal file
54
Geekbot.net/Commands/Randomness/Dog/Dog.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Dog
|
||||||
|
{
|
||||||
|
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<DogResponseDto>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Geekbot.net/Commands/Randomness/Dog/DogResponseDto.cs
Normal file
7
Geekbot.net/Commands/Randomness/Dog/DogResponseDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Commands.Randomness.Dog
|
||||||
|
{
|
||||||
|
internal class DogResponseDto
|
||||||
|
{
|
||||||
|
public string Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
59
Geekbot.net/Commands/Randomness/EightBall.cs
Normal file
59
Geekbot.net/Commands/Randomness/EightBall.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness
|
||||||
|
{
|
||||||
|
public class EightBall : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
public EightBall(IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_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 = new Random().Next(replies.Count);
|
||||||
|
await ReplyAsync(replies[answer]);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_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.Randomness
|
||||||
{
|
{
|
||||||
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()
|
||||||
{
|
{
|
40
Geekbot.net/Commands/Randomness/Gdq.cs
Normal file
40
Geekbot.net/Commands/Randomness/Gdq.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
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.Media;
|
using Geekbot.net.Lib.Media;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Randomness
|
namespace Geekbot.net.Commands.Randomness
|
||||||
{
|
{
|
||||||
public class RandomAnimals : TransactionModuleBase
|
public class RandomAnimals : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IMediaProvider _mediaProvider;
|
private readonly IMediaProvider _mediaProvider;
|
||||||
|
|
||||||
|
@ -16,64 +16,64 @@ namespace Geekbot.Bot.Commands.Randomness
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("panda", RunMode = RunMode.Async)]
|
[Command("panda", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random panda image")]
|
[Summary("Get a random panda image")]
|
||||||
public async Task Panda()
|
public async Task Panda()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Panda)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetPanda()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("croissant", RunMode = RunMode.Async)]
|
[Command("croissant", RunMode = RunMode.Async)]
|
||||||
[Alias("gipfeli")]
|
[Alias("gipfeli")]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random croissant image")]
|
[Summary("Get a random croissant image")]
|
||||||
public async Task Croissant()
|
public async Task Croissant()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Croissant)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetCrossant()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("pumpkin", RunMode = RunMode.Async)]
|
[Command("pumpkin", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random pumpkin image")]
|
[Summary("Get a random pumpkin image")]
|
||||||
public async Task Pumpkin()
|
public async Task Pumpkin()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Pumpkin)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetPumpkin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("squirrel", RunMode = RunMode.Async)]
|
[Command("squirrel", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random squirrel image")]
|
[Summary("Get a random squirrel image")]
|
||||||
public async Task Squirrel()
|
public async Task Squirrel()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Squirrel)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetSquirrel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("turtle", RunMode = RunMode.Async)]
|
[Command("turtle", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random turtle image")]
|
[Summary("Get a random turtle image")]
|
||||||
public async Task Turtle()
|
public async Task Turtle()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Turtle)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetTurtle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("penguin", RunMode = RunMode.Async)]
|
[Command("pinguin", RunMode = RunMode.Async)]
|
||||||
[Alias("pengu")]
|
[Alias("pingu")]
|
||||||
[Summary("Get a random penguin image")]
|
[Remarks(CommandCategories.Randomness)]
|
||||||
public async Task Penguin()
|
[Summary("Get a random pinguin image")]
|
||||||
|
public async Task Pinguin()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Penguin)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetPinguin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("fox", RunMode = RunMode.Async)]
|
[Command("fox", RunMode = RunMode.Async)]
|
||||||
|
[Remarks(CommandCategories.Randomness)]
|
||||||
[Summary("Get a random fox image")]
|
[Summary("Get a random fox image")]
|
||||||
public async Task Fox()
|
public async Task Fox()
|
||||||
{
|
{
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Fox)));
|
await ReplyAsync("", false, Eb(_mediaProvider.GetFox()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("dab", RunMode = RunMode.Async)]
|
private Embed Eb(string image)
|
||||||
[Summary("Get a random dab image")]
|
|
||||||
public async Task Dab()
|
|
||||||
{
|
|
||||||
await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Dab)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Embed Eb(string image)
|
|
||||||
{
|
{
|
||||||
return new EmbedBuilder {ImageUrl = image}.Build();
|
return new EmbedBuilder {ImageUrl = image}.Build();
|
||||||
}
|
}
|
91
Geekbot.net/Commands/Randomness/Ship.cs
Normal file
91
Geekbot.net/Commands/Randomness/Ship.cs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness
|
||||||
|
{
|
||||||
|
public class Ship : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Ship(IDatabase redis, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_redis = redis;
|
||||||
|
_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 = new Random().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";
|
||||||
|
return rate >= 80 ? "It's a match" : "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
Geekbot.net/Commands/Randomness/Slap.cs
Normal file
92
Geekbot.net/Commands/Randomness/Slap.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Randomness
|
||||||
|
{
|
||||||
|
public class Slap : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Slap(IErrorHandler errorHandler, IDatabase redis)
|
||||||
|
{
|
||||||
|
_errorHandler = errorHandler;
|
||||||
|
_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",
|
||||||
|
"cheese slice",
|
||||||
|
"critical 1",
|
||||||
|
"natural 20",
|
||||||
|
"mjölnir (aka mewmew)",
|
||||||
|
"kamehameha",
|
||||||
|
"copy of Twilight",
|
||||||
|
"med pack (get ready for the end boss)",
|
||||||
|
"derp",
|
||||||
|
"condom (used)",
|
||||||
|
"gremlin fed after midnight",
|
||||||
|
"wet baguette",
|
||||||
|
"exploding kitten",
|
||||||
|
"shiny piece of shit",
|
||||||
|
"mismatched pair of socks",
|
||||||
|
"horcrux",
|
||||||
|
"tuna",
|
||||||
|
"suggestion",
|
||||||
|
"teapot",
|
||||||
|
"candle",
|
||||||
|
"dictionary",
|
||||||
|
"powerless banhammer"
|
||||||
|
};
|
||||||
|
|
||||||
|
_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[new Random().Next(things.Count - 1)]}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,31 +3,30 @@ 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 Geekbot.net.Lib.ErrorHandling;
|
||||||
using Geekbot.Core.Database;
|
using Geekbot.net.Lib.Extensions;
|
||||||
using Geekbot.Core.ErrorHandling;
|
using Geekbot.net.Lib.Levels;
|
||||||
using Geekbot.Core.Extensions;
|
using StackExchange.Redis;
|
||||||
using Geekbot.Core.Levels;
|
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.User
|
namespace Geekbot.net.Commands.User
|
||||||
{
|
{
|
||||||
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 +40,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,7 +51,7 @@ namespace Geekbot.Bot.Commands.User
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
130
Geekbot.net/Commands/User/Karma.cs
Normal file
130
Geekbot.net/Commands/User/Karma.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Geekbot.net.Lib.Localization;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.User
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(dateTimeOffsetString) ? DateTimeOffset.Now.Subtract(new TimeSpan(7, 18, 0, 0)) : 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
149
Geekbot.net/Commands/User/Ranking/Rank.cs
Normal file
149
Geekbot.net/Commands/User/Ranking/Rank.cs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
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 Geekbot.net.Lib.Converters;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.User.Ranking
|
||||||
|
{
|
||||||
|
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}");
|
||||||
|
if (messageList.Length == 0)
|
||||||
|
{
|
||||||
|
await ReplyAsync($"No {type.ToLowerInvariant()} found on this server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var sortedList = messageList.OrderByDescending(e => e.Value).ToList();
|
||||||
|
var guildMessages = (int) sortedList.First().Value;
|
||||||
|
var theBot = sortedList.FirstOrDefault(e => e.Name.ToString().Equals(_client.CurrentUser.Id.ToString()));
|
||||||
|
if (!string.IsNullOrEmpty(theBot.Name))
|
||||||
|
{
|
||||||
|
sortedList.Remove(theBot);
|
||||||
|
}
|
||||||
|
if (type == "Messages") sortedList.RemoveAt(0);
|
||||||
|
|
||||||
|
var highscoreUsers = new Dictionary<RankUserPolyfillDto, 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 RankUserPolyfillDto
|
||||||
|
{
|
||||||
|
Username = guildUser.Username,
|
||||||
|
Discriminator = guildUser.Discriminator
|
||||||
|
}, (int) user.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
highscoreUsers.Add(new RankUserPolyfillDto
|
||||||
|
{
|
||||||
|
Id = user.Name
|
||||||
|
}, (int) user.Value);
|
||||||
|
failedToRetrieveUser = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
listLimiter++;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning(LogSource.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
namespace Geekbot.Core.Highscores
|
namespace Geekbot.net.Commands.User.Ranking
|
||||||
{
|
{
|
||||||
public class HighscoreUserDto
|
internal class RankUserPolyfillDto
|
||||||
{
|
{
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public string Avatar { get; set; }
|
|
||||||
public string Discriminator { get; set; }
|
public string Discriminator { get; set; }
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
75
Geekbot.net/Commands/User/Stats.cs
Normal file
75
Geekbot.net/Commands/User/Stats.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Geekbot.net.Lib.Levels;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.User
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,12 +2,12 @@
|
||||||
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.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands.Utils
|
||||||
{
|
{
|
||||||
public class AvatarGetter : TransactionModuleBase
|
public class AvatarGetter : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -17,18 +17,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
70
Geekbot.net/Commands/Utils/Changelog/Changelog.cs
Normal file
70
Geekbot.net/Commands/Utils/Changelog/Changelog.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
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 Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils.Changelog
|
||||||
|
{
|
||||||
|
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<CommitDto>>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs
Normal file
11
Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils.Changelog
|
||||||
|
{
|
||||||
|
public class CommitAuthorDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public DateTimeOffset Date { get; set; }
|
||||||
|
}
|
||||||
|
}
|
7
Geekbot.net/Commands/Utils/Changelog/CommitDto.cs
Normal file
7
Geekbot.net/Commands/Utils/Changelog/CommitDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Commands.Utils.Changelog
|
||||||
|
{
|
||||||
|
public class CommitDto
|
||||||
|
{
|
||||||
|
public CommitInfoDto Commit { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs
Normal file
8
Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Geekbot.net.Commands.Utils.Changelog
|
||||||
|
{
|
||||||
|
public class CommitInfoDto
|
||||||
|
{
|
||||||
|
public CommitAuthorDto Author { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
40
Geekbot.net/Commands/Utils/Choose.cs
Normal file
40
Geekbot.net/Commands/Utils/Choose.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Localization;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils
|
||||||
|
{
|
||||||
|
public class Choose : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
|
||||||
|
public Choose(IErrorHandler errorHandler, ITranslationHandler translation)
|
||||||
|
{
|
||||||
|
_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 = new Random().Next(choicesArray.Length);
|
||||||
|
await ReplyAsync(string.Format(transDict["Choice"], choicesArray[choice]));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
Geekbot.net/Commands/Utils/Dice/Dice.cs
Normal file
115
Geekbot.net/Commands/Utils/Dice/Dice.cs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
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.Utils.Dice
|
||||||
|
{
|
||||||
|
public class Dice : ModuleBase
|
||||||
|
{
|
||||||
|
[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 > 144))
|
||||||
|
{
|
||||||
|
await ReplyAsync("A dice can't have more than 144 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 = new Random().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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
Geekbot.net/Commands/Utils/Dice/DiceTypeDto.cs
Normal file
10
Geekbot.net/Commands/Utils/Dice/DiceTypeDto.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Geekbot.net.Commands.Utils.Dice
|
||||||
|
{
|
||||||
|
internal class DiceTypeDto
|
||||||
|
{
|
||||||
|
public string DiceType { get; set; }
|
||||||
|
public int Times { get; set; }
|
||||||
|
public int Sides { get; set; }
|
||||||
|
public int Mod { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,31 @@
|
||||||
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;
|
||||||
|
using Geekbot.net.Lib.Converters;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands.Utils
|
||||||
{
|
{
|
||||||
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 +34,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,12 +3,12 @@ using System.Text;
|
||||||
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.net.Lib.ErrorHandling;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands.Utils
|
||||||
{
|
{
|
||||||
public class Help : TransactionModuleBase
|
public class Help : ModuleBase
|
||||||
{
|
{
|
||||||
private readonly IErrorHandler _errorHandler;
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
|
||||||
|
@ -18,6 +18,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 +28,13 @@ 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("✅"));
|
await Context.Message.AddReactionAsync(new Emoji("✅"));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,26 +5,30 @@ 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 Geekbot.net.Lib.ErrorHandling;
|
||||||
using Geekbot.Core.Extensions;
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils
|
namespace Geekbot.net.Commands.Utils
|
||||||
{
|
{
|
||||||
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 +36,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 +71,7 @@ namespace Geekbot.Bot.Commands.Utils
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await _errorHandler.HandleCommandException(e, Context);
|
_errorHandler.HandleCommandException(e, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.Utils
|
||||||
{
|
{
|
||||||
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!");
|
180
Geekbot.net/Commands/Utils/Poll/Poll.cs
Normal file
180
Geekbot.net/Commands/Utils/Poll/Poll.cs
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
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 Geekbot.net.Lib.Converters;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Extensions;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils.Poll
|
||||||
|
{
|
||||||
|
[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 PollDataDto
|
||||||
|
{
|
||||||
|
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 PollDataDto GetCurrentPoll()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentPoll = _redis.HashGet($"{Context.Guild.Id}:Polls", Context.Channel.Id);
|
||||||
|
return JsonConvert.DeserializeObject<PollDataDto>(currentPoll.ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new PollDataDto();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<PollResultDto>> GetPollResults(PollDataDto poll)
|
||||||
|
{
|
||||||
|
var message = (IUserMessage) await Context.Channel.GetMessageAsync(poll.MessageId);
|
||||||
|
var results = new List<PollResultDto>();
|
||||||
|
foreach (var r in message.Reactions)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var option = int.Parse(r.Key.Name.ToCharArray()[0].ToString());
|
||||||
|
var result = new PollResultDto
|
||||||
|
{
|
||||||
|
Option = poll.Options[option - 1],
|
||||||
|
VoteCount = r.Value.ReactionCount
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
results.Sort((x, y) => y.VoteCount.CompareTo(x.VoteCount));
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Geekbot.net/Commands/Utils/Poll/PollDataDto.cs
Normal file
13
Geekbot.net/Commands/Utils/Poll/PollDataDto.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils.Poll
|
||||||
|
{
|
||||||
|
internal class PollDataDto
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
8
Geekbot.net/Commands/Utils/Poll/PollResultDto.cs
Normal file
8
Geekbot.net/Commands/Utils/Poll/PollResultDto.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Geekbot.net.Commands.Utils.Poll
|
||||||
|
{
|
||||||
|
internal class PollResultDto
|
||||||
|
{
|
||||||
|
public string Option { get; set; }
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
239
Geekbot.net/Commands/Utils/Quote/Quote.cs
Normal file
239
Geekbot.net/Commands/Utils/Quote/Quote.cs
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Geekbot.net.Lib;
|
||||||
|
using Geekbot.net.Lib.ErrorHandling;
|
||||||
|
using Geekbot.net.Lib.Polyfills;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Commands.Utils.Quote
|
||||||
|
{
|
||||||
|
[Group("quote")]
|
||||||
|
public class Quote : ModuleBase
|
||||||
|
{
|
||||||
|
private readonly IErrorHandler _errorHandler;
|
||||||
|
private readonly IDatabase _redis;
|
||||||
|
|
||||||
|
public Quote(IDatabase redis, IErrorHandler errorHandler)
|
||||||
|
{
|
||||||
|
_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");
|
||||||
|
if (!randomQuotes.Any())
|
||||||
|
{
|
||||||
|
await ReplyAsync("This server doesn't seem to have any quotes yet. You can add a quote with `!quote save @user` or `!quote save <messageId>`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var randomNumber = new Random().Next(randomQuotes.Length - 1);
|
||||||
|
var randomQuote = randomQuotes[randomNumber];
|
||||||
|
var quote = JsonConvert.DeserializeObject<QuoteObjectDto>(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);
|
||||||
|
if (lastMessage == null) return;
|
||||||
|
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);
|
||||||
|
if (lastMessage == null) return;
|
||||||
|
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<QuoteObjectDto>(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)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var list = Context.Channel.GetMessagesAsync().Flatten();
|
||||||
|
return await list.FirstOrDefault(msg =>
|
||||||
|
msg.Author.Id == user.Id &&
|
||||||
|
msg.Embeds.Count == 0 &&
|
||||||
|
msg.Id != Context.Message.Id &&
|
||||||
|
!msg.Content.ToLower().StartsWith("!"));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await ReplyAsync($"No quoteable message have been sent by {user.Username} in this channel");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmbedBuilder QuoteBuilder(QuoteObjectDto quote, int id = 0)
|
||||||
|
{
|
||||||
|
var user = Context.Client.GetUserAsync(quote.UserId).Result ?? new UserPolyfillDto { Username = "Unknown User" };
|
||||||
|
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 QuoteObjectDto CreateQuoteObject(IMessage message)
|
||||||
|
{
|
||||||
|
string image;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
image = message.Attachments.First().Url;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
image = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QuoteObjectDto
|
||||||
|
{
|
||||||
|
UserId = message.Author.Id,
|
||||||
|
Time = message.Timestamp.DateTime,
|
||||||
|
Quote = message.Content,
|
||||||
|
Image = image
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Geekbot.Bot.Commands.Utils.Quote
|
namespace Geekbot.net.Commands.Utils.Quote
|
||||||
{
|
{
|
||||||
internal class QuoteObjectDto
|
internal class QuoteObjectDto
|
||||||
{
|
{
|
87
Geekbot.net/Geekbot.net.csproj
Executable file
87
Geekbot.net/Geekbot.net.csproj
Executable file
|
@ -0,0 +1,87 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<ApplicationIcon>derp.ico</ApplicationIcon>
|
||||||
|
<Version>3.7.0</Version>
|
||||||
|
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||||
|
<Version Condition=" '$(VersionSuffix)' != '' ">$(Version)-$(VersionSuffix)</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="CommandLineParser" Version="2.2.1" />
|
||||||
|
<PackageReference Include="Discord.Net">
|
||||||
|
<Version>2.0.0-beta</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.33.0.1202" />
|
||||||
|
<PackageReference Include="HtmlAgilityPack" Version="1.8.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.1" />
|
||||||
|
<PackageReference Include="MtgApiManager.Lib" Version="1.1.0" />
|
||||||
|
<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="11.0.2" />
|
||||||
|
<PackageReference Include="NLog" Version="4.5.3" />
|
||||||
|
<PackageReference Include="NLog.Config" Version="4.5.3" />
|
||||||
|
<PackageReference Include="Overwatch.Net" Version="3.1.0" />
|
||||||
|
<PackageReference Include="PokeApi.NET" Version="1.1.0" />
|
||||||
|
<PackageReference Include="SharpRaven" Version="2.3.2" />
|
||||||
|
<PackageReference Include="StackExchange.Redis">
|
||||||
|
<Version>1.2.6</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="SumoLogic.Logging.NLog" Version="1.0.0.2" />
|
||||||
|
<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.7" />
|
||||||
|
</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\turtles">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\pinguins">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Storage\foxes">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Lib\Localization\Translations.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Lib\Converters\MtgManaEmojis.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WikipediaApi\WikipediaApi.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
214
Geekbot.net/Handlers.cs
Normal file
214
Geekbot.net/Handlers.cs
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using Geekbot.net.Lib.ReactionListener;
|
||||||
|
using Geekbot.net.Lib.UserRepository;
|
||||||
|
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 IReactionListener _reactionListener;
|
||||||
|
|
||||||
|
public Handlers(IDiscordClient client, IGeekbotLogger logger, IDatabase redis, IServiceProvider servicesProvider, CommandService commands, IUserRepository userRepository, IReactionListener reactionListener)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_logger = logger;
|
||||||
|
_redis = redis;
|
||||||
|
_servicesProvider = servicesProvider;
|
||||||
|
_commands = commands;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
_reactionListener = reactionListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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.StartsWith("hui"))
|
||||||
|
{
|
||||||
|
message.Channel.SendMessageAsync("hui!!!");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
if (lowCaseMsg.StartsWith("ping ") || lowCaseMsg.Equals("ping"))
|
||||||
|
{
|
||||||
|
bool.TryParse(_redis.HashGet($"{((SocketGuildChannel) message.Channel).Guild.Id}:Settings", "ping"), out var allowPings);
|
||||||
|
if (allowPings)
|
||||||
|
{
|
||||||
|
message.Channel.SendMessageAsync("pong");
|
||||||
|
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);
|
||||||
|
_logger.Information(LogSource.Command,
|
||||||
|
context.Message.Content.Split(" ")[0].Replace("!", ""),
|
||||||
|
SimpleConextConverter.ConvertContext(context));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(LogSource.Geekbot, "Failed to Process Message", e);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateStats(SocketMessage message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (message == null) return Task.CompletedTask;
|
||||||
|
if (message.Channel.Name.StartsWith('@'))
|
||||||
|
{
|
||||||
|
_logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message));
|
||||||
|
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(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(LogSource.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(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(LogSource.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(LogSource.Geekbot, "Failed to send leave message", e);
|
||||||
|
}
|
||||||
|
_logger.Information(LogSource.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(LogSource.Geekbot, "Failed to send delete message...", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reactions
|
||||||
|
//
|
||||||
|
|
||||||
|
public Task ReactionAdded(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||||
|
{
|
||||||
|
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||||
|
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||||
|
_reactionListener.GiveRole(socketMessageChannel, reaction);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ReactionRemoved(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||||
|
{
|
||||||
|
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||||
|
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||||
|
_reactionListener.RemoveRole(socketMessageChannel, reaction);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
Geekbot.net/Lib/Audio/AudioUtils.cs
Normal file
96
Geekbot.net/Lib/Audio/AudioUtils.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using Discord.Audio;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Audio
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
15
Geekbot.net/Lib/Audio/IAudioUtils.cs
Normal file
15
Geekbot.net/Lib/Audio/IAudioUtils.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Discord.Audio;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Audio
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
12
Geekbot.net/Lib/Clients/IMalClient.cs
Normal file
12
Geekbot.net/Lib/Clients/IMalClient.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MyAnimeListSharp.Core;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Clients
|
||||||
|
{
|
||||||
|
public interface IMalClient
|
||||||
|
{
|
||||||
|
bool IsLoggedIn();
|
||||||
|
Task<AnimeEntry> GetAnime(string query);
|
||||||
|
Task<MangaEntry> GetManga(string query);
|
||||||
|
}
|
||||||
|
}
|
70
Geekbot.net/Lib/Clients/MalClient.cs
Normal file
70
Geekbot.net/Lib/Clients/MalClient.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using MyAnimeListSharp.Auth;
|
||||||
|
using MyAnimeListSharp.Core;
|
||||||
|
using MyAnimeListSharp.Facade.Async;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Clients
|
||||||
|
{
|
||||||
|
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(LogSource.Geekbot, "Logged in to MAL");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_logger.Debug(LogSource.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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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 static 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";
|
||||||
|
}
|
||||||
|
}
|
16
Geekbot.net/Lib/Constants.cs
Normal file
16
Geekbot.net/Lib/Constants.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib
|
||||||
|
{
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public const string Name = "Geekbot";
|
||||||
|
|
||||||
|
public static string BotVersion()
|
||||||
|
{
|
||||||
|
return typeof(Program).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public const double ApiVersion = 1;
|
||||||
|
}
|
||||||
|
}
|
93
Geekbot.net/Lib/Converters/EmojiConverter.cs
Normal file
93
Geekbot.net/Lib/Converters/EmojiConverter.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Converters
|
||||||
|
{
|
||||||
|
public class EmojiConverter : IEmojiConverter
|
||||||
|
{
|
||||||
|
public string NumberToEmoji(int number)
|
||||||
|
{
|
||||||
|
if (number == 10)
|
||||||
|
{
|
||||||
|
return "🔟";
|
||||||
|
}
|
||||||
|
var emojiMap = new[]
|
||||||
|
{
|
||||||
|
":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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Geekbot.net/Lib/Converters/IEmojiConverter.cs
Normal file
8
Geekbot.net/Lib/Converters/IEmojiConverter.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Geekbot.net.Lib.Converters
|
||||||
|
{
|
||||||
|
public interface IEmojiConverter
|
||||||
|
{
|
||||||
|
string NumberToEmoji(int number);
|
||||||
|
string TextToEmoji(string text);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Geekbot.Core.Converters
|
namespace Geekbot.net.Lib.Converters
|
||||||
{
|
{
|
||||||
public interface IMtgManaConverter
|
public interface IMtgManaConverter
|
||||||
{
|
{
|
33
Geekbot.net/Lib/Converters/MtgManaConverter.cs
Normal file
33
Geekbot.net/Lib/Converters/MtgManaConverter.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Utf8Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Converters
|
||||||
|
{
|
||||||
|
public class MtgManaConverter : IMtgManaConverter
|
||||||
|
{
|
||||||
|
private Dictionary<string, string> _manaDict;
|
||||||
|
|
||||||
|
public MtgManaConverter()
|
||||||
|
{
|
||||||
|
// these emotes can be found at https://discord.gg/bz8HyA7
|
||||||
|
var mtgEmojis = File.ReadAllText(Path.GetFullPath("./Lib/Converters/MtgManaEmojis.json"));
|
||||||
|
_manaDict = JsonSerializer.Deserialize<Dictionary<string, string>>(mtgEmojis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ConvertMana(string mana)
|
||||||
|
{
|
||||||
|
var rgx = Regex.Matches(mana, @"(\{(.*?)\})");
|
||||||
|
foreach (Match manaTypes in rgx)
|
||||||
|
{
|
||||||
|
var m = _manaDict.GetValueOrDefault(manaTypes.Value);
|
||||||
|
if (!string.IsNullOrEmpty(m))
|
||||||
|
{
|
||||||
|
mana = mana.Replace(manaTypes.Value, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mana;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
Geekbot.net/Lib/Converters/MtgManaEmojis.json
Normal file
50
Geekbot.net/Lib/Converters/MtgManaEmojis.json
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"{0}": "<:mtg_0:415216130043412482>",
|
||||||
|
"{1}": "<:mtg_1:415216130253389835>",
|
||||||
|
"{2}": "<:mtg_2:415216130031091713>",
|
||||||
|
"{3}": "<:mtg_3:415216130467037194>",
|
||||||
|
"{4}": "<:mtg_4:415216130026635295>",
|
||||||
|
"{5}": "<:mtg_5:415216130492203008>",
|
||||||
|
"{6}": "<:mtg_6:415216130458779658>",
|
||||||
|
"{7}": "<:mtg_7:415216130190475265>",
|
||||||
|
"{8}": "<:mtg_8:415216130517630986>",
|
||||||
|
"{9}": "<:mtg_9:415216130500722689>",
|
||||||
|
"{10": "<:mtg_10:415216130450391051>",
|
||||||
|
"{11}": "<:mtg_11:415216130811101185>",
|
||||||
|
"{12}": "<:mtg_12:415216130525888532>",
|
||||||
|
"{13}": "<:mtg_13:415216130517631000>",
|
||||||
|
"{14}": "<:mtg_14:415216130165178370>",
|
||||||
|
"{15}": "<:mtg_15:415216130576089108>",
|
||||||
|
"{16}": "<:mtg_16:415216130358247425>",
|
||||||
|
"{17}": "<:mtg_17:415216130601517056>",
|
||||||
|
"{18}": "<:mtg_18:415216130462842891>",
|
||||||
|
"{19}": "<:mtg_19:415216130614099988>",
|
||||||
|
"{20}": "<:mtg_20:415216130656043038>",
|
||||||
|
"{W}": "<:mtg_white:415216131515744256>",
|
||||||
|
"{U}": "<:mtg_blue:415216130521694209>",
|
||||||
|
"{B}": "<:mtg_black:415216130873884683>",
|
||||||
|
"{R}": "<:mtg_red:415216131322806272>",
|
||||||
|
"{G}": "<:mtg_green:415216131180331009>",
|
||||||
|
"{S}": "<:mtg_s:415216131293446144>",
|
||||||
|
"{T}": "<:mtg_tap:415258392727257088>",
|
||||||
|
"{C}": "<:mtg_colorless:415216130706374666>",
|
||||||
|
"{2/W}": "<:mtg_2w:415216130446065664>",
|
||||||
|
"{2/U}": "<:mtg_2u:415216130429550592>",
|
||||||
|
"{2/B}": "<:mtg_2b:415216130160984065>",
|
||||||
|
"{2/R}": "<:mtg_2r:415216130454716436>",
|
||||||
|
"{2/G}": "<:mtg_2g:415216130420899840>",
|
||||||
|
"{W/U}": "<:mtg_wu:415216130970484736>",
|
||||||
|
"{W/B}": "<:mtg_wb:415216131222011914>",
|
||||||
|
"{U/R}": "<:mtg_ur:415216130962096128>",
|
||||||
|
"{U/B}": "<:mtg_ub:415216130865758218>",
|
||||||
|
"{R/W}": "<:mtg_rw:415216130878210057>",
|
||||||
|
"{G/W}": "<:mtg_gw:415216130567962646>",
|
||||||
|
"{G/U}": "<:mtg_gu:415216130739666945>",
|
||||||
|
"{B/R}": "<:mtg_br:415216130580283394>",
|
||||||
|
"{B/G}": "<:mtg_bg:415216130781609994>",
|
||||||
|
"{U/P}": "<:mtg_up:415216130861432842>",
|
||||||
|
"{R/P}": "<:mtg_rp:415216130597322783>",
|
||||||
|
"{G/P}": "<:mtg_gp:415216130760769546>",
|
||||||
|
"{W/P}": "<:mtg_wp:415216131541041172>",
|
||||||
|
"{B/P}": "<:mtg_bp:415216130664169482>"
|
||||||
|
}
|
102
Geekbot.net/Lib/ErrorHandling/ErrorHandler.cs
Normal file
102
Geekbot.net/Lib/ErrorHandling/ErrorHandler.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.Net;
|
||||||
|
using Geekbot.net.Lib.Localization;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using SharpRaven;
|
||||||
|
using SharpRaven.Data;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.ErrorHandling
|
||||||
|
{
|
||||||
|
public class ErrorHandler : IErrorHandler
|
||||||
|
{
|
||||||
|
private readonly IGeekbotLogger _logger;
|
||||||
|
private readonly ITranslationHandler _translation;
|
||||||
|
private readonly IRavenClient _raven;
|
||||||
|
private readonly bool _errorsInChat;
|
||||||
|
|
||||||
|
public ErrorHandler(IGeekbotLogger logger, ITranslationHandler translation, bool errorsInChat)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_translation = translation;
|
||||||
|
_errorsInChat = errorsInChat;
|
||||||
|
|
||||||
|
var sentryDsn = Environment.GetEnvironmentVariable("SENTRY");
|
||||||
|
if (!string.IsNullOrEmpty(sentryDsn))
|
||||||
|
{
|
||||||
|
_raven = new RavenClient(sentryDsn) { Release = Constants.BotVersion() };
|
||||||
|
_logger.Information(LogSource.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);
|
||||||
|
if (e.Message.Contains("50007")) return;
|
||||||
|
if (e.Message.Contains("50013")) return;
|
||||||
|
_logger.Error(LogSource.Geekbot, "An error ocured", e, errorObj);
|
||||||
|
if (!string.IsNullOrEmpty(errorMessage))
|
||||||
|
{
|
||||||
|
if (_errorsInChat)
|
||||||
|
{
|
||||||
|
var resStackTrace = string.IsNullOrEmpty(e.InnerException?.ToString()) ? e.StackTrace : e.InnerException?.ToString();
|
||||||
|
if (!string.IsNullOrEmpty(resStackTrace))
|
||||||
|
{
|
||||||
|
var maxLen = Math.Min(resStackTrace.Length, 1850);
|
||||||
|
context.Channel.SendMessageAsync($"{e.Message}\r\n```\r\n{resStackTrace.Substring(0, maxLen)}\r\n```");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Channel.SendMessageAsync(e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Channel.SendMessageAsync(errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
context.Channel.SendMessageAsync("Something went really really wrong here");
|
||||||
|
_logger.Error(LogSource.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
12
Geekbot.net/Lib/ErrorHandling/IErrorHandler.cs
Normal file
12
Geekbot.net/Lib/ErrorHandling/IErrorHandler.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.Net;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.ErrorHandling
|
||||||
|
{
|
||||||
|
public interface IErrorHandler
|
||||||
|
{
|
||||||
|
void HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def");
|
||||||
|
void HandleHttpException(HttpException e, ICommandContext context);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using Discord;
|
using Discord;
|
||||||
|
|
||||||
namespace Geekbot.Core.Extensions
|
namespace Geekbot.net.Lib.Extensions
|
||||||
{
|
{
|
||||||
public static class EmbedBuilderExtensions
|
public static class EmbedBuilderExtensions
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Geekbot.Core
|
namespace Geekbot.net.Lib
|
||||||
{
|
{
|
||||||
public enum GeekbotExitCode
|
public enum GeekbotExitCode : int
|
||||||
{
|
{
|
||||||
// General
|
// General
|
||||||
Clean = 0,
|
Clean = 0,
|
||||||
|
@ -8,11 +8,9 @@
|
||||||
|
|
||||||
// Geekbot Internals
|
// Geekbot Internals
|
||||||
TranslationsFailed = 201,
|
TranslationsFailed = 201,
|
||||||
KilledByApiCall = 210,
|
|
||||||
|
|
||||||
// Dependent Services
|
// Dependent Services
|
||||||
/* 301 not in use anymore (redis) */
|
RedisConnectionFailed = 301,
|
||||||
DatabaseConnectionFailed = 302,
|
|
||||||
|
|
||||||
// Discord Related
|
// Discord Related
|
||||||
CouldNotLogin = 401
|
CouldNotLogin = 401
|
7
Geekbot.net/Lib/Levels/ILevelCalc.cs
Normal file
7
Geekbot.net/Lib/Levels/ILevelCalc.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Geekbot.net.Lib.Levels
|
||||||
|
{
|
||||||
|
public interface ILevelCalc
|
||||||
|
{
|
||||||
|
int GetLevel(int experience);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Geekbot.Core.Levels
|
namespace Geekbot.net.Lib.Levels
|
||||||
{
|
{
|
||||||
public class LevelCalc : ILevelCalc
|
public class LevelCalc : ILevelCalc
|
||||||
{
|
{
|
||||||
private readonly int[] _levels;
|
private int[] _levels;
|
||||||
|
|
||||||
public LevelCalc()
|
public LevelCalc()
|
||||||
{
|
{
|
||||||
|
@ -20,9 +19,15 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
14
Geekbot.net/Lib/Localization/ITranslationHandler.cs
Normal file
14
Geekbot.net/Lib/Localization/ITranslationHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Discord.Commands;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Localization
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
156
Geekbot.net/Lib/Localization/TranslationHandler.cs
Normal file
156
Geekbot.net/Lib/Localization/TranslationHandler.cs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Geekbot.net.Lib.Logger;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using Utf8Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Localization
|
||||||
|
{
|
||||||
|
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(LogSource.Geekbot, "Loading Translations");
|
||||||
|
LoadTranslations();
|
||||||
|
LoadServerLanguages(clientGuilds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTranslations()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var translationFile = File.ReadAllText(Path.GetFullPath("./Lib/Localization/Translations.json"));
|
||||||
|
var rawTranslations = 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(LogSource.Geekbot, "Failed to load Translations", e);
|
||||||
|
Environment.Exit(GeekbotExitCode.TranslationsFailed.GetHashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(LogSource.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(LogSource.Geekbot, "No translations for command found", 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(LogSource.Geekbot, "No translations for command found", 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[]{ new HashEntry("Language", language) });
|
||||||
|
_serverLanguages[guildId] = language;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(LogSource.Geekbot, "Error while changing language", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GetSupportedLanguages()
|
||||||
|
{
|
||||||
|
return _supportedLanguages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
Geekbot.net/Lib/Localization/Translations.json
Normal file
100
Geekbot.net/Lib/Localization/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 within 24 hours",
|
||||||
|
"CHDE": ":red_circle: {0}, du chasch nid nomol es gliche rate innerhalb vo 24 stund"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
|
using Geekbot.net.Commands.Randomness.Cat;
|
||||||
|
|
||||||
namespace Geekbot.Core.Logger.Adapters
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public class DiscordLogger : IDiscordLogger
|
public class DiscordLogger : IDiscordLogger
|
||||||
{
|
{
|
74
Geekbot.net/Lib/Logger/GeekbotLogger.cs
Normal file
74
Geekbot.net/Lib/Logger/GeekbotLogger.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Logger
|
||||||
|
{
|
||||||
|
public class GeekbotLogger : IGeekbotLogger
|
||||||
|
{
|
||||||
|
private readonly bool _logAsJson;
|
||||||
|
private readonly NLog.Logger _logger;
|
||||||
|
private readonly JsonSerializerSettings _serializerSettings;
|
||||||
|
|
||||||
|
public GeekbotLogger(RunParameters runParameters, bool sumologicActive)
|
||||||
|
{
|
||||||
|
_logAsJson = sumologicActive || runParameters.LogJson;
|
||||||
|
_logger = LoggerFactory.CreateNLog(runParameters, sumologicActive);
|
||||||
|
_serializerSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
|
||||||
|
NullValueHandling = NullValueHandling.Include
|
||||||
|
};
|
||||||
|
Information(LogSource.Geekbot, "Using GeekbotLogger");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trace(LogSource source, string message, object extra = null)
|
||||||
|
{
|
||||||
|
_logger.Trace(CreateLogString("Trace", source, message, null, extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Debug(LogSource source, string message, object extra = null)
|
||||||
|
{
|
||||||
|
if (_logAsJson) _logger.Info(CreateLogString("Debug", source, message, null, extra));
|
||||||
|
else _logger.Debug(CreateLogString("Debug", source, message, null, extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Information(LogSource source, string message, object extra = null)
|
||||||
|
{
|
||||||
|
_logger.Info(CreateLogString("Information", source, message, null, extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null)
|
||||||
|
{
|
||||||
|
if (_logAsJson) _logger.Info(CreateLogString("Warning", source, message, stackTrace, extra));
|
||||||
|
else _logger.Warn(CreateLogString("Warning", source, message, stackTrace, extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Error(LogSource source, string message, Exception stackTrace, object extra = null)
|
||||||
|
{
|
||||||
|
if (_logAsJson) _logger.Info(CreateLogString("Error", source, message, stackTrace, extra));
|
||||||
|
else _logger.Error(stackTrace, CreateLogString("Error", source, message, stackTrace, extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateLogString(string type, LogSource source, string message, Exception stackTrace = null, object extra = null)
|
||||||
|
{
|
||||||
|
if (_logAsJson)
|
||||||
|
{
|
||||||
|
var logObject = new GeekbotLoggerObject
|
||||||
|
{
|
||||||
|
Timestamp = DateTime.Now,
|
||||||
|
Type = type,
|
||||||
|
Source = source,
|
||||||
|
Message = message,
|
||||||
|
StackTrace = stackTrace,
|
||||||
|
Extra = extra
|
||||||
|
};
|
||||||
|
return JsonConvert.SerializeObject(logObject, Formatting.None, _serializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source != LogSource.Message) return $"[{source}] - {message}";
|
||||||
|
|
||||||
|
var m = (MessageDto) extra;
|
||||||
|
return $"[{source}] - [{m?.Guild.Name} - {m?.Channel.Name}] {m?.User.Name}: {m?.Message.Content}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
|
|
||||||
namespace Geekbot.Core.Logger
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public interface IDiscordLogger
|
public interface IDiscordLogger
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Geekbot.Core.Logger
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public interface IGeekbotLogger
|
public interface IGeekbotLogger
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,5 @@ namespace Geekbot.Core.Logger
|
||||||
void Information(LogSource source, string message, object extra = null);
|
void Information(LogSource source, string message, object extra = null);
|
||||||
void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null);
|
void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null);
|
||||||
void Error(LogSource source, string message, Exception stackTrace, object extra = null);
|
void Error(LogSource source, string message, Exception stackTrace, object extra = null);
|
||||||
NLog.Logger GetNLogger();
|
|
||||||
bool LogAsJson();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
14
Geekbot.net/Lib/Logger/LogDto.cs
Normal file
14
Geekbot.net/Lib/Logger/LogDto.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Logger
|
||||||
|
{
|
||||||
|
public class GeekbotLoggerObject
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public LogSource Source { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public Exception StackTrace { get; set; }
|
||||||
|
public object Extra { get; set; }
|
||||||
|
}
|
||||||
|
}
|
20
Geekbot.net/Lib/Logger/LogSource.cs
Normal file
20
Geekbot.net/Lib/Logger/LogSource.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace Geekbot.net.Lib.Logger
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum LogSource
|
||||||
|
{
|
||||||
|
Geekbot,
|
||||||
|
Rest,
|
||||||
|
Gateway,
|
||||||
|
Discord,
|
||||||
|
Redis,
|
||||||
|
Message,
|
||||||
|
UserRepository,
|
||||||
|
Command,
|
||||||
|
Api,
|
||||||
|
Other
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,59 +5,62 @@ using NLog.Config;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using SumoLogic.Logging.NLog;
|
using SumoLogic.Logging.NLog;
|
||||||
|
|
||||||
namespace Geekbot.Core.Logger
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public class LoggerFactory
|
public class LoggerFactory
|
||||||
{
|
{
|
||||||
public static NLog.Logger CreateNLog(RunParameters runParameters)
|
public static NLog.Logger CreateNLog(RunParameters runParameters, bool sumologicActive)
|
||||||
{
|
{
|
||||||
var config = new LoggingConfiguration();
|
var config = new LoggingConfiguration();
|
||||||
var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(runParameters.SumologicEndpoint))
|
if (sumologicActive)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Logging Geekbot Logs to Sumologic");
|
Console.WriteLine("Logging Geekbot Logs to Sumologic");
|
||||||
config.LoggingRules.Add(
|
config.LoggingRules.Add(
|
||||||
new LoggingRule("*", minLevel, LogLevel.Fatal,
|
new LoggingRule("*", LogLevel.Debug, LogLevel.Fatal,
|
||||||
new SumoLogicTarget()
|
new SumoLogicTarget()
|
||||||
{
|
{
|
||||||
Url = runParameters.SumologicEndpoint,
|
Url = Environment.GetEnvironmentVariable("GEEKBOT_SUMO"),
|
||||||
SourceName = "GeekbotLogger",
|
SourceName = "GeekbotLogger",
|
||||||
Layout = "${message}",
|
Layout = "${message}",
|
||||||
UseConsoleLog = false,
|
UseConsoleLog = false,
|
||||||
OptimizeBufferReuse = true,
|
OptimizeBufferReuse = true,
|
||||||
Name = "Geekbot"
|
Name = "Geekbot",
|
||||||
|
AppendException = false
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
|
||||||
else if (runParameters.LogJson)
|
|
||||||
{
|
|
||||||
config.LoggingRules.Add(
|
|
||||||
new LoggingRule("*", minLevel, LogLevel.Fatal,
|
|
||||||
new ConsoleTarget
|
|
||||||
{
|
|
||||||
Name = "Console",
|
|
||||||
Encoding = Encoding.UTF8,
|
|
||||||
Layout = "${message}"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info;
|
||||||
config.LoggingRules.Add(
|
config.LoggingRules.Add(
|
||||||
new LoggingRule("*", minLevel, LogLevel.Fatal,
|
new LoggingRule("*", LogLevel.Info, LogLevel.Fatal,
|
||||||
new ColoredConsoleTarget
|
new ColoredConsoleTarget
|
||||||
{
|
{
|
||||||
Name = "Console",
|
Name = "Console",
|
||||||
Encoding = Encoding.UTF8,
|
Encoding = Encoding.UTF8,
|
||||||
Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}"
|
Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}"
|
||||||
}
|
})
|
||||||
)
|
);
|
||||||
);
|
|
||||||
|
config.LoggingRules.Add(
|
||||||
|
new LoggingRule("*", minLevel, LogLevel.Fatal,
|
||||||
|
new FileTarget
|
||||||
|
{
|
||||||
|
Name = "File",
|
||||||
|
Layout = "[${longdate} ${level}] ${message}",
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
LineEnding = LineEndingMode.Default,
|
||||||
|
MaxArchiveFiles = 30,
|
||||||
|
ArchiveNumbering = ArchiveNumberingMode.Date,
|
||||||
|
ArchiveEvery = FileArchivePeriod.Day,
|
||||||
|
ArchiveFileName = "./Logs/Archive/{#####}.log",
|
||||||
|
FileName = "./Logs/Geekbot.log"
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var loggerConfig = new LogFactory {Configuration = config};
|
var loggerConfig = new LogFactory { Configuration = config };
|
||||||
return loggerConfig.GetCurrentClassLogger();
|
return loggerConfig.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Geekbot.Core.Logger
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public class MessageDto
|
public class MessageDto
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
|
||||||
namespace Geekbot.Core.Logger
|
namespace Geekbot.net.Lib.Logger
|
||||||
{
|
{
|
||||||
public class SimpleConextConverter
|
public class SimpleConextConverter
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ namespace Geekbot.Core.Logger
|
||||||
{
|
{
|
||||||
Message = new MessageDto.MessageContent
|
Message = new MessageDto.MessageContent
|
||||||
{
|
{
|
||||||
Content = context.Message.Content, // Only when an error occurs, including for diagnostic reason
|
Content = context.Message.Content,
|
||||||
Id = context.Message.Id.ToString(),
|
Id = context.Message.Id.ToString(),
|
||||||
Attachments = context.Message.Attachments.Count,
|
Attachments = context.Message.Attachments.Count,
|
||||||
ChannelMentions = context.Message.MentionedChannelIds.Count,
|
ChannelMentions = context.Message.MentionedChannelIds.Count,
|
||||||
|
@ -25,23 +25,24 @@ namespace Geekbot.Core.Logger
|
||||||
},
|
},
|
||||||
Guild = new MessageDto.IdAndName
|
Guild = new MessageDto.IdAndName
|
||||||
{
|
{
|
||||||
Id = context.Guild?.Id.ToString(),
|
Id = context.Guild.Id.ToString(),
|
||||||
Name = context.Guild?.Name
|
Name = context.Guild.Name
|
||||||
},
|
},
|
||||||
Channel = new MessageDto.IdAndName
|
Channel = new MessageDto.IdAndName
|
||||||
{
|
{
|
||||||
Id = context.Channel?.Id.ToString() ?? context.User.Id.ToString(),
|
Id = context.Channel.Id.ToString(),
|
||||||
Name = context.Channel?.Name ?? "DM-Channel"
|
Name = context.Channel.Name
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static MessageDto ConvertSocketMessage(SocketMessage message, bool isPrivate = false)
|
public static MessageDto ConvertSocketMessage(SocketMessage message)
|
||||||
{
|
{
|
||||||
var channel = isPrivate ? null : (SocketGuildChannel) message.Channel;
|
var channel = (SocketGuildChannel) message.Channel;
|
||||||
return new MessageDto
|
return new MessageDto
|
||||||
{
|
{
|
||||||
Message = new MessageDto.MessageContent
|
Message = new MessageDto.MessageContent
|
||||||
{
|
{
|
||||||
|
Content = message.Content,
|
||||||
Id = message.Id.ToString(),
|
Id = message.Id.ToString(),
|
||||||
Attachments = message.Attachments.Count,
|
Attachments = message.Attachments.Count,
|
||||||
ChannelMentions = message.MentionedChannels.Count,
|
ChannelMentions = message.MentionedChannels.Count,
|
||||||
|
@ -60,8 +61,8 @@ namespace Geekbot.Core.Logger
|
||||||
},
|
},
|
||||||
Channel = new MessageDto.IdAndName
|
Channel = new MessageDto.IdAndName
|
||||||
{
|
{
|
||||||
Id = channel?.Id.ToString() ?? message.Author.Id.ToString(),
|
Id = channel?.Id.ToString(),
|
||||||
Name = channel?.Name ?? "DM-Channel"
|
Name = channel?.Name
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Geekbot.Core.Logger;
|
using Geekbot.net.Lib.Logger;
|
||||||
|
|
||||||
namespace Geekbot.Core.Media
|
namespace Geekbot.net.Lib.Media
|
||||||
{
|
{
|
||||||
public class FortunesProvider : IFortunesProvider
|
internal class FortunesProvider : IFortunesProvider
|
||||||
{
|
{
|
||||||
private readonly string[] _fortuneArray;
|
private readonly string[] _fortuneArray;
|
||||||
private readonly int _totalFortunes;
|
private readonly int _totalFortunes;
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Geekbot.Core.Media
|
namespace Geekbot.net.Lib.Media
|
||||||
{
|
{
|
||||||
public interface IFortunesProvider
|
public interface IFortunesProvider
|
||||||
{
|
{
|
14
Geekbot.net/Lib/Media/IMediaProvider.cs
Normal file
14
Geekbot.net/Lib/Media/IMediaProvider.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Geekbot.net.Lib.Media
|
||||||
|
{
|
||||||
|
public interface IMediaProvider
|
||||||
|
{
|
||||||
|
string GetCheckem();
|
||||||
|
string GetPanda();
|
||||||
|
string GetCrossant();
|
||||||
|
string GetSquirrel();
|
||||||
|
string GetPumpkin();
|
||||||
|
string GetTurtle();
|
||||||
|
string GetPinguin();
|
||||||
|
string GetFox();
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue