commit
98edb33673
360
.gitignore
vendored
360
.gitignore
vendored
@ -1,3 +1,85 @@
|
||||
#Manually added files
|
||||
|
||||
src/NadekoBot/credentials.json
|
||||
src/NadekoBot/data/NadekoBot.db
|
||||
src/NadekoBot/data/musicdata
|
||||
|
||||
# Created by https://www.gitignore.io/api/visualstudio,visualstudiocode,windows,linux,macos
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
|
||||
|
||||
### Windows ###
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
|
||||
### macOS ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
@ -6,26 +88,154 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.pfx
|
||||
obj/
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
**/Bin/Release/
|
||||
**/Bin/PRIVATE/
|
||||
!**/Bin/Debug/opus.dll
|
||||
!**/Bin/Debug/libsodium.dll
|
||||
!**/Bin/Debug/Nito.AsyncEx.Enlightenment.dll
|
||||
!**/Bin/Debug/Nito.AsyncEx.dll
|
||||
!**/Bin/Debug/WebSocket4Net.dll
|
||||
!**/Bin/Debug/sqlite3.dll
|
||||
!**/Bin/Debug/credentials_example.json
|
||||
NadekoBot/bin/debug/*.*
|
||||
NadekoBot/bin/debug/data/permissions
|
||||
NadekoBot/bin/debug/data/incidents
|
||||
NadekoBot/bin/debug/data/musicdata
|
||||
NadekoBot/bin/NadekoRelease/*.*
|
||||
!NadekoBot/bin/Debug/data/currency_images/*
|
||||
Tests/bin
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
@ -35,11 +245,109 @@ Tests/bin
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
NadekoBot/bin/Debug/data/nadekobot.sqlite
|
||||
NadekoBot/bin/Debug/data/config.json
|
||||
NadekoBot/bin/Debug/data/ServerSpecificConfigs.json
|
||||
NadekoBot.sln.iml
|
||||
.idea/workspace.xml
|
||||
.idea/vcs.xml
|
||||
.idea/modules.xml
|
||||
NadekoBot/bin/Debug/data/config_xnaas.json
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/
|
||||
|
||||
### VisualStudio Patch ###
|
||||
build/
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +1,4 @@
|
||||
[submodule "discord.net"]
|
||||
path = discord.net
|
||||
url = git://github.com/kwoth/discord.net.git
|
||||
[submodule "ffmpeg-installer"]
|
||||
path = ffmpeg-installer
|
||||
url = https://github.com/kwoth/ffmpeg-installer
|
||||
url = https://github.com/kwoth/discord.net
|
||||
branch = dev
|
||||
|
@ -1,112 +0,0 @@
|
||||
________________________________________________________________________________
|
||||
*Thanks to @Flatbread and Mirai for making this guide*
|
||||
________________________________________________________________________________
|
||||
|
||||
### Setting Up NadekoBot on Windows
|
||||
#### Prerequisites
|
||||
- 1) [NET Framework][NET Framework] 4.5.2 (or 4.6)
|
||||
- 2) [FFMPEG][FFMPEG]
|
||||
- 3) Google Account
|
||||
- 4) Soundcloud Account (if you want soundcloud support)
|
||||
- 5) [7zip][7zip] (or whatever you are using, WinRar)
|
||||
- 6) [Notepad++][Notepad++]
|
||||
|
||||
####Guide:
|
||||
|
||||
- Create a folder, name it `Nadeko`.
|
||||
- Head to [Releases][Releases]* and download `WINDOWS.-.nadeupdater.7z`.
|
||||
- Copy `WINDOWS.-.nadeupdater.7z` to the `Nadeko` (folder we created before) and extract everything.
|
||||
- You will see a file `NadekoUpdater.bat ` and a folder `publish ` after extraction.
|
||||
- Run/Launch/Open the file `NadekoUpdater.bat ` and you will see it running in cmd.exe asking you with **3 options** *1-3*.
|
||||
- 1) Stable release - current stable release, but might not contain all the newest Nadeko updates.
|
||||
- 2) Newest release - release with all features/upgrades.
|
||||
- 3) Exit
|
||||
- Press `2` on your keyboard and hit `Enter`. Type `y` and hit `Enter` again. Downloading might take a while, so just be patient and wait. When download is done, press `3` on your keyboard and close the updater.
|
||||
- You should have a new folder named `NadekoBot` inside the `Nadeko` folder we previously created.
|
||||
|
||||
####Creating DiscordBot application
|
||||
- Go to [DiscordApp][DiscordApp].
|
||||
- Log in with your Discord account.
|
||||
- On the left side, press `New Application`.
|
||||
- Fill out the `App Name` (your bot's name, in this case), put the image you want, and add an app description(optional).
|
||||
- Create the application.
|
||||
- Once the application is created, click on `Create a Bot User` and confirm it.
|
||||
- Keep this window open for now.
|
||||
|
||||
####Setting up Credentials.json file
|
||||
- In our `NadekoBot` folder you should have `.json` file named `credentials_example.json`. (Note: If you do not see a **.json** after `credentials_example.json `, do not add the `**.json**`. You most likely have `"Hide file extensions"` enabled.)
|
||||
- Rename `credentials_example.json` to `credentials.json`.
|
||||
- Open the file with your [Notepad++][Notepad++].
|
||||
- In there you will see fields like `Token`, `ClientId`, `BotId`, `OwnerIDs`.
|
||||
- In your [DiscordApp][DiscordApp], under `Bot User` part, you will see the `Token:click to reveal` part, click to reveal it.
|
||||
- Copy your bot's token, and put it between `" "` in your `credentials.json` file.
|
||||
- Copy `Client ID` and replace it with the example one in your `credentials.json`.
|
||||
- Copy `Bot ID` and replace it with the example one in your `credentials.json`.
|
||||
- Save your `credentials.json` but keep it open. We need to put your `User ID` and owner.
|
||||
|
||||
####Inviting your bot to your server [Invite Guide][Invite Guide]
|
||||
- Create a new server in Discord.
|
||||
- Copy your `Client ID` from your [DiscordApp][DiscordApp].
|
||||
- Replace `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`.
|
||||
- Link should look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID**&scope=bot&permissions=66186303`.
|
||||
- Go to newly created link and pick the server we created, and click `Authorize`.
|
||||
- Bot should be added to your server.
|
||||
|
||||
####Starting the bot
|
||||
- Enter your `NadekoBot` folder that should be (hopefully) in your `Nadeko` folder.
|
||||
- Run `NadekoBot.exe` (Note: There is `NadekoBot.exe` and `NadekoBot.exe.config`, dont run the second one)
|
||||
- Your bot should now be online in the server we added him to.
|
||||
- Note: Your bot will be offline in case you close `NadekoBot.exe`.
|
||||
|
||||
####Setting up OwnerIds:
|
||||
- In the server where your bot is, in a text channel, type `.uid`
|
||||
- Your `User ID` should show, copy it.
|
||||
- Close `NadekoBot.exe`
|
||||
- Replace your `User ID` in the `credentials.json` between `[ ]` and save the changes.
|
||||
- Run `NadekoBot.exe` again.
|
||||
- Now you are the bot owner.
|
||||
- You can add `User IDs` from the other users by separating IDs with a comma if you want to have more owners.
|
||||
|
||||
`*Alternatively, you can download nadekobot from [Releases][Releases] and extract the zip yourself. That is what updater does, except it makes it easier for you to update because it doesn't overwrite important files. If you are downloading releases you will have to be careful about your config, credentials, and other files you edited in order to preserve your data every time you update.`
|
||||
|
||||
________________________________________________________________________________
|
||||
|
||||
#### Setting Up NadekoBot For Music
|
||||
##### Prerequisites
|
||||
- 1) [FFMPEG][FFMPEG] installed.
|
||||
- 2) Setting up API keys.
|
||||
|
||||
- Follow these steps on how to setup Google API keys:
|
||||
- Go to [Google Console][Google Console] and log in.
|
||||
- Create a new project (name does not matter). Once the project is created, go into "Enable and manage APIs."
|
||||
- Under the "Other Popular APIs" section, enable `URL Shortener API` and `Custom Search Api`. Under the `YouTube APIs` section, enable `YouTube Data API`.
|
||||
- On the left tab, access `Credentials`. Click `Create Credentials` button. Click on `API Key`, and then `Server Key` in the new window that appears. Enter in a name for the `Server Key`. A new window will appear with your `Google API key`.
|
||||
- Copy the key.
|
||||
- Open up `credentials.json`.
|
||||
- For `"GoogleAPIKey"`, fill in with the new key we copied.
|
||||
- Follow these steps on how to setup Soundcloud API key:
|
||||
- Go to [Soundcloud][Soundcloud].
|
||||
- Enter a name for the app and create it.
|
||||
- You will see a page with the title of your app, and a field labeled `Client ID`. Copy the ID.
|
||||
- In `credentials.json`, fill in `"SoundcloudClientID"` with the copied ID.
|
||||
- Restart your computer.
|
||||
|
||||
##### Prerequisites for manual `ffmpeg` setup:
|
||||
**Do this step in case you were not able to install `ffmpeg` with the installer.**
|
||||
- Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide)
|
||||
- Download FFMPEG through the link https://ffmpeg.zeranoe.com/builds/ (download static build)
|
||||
- Extract it using `7zip` and place the folder `ffmpeg-xxxxx-git-xxxxx-xxxx-static` inside **C:\ffmpeg**
|
||||
- Before proceeding, check out this gif to set up `ffmpeg` PATH correctly http://i.imgur.com/aR5l1Hn.gif *(thanks to PooPeePants#7135)*
|
||||
- Go to My Computer, right click and select Properties. On the left tab, select Advanced System Settings. Under the Advanced tab, select Environmental Variables near the bottom. One of the variables should be called "Path". Add a semi-colon (;) to the end followed by your FFMPEG's **bin** install location (**for example C:\ffmpeg\ffmpeg-xxxxx-git-xxxxx-xxxx-static\bin**). Save and close.
|
||||
- Setup your API keys as explained above.
|
||||
- Restart your computer.
|
||||
|
||||
[NET Framework]: https://www.microsoft.com/en-us/download/details.aspx?id=48130
|
||||
[FFMPEG]: https://github.com/Soundofdarkness/FFMPEG-Installer
|
||||
[7zip]: http://www.7-zip.org/download.html
|
||||
[Releases]: //github.com/Kwoth/NadekoUpdater/releases/tag/v1.0
|
||||
[DiscordApp]: https://discordapp.com/developers/applications/me
|
||||
[Notepad++]: https://notepad-plus-plus.org/
|
||||
[Invite Guide]: http://discord.kongslien.net/guide.html
|
||||
[Google Console]: https://console.developers.google.com
|
||||
[Soundcloud]: https://soundcloud.com/you/apps/new
|
@ -1,54 +0,0 @@
|
||||
## Docker guide with digitalocean
|
||||
|
||||
#####Prerequisites:
|
||||
- Digital ocean account (you can use my [reflink][reflink] to support the project and get 10$ after you register)
|
||||
- [PuTTY][PuTTY]
|
||||
- A bot account - follow this [guide][guide]
|
||||
- $5
|
||||
- Common sense
|
||||
|
||||
#####Guide
|
||||
- Click on the create droplet button
|
||||
![img](http://i.imgur.com/g2ayOcC.png)
|
||||
|
||||
- Pick one click apps and select docker on 14.04
|
||||
|
||||
![img](http://imgur.com/065Xkme.png)
|
||||
|
||||
- Pick any droplet size you want (5$ will work ok-ish on a few servers)
|
||||
- Pick location closest to your discord server's location
|
||||
- Pick a hostname
|
||||
![img](http://imgur.com/ifPKB6p.png)
|
||||
|
||||
- Click create
|
||||
|
||||
You will get an email from DigitalOcean with your credentials now.
|
||||
|
||||
Open putty and type ip adress **you got in your email** with port 22
|
||||
|
||||
![img](http://imgur.com/Mh5ehsh.png)
|
||||
|
||||
- Console will open and you will be prompted for a username, type `root`.
|
||||
- Type in the password you got in the email.
|
||||
- Confirm the password you just typed in.
|
||||
- Type in the new password.
|
||||
- Confirm new password.
|
||||
|
||||
- When you are successfully logged in, type
|
||||
`docker run --name nadeko -v /nadeko:/config uirel/nadeko`
|
||||
|
||||
- Wait for it to download and at one point it is going to start throwing errors due to `credentials.json` being empty
|
||||
- CTRL+C to exit that
|
||||
- Type `docker stop nadeko`
|
||||
- Type `nano /nadeko/credentials.json` and type in your `credentials`
|
||||
- CTRL+X then CTRL+Y to save
|
||||
- Type `docker start nadeko`
|
||||
- Type `docker logs -f nadeko` to see the console output
|
||||
|
||||
**Your bot is running, enjoy! o/**
|
||||
|
||||
*When you want to update the bot, just type `docker restart nadeko` as it always downloads latest prerelease*
|
||||
|
||||
[reflink]: http://m.do.co/c/46b4d3d44795/
|
||||
[PuTTY]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
|
||||
[guide]: http://discord.kongslien.net/guide.html
|
270
LinuxSetup.md
270
LinuxSetup.md
@ -1,270 +0,0 @@
|
||||
#Setting up NadekoBot on Linux
|
||||
|
||||
####Setting up NadekoBot on Linux Digital Ocean Droplet
|
||||
######If you want Nadeko to play music for you 24/7 without having to hosting it on your PC and want to keep it cheap, reliable and convenient as possible, you can try Nadeko on Linux Digital Ocean Droplet using the link [DigitalOcean][DigitalOcean] (and using this link will be supporting Nadeko and will give you **$10 credit**)
|
||||
|
||||
######Keep this helpful video handy [Linux Setup Video][Linux Setup Video] (thanks to klincheR) it contains how to set up the Digital Ocean droplet aswell.
|
||||
|
||||
####Setting up NadekoBot
|
||||
Assuming you have followed the link above to created an account in Digital Ocean and video to set up the bot until you get the `IP address and root password (in email)` to login, its time to begin.
|
||||
|
||||
#### Prerequisites
|
||||
- Download [PuTTY][PuTTY]
|
||||
- Download [CyberDuck][CyberDuck]
|
||||
|
||||
#### Follow these steps
|
||||
|
||||
- **Open PuTTY.exe** that you downloaded before, and paste or enter your `IP address` and then click **Open**.
|
||||
If you entered your Droplets IP address correctly, it should show **login as:** in a newly opened window.
|
||||
- Now for **login as:**, type `root` and hit enter.
|
||||
- It should then, ask for password, type the `root password` you have received in your **email address registered with Digital Ocean**, then hit Enter.
|
||||
|
||||
*(as you are running it for the first time, it will most likely to ask you to change your root password, for that, type the "password you received through email", hit Enter, enter a "new password", hit Enter and confirm that "new password" again.*
|
||||
**SAVE that new password somewhere safe not just in mind**. After you done that, you are ready to write commands.
|
||||
|
||||
**Copy and just paste** using **mouse right-click** (it should paste automatically)
|
||||
|
||||
######MONO (Source: [Mono Source][Mono Source])
|
||||
|
||||
**1) Installing Mono**
|
||||
|
||||
`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
|
||||
|
||||
`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
|
||||
|
||||
`sudo apt-get update`
|
||||
|
||||
Note if the command is not being initiated, hit **Enter**
|
||||
|
||||
**2)**
|
||||
|
||||
`echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list`
|
||||
|
||||
**2.5)**
|
||||
*ONLY DEBIAN 8 and later*
|
||||
|
||||
`echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list`
|
||||
|
||||
**2.6)**
|
||||
*ONLY CentOS 7, Fedora 19 (and later)*
|
||||
|
||||
`yum install yum-utils`
|
||||
|
||||
`rpm --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"`
|
||||
|
||||
`yum-config-manager --add-repo http://download.mono-project.com/repo/centos/`
|
||||
|
||||
**3)**
|
||||
*Mono Devel*
|
||||
|
||||
`apt-get install mono-devel`
|
||||
|
||||
**Type** `y` **hit Enter**
|
||||
|
||||
|
||||
**4)**
|
||||
Opus Voice Codec
|
||||
|
||||
`sudo apt-get install libopus0 opus-tools`
|
||||
|
||||
**Type** `y` **hit Enter**
|
||||
|
||||
**5)**
|
||||
`sudo apt-get install libopus-dev`
|
||||
|
||||
**In case you are having issues with Mono where you get a random string and the bot won't run, do this:**
|
||||
|
||||
`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
|
||||
|
||||
`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
|
||||
|
||||
`apt-get install ca-certificates-mono`
|
||||
|
||||
`mozroots --import --sync`
|
||||
|
||||
|
||||
####FFMPEG
|
||||
|
||||
**6)**
|
||||
`apt-get install ffmpeg`
|
||||
|
||||
**Type** `y` **hit Enter**
|
||||
|
||||
NOTE: if its "not installing" then, follow the guide here: [FFMPEG Help Guide][FFMPEG Help Guide]
|
||||
|
||||
**All you need to do, if you are running UBUNTU 14.04 is initiate these:**
|
||||
|
||||
`sudo add-apt-repository ppa:mc3man/trusty-media`
|
||||
|
||||
`sudo apt-get update`
|
||||
|
||||
`sudo apt-get dist-upgrade`
|
||||
|
||||
*Before executing* `sudo apt-get install ffmpeg`
|
||||
|
||||
**If you are running Debian 8 Jessie, please, follow these steps:**
|
||||
|
||||
`wget http://luxcaeli.de/installer.sh && sudo bash installer.sh` (Thanks to Eleria<3)
|
||||
|
||||
In case you are not able to install it with installer ^up there, follow these steps:
|
||||
|
||||
`sudo apt-get update`
|
||||
|
||||
`echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/debian-backports.list`
|
||||
|
||||
`sudo apt-get update`
|
||||
|
||||
`sudo apt-get install ffmpeg -y`
|
||||
|
||||
####Uncomplicated Firewall UFW
|
||||
|
||||
**7)**
|
||||
`apt-get install ufw`
|
||||
|
||||
**it is most likely to have it already installed so if you see it is already installed, check with following command, and/or enable it**
|
||||
|
||||
**8)**
|
||||
`ufw status`
|
||||
|
||||
**9)**
|
||||
`ufw enable`
|
||||
|
||||
**Type** `y` **hit Enter**
|
||||
|
||||
**10)**
|
||||
`sudo ufw allow ssh`
|
||||
|
||||
|
||||
|
||||
**11)**
|
||||
Unzip
|
||||
|
||||
`apt-get install unzip`
|
||||
|
||||
**12)**
|
||||
TMUX
|
||||
|
||||
`apt-get install tmux`
|
||||
|
||||
**Type** `y` **hit Enter**
|
||||
|
||||
####NOW WE NEED TO IMPORT SOME DISCORD CERTS
|
||||
**13)**
|
||||
`certmgr -ssl https://discordapp.com`
|
||||
|
||||
**14)**
|
||||
`certmgr -ssl https://gateway.discord.gg`
|
||||
|
||||
Type `yes` and hit Enter **(three times - as it will ask for three times)**
|
||||
|
||||
|
||||
**15)**
|
||||
Create a new folder “nadeko” or anything you prefer
|
||||
|
||||
`mkdir nadeko`
|
||||
|
||||
**16)**
|
||||
Move to “nadeko” folder (note `cd --` to go back the directory)
|
||||
|
||||
`cd nadeko`
|
||||
|
||||
**NOW WE NEED TO GET NADEKO FROM RELEASES**
|
||||
|
||||
Go to this link: [Releases][Releases] and **copy the zip file address** of the lalest version available,
|
||||
it should look like `https://github.com/Kwoth/NadekoBot/releases/download/vx.xx/NadekoBot.vx.x.zip`
|
||||
|
||||
**17)**
|
||||
Get the correct link, type `wget`, then *paste the link*, then hit **Enter**.
|
||||
|
||||
`wget https://github.com/Kwoth/NadekoBot/releases/download/vx.xx/NadekoBot.vx.x.zip`
|
||||
|
||||
**^Do not copy-paste it**
|
||||
|
||||
**18)**
|
||||
|
||||
Now we need to `unzip` the downloaded zip file and to do that, type the file name as it showed in your screen or just copy from the screen, should be like ` NadekoBot.vx.x.zip`
|
||||
|
||||
`unzip NadekoBot.vx.x.zip`
|
||||
|
||||
**^Do not copy-paste it**
|
||||
|
||||
#####NOW TO SETUP NADEKO
|
||||
|
||||
- Open **CyberDuck**
|
||||
- Click on **Open Connection** (top-left corner), a new window should appear.
|
||||
- You should see **FTP (File Transfer Protocol)** in drop-down.
|
||||
- Change it to **SFTP (SSH File Transfer Protocol)**
|
||||
- Now, in **Server:** paste or type in your `Digital Ocean Droplets IP address`, leave `Port: 22` (no need to change it)
|
||||
- In **Username:** type `root`
|
||||
- In **Password:** type `the new root password (you changed at the start)`
|
||||
- Click on **Connect**
|
||||
- It should show you the new folder you created.
|
||||
- Open it.
|
||||
|
||||
#####MAKE SURE YOU READ THE README BEFORE PROCEEDING
|
||||
|
||||
- Copy the `credentials_example.json` to desktop
|
||||
- EDIT it as it is guided here: [Readme][Readme]
|
||||
- Rename it to `credentials.json` and paste/put it back in the folder. `(Yes, using CyberDuck)`
|
||||
- You should see two files `credentials_example.json` and `credentials.json`
|
||||
- Also if you already have nadeko setup and have `credentials.json`, `config.json`, `nadekobot.sqlite`, and `"permissions" folder`, you can just copy and paste it to the Droplets folder using CyberDuck.
|
||||
|
||||
######TIME TO RUN
|
||||
|
||||
Go back to **PuTTY**, `(hope its still running xD)`
|
||||
|
||||
**19)**
|
||||
Type/ Copy and hit **Enter**.
|
||||
|
||||
`tmux new -s nadeko`
|
||||
|
||||
**^this will create a new session named “nadeko”** `(you can replace “nadeko” with anything you prefer and remember its your session name) so you can run the bot in background without having to keep running PuTTY in the background.`
|
||||
|
||||
`cd nadeko`
|
||||
|
||||
**20)**
|
||||
`mono NadekoBot.exe`
|
||||
|
||||
**CHECK THE BOT IN DISCORD, IF EVERYTHING IS WORKING**
|
||||
|
||||
Now time to **move bot to background** and to do that, press **CTRL+B**,release and press **D** (this will detach the nadeko session using TMUX), and you can finally close PuTTY now.
|
||||
|
||||
Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link: `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with it. Go to that link and you will be able to add your bot to your server.
|
||||
|
||||
**NOW YOU HAVE YOUR OWN NADEKO BOT** `Thanks to Kwoth <3`
|
||||
|
||||
######SOME MORE INFO (JUST TO KNOW):
|
||||
|
||||
-If you want to **see the sessions** after logging back again, type `tmux ls`, and that will give you the list of sessions running.
|
||||
-If you want to **switch to/ see that session**, type `tmux a -t nadeko` (**nadeko** is the name of the session we created before so, replace **“nadeko”** with the session name you created.)
|
||||
|
||||
**21)**
|
||||
-If you want to **kill** NadekoBot **session**, type `tmux kill-session -t nadeko`
|
||||
|
||||
######TO RESTART YOUR BOT ALONG WITH THE WHOLE SERVER (for science):
|
||||
**22)**
|
||||
Open **PuTTY** and login as you have before, type `reboot` and hit Enter.
|
||||
|
||||
######IF YOU WANT TO UPDATE YOUR BOT
|
||||
|
||||
**FOLLOW THESE STEPS SERIALLY**
|
||||
|
||||
- **-21 OR 22**
|
||||
- **-19**
|
||||
- **-16**
|
||||
- **-17**
|
||||
- **-18**
|
||||
- **-20**
|
||||
|
||||
HIT **CTRL+B**,release, press **D** and close **PuTTY**
|
||||
|
||||
`IF YOU FACE ANY TROUBLE ANYWHERE IN THE GUIDE JUST FIND US IN NADEKO'S DISCORD SERVER`
|
||||
|
||||
[PuTTY]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
|
||||
[CyberDuck]: https://cyberduck.io
|
||||
[Linux Setup Video]: https://www.youtube.com/watch?v=icV4_WPqPQk&feature=youtu.be
|
||||
[Releases]: https://github.com/Kwoth/NadekoBot/releases
|
||||
[Readme]: https://github.com/Kwoth/NadekoBot/blob/master/README.md
|
||||
[FFMPEG Help Guide]: http://www.faqforge.com/linux/how-to-install-ffmpeg-on-ubuntu-14-04/
|
||||
[Mono Source]: http://www.mono-project.com/docs/getting-started/install/linux/
|
||||
[DigitalOcean]: http://m.do.co/c/46b4d3d44795/
|
127
NadekoBot.sln
127
NadekoBot.sln
@ -3,116 +3,49 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Audio", "discord.net\src\Discord.Net.Audio.Net45\Discord.Net.Audio.csproj", "{7BFEF748-B934-4621-9B11-6302E3A9F6B3}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0B2F1537-4BF0-422B-A0DD-8F9CCEFB340F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "discord.net\src\Discord.Net.Net45\Discord.Net.csproj", "{8D71A857-879A-4A10-859E-5FF824ED6688}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "NadekoBot", "src\NadekoBot\NadekoBot.xproj", "{45EC1473-C678-4857-A544-07DFE0D0B478}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "discord.net\src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj", "{3091164F-66AE-4543-A63D-167C1116241D}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "discord.net\src\Discord.Net\Discord.Net.xproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{1b5603b4-6f8f-4289-b945-7baae523d740}*SharedItemsImports = 4
|
||||
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{3091164f-66ae-4543-a63d-167c1116241d}*SharedItemsImports = 4
|
||||
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{7bfef748-b934-4621-9b11-6302e3a9f6b3}*SharedItemsImports = 4
|
||||
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{8d71a857-879a-4a10-859e-5ff824ed6688}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
FullDebug|Any CPU = FullDebug|Any CPU
|
||||
FullDebug|x64 = FullDebug|x64
|
||||
NadekoRelease|Any CPU = NadekoRelease|Any CPU
|
||||
NadekoRelease|x64 = NadekoRelease|x64
|
||||
GlobalNadeko|Any CPU = GlobalNadeko|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.Build.0 = Debug|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.ActiveCfg = Debug|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.Build.0 = Debug|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.ActiveCfg = NadekoRelease|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.Build.0 = NadekoRelease|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.ActiveCfg = Release|x64
|
||||
{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.Build.0 = Release|x64
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.Build.0 = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.Build.0 = Release|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
@ -1,8 +0,0 @@
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
class BombermanGame
|
||||
{
|
||||
public ulong ChannelId { get; internal set; }
|
||||
public bool Ended { get; internal set; }
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
using NadekoBot.DataModels;
|
||||
using SQLite;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal class DbHandler
|
||||
{
|
||||
public static DbHandler Instance { get; } = new DbHandler();
|
||||
|
||||
private string FilePath { get; } = "data/nadekobot.sqlite";
|
||||
|
||||
public SQLiteConnection Connection { get; set; }
|
||||
|
||||
static DbHandler() { }
|
||||
public DbHandler()
|
||||
{
|
||||
Connection = new SQLiteConnection(FilePath);
|
||||
Connection.CreateTable<Stats>();
|
||||
Connection.CreateTable<Command>();
|
||||
Connection.CreateTable<Announcement>();
|
||||
Connection.CreateTable<Request>();
|
||||
Connection.CreateTable<TypingArticle>();
|
||||
Connection.CreateTable<CurrencyState>();
|
||||
Connection.CreateTable<CurrencyTransaction>();
|
||||
Connection.CreateTable<Donator>();
|
||||
Connection.CreateTable<UserPokeTypes>();
|
||||
Connection.CreateTable<UserQuote>();
|
||||
Connection.CreateTable<Reminder>();
|
||||
Connection.CreateTable<SongInfo>();
|
||||
Connection.CreateTable<PlaylistSongInfo>();
|
||||
Connection.CreateTable<MusicPlaylist>();
|
||||
Connection.CreateTable<Incident>();
|
||||
Connection.Execute(Queries.TransactionTriggerQuery);
|
||||
try
|
||||
{
|
||||
Connection.Execute(Queries.DeletePlaylistTriggerQuery);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
internal T FindOne<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
return Connection.Table<T>().Where(p).FirstOrDefault();
|
||||
|
||||
}
|
||||
|
||||
internal IList<T> FindAll<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
|
||||
return Connection.Table<T>().Where(p).ToList();
|
||||
|
||||
}
|
||||
|
||||
internal void DeleteWhere<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
var id = Connection.Table<T>().Where(p).FirstOrDefault()?.Id;
|
||||
if (id.HasValue)
|
||||
Connection.Delete<T>(id);
|
||||
}
|
||||
|
||||
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
|
||||
{
|
||||
return new HashSet<T>(Connection.Table<T>());
|
||||
}
|
||||
|
||||
internal CurrencyState GetStateByUserId(long id)
|
||||
{
|
||||
return Connection.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
|
||||
}
|
||||
|
||||
internal T Delete<T>(int id) where T : IDataModel, new()
|
||||
{
|
||||
var found = Connection.Find<T>(id);
|
||||
if (found != null)
|
||||
Connection.Delete<T>(found.Id);
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing object or creates a new one
|
||||
/// </summary>
|
||||
internal void Save<T>(T o) where T : IDataModel, new()
|
||||
{
|
||||
var found = Connection.Find<T>(o.Id);
|
||||
if (found == null)
|
||||
Connection.Insert(o, typeof(T));
|
||||
else
|
||||
Connection.Update(o, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing object or creates a new one
|
||||
/// </summary>
|
||||
internal void SaveAll<T>(IEnumerable<T> ocol) where T : IDataModel, new()
|
||||
{
|
||||
foreach (var o in ocol)
|
||||
Connection.InsertOrReplace(o);
|
||||
}
|
||||
|
||||
internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
var r = new Random();
|
||||
return Connection.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="num">Page number (0+)</param>
|
||||
/// <returns></returns>
|
||||
internal List<PlaylistData> GetPlaylistData(int num)
|
||||
{
|
||||
return Connection.Query<PlaylistData>(
|
||||
@"SELECT mp.Name as 'Name',mp.Id as 'Id', mp.CreatorName as 'Creator', Count(*) as 'SongCnt' FROM MusicPlaylist as mp
|
||||
INNER JOIN PlaylistSongInfo as psi
|
||||
ON mp.Id = psi.PlaylistId
|
||||
Group BY mp.Name
|
||||
Order By mp.DateAdded desc
|
||||
Limit 20 OFFSET ?", num * 20);
|
||||
|
||||
}
|
||||
|
||||
internal IEnumerable<CurrencyState> GetTopRichest(int n = 10)
|
||||
{
|
||||
return Connection.Table<CurrencyState>().OrderByDescending(cs => cs.Value).Take(n).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PlaylistData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string Creator { get; set; }
|
||||
public int SongCnt { get; set; }
|
||||
}
|
||||
|
||||
public static class Queries
|
||||
{
|
||||
public const string TransactionTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
|
||||
AFTER INSERT ON CurrencyTransaction
|
||||
BEGIN
|
||||
INSERT OR REPLACE INTO CurrencyState (Id, UserId, Value, DateAdded)
|
||||
VALUES (COALESCE((SELECT Id from CurrencyState where UserId = NEW.UserId),(SELECT COALESCE(MAX(Id),0)+1 from CurrencyState)),
|
||||
NEW.UserId,
|
||||
COALESCE((SELECT Value+New.Value FROM CurrencyState Where UserId = NEW.UserId),NEW.Value),
|
||||
NEW.DateAdded);
|
||||
END
|
||||
";
|
||||
public const string DeletePlaylistTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS music_playlist
|
||||
AFTER DELETE ON MusicPlaylist
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DELETE FROM PlaylistSongInfo WHERE PlaylistId = OLD.Id;
|
||||
END";
|
||||
}
|
@ -1,378 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Extensions
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
private static Random rng = new Random();
|
||||
|
||||
public static string Scramble(this string word)
|
||||
{
|
||||
|
||||
var letters = word.ToArray();
|
||||
var count = 0;
|
||||
for (var i = 0; i < letters.Length; i++)
|
||||
{
|
||||
if (letters[i] == ' ')
|
||||
continue;
|
||||
|
||||
count++;
|
||||
if (count <= letters.Length / 5)
|
||||
continue;
|
||||
|
||||
if (count % 3 == 0)
|
||||
continue;
|
||||
|
||||
if (letters[i] != ' ')
|
||||
letters[i] = '_';
|
||||
}
|
||||
return "`" + string.Join(" ", letters) + "`";
|
||||
}
|
||||
public static string TrimTo(this string str, int num, bool hideDots = false)
|
||||
{
|
||||
if (num < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(num), "TrimTo argument cannot be less than 0");
|
||||
if (num == 0)
|
||||
return string.Empty;
|
||||
if (num <= 3)
|
||||
return string.Concat(str.Select(c => '.'));
|
||||
if (str.Length < num)
|
||||
return str;
|
||||
return string.Concat(str.Take(num - 3)) + (hideDots ? "" : "...");
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes trailing S or ES (if specified) on the given string if the num is 1
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="num"></param>
|
||||
/// <param name="es"></param>
|
||||
/// <returns>String with the correct singular/plural form</returns>
|
||||
public static string SnPl(this string str, int? num, bool es = false)
|
||||
{
|
||||
if (str == null)
|
||||
throw new ArgumentNullException(nameof(str));
|
||||
if (num == null)
|
||||
throw new ArgumentNullException(nameof(num));
|
||||
return num == 1 ? str.Remove(str.Length - 1, es ? 2 : 1) : str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to the channel from which this command is called.
|
||||
/// </summary>
|
||||
/// <param name="e">EventArg</param>
|
||||
/// <param name="message">Message to be sent</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Message> Send(this CommandEventArgs e, string message)
|
||||
=> await e.Channel.SendMessage(message).ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to the channel from which MessageEventArg came.
|
||||
/// </summary>
|
||||
/// <param name="e">EventArg</param>
|
||||
/// <param name="message">Message to be sent</param>
|
||||
/// <returns></returns>
|
||||
public static async Task Send(this MessageEventArgs e, string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return;
|
||||
await e.Channel.SendMessage(message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to this channel.
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Send(this Channel c, string message)
|
||||
{
|
||||
await c.SendMessage(message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a private message to this user.
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Send(this User u, string message)
|
||||
{
|
||||
await u.SendMessage(message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replies to a user who invoked this command, message start with that user's mention.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Reply(this CommandEventArgs e, string message)
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replies to a user who invoked this command, message start with that user's mention.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Reply(this MessageEventArgs e, string message)
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes element order in a list
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
public static IList<T> Shuffle<T>(this IList<T> list)
|
||||
{
|
||||
|
||||
// Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
|
||||
var provider = new RNGCryptoServiceProvider();
|
||||
var n = list.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
var box = new byte[(n / Byte.MaxValue) + 1];
|
||||
int boxSum;
|
||||
do
|
||||
{
|
||||
provider.GetBytes(box);
|
||||
boxSum = box.Sum(b => b);
|
||||
}
|
||||
while (!(boxSum < n * ((Byte.MaxValue * box.Length) / n)));
|
||||
var k = (boxSum % n);
|
||||
n--;
|
||||
var value = list[k];
|
||||
list[k] = list[n];
|
||||
list[n] = value;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shortens a string URL
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="action"></param>
|
||||
public static async Task<string> ShortenUrl(this string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await SearchHelper.ShortenUrl(str).ConfigureAwait(false);
|
||||
return result;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
throw new InvalidOperationException("You must enable URL shortner in google developers console.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOnPage<T>(this IEnumerable<T> source, int pageIndex, int itemsPerPage = 5)
|
||||
{
|
||||
var items = source.Skip(pageIndex * itemsPerPage).Take(itemsPerPage);
|
||||
if (!items.Any())
|
||||
{
|
||||
return $"No items on page {pageIndex + 1}.";
|
||||
}
|
||||
var sb = new StringBuilder($"---page {pageIndex + 1} --\n");
|
||||
var itemsDC = items as IEnumerable<KeyValuePair<string, IEnumerable<string>>>;
|
||||
var itemsDS = items as IEnumerable<KeyValuePair<string, string>>;
|
||||
if (itemsDC != null)
|
||||
{
|
||||
foreach (var item in itemsDC)
|
||||
{
|
||||
sb.Append($"{ Format.Code(item.Key)}\n");
|
||||
int i = 1;
|
||||
var last = item.Value.Last();
|
||||
foreach (var value in item.Value)
|
||||
{
|
||||
if (last != value)
|
||||
sb.AppendLine(" `├" + i++ + "─`" + Format.Bold(value));
|
||||
else
|
||||
sb.AppendLine(" `└" + i++ + "─`" + Format.Bold(value));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (itemsDS != null)
|
||||
{
|
||||
foreach (var item in itemsDS)
|
||||
{
|
||||
sb.Append($"{ Format.Code(item.Key)}\n");
|
||||
sb.AppendLine(" `└─`" + Format.Bold(item.Value));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
sb.Append($"{ Format.Code(item.ToString())} \n");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the program runtime
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="action"></param>
|
||||
public static string GetRuntime(this DiscordClient c) => ".Net Framework 4.5.2";
|
||||
|
||||
public static string Matrix(this string s)
|
||||
=>
|
||||
string.Concat(s.Select(c => c.ToString() + " ̵̢̬̜͉̞̭̖̰͋̉̎ͬ̔̇̌̀".TrimTo(rng.Next(0, 12), true)));
|
||||
//.Replace("`", "");
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (var element in source)
|
||||
{
|
||||
action(element);
|
||||
}
|
||||
}
|
||||
|
||||
//http://www.dotnetperls.com/levenshtein
|
||||
public static int LevenshteinDistance(this string s, string t)
|
||||
{
|
||||
var n = s.Length;
|
||||
var m = t.Length;
|
||||
var d = new int[n + 1, m + 1];
|
||||
|
||||
// Step 1
|
||||
if (n == 0)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
// Step 2
|
||||
for (var i = 0; i <= n; d[i, 0] = i++)
|
||||
{
|
||||
}
|
||||
|
||||
for (var j = 0; j <= m; d[0, j] = j++)
|
||||
{
|
||||
}
|
||||
|
||||
// Step 3
|
||||
for (var i = 1; i <= n; i++)
|
||||
{
|
||||
//Step 4
|
||||
for (var j = 1; j <= m; j++)
|
||||
{
|
||||
// Step 5
|
||||
var cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
|
||||
|
||||
// Step 6
|
||||
d[i, j] = Math.Min(
|
||||
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
|
||||
d[i - 1, j - 1] + cost);
|
||||
}
|
||||
}
|
||||
// Step 7
|
||||
return d[n, m];
|
||||
}
|
||||
|
||||
public static int KiB(this int value) => value * 1024;
|
||||
public static int KB(this int value) => value * 1000;
|
||||
|
||||
public static int MiB(this int value) => value.KiB() * 1024;
|
||||
public static int MB(this int value) => value.KB() * 1000;
|
||||
|
||||
public static int GiB(this int value) => value.MiB() * 1024;
|
||||
public static int GB(this int value) => value.MB() * 1000;
|
||||
|
||||
public static ulong KiB(this ulong value) => value * 1024;
|
||||
public static ulong KB(this ulong value) => value * 1000;
|
||||
|
||||
public static ulong MiB(this ulong value) => value.KiB() * 1024;
|
||||
public static ulong MB(this ulong value) => value.KB() * 1000;
|
||||
|
||||
public static ulong GiB(this ulong value) => value.MiB() * 1024;
|
||||
public static ulong GB(this ulong value) => value.MB() * 1000;
|
||||
|
||||
public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null)
|
||||
{
|
||||
if (format == null)
|
||||
format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
||||
var stream = new MemoryStream();
|
||||
img.Save(stream, format);
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges Images into 1 Image and returns a bitmap.
|
||||
/// </summary>
|
||||
/// <param name="images">The Images you want to merge.</param>
|
||||
/// <returns>Merged bitmap</returns>
|
||||
public static Bitmap Merge(this IEnumerable<Image> images, int reverseScaleFactor = 1)
|
||||
{
|
||||
var imageArray = images as Image[] ?? images.ToArray();
|
||||
if (!imageArray.Any()) return null;
|
||||
var width = imageArray.Sum(i => i.Width);
|
||||
var height = imageArray.First().Height;
|
||||
var bitmap = new Bitmap(width / reverseScaleFactor, height / reverseScaleFactor);
|
||||
var r = new Random();
|
||||
var offsetx = 0;
|
||||
foreach (var img in imageArray)
|
||||
{
|
||||
var bm = new Bitmap(img);
|
||||
for (var w = 0; w < img.Width; w++)
|
||||
{
|
||||
for (var h = 0; h < bitmap.Height; h++)
|
||||
{
|
||||
bitmap.SetPixel(w / reverseScaleFactor + offsetx, h, bm.GetPixel(w, h * reverseScaleFactor));
|
||||
}
|
||||
}
|
||||
offsetx += img.Width / reverseScaleFactor;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges Images into 1 Image and returns a bitmap asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="images">The Images you want to merge.</param>
|
||||
/// <param name="reverseScaleFactor"></param>
|
||||
/// <returns>Merged bitmap</returns>
|
||||
public static async Task<Bitmap> MergeAsync(this IEnumerable<Image> images, int reverseScaleFactor = 1) =>
|
||||
await Task.Run(() => images.Merge(reverseScaleFactor)).ConfigureAwait(false);
|
||||
|
||||
public static string Unmention(this string str) => str.Replace("@", "ම");
|
||||
|
||||
public static Stream ToStream(this string str)
|
||||
{
|
||||
var sw = new StreamWriter(new MemoryStream());
|
||||
sw.Write(str);
|
||||
sw.Flush();
|
||||
sw.BaseStream.Position = 0;
|
||||
return sw.BaseStream;
|
||||
}
|
||||
|
||||
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal static class FlowersHandler
|
||||
{
|
||||
public static async Task AddFlowersAsync(Discord.User u, string reason, int amount, bool silent = false)
|
||||
{
|
||||
if (amount <= 0)
|
||||
return;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
|
||||
{
|
||||
Reason = reason,
|
||||
UserId = (long)u.Id,
|
||||
Value = amount,
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
if (silent)
|
||||
return;
|
||||
|
||||
var flows = amount + " " + NadekoBot.Config.CurrencySign;
|
||||
|
||||
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<bool> RemoveFlowers(Discord.User u, string reason, int amount, bool silent=false, string message="👎`Bot owner has taken {0}{1} from you.`")
|
||||
{
|
||||
if (amount <= 0)
|
||||
return false;
|
||||
var uid = (long)u.Id;
|
||||
var state = DbHandler.Instance.FindOne<DataModels.CurrencyState>(cs => cs.UserId == uid);
|
||||
|
||||
if (state.Value < amount)
|
||||
return false;
|
||||
|
||||
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
|
||||
{
|
||||
Reason = reason,
|
||||
UserId = (long)u.Id,
|
||||
Value = -amount,
|
||||
});
|
||||
|
||||
if (silent)
|
||||
return true;
|
||||
|
||||
await u.SendMessage(string.Format(message,amount,NadekoBot.Config.CurrencySign)).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using NadekoBot.DataModels;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal static class IncidentsHandler
|
||||
{
|
||||
public static void Add(ulong serverId, ulong channelId, string text)
|
||||
{
|
||||
var def = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"INCIDENT: {text}");
|
||||
Console.ForegroundColor = def;
|
||||
var incident = new Incident
|
||||
{
|
||||
ChannelId = (long)channelId,
|
||||
ServerId = (long)serverId,
|
||||
Text = text,
|
||||
Read = false
|
||||
};
|
||||
|
||||
DbHandler.Instance.Connection.Insert(incident, typeof(Incident));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Commands;
|
||||
using NadekoBot.Modules.Music;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
#if NADEKO_RELEASE
|
||||
using System.IO;
|
||||
#endif
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
public class NadekoStats
|
||||
{
|
||||
public static NadekoStats Instance { get; } = new NadekoStats();
|
||||
|
||||
public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
|
||||
|
||||
private int commandsRan = 0;
|
||||
private string statsCache = "";
|
||||
private readonly Stopwatch statsStopwatch = new Stopwatch();
|
||||
|
||||
public int ServerCount { get; private set; } = 0;
|
||||
public int TextChannelsCount { get; private set; } = 0;
|
||||
public int VoiceChannelsCount { get; private set; } = 0;
|
||||
|
||||
private readonly Timer commandLogTimer = new Timer() { Interval = 10000 };
|
||||
private readonly Timer carbonStatusTimer = new Timer() { Interval = 3600000 };
|
||||
|
||||
private static ulong messageCounter = 0;
|
||||
public static ulong MessageCounter => messageCounter;
|
||||
|
||||
static NadekoStats() { }
|
||||
|
||||
private NadekoStats()
|
||||
{
|
||||
var commandService = NadekoBot.Client.GetService<CommandService>();
|
||||
|
||||
statsStopwatch.Start();
|
||||
|
||||
commandService.CommandExecuted += StatsCollector_RanCommand;
|
||||
commandService.CommandFinished += CommandService_CommandFinished;
|
||||
commandService.CommandErrored += CommandService_CommandFinished;
|
||||
|
||||
Task.Run(StartCollecting);
|
||||
|
||||
commandLogTimer.Start();
|
||||
|
||||
ServerCount = NadekoBot.Client.Servers.Count();
|
||||
var channels = NadekoBot.Client.Servers.SelectMany(s => s.AllChannels);
|
||||
var channelsArray = channels as Channel[] ?? channels.ToArray();
|
||||
TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
|
||||
VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
|
||||
|
||||
NadekoBot.Client.MessageReceived += (s, e) => messageCounter++;
|
||||
|
||||
NadekoBot.Client.JoinedServer += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerCount++;
|
||||
TextChannelsCount += e.Server.TextChannels.Count();
|
||||
VoiceChannelsCount += e.Server.VoiceChannels.Count();
|
||||
//await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.LeftServer += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerCount--;
|
||||
TextChannelsCount -= e.Server.TextChannels.Count();
|
||||
VoiceChannelsCount -= e.Server.VoiceChannels.Count();
|
||||
//await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.ChannelCreated += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel.IsPrivate)
|
||||
return;
|
||||
if (e.Channel.Type == ChannelType.Text)
|
||||
TextChannelsCount++;
|
||||
else if (e.Channel.Type == ChannelType.Voice)
|
||||
VoiceChannelsCount++;
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.ChannelDestroyed += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel.IsPrivate)
|
||||
return;
|
||||
if (e.Channel.Type == ChannelType.Text)
|
||||
TextChannelsCount--;
|
||||
else if (e.Channel.Type == ChannelType.Voice)
|
||||
VoiceChannelsCount--;
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
carbonStatusTimer.Start();
|
||||
}
|
||||
|
||||
HttpClient carbonClient = new HttpClient();
|
||||
private async Task SendUpdateToCarbon()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(new Dictionary<string, string> {
|
||||
{ "servercount", NadekoBot.Client.Servers.Count().ToString() },
|
||||
{ "key", NadekoBot.Creds.CarbonKey }
|
||||
}))
|
||||
{
|
||||
content.Headers.Clear();
|
||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
var res = await carbonClient.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Failed sending status update to carbon.");
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan GetUptime() =>
|
||||
DateTime.Now - Process.GetCurrentProcess().StartTime;
|
||||
|
||||
public string GetUptimeString()
|
||||
{
|
||||
var time = GetUptime();
|
||||
return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
|
||||
}
|
||||
|
||||
public Task LoadStats() =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
var songs = MusicModule.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
|
||||
sb.AppendLine($"`Bot Version: {BotVersion}`");
|
||||
sb.AppendLine($"`Bot id: {NadekoBot.Client.CurrentUser.Id}`");
|
||||
sb.Append("`Owners' Ids:` ");
|
||||
sb.AppendLine("`" + String.Join(", ", NadekoBot.Creds.OwnerIds) + "`");
|
||||
sb.AppendLine($"`Uptime: {GetUptimeString()}`");
|
||||
sb.Append($"`Servers: {ServerCount}");
|
||||
sb.Append($" | TextChannels: {TextChannelsCount}");
|
||||
sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
|
||||
sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
|
||||
sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`");
|
||||
sb.Append($"`Greeted {ServerGreetCommand.Greeted} times.`");
|
||||
sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) +
|
||||
$"{MusicModule.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
|
||||
sb.AppendLine($"`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap(false)}`");
|
||||
statsCache = sb.ToString();
|
||||
});
|
||||
|
||||
public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString();
|
||||
|
||||
public async Task<string> GetStats()
|
||||
{
|
||||
if (statsStopwatch.Elapsed.Seconds < 4 &&
|
||||
!string.IsNullOrWhiteSpace(statsCache)) return statsCache;
|
||||
await LoadStats().ConfigureAwait(false);
|
||||
statsStopwatch.Restart();
|
||||
return statsCache;
|
||||
}
|
||||
|
||||
private async Task StartCollecting()
|
||||
{
|
||||
var statsSw = new Stopwatch();
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
|
||||
statsSw.Start();
|
||||
try
|
||||
{
|
||||
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false);
|
||||
var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
|
||||
.Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)))
|
||||
.ConfigureAwait(false);
|
||||
var connectedServers = NadekoBot.Client.Servers.Count();
|
||||
|
||||
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Stats
|
||||
{
|
||||
OnlineUsers = onlineUsers,
|
||||
RealOnlineUsers = realOnlineUsers,
|
||||
Uptime = GetUptime(),
|
||||
ConnectedServers = connectedServers,
|
||||
DateAdded = DateTime.Now
|
||||
});
|
||||
|
||||
statsSw.Stop();
|
||||
var clr = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
Console.WriteLine($"--------------\nCollecting stats finished in {statsSw.Elapsed.TotalSeconds}s\n-------------");
|
||||
Console.ForegroundColor = clr;
|
||||
statsSw.Reset();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("DB Exception in stats collecting.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<ulong, DateTime> commandTracker = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
private void CommandService_CommandFinished(object sender, CommandEventArgs e)
|
||||
{
|
||||
|
||||
DateTime dt;
|
||||
if (!commandTracker.TryGetValue(e.Message.Id, out dt))
|
||||
return;
|
||||
#if NADEKO_RELEASE
|
||||
try
|
||||
{
|
||||
if (e is CommandErrorEventArgs)
|
||||
{
|
||||
var er = e as CommandErrorEventArgs;
|
||||
if (er.ErrorType == CommandErrorType.Exception)
|
||||
{
|
||||
File.AppendAllText("errors.txt", $@"Command: {er.Command}
|
||||
{er.Exception}
|
||||
-------------------------------------
|
||||
");
|
||||
Console.WriteLine($">>COMMAND ERRORED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
#endif
|
||||
}
|
||||
|
||||
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
|
||||
{
|
||||
commandTracker.TryAdd(e.Message.Id, DateTime.UtcNow);
|
||||
Console.WriteLine($">>COMMAND STARTED\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
commandsRan++;
|
||||
#if !NADEKO_RELEASE
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Command
|
||||
{
|
||||
ServerId = (long)(e.Server?.Id ?? 0),
|
||||
ServerName = e.Server?.Name ?? "--Direct Message--",
|
||||
ChannelId = (long)e.Channel.Id,
|
||||
ChannelName = e.Channel.IsPrivate ? "--Direct Message" : e.Channel.Name,
|
||||
UserId = (long)e.User.Id,
|
||||
UserName = e.User.Name,
|
||||
CommandName = e.Command.Text,
|
||||
DateAdded = DateTime.Now
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Probably unimportant error in ran command DB write.");
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// File: ObservableConcurrentDictionary.cs
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a thread-safe dictionary for use with data binding.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam>
|
||||
/// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam>
|
||||
[DebuggerDisplay("Count={Count}")]
|
||||
public class ObservableConcurrentDictionary<TKey, TValue> :
|
||||
ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,
|
||||
INotifyCollectionChanged, INotifyPropertyChanged
|
||||
{
|
||||
private readonly SynchronizationContext _context;
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the ObservableConcurrentDictionary class.
|
||||
/// </summary>
|
||||
public ObservableConcurrentDictionary()
|
||||
{
|
||||
_context = AsyncOperationManager.SynchronizationContext;
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
/// <summary>Event raised when the collection changes.</summary>
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
/// <summary>Event raised when a property on the collection changes.</summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
|
||||
/// </summary>
|
||||
private void NotifyObserversOfChange()
|
||||
{
|
||||
var collectionHandler = CollectionChanged;
|
||||
var propertyHandler = PropertyChanged;
|
||||
if (collectionHandler != null || propertyHandler != null)
|
||||
{
|
||||
_context.Post(s =>
|
||||
{
|
||||
if (collectionHandler != null)
|
||||
{
|
||||
collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
if (propertyHandler != null)
|
||||
{
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Count"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Keys"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Values"));
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="item">The item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return TryAddWithNotification(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be added.</param>
|
||||
/// <param name="value">The value of the item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(TKey key, TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryAdd(key, value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be removed.</param>
|
||||
/// <param name="value">The value of the item removed.</param>
|
||||
/// <returns>Whether the removal was successful.</returns>
|
||||
private bool TryRemoveWithNotification(TKey key, out TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryRemove(key, out value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be updated.</param>
|
||||
/// <param name="value">The new value to set for the item.</param>
|
||||
/// <returns>Whether the update was successful.</returns>
|
||||
private void UpdateWithNotification(TKey key, TValue value)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
#region ICollection<KeyValuePair<TKey,TValue>> Members
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TryAddWithNotification(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear();
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
int ICollection<KeyValuePair<TKey, TValue>>.Count {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(item.Key, out temp);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<KeyValuePair<TKey,TValue>> Members
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDictionary<TKey,TValue> Members
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public ICollection<TKey> Keys {
|
||||
get { return _dictionary.Keys; }
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(key, out temp);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
return TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public ICollection<TValue> Values {
|
||||
get { return _dictionary.Values; }
|
||||
}
|
||||
|
||||
public TValue this[TKey key] {
|
||||
get { return _dictionary[key]; }
|
||||
set { UpdateWithNotification(key, value); }
|
||||
}
|
||||
|
||||
public bool TryRemove(TKey key, out TValue value)
|
||||
{
|
||||
return TryRemoveWithNotification(key, out value);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,402 +0,0 @@
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Authentication;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
public enum RequestHttpMethod
|
||||
{
|
||||
Get,
|
||||
Post
|
||||
}
|
||||
|
||||
public static class SearchHelper
|
||||
{
|
||||
private static DateTime lastRefreshed = DateTime.MinValue;
|
||||
private static string token { get; set; } = "";
|
||||
|
||||
public static async Task<Stream> GetResponseStreamAsync(string url,
|
||||
IEnumerable<KeyValuePair<string, string>> headers = null, RequestHttpMethod method = RequestHttpMethod.Get)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
var cl = new HttpClient();
|
||||
cl.DefaultRequestHeaders.Clear();
|
||||
switch (method)
|
||||
{
|
||||
case RequestHttpMethod.Get:
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
cl.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
return await cl.GetStreamAsync(url).ConfigureAwait(false);
|
||||
case RequestHttpMethod.Post:
|
||||
FormUrlEncodedContent formContent = null;
|
||||
if (headers != null)
|
||||
{
|
||||
formContent = new FormUrlEncodedContent(headers);
|
||||
}
|
||||
var message = await cl.PostAsync(url, formContent).ConfigureAwait(false);
|
||||
return await message.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
default:
|
||||
throw new NotImplementedException("That type of request is unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> GetResponseStringAsync(string url,
|
||||
IEnumerable<KeyValuePair<string, string>> headers = null,
|
||||
RequestHttpMethod method = RequestHttpMethod.Get)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
var cl = new HttpClient();
|
||||
cl.DefaultRequestHeaders.Clear();
|
||||
switch (method)
|
||||
{
|
||||
case RequestHttpMethod.Get:
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
cl.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
return await cl.GetStringAsync(url).ConfigureAwait(false);
|
||||
case RequestHttpMethod.Post:
|
||||
FormUrlEncodedContent formContent = null;
|
||||
if (headers != null)
|
||||
{
|
||||
formContent = new FormUrlEncodedContent(headers);
|
||||
}
|
||||
var message = await cl.PostAsync(url, formContent).ConfigureAwait(false);
|
||||
return await message.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
default:
|
||||
throw new NotImplementedException("That type of request is unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<AnimeResult> GetAnimeData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
await RefreshAnilistToken().ConfigureAwait(false);
|
||||
|
||||
var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
|
||||
var smallContent = "";
|
||||
var cl = new RestSharp.RestClient("http://anilist.co/api");
|
||||
var rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query));
|
||||
rq.AddParameter("access_token", token);
|
||||
smallContent = cl.Execute(rq).Content;
|
||||
var smallObj = JArray.Parse(smallContent)[0];
|
||||
|
||||
rq = new RestSharp.RestRequest("/anime/" + smallObj["id"]);
|
||||
rq.AddParameter("access_token", token);
|
||||
var content = cl.Execute(rq).Content;
|
||||
|
||||
return await Task.Run(() => JsonConvert.DeserializeObject<AnimeResult>(content)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<MangaResult> GetMangaData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
await RefreshAnilistToken().ConfigureAwait(false);
|
||||
|
||||
var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
|
||||
var smallContent = "";
|
||||
var cl = new RestSharp.RestClient("http://anilist.co/api");
|
||||
var rq = new RestSharp.RestRequest("/manga/search/" + Uri.EscapeUriString(query));
|
||||
rq.AddParameter("access_token", token);
|
||||
smallContent = cl.Execute(rq).Content;
|
||||
var smallObj = JArray.Parse(smallContent)[0];
|
||||
|
||||
rq = new RestSharp.RestRequest("/manga/" + smallObj["id"]);
|
||||
rq.AddParameter("access_token", token);
|
||||
var content = cl.Execute(rq).Content;
|
||||
|
||||
return await Task.Run(() => JsonConvert.DeserializeObject<MangaResult>(content)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task RefreshAnilistToken()
|
||||
{
|
||||
if (DateTime.Now - lastRefreshed > TimeSpan.FromMinutes(29))
|
||||
lastRefreshed = DateTime.Now;
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
var headers = new Dictionary<string, string> {
|
||||
{"grant_type", "client_credentials"},
|
||||
{"client_id", "kwoth-w0ki9"},
|
||||
{"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
|
||||
};
|
||||
var content = await GetResponseStringAsync(
|
||||
"http://anilist.co/api/auth/access_token",
|
||||
headers,
|
||||
RequestHttpMethod.Post).ConfigureAwait(false);
|
||||
|
||||
token = JObject.Parse(content)["access_token"].ToString();
|
||||
}
|
||||
|
||||
public static async Task<bool> ValidateQuery(Discord.Channel ch, string query)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(query.Trim())) return true;
|
||||
await ch.Send("Please specify search parameters.").ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task<string> FindYoutubeUrlByKeywords(string keywords)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(keywords))
|
||||
throw new ArgumentNullException(nameof(keywords), "Query not specified.");
|
||||
if (keywords.Length > 150)
|
||||
throw new ArgumentException("Query is too long.");
|
||||
|
||||
//maybe it is already a youtube url, in which case we will just extract the id and prepend it with youtube.com?v=
|
||||
var match = new Regex("(?:youtu\\.be\\/|v=)(?<id>[\\da-zA-Z\\-_]*)").Match(keywords);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
return $"https://www.youtube.com/watch?v={match.Groups["id"].Value}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
throw new InvalidCredentialException("Google API Key is missing.");
|
||||
|
||||
var response = await GetResponseStringAsync(
|
||||
$"https://www.googleapis.com/youtube/v3/search?" +
|
||||
$"part=snippet&maxResults=1" +
|
||||
$"&q={Uri.EscapeDataString(keywords)}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
|
||||
|
||||
if (data.items.Length > 0)
|
||||
{
|
||||
var toReturn = "http://www.youtube.com/watch?v=" + data.items[0].id.videoId.ToString();
|
||||
return toReturn;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<string>> GetRelatedVideoIds(string id, int count = 1)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
var match = new Regex("(?:youtu\\.be\\/|v=)(?<id>[\\da-zA-Z\\-_]*)").Match(id);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
id = match.Groups["id"].Value;
|
||||
}
|
||||
var response = await GetResponseStringAsync(
|
||||
$"https://www.googleapis.com/youtube/v3/search?" +
|
||||
$"part=snippet&maxResults={count}&type=video" +
|
||||
$"&relatedToVideoId={id}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
|
||||
|
||||
return data.items.Select(v => "http://www.youtube.com/watch?v=" + v.id.videoId);
|
||||
}
|
||||
|
||||
public static async Task<string> GetPlaylistIdByKeyword(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
var match = new Regex("(?:youtu\\.be\\/|list=)(?<id>[\\da-zA-Z\\-_]*)").Match(query);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
return match.Groups["id"].Value.ToString();
|
||||
}
|
||||
var link = "https://www.googleapis.com/youtube/v3/search?part=snippet" +
|
||||
"&maxResults=1&type=playlist" +
|
||||
$"&q={Uri.EscapeDataString(query)}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
|
||||
var response = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var data = JsonConvert.DeserializeObject<YoutubePlaylistSearch>(response);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
return data.items.Length > 0 ? data.items[0].id.playlistId.ToString() : null;
|
||||
}
|
||||
|
||||
public static async Task<IList<string>> GetVideoIDs(string playlist, int number = 50)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(playlist));
|
||||
}
|
||||
if (number < 1)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
string nextPageToken = null;
|
||||
|
||||
List<string> toReturn = new List<string>();
|
||||
|
||||
do
|
||||
{
|
||||
var toGet = number > 50 ? 50 : number;
|
||||
number -= toGet;
|
||||
var link =
|
||||
$"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails" +
|
||||
$"&maxResults={toGet}" +
|
||||
$"&playlistId={playlist}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
if (!string.IsNullOrWhiteSpace(nextPageToken))
|
||||
link += $"&pageToken={nextPageToken}";
|
||||
var response = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var data = await Task.Run(() => JsonConvert.DeserializeObject<PlaylistItemsSearch>(response)).ConfigureAwait(false);
|
||||
nextPageToken = data.nextPageToken;
|
||||
toReturn.AddRange(data.items.Select(i => i.contentDetails.videoId));
|
||||
} while (number > 0 && !string.IsNullOrWhiteSpace(nextPageToken));
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<string> GetDanbooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
|
||||
if (tag == "loli") //loli doesn't work for some reason atm
|
||||
tag = "flat_chest";
|
||||
|
||||
var link = $"http://danbooru.donmai.us/posts?" +
|
||||
$"page={rng.Next(0, 15)}";
|
||||
if (!string.IsNullOrWhiteSpace(tag))
|
||||
link += $"&tags={tag.Replace(" ", "_")}";
|
||||
|
||||
var webpage = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "data-large-file-url=\"(?<id>.*?)\"");
|
||||
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
return $"http://danbooru.donmai.us" +
|
||||
$"{matches[rng.Next(0, matches.Count)].Groups["id"].Value}";
|
||||
}
|
||||
|
||||
public static async Task<string> GetGelbooruImageLink(string tag)
|
||||
{
|
||||
var headers = new Dictionary<string, string>() {
|
||||
{"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
|
||||
{"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
|
||||
};
|
||||
var url =
|
||||
$"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url, headers).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var rng = new Random();
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
public static async Task<string> GetSafebooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
public static async Task<string> GetRule34ImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return "http:" + matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
|
||||
internal static async Task<string> GetE621ImageLink(string tags)
|
||||
{
|
||||
try
|
||||
{
|
||||
var headers = new Dictionary<string, string>() {
|
||||
{"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
|
||||
{"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
|
||||
};
|
||||
var data = await GetResponseStreamAsync(
|
||||
"http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1",
|
||||
headers);
|
||||
var doc = XDocument.Load(data);
|
||||
return doc.Descendants("file_url").FirstOrDefault().Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error in e621 search: \n" + ex);
|
||||
return "Error, do you have too many tags?";
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> ShortenUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey)) return url;
|
||||
try
|
||||
{
|
||||
var httpWebRequest =
|
||||
(HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" +
|
||||
NadekoBot.Creds.GoogleAPIKey);
|
||||
httpWebRequest.ContentType = "application/json";
|
||||
httpWebRequest.Method = "POST";
|
||||
|
||||
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
|
||||
{
|
||||
var json = "{\"longUrl\":\"" + Uri.EscapeDataString(url) + "\"}";
|
||||
streamWriter.Write(json);
|
||||
}
|
||||
|
||||
var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse;
|
||||
var responseStream = httpResponse.GetResponseStream();
|
||||
using (var streamReader = new StreamReader(responseStream))
|
||||
{
|
||||
var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||
return Regex.Match(responseText, @"""id"": ?""(?<id>.+)""").Groups["id"].Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Shortening of this url failed: " + url);
|
||||
Console.WriteLine(ex.ToString());
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ShowInPrettyCode<T>(IEnumerable<T> items, Func<T, string> howToPrint, int cols = 3)
|
||||
{
|
||||
var i = 0;
|
||||
return "```xl\n" + string.Join("\n", items.GroupBy(item => (i++) / cols)
|
||||
.Select(ig => string.Concat(ig.Select(el => howToPrint(el)))))
|
||||
+ $"\n```";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,290 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal class SpecificConfigurations
|
||||
{
|
||||
public static SpecificConfigurations Default { get; } = new SpecificConfigurations();
|
||||
public static bool Instantiated { get; private set; }
|
||||
|
||||
private const string filePath = "data/ServerSpecificConfigs.json";
|
||||
|
||||
static SpecificConfigurations() { }
|
||||
|
||||
private SpecificConfigurations()
|
||||
{
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
configs = JsonConvert
|
||||
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
|
||||
File.ReadAllText(filePath), new JsonSerializerSettings()
|
||||
{
|
||||
Error = (s, e) =>
|
||||
{
|
||||
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
|
||||
{
|
||||
e.ErrorContext.Handled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Deserialization failing: {ex}");
|
||||
}
|
||||
}
|
||||
if (configs == null)
|
||||
configs = new ConcurrentDictionary<ulong, ServerSpecificConfig>();
|
||||
Instantiated = true;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, ServerSpecificConfig> configs;
|
||||
|
||||
public IEnumerable<ServerSpecificConfig> AllConfigs => configs.Values;
|
||||
|
||||
public ServerSpecificConfig Of(ulong id) =>
|
||||
configs.GetOrAdd(id, _ => new ServerSpecificConfig());
|
||||
|
||||
private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public async Task Save()
|
||||
{
|
||||
await saveLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await Task.Run(() => File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
saveLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ServerSpecificConfig : INotifyPropertyChanged
|
||||
{
|
||||
[JsonProperty("VoicePlusTextEnabled")]
|
||||
private bool voicePlusTextEnabled;
|
||||
[JsonIgnore]
|
||||
public bool VoicePlusTextEnabled {
|
||||
get { return voicePlusTextEnabled; }
|
||||
set {
|
||||
voicePlusTextEnabled = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[JsonProperty("SendPrivateMessageOnMention")]
|
||||
private bool sendPrivateMessageOnMention;
|
||||
[JsonIgnore]
|
||||
public bool SendPrivateMessageOnMention {
|
||||
get { return sendPrivateMessageOnMention; }
|
||||
set {
|
||||
sendPrivateMessageOnMention = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogChannel")]
|
||||
private ulong? logServerChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogServerChannel {
|
||||
get { return logServerChannel; }
|
||||
set {
|
||||
logServerChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> logserverIgnoreChannels;
|
||||
public ObservableCollection<ulong> LogserverIgnoreChannels {
|
||||
get { return logserverIgnoreChannels; }
|
||||
set {
|
||||
logserverIgnoreChannels = value;
|
||||
if (value != null)
|
||||
logserverIgnoreChannels.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogPresenceChannel")]
|
||||
private ulong? logPresenceChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogPresenceChannel {
|
||||
get { return logPresenceChannel; }
|
||||
set {
|
||||
logPresenceChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableConcurrentDictionary<ulong, ulong> voiceChannelLog;
|
||||
public ObservableConcurrentDictionary<ulong, ulong> VoiceChannelLog {
|
||||
get { return voiceChannelLog; }
|
||||
set {
|
||||
voiceChannelLog = value;
|
||||
if (value != null)
|
||||
voiceChannelLog.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> listOfSelfAssignableRoles;
|
||||
public ObservableCollection<ulong> ListOfSelfAssignableRoles {
|
||||
get { return listOfSelfAssignableRoles; }
|
||||
set {
|
||||
listOfSelfAssignableRoles = value;
|
||||
if (value != null)
|
||||
listOfSelfAssignableRoles.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private ulong autoAssignedRole = 0;
|
||||
public ulong AutoAssignedRole {
|
||||
get { return autoAssignedRole; }
|
||||
set {
|
||||
autoAssignedRole = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableConcurrentDictionary<ulong, int> generateCurrencyChannels;
|
||||
public ObservableConcurrentDictionary<ulong, int> GenerateCurrencyChannels {
|
||||
get { return generateCurrencyChannels; }
|
||||
set {
|
||||
generateCurrencyChannels = value;
|
||||
if (value != null)
|
||||
generateCurrencyChannels.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool autoDeleteMessagesOnCommand = false;
|
||||
public bool AutoDeleteMessagesOnCommand {
|
||||
get { return autoDeleteMessagesOnCommand; }
|
||||
set {
|
||||
autoDeleteMessagesOnCommand = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool exclusiveSelfAssignedRoles = false;
|
||||
public bool ExclusiveSelfAssignedRoles {
|
||||
get { return exclusiveSelfAssignedRoles; }
|
||||
set {
|
||||
exclusiveSelfAssignedRoles = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<StreamNotificationConfig> observingStreams;
|
||||
public ObservableCollection<StreamNotificationConfig> ObservingStreams {
|
||||
get { return observingStreams; }
|
||||
set {
|
||||
observingStreams = value;
|
||||
if (value != null)
|
||||
observingStreams.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private float defaultMusicVolume = 1f;
|
||||
public float DefaultMusicVolume {
|
||||
get { return defaultMusicVolume; }
|
||||
set {
|
||||
defaultMusicVolume = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ServerSpecificConfig()
|
||||
{
|
||||
ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
|
||||
ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
|
||||
GenerateCurrencyChannels = new ObservableConcurrentDictionary<ulong, int>();
|
||||
VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>();
|
||||
LogserverIgnoreChannels = new ObservableCollection<ulong>();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); };
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
public class StreamNotificationConfig : IEquatable<StreamNotificationConfig>
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public StreamType Type { get; set; }
|
||||
public ulong ServerId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public bool LastStatus { get; set; }
|
||||
|
||||
public enum StreamType
|
||||
{
|
||||
Twitch,
|
||||
Beam,
|
||||
Hitbox,
|
||||
YoutubeGaming
|
||||
}
|
||||
|
||||
public bool Equals(StreamNotificationConfig other) =>
|
||||
this.Username.ToUpperInvariant().Trim() == other.Username.ToUpperInvariant().Trim() &&
|
||||
this.Type == other.Type &&
|
||||
this.ServerId == other.ServerId;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)ServerId + Username.Length + (int)Type;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,901 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
internal class AdministrationModule : DiscordModule
|
||||
{
|
||||
public AdministrationModule()
|
||||
{
|
||||
commands.Add(new ServerGreetCommand(this));
|
||||
commands.Add(new LogCommand(this));
|
||||
commands.Add(new MessageRepeater(this));
|
||||
commands.Add(new PlayingRotate(this));
|
||||
commands.Add(new RatelimitCommand(this));
|
||||
commands.Add(new VoicePlusTextCommand(this));
|
||||
commands.Add(new CrossServerTextChannel(this));
|
||||
commands.Add(new SelfAssignedRolesCommand(this));
|
||||
commands.Add(new CustomReactionsCommands(this));
|
||||
commands.Add(new AutoAssignRole(this));
|
||||
commands.Add(new SelfCommands(this));
|
||||
commands.Add(new IncidentsCommands(this));
|
||||
|
||||
NadekoBot.Client.GetService<CommandService>().CommandExecuted += DeleteCommandMessage;
|
||||
}
|
||||
|
||||
private void DeleteCommandMessage(object sender, CommandEventArgs e)
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate)
|
||||
return;
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (!conf.AutoDeleteMessagesOnCommand)
|
||||
return;
|
||||
try
|
||||
{
|
||||
e.Message.Delete();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
var client = manager.Client;
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "delmsgoncmd")
|
||||
.Description($"Toggles the automatic deletion of user's successful command message to prevent chat flood. **Server Manager Only.** | `{Prefix}delmsgoncmd`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
|
||||
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
if (conf.AutoDeleteMessagesOnCommand)
|
||||
await e.Channel.SendMessage("❗`Now automatically deleting successful command invokations.`");
|
||||
else
|
||||
await e.Channel.SendMessage("❗`Stopped automatic deletion of successful command invokations.`");
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "restart")
|
||||
.Description($"Restarts the bot. Might not work. **Bot Owner Only** | `{Prefix}restart`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage("`Restarting in 2 seconds...`");
|
||||
await Task.Delay(2000);
|
||||
System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
|
||||
.Description($"Sets a role for a given user. **Needs Manage Roles Permissions.**| `{Prefix}sr @User Guest`")
|
||||
.Parameter("user_name", ParameterType.Required)
|
||||
.Parameter("role_name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var userName = e.GetArg("user_name");
|
||||
var roleName = e.GetArg("role_name");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(roleName)) return;
|
||||
|
||||
if (!e.User.ServerPermissions.ManageRoles)
|
||||
{
|
||||
await e.Channel.SendMessage("You have insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var usr = e.Server.FindUsers(userName).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var role = e.Server.FindRoles(roleName).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage("You failed to supply a valid role").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await usr.AddRoles(role).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully added role **{role.Name}** to user **{usr.Name}**").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to add roles. Bot has insufficient permissions.\n").ConfigureAwait(false);
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
|
||||
.Description($"Removes a role from a given user. **Needs Manage Roles Permissions.**| `{Prefix}rr @User Admin`")
|
||||
.Parameter("user_name", ParameterType.Required)
|
||||
.Parameter("role_name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var userName = e.GetArg("user_name");
|
||||
var roleName = e.GetArg("role_name");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(roleName)) return;
|
||||
|
||||
var usr = e.Server.FindUsers(userName).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var role = e.Server.FindRoles(roleName).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage("You failed to supply a valid role").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await usr.RemoveRoles(role).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully removed role **{role.Name}** from user **{usr.Name}**").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "renamerole")
|
||||
.Alias(Prefix + "renr")
|
||||
.Description($"Renames a role. Roles you are renaming must be lower than bot's highest role. **Manage Roles Permissions.** | `{Prefix}renr \"First role\" SecondRole`")
|
||||
.Parameter("r1", ParameterType.Required)
|
||||
.Parameter("r2", ParameterType.Required)
|
||||
.AddCheck(new SimpleCheckers.ManageRoles())
|
||||
.Do(async e =>
|
||||
{
|
||||
var r1 = e.GetArg("r1").Trim();
|
||||
var r2 = e.GetArg("r2").Trim();
|
||||
|
||||
var roleToEdit = e.Server.FindRoles(r1).FirstOrDefault();
|
||||
if (roleToEdit == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Can't find that role.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (roleToEdit.Position > e.Server.CurrentUser.Roles.Max(r => r.Position))
|
||||
{
|
||||
await e.Channel.SendMessage("I can't edit roles higher than my highest role.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await roleToEdit.Edit(r2);
|
||||
await e.Channel.SendMessage("Role renamed.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to rename role. Probably insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
|
||||
.Description($"Removes all roles from a mentioned user. **Needs Manage Roles Permissions.**| `{Prefix}rar @User`")
|
||||
.Parameter("user_name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var userName = e.GetArg("user_name");
|
||||
|
||||
var usr = e.Server.FindUsers(userName).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await usr.RemoveRoles(usr.Roles.ToArray()).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully removed **all** roles from user **{usr.Name}**").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr")
|
||||
.Description($"Creates a role with a given name. **Needs Manage Roles Permissions.**| `{Prefix}cr Awesome Role`")
|
||||
.Parameter("role_name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("role_name")))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var r = await e.Server.CreateRole(e.GetArg("role_name")).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully created role **{r.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await e.Channel.SendMessage(":warning: Unspecified error.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rolecolor").Alias(Prefix + "rc")
|
||||
.Parameter("role_name", ParameterType.Required)
|
||||
.Parameter("r", ParameterType.Optional)
|
||||
.Parameter("g", ParameterType.Optional)
|
||||
.Parameter("b", ParameterType.Optional)
|
||||
.Description($"Set a role's color to the hex or 0-255 rgb color value provided. **Needs Manage Roles Permissions.** | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageRoles)
|
||||
{
|
||||
await e.Channel.SendMessage("You don't have permission to use this!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var args = e.Args.Where(s => s != string.Empty);
|
||||
|
||||
if (args.Count() != 2 && args.Count() != 4)
|
||||
{
|
||||
await e.Channel.SendMessage("The parameters are invalid.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var role = e.Server.FindRoles(e.Args[0]).FirstOrDefault();
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage("That role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var rgb = args.Count() == 4;
|
||||
var arg1 = e.Args[1].Replace("#", "");
|
||||
|
||||
var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16));
|
||||
var green = Convert.ToByte(rgb ? int.Parse(e.Args[2]) : Convert.ToInt32(arg1.Substring(2, 2), 16));
|
||||
var blue = Convert.ToByte(rgb ? int.Parse(e.Args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16));
|
||||
|
||||
await role.Edit(color: new Color(red, green, blue)).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Role {role.Name}'s color has been changed.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await e.Channel.SendMessage("Error occured, most likely invalid parameters or insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
|
||||
.Parameter("user", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Description($"Bans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var msg = e.GetArg("msg");
|
||||
var user = e.GetArg("user");
|
||||
if (e.User.ServerPermissions.BanMembers)
|
||||
{
|
||||
var usr = e.Server.FindUsers(user).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
await usr.SendMessage($"**You have been BANNED from `{e.Server.Name}` server.**\n" +
|
||||
$"Reason: {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
|
||||
}
|
||||
try
|
||||
{
|
||||
await e.Server.Ban(usr, 7).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
|
||||
.Parameter("user", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Description($"Bans and then unbans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var msg = e.GetArg("msg");
|
||||
var user = e.GetArg("user");
|
||||
if (e.User.ServerPermissions.BanMembers)
|
||||
{
|
||||
var usr = e.Server.FindUsers(user).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
await usr.SendMessage($"**You have been SOFT-BANNED from `{e.Server.Name}` server.**\n" +
|
||||
$"Reason: {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
|
||||
}
|
||||
try
|
||||
{
|
||||
await e.Server.Ban(usr, 7).ConfigureAwait(false);
|
||||
await e.Server.Unban(usr).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage("Soft-Banned user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k")
|
||||
.Parameter("user")
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Description($"Kicks a mentioned user. **Needs Kick Permissions.**| `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var msg = e.GetArg("msg");
|
||||
var user = e.GetArg("user");
|
||||
if (e.User.ServerPermissions.KickMembers)
|
||||
{
|
||||
var usr = e.Server.FindUsers(user).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
await usr.SendMessage($"**You have been KICKED from `{e.Server.Name}` server.**\n" +
|
||||
$"Reason: {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
|
||||
}
|
||||
try
|
||||
{
|
||||
await usr.Kick().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage("Kicked user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "mute")
|
||||
.Description($"Mutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
|
||||
.Parameter("throwaway", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.MuteMembers)
|
||||
{
|
||||
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.Message.MentionedUsers.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
foreach (var u in e.Message.MentionedUsers)
|
||||
{
|
||||
await u.Edit(isMuted: true).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage("Mute successful").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "unmute")
|
||||
.Description($"Unmutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
|
||||
.Parameter("throwaway", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.MuteMembers)
|
||||
{
|
||||
await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.Message.MentionedUsers.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
foreach (var u in e.Message.MentionedUsers)
|
||||
{
|
||||
await u.Edit(isMuted: false).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage("Unmute successful").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "deafen")
|
||||
.Alias(Prefix + "deaf")
|
||||
.Description($"Deafens mentioned user or users. **Needs Deafen Permissions.**| `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
|
||||
.Parameter("throwaway", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.DeafenMembers)
|
||||
{
|
||||
await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.Message.MentionedUsers.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
foreach (var u in e.Message.MentionedUsers)
|
||||
{
|
||||
await u.Edit(isDeafened: true).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage("Deafen successful").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "undeafen")
|
||||
.Alias(Prefix + "undef")
|
||||
.Description($"Undeafens mentioned user or users. **Needs Deafen Permissions.** | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
|
||||
.Parameter("throwaway", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.DeafenMembers)
|
||||
{
|
||||
await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.Message.MentionedUsers.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
foreach (var u in e.Message.MentionedUsers)
|
||||
{
|
||||
await u.Edit(isDeafened: false).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage("Undeafen successful").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "delvoichanl")
|
||||
.Alias(Prefix + "dvch")
|
||||
.Description($"Deletes a voice channel with a given name. **Needs Manage Channel Permissions.**| `{Prefix}dvch VoiceChannelName`")
|
||||
.Parameter("channel_name", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.User.ServerPermissions.ManageChannels)
|
||||
{
|
||||
var ch = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Voice).FirstOrDefault();
|
||||
if (ch == null)
|
||||
return;
|
||||
await ch.Delete().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Removed channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Insufficient permissions.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "creatvoichanl")
|
||||
.Alias(Prefix + "cvch")
|
||||
.Description($"Creates a new voice channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}cvch VoiceChannelName`")
|
||||
.Parameter("channel_name", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.User.ServerPermissions.ManageChannels)
|
||||
{
|
||||
await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Voice).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Created voice channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "deltxtchanl")
|
||||
.Alias(Prefix + "dtch")
|
||||
.Description($"Deletes a text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}dtch TextChannelName`")
|
||||
.Parameter("channel_name", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.User.ServerPermissions.ManageChannels)
|
||||
{
|
||||
var channel = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Text).FirstOrDefault();
|
||||
if (channel == null) return;
|
||||
await channel.Delete().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Removed text channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "creatxtchanl")
|
||||
.Alias(Prefix + "ctch")
|
||||
.Description($"Creates a new text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}ctch TextChannelName`")
|
||||
.Parameter("channel_name", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.User.ServerPermissions.ManageChannels)
|
||||
{
|
||||
await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Text).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Added text channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "settopic")
|
||||
.Alias(Prefix + "st")
|
||||
.Description($"Sets a topic on the current channel. **Needs Manage Channel Permissions.** | `{Prefix}st My new topic`")
|
||||
.AddCheck(SimpleCheckers.ManageChannels())
|
||||
.Parameter("topic", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var topic = e.GetArg("topic")?.Trim() ?? "";
|
||||
await e.Channel.Edit(topic: topic).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(":ok: **New channel topic set.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "setchanlname")
|
||||
.Alias(Prefix + "schn")
|
||||
.Description($"Changed the name of the current channel. **Needs Manage Channel Permissions.**| `{Prefix}schn NewName`")
|
||||
.AddCheck(SimpleCheckers.ManageChannels())
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name");
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
await e.Channel.Edit(name: name).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(":ok: **New channel name set.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "heap")
|
||||
.Description($"Shows allocated memory - **Bot Owner Only!** | `{Prefix}heap`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var heap = await Task.Run(() => NadekoStats.Instance.Heap()).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Heap Size:` {heap}").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "prune")
|
||||
.Alias(Prefix + "clr")
|
||||
.Description(
|
||||
"`.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. **Needs Manage Messages Permissions**" +
|
||||
$"| `{Prefix}prune` or `{Prefix}prune 5` or `{Prefix}prune @Someone` or `{Prefix}prune @Someone X`")
|
||||
.Parameter("user_or_num", ParameterType.Optional)
|
||||
.Parameter("num", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
|
||||
{
|
||||
var msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User?.Id == e.Server.CurrentUser.Id)?.ToArray();
|
||||
if (msgs == null || !msgs.Any())
|
||||
return;
|
||||
var toDelete = msgs as Message[] ?? msgs.ToArray();
|
||||
await e.Channel.DeleteMessages(toDelete).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.User.GetPermissions(e.Channel).ManageMessages)
|
||||
return;
|
||||
else if (!e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
|
||||
{
|
||||
await e.Channel.SendMessage("💢I don't have the permission to manage messages.");
|
||||
return;
|
||||
}
|
||||
int val;
|
||||
if (int.TryParse(e.GetArg("user_or_num"), out val)) // if num is set in the first argument,
|
||||
//delete that number of messages.
|
||||
{
|
||||
if (val <= 0)
|
||||
return;
|
||||
val++;
|
||||
await e.Channel.DeleteMessages((await e.Channel.DownloadMessages(val).ConfigureAwait(false)).ToArray()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//else if first argument is user
|
||||
var usr = e.Server.FindUsers(e.GetArg("user_or_num")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
return;
|
||||
val = 100;
|
||||
if (!int.TryParse(e.GetArg("num"), out val))
|
||||
val = 100;
|
||||
var mesgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User?.Id == usr.Id).Take(val);
|
||||
if (mesgs == null || !mesgs.Any())
|
||||
return;
|
||||
await e.Channel.DeleteMessages(mesgs as Message[] ?? mesgs.ToArray()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "die")
|
||||
.Description($"Shuts the bot down and notifies users about the restart. **Bot Owner Only!** | `{Prefix}die`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage("`Shutting down.`").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "setname")
|
||||
.Alias(Prefix + "newnm")
|
||||
.Description($"Give the bot a new name. **Bot Owner Only!** | `{Prefix}newnm BotName`")
|
||||
.Parameter("new_name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (e.GetArg("new_name") == null) return;
|
||||
|
||||
await client.CurrentUser.Edit("", e.GetArg("new_name")).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "newavatar")
|
||||
.Alias(Prefix + "setavatar")
|
||||
.Description($"Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `{Prefix}setavatar http://i.imgur.com/xTG3a1I.jpg`")
|
||||
.Parameter("img", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("img")))
|
||||
return;
|
||||
// Gather user provided URL.
|
||||
var avatarAddress = e.GetArg("img");
|
||||
var imageStream = await SearchHelper.GetResponseStreamAsync(avatarAddress).ConfigureAwait(false);
|
||||
var image = System.Drawing.Image.FromStream(imageStream);
|
||||
await client.CurrentUser.Edit("", avatar: image.ToStream()).ConfigureAwait(false);
|
||||
|
||||
// Send confirm.
|
||||
await e.Channel.SendMessage("New avatar set.").ConfigureAwait(false);
|
||||
|
||||
// Save the image to disk.
|
||||
image.Save("data/avatar.png", System.Drawing.Imaging.ImageFormat.Png);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "setgame")
|
||||
.Description($"Sets the bots game. **Bot Owner Only!** | `{Prefix}setgame Playing with kwoth`")
|
||||
.Parameter("set_game", ParameterType.Unparsed)
|
||||
.Do(e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("set_game") == null) return;
|
||||
|
||||
client.SetGame(e.GetArg("set_game"));
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "send")
|
||||
.Description($"Send a message to someone on a different server through the bot. **Bot Owner Only!** | `{Prefix}send sid|u:uid Hello user!` or `{Prefix}send sid|c:cid Message to channel!` (cid = channel id, sid = server id)")
|
||||
.Parameter("ids", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var msg = e.GetArg("msg")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
return;
|
||||
|
||||
var ids = e.GetArg("ids").Split('|');
|
||||
if (ids.Length != 2)
|
||||
return;
|
||||
var sid = ulong.Parse(ids[0]);
|
||||
var server = NadekoBot.Client.Servers.Where(s => s.Id == sid).FirstOrDefault();
|
||||
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:"))
|
||||
{
|
||||
var cid = ulong.Parse(ids[1].Substring(2));
|
||||
var channel = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
|
||||
if (channel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await channel.SendMessage(msg);
|
||||
}
|
||||
else if (ids[1].ToUpperInvariant().StartsWith("U:"))
|
||||
{
|
||||
var uid = ulong.Parse(ids[1].Substring(2));
|
||||
var user = server.Users.Where(u => u.Id == uid).FirstOrDefault();
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await user.SendMessage(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("`Invalid format.`");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "mentionrole")
|
||||
.Alias(Prefix + "menro")
|
||||
.Description($"Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `{Prefix}menro RoleName`")
|
||||
.Parameter("roles", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.MentionEveryone) return;
|
||||
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
|
||||
string send = $"--{e.User.Mention} has invoked a mention on the following roles--";
|
||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
var role = e.Server.FindRoles(roleStr).FirstOrDefault();
|
||||
if (role == null) continue;
|
||||
send += $"\n`{role.Name}`\n";
|
||||
send += string.Join(", ", role.Members.Select(r => r.Mention));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
{
|
||||
var curstr = send.Substring(0, 2000);
|
||||
await
|
||||
e.Channel.Send(curstr.Substring(0,
|
||||
curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
send.Substring(2000);
|
||||
}
|
||||
await e.Channel.Send(send).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "unstuck")
|
||||
.Description($"Clears the message queue. **Bot Owner Only!** | `{Prefix}unstuck`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(e =>
|
||||
{
|
||||
NadekoBot.Client.MessageQueue.Clear();
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "donators")
|
||||
.Description($"List of lovely people who donated to keep this project alive. | `{Prefix}donators`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var rows = DbHandler.Instance.GetAllRows<Donator>();
|
||||
var donatorsOrdered = rows.OrderByDescending(d => d.Amount);
|
||||
string str = $"**Thanks to the people listed below for making this project happen!**\n";
|
||||
|
||||
await e.Channel.SendMessage(str + string.Join("⭐", donatorsOrdered.Select(d => d.UserName))).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "donadd")
|
||||
.Description($"Add a donator to the database. **Kwoth Only** | `{Prefix}donadd Donate Amount`")
|
||||
.Parameter("donator")
|
||||
.Parameter("amount")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var donator = e.Server.FindUsers(e.GetArg("donator")).FirstOrDefault();
|
||||
var amount = int.Parse(e.GetArg("amount"));
|
||||
if (donator == null) return;
|
||||
try
|
||||
{
|
||||
DbHandler.Instance.Connection.Insert(new Donator
|
||||
{
|
||||
Amount = amount,
|
||||
UserName = donator.Name,
|
||||
UserId = (long)donator.Id
|
||||
});
|
||||
e.Channel.SendMessage("Successfuly added a new donator. 👑").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "announce")
|
||||
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `{Prefix}announce Useless spam`")
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
foreach (var ch in NadekoBot.Client.Servers.Select(s => s.DefaultChannel))
|
||||
{
|
||||
await ch.SendMessage(e.GetArg("msg")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "savechat")
|
||||
.Description($"Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `{Prefix}savechat 150`")
|
||||
.Parameter("cnt", ParameterType.Required)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var cntstr = e.GetArg("cnt")?.Trim();
|
||||
int cnt;
|
||||
if (!int.TryParse(cntstr, out cnt))
|
||||
return;
|
||||
ulong? lastmsgId = null;
|
||||
var sb = new StringBuilder();
|
||||
var msgs = new List<Message>(cnt);
|
||||
while (cnt > 0)
|
||||
{
|
||||
var dlcnt = cnt < 100 ? cnt : 100;
|
||||
|
||||
var dledMsgs = await e.Channel.DownloadMessages(dlcnt, lastmsgId);
|
||||
if (!dledMsgs.Any())
|
||||
break;
|
||||
msgs.AddRange(dledMsgs);
|
||||
lastmsgId = msgs[msgs.Count - 1].Id;
|
||||
cnt -= 100;
|
||||
}
|
||||
await e.User.SendFile($"Chatlog-{e.Server.Name}/#{e.Channel.Name}-{DateTime.Now}.txt", JsonConvert.SerializeObject(new { Messages = msgs.Select(s => s.ToString()) }, Formatting.Indented).ToStream()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
class AutoAssignRole : DiscordCommand
|
||||
{
|
||||
public AutoAssignRole(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () => NadekoBot.Client.UserJoined += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var role = e.Server.Roles.Where(r => r.Id == config.AutoAssignedRole).FirstOrDefault();
|
||||
|
||||
if (role == null)
|
||||
return;
|
||||
|
||||
e.User.AddRoles(role);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"aar exception. {ex}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "autoassignrole")
|
||||
.Alias(Module.Prefix + "aar")
|
||||
.Description($"Automaticaly assigns a specified role to every user who joins the server. **Needs Manage Roles Permissions.** |`{Prefix}aar` to disable, `{Prefix}aar Role Name` to enable")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.AddCheck(new SimpleCheckers.ManageRoles())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.Server.CurrentUser.ServerPermissions.ManageRoles)
|
||||
{
|
||||
await e.Channel.SendMessage("I do not have the permission to manage roles.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var r = e.GetArg("role")?.Trim();
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(r)) //if role is not specified, disable
|
||||
{
|
||||
config.AutoAssignedRole = 0;
|
||||
|
||||
await e.Channel.SendMessage("`Auto assign role on user join is now disabled.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var role = e.Server.FindRoles(r).FirstOrDefault();
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 `Role not found.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
config.AutoAssignedRole = role.Id;
|
||||
await e.Channel.SendMessage("`Auto assigned role is set.`").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
class CrossServerTextChannel : DiscordCommand
|
||||
{
|
||||
public CrossServerTextChannel(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
foreach (var subscriber in Subscribers)
|
||||
{
|
||||
var set = subscriber.Value;
|
||||
if (!set.Contains(e.Channel))
|
||||
continue;
|
||||
foreach (var chan in set.Except(new[] { e.Channel }))
|
||||
{
|
||||
await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.MessageUpdated += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
foreach (var subscriber in Subscribers)
|
||||
{
|
||||
var set = subscriber.Value;
|
||||
if (!set.Contains(e.Channel))
|
||||
continue;
|
||||
foreach (var chan in set.Except(new[] { e.Channel }))
|
||||
{
|
||||
var msg = chan.Messages
|
||||
.FirstOrDefault(m =>
|
||||
m.RawText == GetText(e.Server, e.Channel, e.User, e.Before));
|
||||
if (msg != default(Message))
|
||||
await msg.Edit(GetText(e.Server, e.Channel, e.User, e.After)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private string GetText(Server server, Channel channel, User user, Message message) =>
|
||||
$"**{server.Name} | {channel.Name}** `{user.Name}`: " + message.RawText;
|
||||
|
||||
public static readonly ConcurrentDictionary<int, HashSet<Channel>> Subscribers = new ConcurrentDictionary<int, HashSet<Channel>>();
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "scsc")
|
||||
.Description("Starts an instance of cross server channel. You will get a token as a DM " +
|
||||
$"that other people will use to tune in to the same instance. **Bot Owner Only.** | `{Prefix}scsc`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var token = new Random().Next();
|
||||
var set = new HashSet<Channel>();
|
||||
if (Subscribers.TryAdd(token, set))
|
||||
{
|
||||
set.Add(e.Channel);
|
||||
await e.User.SendMessage("This is your CSC token:" + token.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "jcsc")
|
||||
.Description($"Joins current channel to an instance of cross server channel using the token. **Needs Manage Server Permissions.**| `{Prefix}jcsc`")
|
||||
.Parameter("token")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
int token;
|
||||
if (!int.TryParse(e.GetArg("token"), out token))
|
||||
return;
|
||||
HashSet<Channel> set;
|
||||
if (!Subscribers.TryGetValue(token, out set))
|
||||
return;
|
||||
set.Add(e.Channel);
|
||||
await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "lcsc")
|
||||
.Description($"Leaves Cross server channel instance from this channel. **Needs Manage Server Permissions.**| `{Prefix}lcsc`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
foreach (var subscriber in Subscribers)
|
||||
{
|
||||
subscriber.Value.Remove(e.Channel);
|
||||
}
|
||||
await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
class CustomReactionsCommands : DiscordCommand
|
||||
{
|
||||
public CustomReactionsCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
var Prefix = Module.Prefix;
|
||||
|
||||
cgb.CreateCommand(Prefix + "addcustreact")
|
||||
.Alias(Prefix + "acr")
|
||||
.Description($"Add a custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions> **Bot Owner Only!** | `{Prefix}acr \"hello\" Hi there %user%`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Parameter("name", ParameterType.Required)
|
||||
.Parameter("message", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name");
|
||||
var message = e.GetArg("message")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
await e.Channel.SendMessage($"Incorrect command usage. See -h {Prefix}acr for correct formatting").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
NadekoBot.Config.CustomReactions[name].Add(message);
|
||||
else
|
||||
NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List<string>() { message });
|
||||
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "listcustreact")
|
||||
.Alias(Prefix + "lcr")
|
||||
.Description($"Lists custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. |`{Prefix}lcr 1`")
|
||||
.Parameter("num", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var numStr = e.GetArg("num");
|
||||
|
||||
if (numStr.ToUpperInvariant() == "ALL")
|
||||
{
|
||||
var fullstr = String.Join("\n", NadekoBot.Config.CustomReactions.Select(kvp => kvp.Key));
|
||||
do
|
||||
{
|
||||
var str = string.Concat(fullstr.Take(1900));
|
||||
fullstr = new string(fullstr.Skip(1900).ToArray());
|
||||
await e.User.SendMessage("```xl\n" + str + "```");
|
||||
} while (fullstr.Length != 0);
|
||||
return;
|
||||
}
|
||||
int num;
|
||||
if (!int.TryParse(numStr, out num) || num <= 0) num = 1;
|
||||
var cmds = GetCustomsOnPage(num - 1);
|
||||
if (!cmds.Any())
|
||||
{
|
||||
await e.Channel.SendMessage("`There are no custom reactions.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
string result = SearchHelper.ShowInPrettyCode<string>(cmds, s => $"{s,-25}"); //People prefer starting with 1
|
||||
await e.Channel.SendMessage($"`Showing page {num}:`\n" + result).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "showcustreact")
|
||||
.Alias(Prefix + "scr")
|
||||
.Description($"Shows all possible responses from a single custom reaction. |`{Prefix}scr %mention% bb`")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
{
|
||||
await e.Channel.SendMessage("`Can't find that custom reaction.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var items = NadekoBot.Config.CustomReactions[name];
|
||||
var message = new StringBuilder($"Responses for {Format.Bold(name)}:\n");
|
||||
var last = items.Last();
|
||||
|
||||
int i = 1;
|
||||
foreach (var reaction in items)
|
||||
{
|
||||
message.AppendLine($"[{i++}] " + Format.Code(Format.Escape(reaction)));
|
||||
}
|
||||
await e.Channel.SendMessage(message.ToString());
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "editcustreact")
|
||||
.Alias(Prefix + "ecr")
|
||||
.Description($"Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `{Prefix}ecr \"%mention% disguise\" 2 Test 123`")
|
||||
.Parameter("name", ParameterType.Required)
|
||||
.Parameter("index", ParameterType.Required)
|
||||
.Parameter("message", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
var indexstr = e.GetArg("index")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(indexstr))
|
||||
return;
|
||||
var msg = e.GetArg("message")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
return;
|
||||
|
||||
|
||||
|
||||
if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
{
|
||||
await e.Channel.SendMessage("`Could not find given commandname`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (!int.TryParse(indexstr, out index) || index < 1 || index > NadekoBot.Config.CustomReactions[name].Count)
|
||||
{
|
||||
await e.Channel.SendMessage("`Invalid index.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
index = index - 1;
|
||||
NadekoBot.Config.CustomReactions[name][index] = msg;
|
||||
|
||||
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "delcustreact")
|
||||
.Alias(Prefix + "dcr")
|
||||
.Description($"Deletes a custom reaction with given name (and optional index). **Bot Owner Only.**| `{Prefix}dcr \"Reaction Name\"` or `{Prefix}dcr \"Reaction Name\" 3`")
|
||||
.Parameter("name", ParameterType.Required)
|
||||
.Parameter("index", ParameterType.Optional)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
{
|
||||
await e.Channel.SendMessage("Could not find given commandname").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
string message = "";
|
||||
int index;
|
||||
if (int.TryParse(e.GetArg("index")?.Trim() ?? "", out index))
|
||||
{
|
||||
index = index - 1;
|
||||
if (index < 0 || index > NadekoBot.Config.CustomReactions[name].Count)
|
||||
{
|
||||
await e.Channel.SendMessage("Given index was out of range").ConfigureAwait(false);
|
||||
return;
|
||||
|
||||
}
|
||||
NadekoBot.Config.CustomReactions[name].RemoveAt(index);
|
||||
if (!NadekoBot.Config.CustomReactions[name].Any())
|
||||
{
|
||||
NadekoBot.Config.CustomReactions.Remove(name);
|
||||
}
|
||||
message = $"Deleted response #{index + 1} from `{name}`";
|
||||
}
|
||||
else
|
||||
{
|
||||
NadekoBot.Config.CustomReactions.Remove(name);
|
||||
message = $"Deleted custom reaction: `{name}`";
|
||||
}
|
||||
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(message).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private readonly int ItemsPerPage = 30;
|
||||
|
||||
private IEnumerable<string> GetCustomsOnPage(int page)
|
||||
{
|
||||
var items = NadekoBot.Config.CustomReactions.Skip(page * ItemsPerPage).Take(ItemsPerPage);
|
||||
if (!items.Any())
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
return items.Select(kvp => kvp.Key);
|
||||
/*
|
||||
var message = new StringBuilder($"--- Custom reactions - page {page + 1} ---\n");
|
||||
foreach (var cr in items)
|
||||
{
|
||||
message.Append($"{Format.Code(cr.Key)}\n");
|
||||
int i = 1;
|
||||
var last = cr.Value.Last();
|
||||
foreach (var reaction in cr.Value)
|
||||
{
|
||||
if (last != reaction)
|
||||
message.AppendLine(" `├" + i++ + "─`" + Format.Bold(reaction));
|
||||
else
|
||||
message.AppendLine(" `└" + i++ + "─`" + Format.Bold(reaction));
|
||||
}
|
||||
}
|
||||
return message.ToString() + "\n";
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
// zeta is a god
|
||||
//├
|
||||
//─
|
||||
//│
|
||||
//└
|
@ -1,47 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class IncidentsCommands : DiscordCommand
|
||||
{
|
||||
public IncidentsCommands(DiscordModule module) : base(module) { }
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "listincidents")
|
||||
.Alias(Prefix + "lin")
|
||||
.Description($"List all UNREAD incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lin`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var sid = (long)e.Server.Id;
|
||||
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid && i.Read == false);
|
||||
DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
|
||||
|
||||
await e.User.SendMessage(string.Join("\n----------------------", incs.Select(i => i.Text)));
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "listallincidents")
|
||||
.Alias(Prefix + "lain")
|
||||
.Description($"Sends you a file containing all incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lain`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var sid = (long)e.Server.Id;
|
||||
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid);
|
||||
DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
|
||||
var data = string.Join("\n----------------------\n", incs.Select(i => i.Text));
|
||||
MemoryStream ms = new MemoryStream();
|
||||
var sw = new StreamWriter(ms);
|
||||
sw.WriteLine(data);
|
||||
sw.Flush();
|
||||
sw.BaseStream.Position = 0;
|
||||
await e.User.SendFile("incidents.txt", sw.BaseStream);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,489 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class LogCommand : DiscordCommand
|
||||
{
|
||||
private string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
|
||||
|
||||
private ConcurrentBag<KeyValuePair<Channel, string>> voicePresenceUpdates = new ConcurrentBag<KeyValuePair<Channel, string>>();
|
||||
|
||||
public LogCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
//NadekoBot.Client.MessageReceived += MsgRecivd;
|
||||
NadekoBot.Client.MessageDeleted += MsgDltd;
|
||||
NadekoBot.Client.MessageUpdated += MsgUpdtd;
|
||||
NadekoBot.Client.UserUpdated += UsrUpdtd;
|
||||
NadekoBot.Client.UserBanned += UsrBanned;
|
||||
NadekoBot.Client.UserLeft += UsrLeft;
|
||||
NadekoBot.Client.UserJoined += UsrJoined;
|
||||
NadekoBot.Client.UserUnbanned += UsrUnbanned;
|
||||
NadekoBot.Client.ChannelCreated += ChannelCreated;
|
||||
NadekoBot.Client.ChannelDestroyed += ChannelDestroyed;
|
||||
NadekoBot.Client.ChannelUpdated += ChannelUpdated;
|
||||
|
||||
|
||||
NadekoBot.Client.MessageReceived += async (s, e) =>
|
||||
{
|
||||
if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
if (!SpecificConfigurations.Default.Of(e.Server.Id).SendPrivateMessageOnMention) return;
|
||||
try
|
||||
{
|
||||
var usr = e.Message.MentionedUsers.FirstOrDefault(u => u != e.User);
|
||||
if (usr?.Status != UserStatus.Offline)
|
||||
return;
|
||||
await e.Channel.SendMessage($"User `{usr.Name}` is offline. PM sent.").ConfigureAwait(false);
|
||||
await usr.SendMessage(
|
||||
$"User `{e.User.Name}` mentioned you on " +
|
||||
$"`{e.Server.Name}` server while you were offline.\n" +
|
||||
$"`Message:` {e.Message.Text}").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
};
|
||||
|
||||
// start the userpresence queue
|
||||
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var toSend = new Dictionary<Channel, string>();
|
||||
//take everything from the queue and merge the messages which are going to the same channel
|
||||
KeyValuePair<Channel, string> item;
|
||||
while (voicePresenceUpdates.TryTake(out item))
|
||||
{
|
||||
if (toSend.ContainsKey(item.Key))
|
||||
{
|
||||
toSend[item.Key] = toSend[item.Key] + Environment.NewLine + item.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
toSend.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
//send merged messages to each channel
|
||||
foreach (var k in toSend)
|
||||
{
|
||||
try { await k.Key.SendMessage(Environment.NewLine + k.Value).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private async void ChannelUpdated(object sender, ChannelUpdatedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId == null || config.LogserverIgnoreChannels.Contains(e.After.Id))
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
if (e.Before.Name != e.After.Name)
|
||||
await ch.SendMessage($@"`{prettyCurrentTime}` **Channel Name Changed** `#{e.Before.Name}` (*{e.After.Id}*)
|
||||
`New:` {e.After.Name}").ConfigureAwait(false);
|
||||
else if (e.Before.Topic != e.After.Topic)
|
||||
await ch.SendMessage($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{e.After.Name}` (*{e.After.Id}*)
|
||||
`Old:` {e.Before.Topic}
|
||||
`New:` {e.After.Topic}").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void ChannelDestroyed(object sender, ChannelEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"❗`{prettyCurrentTime}`❗`Channel Deleted:` #{e.Channel.Name} (*{e.Channel.Id}*)").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void ChannelCreated(object sender, ChannelEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`🆕`Channel Created:` #{e.Channel.Mention} (*{e.Channel.Id}*)").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void UsrUnbanned(object sender, UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`♻`User was unbanned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void UsrJoined(object sender, UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`✅`User joined:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void UsrLeft(object sender, UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`❗`User left:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void UsrBanned(object sender, UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"❗`{prettyCurrentTime}`❌`User banned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// private async void MsgRecivd(object sender, MessageEventArgs e)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
// return;
|
||||
// var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
// var chId = config.LogServerChannel;
|
||||
// if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
|
||||
// return;
|
||||
// Channel ch;
|
||||
// if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
// return;
|
||||
// if (!string.IsNullOrWhiteSpace(e.Message.Text))
|
||||
// {
|
||||
// await ch.SendMessage(
|
||||
// $@"🕔`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}`
|
||||
//👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// await ch.SendMessage(
|
||||
// $@"🕔`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}`
|
||||
//👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// }
|
||||
// catch { }
|
||||
// }
|
||||
private async void MsgDltd(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
if (!string.IsNullOrWhiteSpace(e.Message.Text))
|
||||
{
|
||||
await ch.SendMessage(
|
||||
$@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{e.Channel.Name}`
|
||||
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ch.SendMessage(
|
||||
$@"🕔`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}`
|
||||
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage(
|
||||
$@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
👤`{e.User?.ToString() ?? ("NULL")}`
|
||||
`Old:` {e.Before.Text.Unmention()}
|
||||
`New:` {e.After.Text.Unmention()}").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private async void UsrUpdtd(object sender, UserUpdatedEventArgs e)
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
try
|
||||
{
|
||||
var chId = config.LogPresenceChannel;
|
||||
if (chId != null)
|
||||
{
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) != null)
|
||||
{
|
||||
if (e.Before.Status != e.After.Status)
|
||||
{
|
||||
voicePresenceUpdates.Add(new KeyValuePair<Channel, string>(ch, $"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
ulong notifyChBeforeId;
|
||||
ulong notifyChAfterId;
|
||||
Channel notifyChBefore = null;
|
||||
Channel notifyChAfter = null;
|
||||
var beforeVch = e.Before.VoiceChannel;
|
||||
var afterVch = e.After.VoiceChannel;
|
||||
var notifyLeave = false;
|
||||
var notifyJoin = false;
|
||||
if ((beforeVch != null || afterVch != null) && (beforeVch != afterVch)) // this means we need to notify for sure.
|
||||
{
|
||||
if (beforeVch != null && config.VoiceChannelLog.TryGetValue(beforeVch.Id, out notifyChBeforeId) && (notifyChBefore = e.Before.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChBeforeId)) != null)
|
||||
{
|
||||
notifyLeave = true;
|
||||
}
|
||||
if (afterVch != null && config.VoiceChannelLog.TryGetValue(afterVch.Id, out notifyChAfterId) && (notifyChAfter = e.After.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChAfterId)) != null)
|
||||
{
|
||||
notifyJoin = true;
|
||||
}
|
||||
if ((notifyLeave && notifyJoin) && (notifyChAfter == notifyChBefore))
|
||||
{
|
||||
await notifyChAfter.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} moved from **{beforeVch.Mention}** to **{afterVch.Mention}** voice channel.").ConfigureAwait(false);
|
||||
}
|
||||
else if (notifyJoin)
|
||||
{
|
||||
await notifyChAfter.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} has joined **{afterVch.Mention}** voice channel.").ConfigureAwait(false);
|
||||
}
|
||||
else if (notifyLeave)
|
||||
{
|
||||
await notifyChBefore.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} has left **{beforeVch.Mention}** voice channel.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
string str = $"🕔`{prettyCurrentTime}`";
|
||||
if (e.Before.Name != e.After.Name)
|
||||
str += $"**Name Changed**👤`{e.Before?.ToString()}`\n\t\t`New:`{e.After.ToString()}`";
|
||||
else if (e.Before.Nickname != e.After.Nickname)
|
||||
str += $"**Nickname Changed**👤`{e.Before?.ToString()}`\n\t\t`Old:` {e.Before.Nickname}#{e.Before.Discriminator}\n\t\t`New:` {e.After.Nickname}#{e.After.Discriminator}";
|
||||
else if (e.Before.AvatarUrl != e.After.AvatarUrl)
|
||||
str += $"**Avatar Changed**👤`{e.Before?.ToString()}`\n\t {await e.Before.AvatarUrl.ShortenUrl()} `=>` {await e.After.AvatarUrl.ShortenUrl()}";
|
||||
else if (!e.Before.Roles.SequenceEqual(e.After.Roles))
|
||||
{
|
||||
if (e.Before.Roles.Count() < e.After.Roles.Count())
|
||||
{
|
||||
var diffRoles = e.After.Roles.Where(r => !e.Before.Roles.Contains(r)).Select(r => "`" + r.Name + "`");
|
||||
str += $"**User's Roles changed ⚔➕**👤`{e.Before?.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role.";
|
||||
}
|
||||
else if (e.Before.Roles.Count() > e.After.Roles.Count())
|
||||
{
|
||||
var diffRoles = e.Before.Roles.Where(r => !e.After.Roles.Contains(r)).Select(r => "`" + r.Name + "`");
|
||||
str += $"**User's Roles changed ⚔➖**👤`{e.Before?.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("SEQUENCE NOT EQUAL BUT NO DIFF ROLES - REPORT TO KWOTH on #NADEKOLOG server");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return;
|
||||
await ch.SendMessage(str).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "spmom")
|
||||
.Description($"Toggles whether mentions of other offline users on your server will send a pm to them. **Needs Manage Server Permissions.**| `{Prefix}spmom`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var specificConfig = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
specificConfig.SendPrivateMessageOnMention =
|
||||
!specificConfig.SendPrivateMessageOnMention;
|
||||
if (specificConfig.SendPrivateMessageOnMention)
|
||||
await e.Channel.SendMessage(":ok: I will send private messages " +
|
||||
"to mentioned offline users.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage(":ok: I won't send private messages " +
|
||||
"to mentioned offline users anymore.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "logserver")
|
||||
.Description($"Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!** | `{Prefix}logserver`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
{
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = e.Channel.Id;
|
||||
await e.Channel.SendMessage($"❗**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**❗").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = null;
|
||||
await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
|
||||
cgb.CreateCommand(Prefix + "logignore")
|
||||
.Description($"Toggles whether the {Prefix}logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Bot Owner Only!**| `{Prefix}logignore`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (config.LogserverIgnoreChannels.Remove(e.Channel.Id))
|
||||
{
|
||||
await e.Channel.SendMessage($"`{Prefix}logserver will stop ignoring this channel.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
config.LogserverIgnoreChannels.Add(e.Channel.Id);
|
||||
await e.Channel.SendMessage($"`{Prefix}logserver will ignore this channel.`");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "userpresence")
|
||||
.Description($"Starts logging to this channel when someone from the server goes online/offline/idle. **Needs Manage Server Permissions.**| `{Prefix}userpresence`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel;
|
||||
if (chId == null)
|
||||
{
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel = e.Channel.Id;
|
||||
await e.Channel.SendMessage($"**User presence notifications enabled.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel = null;
|
||||
await e.Channel.SendMessage($"**User presence notifications disabled.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "voicepresence")
|
||||
.Description($"Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. **Needs Manage Server Permissions.**| `{Prefix}voicerpresence`")
|
||||
.Parameter("all", ParameterType.Optional)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (e.GetArg("all")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var voiceChannel in e.Server.VoiceChannels)
|
||||
{
|
||||
config.VoiceChannelLog.TryAdd(voiceChannel.Id, e.Channel.Id);
|
||||
}
|
||||
await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.User.VoiceChannel == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
ulong throwaway;
|
||||
if (!config.VoiceChannelLog.TryRemove(e.User.VoiceChannel.Id, out throwaway))
|
||||
{
|
||||
config.VoiceChannelLog.TryAdd(e.User.VoiceChannel.Id, e.Channel.Id);
|
||||
await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage($"`Stopped logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
class MessageRepeater : DiscordCommand
|
||||
{
|
||||
private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>();
|
||||
private class Repeater
|
||||
{
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public Timer MessageTimer { get; set; }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public Channel RepeatingChannel { get; set; }
|
||||
|
||||
public ulong RepeatingServerId { get; set; }
|
||||
public ulong RepeatingChannelId { get; set; }
|
||||
public Message lastMessage { get; set; } = null;
|
||||
public string RepeatingMessage { get; set; }
|
||||
public int Interval { get; set; }
|
||||
|
||||
public Repeater Start()
|
||||
{
|
||||
MessageTimer = new Timer { Interval = Interval };
|
||||
MessageTimer.Elapsed += async (s, e) => await Invoke();
|
||||
return this;
|
||||
}
|
||||
|
||||
public async Task Invoke()
|
||||
{
|
||||
var ch = RepeatingChannel;
|
||||
var msg = RepeatingMessage;
|
||||
if (ch != null && !string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (lastMessage != null)
|
||||
await lastMessage.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
lastMessage = await ch.SendMessage(msg).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "repeatinvoke")
|
||||
.Alias(Module.Prefix + "repinv")
|
||||
.Description($"Immediately shows the repeat message and restarts the timer. **Needs Manage Messages Permissions.**| `{Prefix}repinv`")
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Do(async e =>
|
||||
{
|
||||
Repeater rep;
|
||||
if (!repeaters.TryGetValue(e.Server, out rep))
|
||||
{
|
||||
await e.Channel.SendMessage("`No repeating message found on this server.`");
|
||||
return;
|
||||
}
|
||||
|
||||
await rep.Invoke();
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "repeat")
|
||||
.Description("Repeat a message every X minutes. If no parameters are specified, " +
|
||||
$"repeat is disabled. **Needs Manage Messages Permissions.** |`{Prefix}repeat 5 Hello there`")
|
||||
.Parameter("minutes", ParameterType.Optional)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Do(async e =>
|
||||
{
|
||||
var minutesStr = e.GetArg("minutes");
|
||||
var msg = e.GetArg("msg");
|
||||
|
||||
// if both null, disable
|
||||
if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr))
|
||||
{
|
||||
|
||||
Repeater rep;
|
||||
if (!repeaters.TryRemove(e.Server, out rep))
|
||||
return;
|
||||
rep.MessageTimer.Stop();
|
||||
await e.Channel.SendMessage("Repeating disabled").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
int minutes;
|
||||
if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 1440)
|
||||
{
|
||||
await e.Channel.SendMessage("Invalid value").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var repeater = repeaters.GetOrAdd(
|
||||
e.Server,
|
||||
s => new Repeater
|
||||
{
|
||||
Interval = minutes * 60 * 1000,
|
||||
RepeatingChannel = e.Channel,
|
||||
RepeatingChannelId = e.Channel.Id,
|
||||
RepeatingServerId = e.Server.Id,
|
||||
}.Start()
|
||||
);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
repeater.RepeatingMessage = msg;
|
||||
|
||||
repeater.MessageTimer.Stop();
|
||||
repeater.MessageTimer.Start();
|
||||
|
||||
await e.Channel.SendMessage(String.Format("👌 Repeating `{0}` every " +
|
||||
"**{1}** minutes on {2} channel.",
|
||||
repeater.RepeatingMessage, minutes, repeater.RepeatingChannel))
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
public MessageRepeater(DiscordModule module) : base(module) { }
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Modules.Music;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class PlayingRotate : DiscordCommand
|
||||
{
|
||||
private static readonly Timer timer = new Timer(20000);
|
||||
|
||||
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
|
||||
new Dictionary<string, Func<string>> {
|
||||
{"%servers%", () => NadekoBot.Client.Servers.Count().ToString()},
|
||||
{"%users%", () => NadekoBot.Client.Servers.SelectMany(s => s.Users).Count().ToString()},
|
||||
{"%playing%", () => {
|
||||
var cnt = MusicModule.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
||||
if (cnt != 1) return cnt.ToString();
|
||||
try {
|
||||
var mp = MusicModule.MusicPlayers.FirstOrDefault();
|
||||
return mp.Value.CurrentSong.SongInfo.Title;
|
||||
}
|
||||
catch {
|
||||
return "No songs";
|
||||
}
|
||||
}
|
||||
},
|
||||
{"%queued%", () => MusicModule.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
|
||||
{"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()}
|
||||
};
|
||||
|
||||
private readonly SemaphoreSlim playingPlaceholderLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public PlayingRotate(DiscordModule module) : base(module)
|
||||
{
|
||||
var i = -1;
|
||||
timer.Elapsed += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
i++;
|
||||
var status = "";
|
||||
//wtf am i doing, just use a queue ffs
|
||||
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (PlayingPlaceholders.Count == 0
|
||||
|| NadekoBot.Config.RotatingStatuses.Count == 0
|
||||
|| i >= NadekoBot.Config.RotatingStatuses.Count)
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
status = NadekoBot.Config.RotatingStatuses[i];
|
||||
status = PlayingPlaceholders.Aggregate(status,
|
||||
(current, kvp) => current.Replace(kvp.Key, kvp.Value()));
|
||||
}
|
||||
finally { playingPlaceholderLock.Release(); }
|
||||
if (string.IsNullOrWhiteSpace(status))
|
||||
return;
|
||||
await Task.Run(() => { NadekoBot.Client.SetGame(status); });
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.OnReady += () => timer.Enabled = NadekoBot.Config.IsRotatingStatus;
|
||||
}
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc() => async e =>
|
||||
{
|
||||
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (timer.Enabled)
|
||||
timer.Stop();
|
||||
else
|
||||
timer.Start();
|
||||
NadekoBot.Config.IsRotatingStatus = timer.Enabled;
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
playingPlaceholderLock.Release();
|
||||
}
|
||||
await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false);
|
||||
};
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "rotateplaying")
|
||||
.Alias(Module.Prefix + "ropl")
|
||||
.Description($"Toggles rotation of playing status of the dynamic strings you specified earlier. **Bot Owner Only!** | `{Prefix}ropl`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(DoFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "addplaying")
|
||||
.Alias(Module.Prefix + "adpl")
|
||||
.Description("Adds a specified string to the list of playing strings to rotate. " +
|
||||
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys) + $" **Bot Owner Only!**| `{Prefix}adpl`")
|
||||
.Parameter("text", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("text");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
NadekoBot.Config.RotatingStatuses.Add(arg);
|
||||
await ConfigHandler.SaveConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
playingPlaceholderLock.Release();
|
||||
}
|
||||
await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "listplaying")
|
||||
.Alias(Module.Prefix + "lipl")
|
||||
.Description($"Lists all playing statuses with their corresponding number. **Bot Owner Only!**| `{Prefix}lipl`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (NadekoBot.Config.RotatingStatuses.Count == 0)
|
||||
await e.Channel.SendMessage("`There are no playing strings. " +
|
||||
"Add some with .addplaying [text] command.`").ConfigureAwait(false);
|
||||
var sb = new StringBuilder();
|
||||
for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++)
|
||||
{
|
||||
sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}");
|
||||
}
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "removeplaying")
|
||||
.Alias(Module.Prefix + "repl", Module.Prefix + "rmpl")
|
||||
.Description($"Removes a playing string on a given number. **Bot Owner Only!**| `{Prefix}rmpl`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("number");
|
||||
int num;
|
||||
string str;
|
||||
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
|
||||
return;
|
||||
str = NadekoBot.Config.RotatingStatuses[num - 1];
|
||||
NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
}
|
||||
finally { playingPlaceholderLock.Release(); }
|
||||
await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class RatelimitCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>();
|
||||
|
||||
private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5);
|
||||
|
||||
public RatelimitCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () => NadekoBot.Client.MessageReceived += async (s, e) =>
|
||||
{
|
||||
if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
ConcurrentDictionary<ulong, DateTime> userTimePair;
|
||||
if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return;
|
||||
DateTime lastMessageTime;
|
||||
if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime))
|
||||
{
|
||||
if (DateTime.Now - lastMessageTime < ratelimitTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
return;
|
||||
}
|
||||
}
|
||||
userTimePair.AddOrUpdate(e.User.Id, id => DateTime.Now, (id, dt) => DateTime.Now);
|
||||
};
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "slowmode")
|
||||
.Description($"Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds. **Needs Manage Messages Permissions.**| `{Prefix}slowmode`")
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Do(async e =>
|
||||
{
|
||||
ConcurrentDictionary<ulong, DateTime> throwaway;
|
||||
if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway))
|
||||
{
|
||||
await e.Channel.SendMessage("Slow mode disabled.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary<ulong, DateTime>()))
|
||||
{
|
||||
await e.Channel.SendMessage("Slow mode initiated. " +
|
||||
"Users can't send more than 1 message every 5 seconds.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Net;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class SelfAssignedRolesCommand : DiscordCommand
|
||||
{
|
||||
public SelfAssignedRolesCommand(DiscordModule module) : base(module) { }
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "asar")
|
||||
.Description("Adds a role, or list of roles separated by whitespace" +
|
||||
$"(use quotations for multiword roles) to the list of self-assignable roles. **Needs Manage Roles Permissions.**| `{Prefix}asar Gamer`")
|
||||
.Parameter("roles", ParameterType.Multiple)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var msg = new StringBuilder();
|
||||
foreach (var arg in e.Args)
|
||||
{
|
||||
var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault();
|
||||
if (role == null)
|
||||
msg.AppendLine($":anger:Role **{arg}** not found.");
|
||||
else
|
||||
{
|
||||
if (config.ListOfSelfAssignableRoles.Contains(role.Id))
|
||||
{
|
||||
msg.AppendLine($":anger:Role **{role.Name}** is already in the list.");
|
||||
continue;
|
||||
}
|
||||
config.ListOfSelfAssignableRoles.Add(role.Id);
|
||||
msg.AppendLine($":ok:Role **{role.Name}** added to the list.");
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "rsar")
|
||||
.Description($"Removes a specified role from the list of self-assignable roles. | `{Prefix}rsar`")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var roleName = e.GetArg("role")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
var role = e.Server.FindRoles(roleName).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
config.ListOfSelfAssignableRoles.Remove(role.Id);
|
||||
await e.Channel.SendMessage($":ok:**{role.Name}** has been removed from the list of self-assignable roles").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "lsar")
|
||||
.Description($"Lists all self-assignable roles. | `{Prefix}lsar`")
|
||||
.Parameter("roles", ParameterType.Multiple)
|
||||
.Do(async e =>
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
|
||||
var toRemove = new HashSet<ulong>();
|
||||
foreach (var roleId in config.ListOfSelfAssignableRoles.OrderBy(r => r.ToString()))
|
||||
{
|
||||
var role = e.Server.GetRole(roleId);
|
||||
if (role == null)
|
||||
{
|
||||
msg.Append($"`{roleId} not found. Cleaned up.`, ");
|
||||
toRemove.Add(roleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Append($"**{role.Name}**, ");
|
||||
}
|
||||
}
|
||||
foreach (var id in toRemove)
|
||||
{
|
||||
config.ListOfSelfAssignableRoles.Remove(id);
|
||||
}
|
||||
await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "togglexclsar").Alias(Module.Prefix + "tesar")
|
||||
.Description($"toggle whether the self-assigned roles should be exclusive | `{Prefix}tesar`")
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
|
||||
string exl = config.ExclusiveSelfAssignedRoles ? "exclusive" : "not exclusive";
|
||||
await e.Channel.SendMessage("Self assigned roles are now " + exl);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "iam")
|
||||
.Description("Adds a role to you that you choose. " +
|
||||
"Role must be on a list of self-assignable roles." +
|
||||
$" | `{Prefix}iam Gamer`")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var roleName = e.GetArg("role")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
var role = e.Server.FindRoles(roleName).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (e.User.HasRole(role))
|
||||
{
|
||||
await e.Channel.SendMessage($":anger:You already have {role.Name} role.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var sameRoles = e.User.Roles.Where(r => config.ListOfSelfAssignableRoles.Contains(r.Id));
|
||||
if (config.ExclusiveSelfAssignedRoles && sameRoles.Any())
|
||||
{
|
||||
await e.Channel.SendMessage($":anger:You already have {sameRoles.FirstOrDefault().Name} role.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await e.User.AddRoles(role).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($":anger:`I am unable to add that role to you. I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
|
||||
await Task.Delay(3000).ConfigureAwait(false);
|
||||
await msg.Delete().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "iamnot")
|
||||
.Alias(Module.Prefix + "iamn")
|
||||
.Description("Removes a role to you that you choose. " +
|
||||
"Role must be on a list of self-assignable roles." +
|
||||
$" | `{Prefix}iamn Gamer`")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var roleName = e.GetArg("role")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
var role = e.Server.FindRoles(roleName).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!e.User.HasRole(role))
|
||||
{
|
||||
await e.Channel.SendMessage($":anger:You don't have {role.Name} role.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.User.RemoveRoles(role).ConfigureAwait(false);
|
||||
var msg = await e.Channel.SendMessage($":ok:Successfuly removed {role.Name} role from you.").ConfigureAwait(false);
|
||||
await Task.Delay(3000).ConfigureAwait(false);
|
||||
await msg.Delete().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
class SelfCommands : DiscordCommand
|
||||
{
|
||||
public SelfCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "leave")
|
||||
.Description($"Makes Nadeko leave the server. Either name or id required. **Bot Owner Only!**| `{Prefix}leave 123123123331`")
|
||||
.Parameter("arg", ParameterType.Required)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("arg").Trim();
|
||||
var server = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id.ToString() == arg) ??
|
||||
NadekoBot.Client.FindServers(arg).FirstOrDefault();
|
||||
if (server == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Cannot find that server").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!server.IsOwner)
|
||||
{
|
||||
await server.Leave().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await server.Delete().ConfigureAwait(false);
|
||||
}
|
||||
await NadekoBot.SendMessageToOwner("Left server " + server.Name).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,336 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/* Voltana's legacy
|
||||
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||
{
|
||||
public AsyncLazy(Func<T> valueFactory) :
|
||||
base(() => Task.Factory.StartNew(valueFactory)) { }
|
||||
|
||||
public AsyncLazy(Func<Task<T>> taskFactory) :
|
||||
base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap()) { }
|
||||
|
||||
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
|
||||
}
|
||||
*/
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class ServerGreetCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary;
|
||||
|
||||
public static long Greeted = 0;
|
||||
|
||||
public ServerGreetCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>();
|
||||
|
||||
//gotta subscribe after ready, to prevent trying to send these before all guilds are initialized
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
NadekoBot.Client.UserJoined += UserJoined;
|
||||
NadekoBot.Client.UserLeft += UserLeft;
|
||||
};
|
||||
|
||||
var data = Classes.DbHandler.Instance.GetAllRows<DataModels.Announcement>();
|
||||
|
||||
if (!data.Any()) return;
|
||||
foreach (var obj in data)
|
||||
AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj));
|
||||
}
|
||||
|
||||
private async void UserLeft(object sender, UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
|
||||
!AnnouncementsDictionary[e.Server.Id].Bye) return;
|
||||
|
||||
var controls = AnnouncementsDictionary[e.Server.Id];
|
||||
var channel = NadekoBot.Client.GetChannel(controls.ByeChannel);
|
||||
var msg = controls.ByeText.Replace("%user%", "**" + e.User.Name + "**").Trim();
|
||||
if (string.IsNullOrEmpty(msg))
|
||||
return;
|
||||
|
||||
if (controls.ByePM)
|
||||
{
|
||||
Greeted++;
|
||||
try
|
||||
{
|
||||
await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (channel == null) return;
|
||||
Greeted++;
|
||||
var toDelete = await channel.SendMessage(msg).ConfigureAwait(false);
|
||||
if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages)
|
||||
{
|
||||
await Task.Delay(30000).ConfigureAwait(false); // 5 minutes
|
||||
await toDelete.Delete().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void UserJoined(object sender, Discord.UserEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
|
||||
!AnnouncementsDictionary[e.Server.Id].Greet) return;
|
||||
|
||||
var controls = AnnouncementsDictionary[e.Server.Id];
|
||||
var channel = NadekoBot.Client.GetChannel(controls.GreetChannel);
|
||||
|
||||
var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim();
|
||||
if (string.IsNullOrEmpty(msg))
|
||||
return;
|
||||
if (controls.GreetPM)
|
||||
{
|
||||
Greeted++;
|
||||
await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (channel == null) return;
|
||||
Greeted++;
|
||||
var toDelete = await channel.SendMessage(msg).ConfigureAwait(false);
|
||||
if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages)
|
||||
{
|
||||
await Task.Delay(30000).ConfigureAwait(false); // 5 minutes
|
||||
await toDelete.Delete().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public class AnnounceControls
|
||||
{
|
||||
private DataModels.Announcement _model { get; }
|
||||
|
||||
public bool Greet {
|
||||
get { return _model.Greet; }
|
||||
set { _model.Greet = value; Save(); }
|
||||
}
|
||||
|
||||
public ulong GreetChannel {
|
||||
get { return (ulong)_model.GreetChannelId; }
|
||||
set { _model.GreetChannelId = (long)value; Save(); }
|
||||
}
|
||||
|
||||
public bool GreetPM {
|
||||
get { return _model.GreetPM; }
|
||||
set { _model.GreetPM = value; Save(); }
|
||||
}
|
||||
|
||||
public bool ByePM {
|
||||
get { return _model.ByePM; }
|
||||
set { _model.ByePM = value; Save(); }
|
||||
}
|
||||
|
||||
public string GreetText {
|
||||
get { return _model.GreetText; }
|
||||
set { _model.GreetText = value; Save(); }
|
||||
}
|
||||
|
||||
public bool Bye {
|
||||
get { return _model.Bye; }
|
||||
set { _model.Bye = value; Save(); }
|
||||
}
|
||||
public ulong ByeChannel {
|
||||
get { return (ulong)_model.ByeChannelId; }
|
||||
set { _model.ByeChannelId = (long)value; Save(); }
|
||||
}
|
||||
|
||||
public string ByeText {
|
||||
get { return _model.ByeText; }
|
||||
set { _model.ByeText = value; Save(); }
|
||||
}
|
||||
|
||||
public ulong ServerId {
|
||||
get { return (ulong)_model.ServerId; }
|
||||
set { _model.ServerId = (long)value; }
|
||||
}
|
||||
|
||||
public bool DeleteGreetMessages {
|
||||
get {
|
||||
return _model.DeleteGreetMessages;
|
||||
}
|
||||
set {
|
||||
_model.DeleteGreetMessages = value; Save();
|
||||
}
|
||||
}
|
||||
|
||||
public AnnounceControls(DataModels.Announcement model)
|
||||
{
|
||||
this._model = model;
|
||||
}
|
||||
|
||||
public AnnounceControls(ulong serverId)
|
||||
{
|
||||
this._model = new DataModels.Announcement();
|
||||
ServerId = serverId;
|
||||
}
|
||||
|
||||
internal bool ToggleBye(ulong id)
|
||||
{
|
||||
if (Bye)
|
||||
{
|
||||
return Bye = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ByeChannel = id;
|
||||
return Bye = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ToggleGreet(ulong id)
|
||||
{
|
||||
if (Greet)
|
||||
{
|
||||
return Greet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GreetChannel = id;
|
||||
return Greet = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ToggleDelete() => DeleteGreetMessages = !DeleteGreetMessages;
|
||||
internal bool ToggleGreetPM() => GreetPM = !GreetPM;
|
||||
internal bool ToggleByePM() => ByePM = !ByePM;
|
||||
|
||||
private void Save()
|
||||
{
|
||||
Classes.DbHandler.Instance.Save(_model);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "grdel")
|
||||
.Description($"Toggles automatic deletion of greet and bye messages. **Needs Manage Server Permissions.**| `{Prefix}grdel`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
|
||||
if (ann.ToggleDelete())
|
||||
await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been enabled.`").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been disabled.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "greet")
|
||||
.Description($"Toggles anouncements on the current channel when someone joins the server. **Needs Manage Server Permissions.**| `{Prefix}greet`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
|
||||
if (ann.ToggleGreet(e.Channel.Id))
|
||||
await e.Channel.SendMessage("Greet announcements enabled on this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("Greet announcements disabled.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "greetmsg")
|
||||
.Description($"Sets a new join announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Needs Manage Server Permissions.**| `{Prefix}greetmsg Welcome, %user%.`")
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("msg")))
|
||||
{
|
||||
await e.Channel.SendMessage("`Current greet message:` " + ann.GreetText);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ann.GreetText = e.GetArg("msg");
|
||||
await e.Channel.SendMessage("New greet message set.").ConfigureAwait(false);
|
||||
if (!ann.Greet)
|
||||
await e.Channel.SendMessage("Enable greet messsages by typing `.greet`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "bye")
|
||||
.Description($"Toggles anouncements on the current channel when someone leaves the server. | `{Prefix}bye`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
|
||||
if (ann.ToggleBye(e.Channel.Id))
|
||||
await e.Channel.SendMessage("Bye announcements enabled on this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("Bye announcements disabled.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "byemsg")
|
||||
.Description($"Sets a new leave announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current bye message. **Needs Manage Server Permissions.**| `{Prefix}byemsg %user% has left.`")
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("msg")))
|
||||
{
|
||||
await e.Channel.SendMessage("`Current bye message:` " + ann.ByeText);
|
||||
return;
|
||||
}
|
||||
|
||||
ann.ByeText = e.GetArg("msg");
|
||||
await e.Channel.SendMessage("New bye message set.").ConfigureAwait(false);
|
||||
if (!ann.Bye)
|
||||
await e.Channel.SendMessage("Enable bye messsages by typing `.bye`.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "byepm")
|
||||
.Description($"Toggles whether the good bye messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}byepm`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
|
||||
|
||||
if (ann.ToggleByePM())
|
||||
await e.Channel.SendMessage("Bye messages will be sent in a PM from now on.\n ⚠ Keep in mind this might fail if the user and the bot have no common servers after the user leaves.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("Bye messages will be sent in a bound channel from now on.").ConfigureAwait(false);
|
||||
if (!ann.Bye)
|
||||
await e.Channel.SendMessage("Enable bye messsages by typing `.bye`, and set the bye message using `.byemsg`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "greetpm")
|
||||
.Description($"Toggles whether the greet messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}greetpm`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageServer) return;
|
||||
|
||||
var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
|
||||
|
||||
if (ann.ToggleGreetPM())
|
||||
await e.Channel.SendMessage("Greet messages will be sent in a PM from now on.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("Greet messages will be sent in a bound channel from now on.").ConfigureAwait(false);
|
||||
if (!ann.Greet)
|
||||
await e.Channel.SendMessage("Enable greet messsages by typing `.greet`, and set the greet message using `.greetmsg`").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ChPermOverride = Discord.ChannelPermissionOverrides;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class VoicePlusTextCommand : DiscordCommand
|
||||
{
|
||||
Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||
public VoicePlusTextCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
// changing servers may cause bugs
|
||||
NadekoBot.OnReady += () => NadekoBot.Client.UserUpdated += async (sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server == null)
|
||||
return;
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (e.Before.VoiceChannel == e.After.VoiceChannel) return;
|
||||
if (!config.VoicePlusTextEnabled)
|
||||
return;
|
||||
var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions;
|
||||
if (serverPerms == null)
|
||||
return;
|
||||
if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
await e.Server.Owner.SendMessage(
|
||||
"I don't have manage server and/or Manage Channels permission," +
|
||||
$" so I cannot run voice+text on **{e.Server.Name}** server.").ConfigureAwait(false);
|
||||
}
|
||||
catch { } // meh
|
||||
config.VoicePlusTextEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var beforeVch = e.Before.VoiceChannel;
|
||||
if (beforeVch != null)
|
||||
{
|
||||
var textChannel =
|
||||
e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault();
|
||||
if (textChannel != null)
|
||||
await textChannel.AddPermissionsRule(e.Before,
|
||||
new ChPermOverride(readMessages: PermValue.Deny,
|
||||
sendMessages: PermValue.Deny)).ConfigureAwait(false);
|
||||
}
|
||||
var afterVch = e.After.VoiceChannel;
|
||||
if (afterVch != null && e.Server.AFKChannel != afterVch)
|
||||
{
|
||||
var textChannel = e.Server.FindChannels(
|
||||
GetChannelName(afterVch.Name),
|
||||
ChannelType.Text)
|
||||
.FirstOrDefault();
|
||||
if (textChannel == null)
|
||||
{
|
||||
textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text).ConfigureAwait(false));
|
||||
await textChannel.AddPermissionsRule(e.Server.EveryoneRole,
|
||||
new ChPermOverride(readMessages: PermValue.Deny,
|
||||
sendMessages: PermValue.Deny)).ConfigureAwait(false);
|
||||
}
|
||||
await textChannel.AddPermissionsRule(e.After,
|
||||
new ChPermOverride(readMessages: PermValue.Allow,
|
||||
sendMessages: PermValue.Allow)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private string GetChannelName(string voiceName) =>
|
||||
channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "cleanv+t")
|
||||
.Alias(Module.Prefix + "cv+t")
|
||||
.Description($"Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk. Needs Manage Roles and Manage Channels Permissions.** | `{Prefix}cleanv+t`")
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.AddCheck(SimpleCheckers.ManageChannels())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.Server.CurrentUser.ServerPermissions.ManageChannels)
|
||||
{
|
||||
await e.Channel.SendMessage("`I have insufficient permission to do that.`");
|
||||
return;
|
||||
}
|
||||
|
||||
var allTxtChannels = e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice"));
|
||||
var validTxtChannelNames = e.Server.VoiceChannels.Select(c => GetChannelName(c.Name));
|
||||
|
||||
var invalidTxtChannels = allTxtChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
||||
|
||||
foreach (var c in invalidTxtChannels)
|
||||
{
|
||||
try
|
||||
{
|
||||
await c.Delete();
|
||||
}
|
||||
catch { }
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage("`Done.`");
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "voice+text")
|
||||
.Alias(Module.Prefix + "v+t")
|
||||
.Description("Creates a text channel for each voice channel only users in that voice channel can see." +
|
||||
$"If you are server owner, keep in mind you will see them all the time regardless. **Needs Manage Roles and Manage Channels Permissions.**| `{Prefix}voice+text`")
|
||||
.AddCheck(SimpleCheckers.ManageChannels())
|
||||
.AddCheck(SimpleCheckers.CanManageRoles)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (config.VoicePlusTextEnabled == true)
|
||||
{
|
||||
config.VoicePlusTextEnabled = false;
|
||||
foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice")))
|
||||
{
|
||||
try
|
||||
{
|
||||
await textChannel.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage(
|
||||
":anger: Error: Most likely i don't have permissions to do this.")
|
||||
.ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage("Successfuly removed voice + text feature.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
config.VoicePlusTextEnabled = true;
|
||||
await e.Channel.SendMessage("Successfuly enabled voice + text feature. " +
|
||||
"**Make sure the bot has manage roles and manage channels permissions**")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage(ex.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
//using Manatee.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Classes.ClashOfClans
|
||||
{
|
||||
public enum DestroyStars
|
||||
{
|
||||
One, Two, Three
|
||||
}
|
||||
public enum WarState
|
||||
{
|
||||
Started, Ended, Created
|
||||
}
|
||||
[System.Serializable]
|
||||
internal class Caller
|
||||
{
|
||||
public string CallUser { get; set; }
|
||||
|
||||
public DateTime TimeAdded { get; set; }
|
||||
|
||||
public bool BaseDestroyed { get; set; }
|
||||
|
||||
public int Stars { get; set; } = 3;
|
||||
|
||||
public Caller() { }
|
||||
|
||||
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
|
||||
{
|
||||
CallUser = callUser;
|
||||
TimeAdded = timeAdded;
|
||||
BaseDestroyed = baseDestroyed;
|
||||
}
|
||||
|
||||
public void ResetTime()
|
||||
{
|
||||
TimeAdded = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
BaseDestroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClashWar
|
||||
{
|
||||
private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
|
||||
|
||||
public string EnemyClan { get; set; }
|
||||
public int Size { get; set; }
|
||||
|
||||
public Caller[] Bases { get; set; }
|
||||
public WarState WarState { get; set; } = WarState.Created;
|
||||
//public bool Started { get; set; } = false;
|
||||
public DateTime StartedAt { get; set; }
|
||||
//public bool Ended { get; private set; } = false;
|
||||
|
||||
public ulong ServerId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Discord.Channel Channel { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// This init is purely for the deserialization
|
||||
/// </summary>
|
||||
public ClashWar() { }
|
||||
|
||||
public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId)
|
||||
{
|
||||
this.EnemyClan = enemyClan;
|
||||
this.Size = size;
|
||||
this.Bases = new Caller[size];
|
||||
this.ServerId = serverId;
|
||||
this.ChannelId = channelId;
|
||||
this.Channel = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id == serverId)?.TextChannels.FirstOrDefault(c => c.Id == channelId);
|
||||
}
|
||||
|
||||
internal void End()
|
||||
{
|
||||
//Ended = true;
|
||||
WarState = WarState.Ended;
|
||||
}
|
||||
|
||||
internal void Call(string u, int baseNumber)
|
||||
{
|
||||
if (baseNumber < 0 || baseNumber >= Bases.Length)
|
||||
throw new ArgumentException("Invalid base number");
|
||||
if (Bases[baseNumber] != null)
|
||||
throw new ArgumentException("That base is already claimed.");
|
||||
for (var i = 0; i < Bases.Length; i++)
|
||||
{
|
||||
if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
|
||||
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
|
||||
}
|
||||
|
||||
Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false);
|
||||
}
|
||||
|
||||
internal void Start()
|
||||
{
|
||||
if (WarState == WarState.Started)
|
||||
throw new InvalidOperationException("War already started");
|
||||
//if (Started)
|
||||
// throw new InvalidOperationException();
|
||||
//Started = true;
|
||||
WarState = WarState.Started;
|
||||
StartedAt = DateTime.UtcNow;
|
||||
foreach (var b in Bases.Where(b => b != null))
|
||||
{
|
||||
b.ResetTime();
|
||||
}
|
||||
}
|
||||
|
||||
internal int Uncall(string user)
|
||||
{
|
||||
user = user.Trim();
|
||||
for (var i = 0; i < Bases.Length; i++)
|
||||
{
|
||||
if (Bases[i]?.CallUser != user) continue;
|
||||
Bases[i] = null;
|
||||
return i;
|
||||
}
|
||||
throw new InvalidOperationException("You are not participating in that war.");
|
||||
}
|
||||
|
||||
public string ShortPrint() =>
|
||||
$"`{EnemyClan}` ({Size} v {Size})";
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
|
||||
if (WarState == WarState.Created)
|
||||
sb.AppendLine("`not started`");
|
||||
for (var i = 0; i < Bases.Length; i++)
|
||||
{
|
||||
if (Bases[i] == null)
|
||||
{
|
||||
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bases[i].BaseDestroyed)
|
||||
{
|
||||
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var left = (WarState == WarState.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire;
|
||||
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal int FinishClaim(string user, int stars = 3)
|
||||
{
|
||||
user = user.Trim();
|
||||
for (var i = 0; i < Bases.Length; i++)
|
||||
{
|
||||
if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
|
||||
Bases[i].BaseDestroyed = true;
|
||||
Bases[i].Stars = stars;
|
||||
return i;
|
||||
}
|
||||
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,421 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes.ClashOfClans;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
internal class ClashOfClansModule : DiscordModule
|
||||
{
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
|
||||
|
||||
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
||||
|
||||
private readonly object writeLock = new object();
|
||||
|
||||
public ClashOfClansModule()
|
||||
{
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (File.Exists("data/clashofclans/wars.json"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var content = File.ReadAllText("data/clashofclans/wars.json");
|
||||
|
||||
var dict = JsonConvert.DeserializeObject<Dictionary<ulong, List<ClashWar>>>(content);
|
||||
|
||||
foreach (var cw in dict)
|
||||
{
|
||||
cw.Value.ForEach(war =>
|
||||
{
|
||||
war.Channel = NadekoBot.Client.GetServer(war.ServerId)?.GetChannel(war.ChannelId);
|
||||
if (war.Channel == null)
|
||||
{
|
||||
cw.Value.Remove(war);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
//urgh
|
||||
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(dict);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Could not load coc wars: " + e.Message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//Can't this be disabled if the modules is disabled too :)
|
||||
var callExpire = new TimeSpan(2, 0, 0);
|
||||
var warExpire = new TimeSpan(23, 0, 0);
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var hash = ClashWars.GetHashCode();
|
||||
foreach (var cw in ClashWars)
|
||||
{
|
||||
foreach (var war in cw.Value)
|
||||
{
|
||||
await CheckWar(callExpire, war);
|
||||
}
|
||||
List<ClashWar> newVal = new List<ClashWar>();
|
||||
foreach (var w in cw.Value)
|
||||
{
|
||||
//We add when A: the war is not ended
|
||||
if (w.WarState != WarState.Ended)
|
||||
{
|
||||
//and B: the war has not expired
|
||||
if ((w.WarState == WarState.Started && DateTime.UtcNow - w.StartedAt <= warExpire) || w.WarState == WarState.Created)
|
||||
{
|
||||
newVal.Add(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
//var newVal = cw.Value.Where(w => !(w.Ended || DateTime.UtcNow - w.StartedAt >= warExpire)).ToList();
|
||||
foreach (var exWar in cw.Value.Except(newVal))
|
||||
{
|
||||
await exWar.Channel.SendMessage($"War against {exWar.EnemyClan} ({exWar.Size}v{exWar.Size}) has ended");
|
||||
}
|
||||
|
||||
if (newVal.Count == 0)
|
||||
{
|
||||
List<ClashWar> obj;
|
||||
ClashWars.TryRemove(cw.Key, out obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClashWars.AddOrUpdate(cw.Key, newVal, (x, s) => newVal);
|
||||
}
|
||||
}
|
||||
if (hash != ClashWars.GetHashCode()) //something changed
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch { }
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private static void Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory("data/clashofclans");
|
||||
File.WriteAllText("data/clashofclans/wars.json", JsonConvert.SerializeObject(ClashWars, Formatting.Indented));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
|
||||
{
|
||||
var Bases = war.Bases;
|
||||
for (var i = 0; i < Bases.Length; i++)
|
||||
{
|
||||
if (Bases[i] == null) continue;
|
||||
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
|
||||
{
|
||||
await war.Channel.SendMessage($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
|
||||
Bases[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region commands
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
cgb.CreateCommand(Prefix + "createwar")
|
||||
.Alias(Prefix + "cw")
|
||||
.Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | `{Prefix}cw 15 The Enemy Clan`")
|
||||
.Parameter("size")
|
||||
.Parameter("enemy_clan", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageChannels)
|
||||
return;
|
||||
var enemyClan = e.GetArg("enemy_clan");
|
||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
List<ClashWar> wars;
|
||||
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
|
||||
{
|
||||
wars = new List<ClashWar>();
|
||||
if (!ClashWars.TryAdd(e.Server.Id, wars))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
|
||||
//cw.Start();
|
||||
|
||||
wars.Add(cw);
|
||||
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
|
||||
Save();
|
||||
//war with the index X started.
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "startwar")
|
||||
.Alias(Prefix + "sw")
|
||||
.Description($"Starts a war with a given number. | `{Prefix}sw 15`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var warsInfo = GetInfo(e);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
try
|
||||
{
|
||||
war.Start();
|
||||
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
|
||||
}
|
||||
Save();
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "listwar")
|
||||
.Alias(Prefix + "lw")
|
||||
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `{Prefix}lw [war_number] or {Prefix}lw`")
|
||||
.Parameter("number", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
// if number is null, print all wars in a short way
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("number")))
|
||||
{
|
||||
//check if there are any wars
|
||||
List<ClashWar> wars = null;
|
||||
ClashWars.TryGetValue(e.Server.Id, out wars);
|
||||
if (wars == null || wars.Count == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("🔰 **No active wars.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
|
||||
sb.AppendLine("**-------------------------**");
|
||||
for (var i = 0; i < wars.Count; i++)
|
||||
{
|
||||
sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
|
||||
sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
|
||||
sb.AppendLine("**-------------------------**");
|
||||
}
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
return;
|
||||
|
||||
}
|
||||
//if number is not null, print the war needed
|
||||
var warsInfo = GetInfo(e);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(warsInfo.Item1[warsInfo.Item2].ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "claim")
|
||||
.Alias(Prefix + "call")
|
||||
.Alias(Prefix + "c")
|
||||
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `{Prefix}call [war_number] [base_number] [optional_other_name]`")
|
||||
.Parameter("number")
|
||||
.Parameter("baseNumber")
|
||||
.Parameter("other_name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var warsInfo = GetInfo(e);
|
||||
if (warsInfo == null || warsInfo.Item1.Count == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
int baseNum;
|
||||
if (!int.TryParse(e.GetArg("baseNumber"), out baseNum))
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **Invalid base number.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var usr =
|
||||
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
|
||||
e.User.Name :
|
||||
e.GetArg("other_name");
|
||||
try
|
||||
{
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
war.Call(usr, baseNum - 1);
|
||||
await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "claimfinish")
|
||||
.Alias(Prefix + "cf")
|
||||
.Alias(Prefix + "cf3")
|
||||
.Alias(Prefix + "claimfinish3")
|
||||
.Description($"Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.Parameter("other_name", ParameterType.Unparsed)
|
||||
.Do(e => FinishClaim(e));
|
||||
|
||||
cgb.CreateCommand(Prefix + "claimfinish2")
|
||||
.Alias(Prefix + "cf2")
|
||||
.Description($"Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.Parameter("other_name", ParameterType.Unparsed)
|
||||
.Do(e => FinishClaim(e, 2));
|
||||
|
||||
cgb.CreateCommand(Prefix + "claimfinish1")
|
||||
.Alias(Prefix + "cf1")
|
||||
.Description($"Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.Parameter("other_name", ParameterType.Unparsed)
|
||||
.Do(e => FinishClaim(e, 1));
|
||||
|
||||
cgb.CreateCommand(Prefix + "unclaim")
|
||||
.Alias(Prefix + "uncall")
|
||||
.Alias(Prefix + "uc")
|
||||
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `{Prefix}uc [war_number] [optional_other_name]`")
|
||||
.Parameter("number", ParameterType.Required)
|
||||
.Parameter("other_name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var warsInfo = GetInfo(e);
|
||||
if (warsInfo == null || warsInfo.Item1.Count == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var usr =
|
||||
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
|
||||
e.User.Name :
|
||||
e.GetArg("other_name");
|
||||
try
|
||||
{
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
var baseNumber = war.Uncall(usr);
|
||||
await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "endwar")
|
||||
.Alias(Prefix + "ew")
|
||||
.Description($"Ends the war with a given index. | `{Prefix}ew [war_number]`")
|
||||
.Parameter("number")
|
||||
.Do(async e =>
|
||||
{
|
||||
var warsInfo = GetInfo(e);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 That war does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
warsInfo.Item1[warsInfo.Item2].End();
|
||||
await e.Channel.SendMessage($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
|
||||
|
||||
var size = warsInfo.Item1[warsInfo.Item2].Size;
|
||||
warsInfo.Item1.RemoveAt(warsInfo.Item2);
|
||||
Save();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
|
||||
{
|
||||
var warInfo = GetInfo(e);
|
||||
if (warInfo == null || warInfo.Item1.Count == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var usr =
|
||||
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
|
||||
e.User.Name :
|
||||
e.GetArg("other_name");
|
||||
|
||||
var war = warInfo.Item1[warInfo.Item2];
|
||||
try
|
||||
{
|
||||
var baseNum = war.FinishClaim(usr, stars);
|
||||
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<List<ClashWar>, int> GetInfo(CommandEventArgs e)
|
||||
{
|
||||
//check if there are any wars
|
||||
List<ClashWar> wars = null;
|
||||
ClashWars.TryGetValue(e.Server.Id, out wars);
|
||||
if (wars == null || wars.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// get the number of the war
|
||||
int num;
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("number")))
|
||||
num = 0;
|
||||
else if (!int.TryParse(e.GetArg("number"), out num) || num > wars.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
num -= 1;
|
||||
//get the actual war
|
||||
return new Tuple<List<ClashWar>, int>(wars, num);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using NadekoBot.Properties;
|
||||
using System.IO;
|
||||
using System.Drawing.Imaging;
|
||||
using NadekoBot.Extensions;
|
||||
|
||||
namespace NadekoBot.Modules.Conversations.Commands
|
||||
{
|
||||
class RipCommand : DiscordCommand
|
||||
{
|
||||
public RipCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand("rip")
|
||||
.Description("Shows a grave image of someone with a start year | `@NadekoBot rip @Someone 2000`")
|
||||
.Parameter("user", ParameterType.Required)
|
||||
.Parameter("year", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
return;
|
||||
var usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
var text = "";
|
||||
Stream file;
|
||||
if (usr == null)
|
||||
{
|
||||
text = e.GetArg("user");
|
||||
file = RipName(text, string.IsNullOrWhiteSpace(e.GetArg("year"))
|
||||
? null
|
||||
: e.GetArg("year"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var avatar = await GetAvatar(usr.AvatarUrl);
|
||||
text = usr.Name;
|
||||
file = RipUser(text, avatar, string.IsNullOrWhiteSpace(e.GetArg("year"))
|
||||
? null
|
||||
: e.GetArg("year"));
|
||||
}
|
||||
await e.Channel.SendFile("ripzor_m8.png",
|
||||
file);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a RIP image of the given name and avatar, with an optional year
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="avatar"></param>
|
||||
/// <param name="year"></param>
|
||||
/// <returns></returns>
|
||||
public Stream RipUser(string name, Image avatar, string year = null)
|
||||
{
|
||||
var bm = Resources.rip;
|
||||
int width = 300;
|
||||
var fontSize = width / name.Length -2;
|
||||
if (fontSize > 20) fontSize = 20;
|
||||
var g = Graphics.FromImage(bm);
|
||||
Font nameFont = new Font("Comic Sans MS", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
|
||||
SizeF nameSize = g.MeasureString(name, nameFont);
|
||||
g.DrawString(name, new Font("Comic Sans MS", fontSize, FontStyle.Bold), Brushes.Black, (bm.Width /2 - 8) - (nameSize.Width /2), 243 - nameSize.Height);
|
||||
g.DrawString((year ?? "?") + " - " + DateTime.Now.Year, new Font("Consolas", 12, FontStyle.Bold), Brushes.Black, 80, 240);
|
||||
|
||||
g.DrawImage(avatar, 80, 135);
|
||||
g.DrawImage((Image)Resources.rose_overlay, 0, 0);
|
||||
g.Flush();
|
||||
g.Dispose();
|
||||
|
||||
return bm.ToStream(ImageFormat.Png);
|
||||
}
|
||||
|
||||
public Stream RipName(string name, string year = null)
|
||||
{
|
||||
var bm = Resources.rip;
|
||||
int width = 190;
|
||||
var offset = name.Length * 5;
|
||||
var fontSize = width / name.Length;
|
||||
if (fontSize > 20) fontSize = 20;
|
||||
var g = Graphics.FromImage(bm);
|
||||
Font nameFont = new Font("Comic Sans MS", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
|
||||
SizeF nameSize = g.MeasureString(name, nameFont);
|
||||
g.DrawString(name, nameFont, Brushes.Black, (bm.Width / 2) - (nameSize.Width / 2), 200);
|
||||
g.DrawString((year ?? "?") + " - " + DateTime.Now.Year, new Font("Consolas", 12, FontStyle.Bold), Brushes.Black, 80, 235);
|
||||
g.Flush();
|
||||
g.Dispose();
|
||||
|
||||
return bm.ToStream(ImageFormat.Png);
|
||||
}
|
||||
|
||||
public static async Task<Image> GetAvatar(string url)
|
||||
{
|
||||
var stream = await SearchHelper.GetResponseStreamAsync(url);
|
||||
Bitmap bmp = new Bitmap(100, 100);
|
||||
using (GraphicsPath gp = new GraphicsPath())
|
||||
{
|
||||
gp.AddEllipse(0, 0, bmp.Width, bmp.Height);
|
||||
using (Graphics gr = Graphics.FromImage(bmp))
|
||||
{
|
||||
gr.SetClip(gp);
|
||||
gr.DrawImage(Image.FromStream(stream), Point.Empty);
|
||||
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Conversations.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Conversations
|
||||
{
|
||||
internal class Conversations : DiscordModule
|
||||
{
|
||||
private const string firestr = "🔥 ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้ 🔥";
|
||||
public Conversations()
|
||||
{
|
||||
commands.Add(new RipCommand(this));
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = String.Format(NadekoBot.Config.CommandPrefixes.Conversations, NadekoBot.Creds.BotId);
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
var rng = new Random();
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
cgb.CreateCommand("..")
|
||||
.Description("Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`")
|
||||
.Parameter("keyword", ParameterType.Required)
|
||||
.Parameter("text", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var text = e.GetArg("text");
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
await Task.Run(() =>
|
||||
Classes.DbHandler.Instance.Connection.Insert(new DataModels.UserQuote()
|
||||
{
|
||||
DateAdded = DateTime.Now,
|
||||
Keyword = e.GetArg("keyword").ToLowerInvariant(),
|
||||
Text = text,
|
||||
UserName = e.User.Name,
|
||||
})).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage("`New quote added.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("...")
|
||||
.Description("Shows a random quote with a specified name. | `... abc`")
|
||||
.Parameter("keyword", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var keyword = e.GetArg("keyword")?.ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(keyword))
|
||||
return;
|
||||
|
||||
var quote =
|
||||
Classes.DbHandler.Instance.GetRandom<DataModels.UserQuote>(
|
||||
uqm => uqm.Keyword == keyword);
|
||||
|
||||
if (quote != null)
|
||||
await e.Channel.SendMessage($"📣 {quote.Text}").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("💢`No quote found.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("..qdel")
|
||||
.Alias("..quotedelete")
|
||||
.Description("Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`")
|
||||
.Parameter("quote", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var text = e.GetArg("quote")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
Classes.DbHandler.Instance.DeleteWhere<UserQuote>(uq => uq.Keyword == text);
|
||||
else
|
||||
Classes.DbHandler.Instance.DeleteWhere<UserQuote>(uq => uq.Keyword == text && uq.UserName == e.User.Name);
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage("`Done.`").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
|
||||
manager.CreateCommands(NadekoBot.BotMention, cgb =>
|
||||
{
|
||||
var client = manager.Client;
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand("die")
|
||||
.Description("Works only for the owner. Shuts the bot down. | `@NadekoBot die`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + ", Yes, my love.").ConfigureAwait(false);
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage(e.User.Mention + ", No.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
var randServerSw = new Stopwatch();
|
||||
randServerSw.Start();
|
||||
|
||||
cgb.CreateCommand("do you love me")
|
||||
.Description("Replies with positive answer only to the bot owner. | `@NadekoBot do you love me`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
await e.Channel.SendMessage(e.User.Mention + ", Of course I do, my Master.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage(e.User.Mention + ", Don't be silly.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("how are you")
|
||||
.Alias("how are you?")
|
||||
.Description("Replies positive only if bot owner is online. | `@NadekoBot how are you`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + " I am great as long as you are here.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var kw = e.Server.GetUser(NadekoBot.Creds.OwnerIds[0]);
|
||||
if (kw != null && kw.Status == UserStatus.Online)
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + " I am great as long as " + kw.Mention + " is with me.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage(e.User.Mention + " I am sad. My Master is not with me.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand("fire")
|
||||
.Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | `@NadekoBot fire [x]`")
|
||||
.Parameter("times", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
int count;
|
||||
if (string.IsNullOrWhiteSpace(e.Args[0]))
|
||||
count = 1;
|
||||
else
|
||||
int.TryParse(e.Args[0], out count);
|
||||
if (count < 1 || count > 12)
|
||||
{
|
||||
await e.Channel.SendMessage("Number must be between 1 and 12").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var str = new StringBuilder();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
str.Append(firestr);
|
||||
}
|
||||
await e.Channel.SendMessage(str.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("dump")
|
||||
.Description("Dumps all of the invites it can to dump.txt.** Owner Only.** | `@NadekoBot dump`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id)) return;
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var invites = "";
|
||||
foreach (var s in client.Servers)
|
||||
{
|
||||
try
|
||||
{
|
||||
var invite = await s.CreateInvite(0).ConfigureAwait(false);
|
||||
invites += invite.Url + "\n";
|
||||
i++;
|
||||
}
|
||||
catch
|
||||
{
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
File.WriteAllText("dump.txt", invites);
|
||||
await e.Channel.SendMessage($"Got invites for {i} servers and failed to get invites for {j} servers")
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("ab")
|
||||
.Description("Try to get 'abalabahaha'| `@NadekoBot ab`")
|
||||
.Do(async e =>
|
||||
{
|
||||
string[] strings = { "ba", "la", "ha" };
|
||||
var construct = "@a";
|
||||
var cnt = rng.Next(4, 7);
|
||||
while (cnt-- > 0)
|
||||
{
|
||||
construct += strings[rng.Next(0, strings.Length)];
|
||||
}
|
||||
await e.Channel.SendMessage(construct).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Func<CommandEventArgs, Task> SayYes()
|
||||
=> async e => await e.Channel.SendMessage("Yes. :)").ConfigureAwait(false);
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
internal class CustomReactionsModule : DiscordModule
|
||||
{
|
||||
public override string Prefix { get; } = "";
|
||||
|
||||
private Random rng = new Random();
|
||||
|
||||
private Dictionary<Regex, Func<CommandEventArgs, Match, string>> commandFuncs;
|
||||
|
||||
public CustomReactionsModule()
|
||||
{
|
||||
commandFuncs = new Dictionary<Regex, Func<CommandEventArgs, Match, string>>
|
||||
{
|
||||
{new Regex(@"(?:%rng%|%rng:(\d{1,9})-(\d{1,9})%)"), (e,m) => {
|
||||
int start, end;
|
||||
if (m.Groups[1].Success)
|
||||
{
|
||||
start = int.Parse(m.Groups[1].Value);
|
||||
end = int.Parse(m.Groups[2].Value);
|
||||
return rng.Next(start, end).ToString();
|
||||
}else return rng.Next().ToString();
|
||||
} },
|
||||
{new Regex("%mention%"), (e,m) => NadekoBot.BotMention },
|
||||
{new Regex("%user%"), (e,m) => e.User.Mention },
|
||||
{new Regex("%target%"), (e,m) => e.GetArg("args")?.Trim() ?? "" },
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
foreach (var command in NadekoBot.Config.CustomReactions)
|
||||
{
|
||||
var commandName = command.Key.Replace("%mention%", NadekoBot.BotMention);
|
||||
|
||||
var c = cgb.CreateCommand(commandName);
|
||||
if (commandName.Contains(NadekoBot.BotMention))
|
||||
c.Alias(commandName.Replace("<@", "<@!"));
|
||||
c.Description($"Custom reaction. | `{command.Key}`")
|
||||
.Parameter("args", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
string str = command.Value[rng.Next(0, command.Value.Count())];
|
||||
commandFuncs.Keys.ForEach(key => str = key.Replace(str, m => commandFuncs[key](e, m)));
|
||||
|
||||
|
||||
await e.Channel.SendMessage(str).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Modules;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
/// <summary>
|
||||
/// Base DiscordCommand Class.
|
||||
/// Inherit this class to create your own command.
|
||||
/// </summary>
|
||||
public abstract class DiscordCommand
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Parent module
|
||||
/// </summary>
|
||||
protected DiscordModule Module { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent module's prefix
|
||||
/// </summary>
|
||||
protected string Prefix => Module.Prefix;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of discord command,
|
||||
/// use ": base(module)" in the derived class'
|
||||
/// constructor to make sure module is assigned
|
||||
/// </summary>
|
||||
/// <param name="module">Module this command resides in</param>
|
||||
protected DiscordCommand(DiscordModule module)
|
||||
{
|
||||
this.Module = module;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the CommandBuilder with values using CommandGroupBuilder
|
||||
/// </summary>
|
||||
internal abstract void Init(CommandGroupBuilder cgb);
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using Discord.Modules;
|
||||
using System.Collections.Generic;
|
||||
using NadekoBot.Classes;
|
||||
|
||||
namespace NadekoBot.Modules {
|
||||
public abstract class DiscordModule : IModule {
|
||||
protected readonly HashSet<DiscordCommand> commands = new HashSet<DiscordCommand>();
|
||||
|
||||
public abstract string Prefix { get; }
|
||||
|
||||
public abstract void Install(ModuleManager manager);
|
||||
}
|
||||
}
|
@ -1,295 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Commands
|
||||
{
|
||||
class AnimalRacing : DiscordCommand
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces = new ConcurrentDictionary<ulong, AnimalRace>();
|
||||
|
||||
public AnimalRacing(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "race")
|
||||
.Description($"Starts a new animal race. | `{Prefix}race`")
|
||||
.Do(e =>
|
||||
{
|
||||
var ar = new AnimalRace(e.Server.Id, e.Channel);
|
||||
if (ar.Fail)
|
||||
{
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
cgb.CreateCommand(Prefix + "joinrace")
|
||||
.Alias(Prefix + "jr")
|
||||
.Description($"Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `{Prefix}jr` or `{Prefix}jr 5`")
|
||||
.Parameter("amount", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
int amount;
|
||||
if (!int.TryParse(e.GetArg("amount"), out amount) || amount < 0)
|
||||
amount = 0;
|
||||
|
||||
var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
|
||||
|
||||
if (userFlowers < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > 0)
|
||||
await FlowersHandler.RemoveFlowers(e.User, "BetRace", (int)amount, true).ConfigureAwait(false);
|
||||
|
||||
AnimalRace ar;
|
||||
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar))
|
||||
{
|
||||
await e.Channel.SendMessage("No race exists on this server");
|
||||
return;
|
||||
}
|
||||
await ar.JoinRace(e.User, amount);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public class AnimalRace
|
||||
{
|
||||
|
||||
private ConcurrentQueue<string> animals = new ConcurrentQueue<string>(NadekoBot.Config.RaceAnimals.Shuffle());
|
||||
|
||||
public bool Fail { get; internal set; }
|
||||
|
||||
public List<Participant> participants = new List<Participant>();
|
||||
private ulong serverId;
|
||||
private int messagesSinceGameStarted = 0;
|
||||
|
||||
public Channel raceChannel { get; set; }
|
||||
public bool Started { get; private set; } = false;
|
||||
|
||||
public AnimalRace(ulong serverId, Channel ch)
|
||||
{
|
||||
this.serverId = serverId;
|
||||
this.raceChannel = ch;
|
||||
if (!AnimalRaces.TryAdd(serverId, this))
|
||||
{
|
||||
Fail = true;
|
||||
return;
|
||||
}
|
||||
var cancelSource = new CancellationTokenSource();
|
||||
var token = cancelSource.Token;
|
||||
var fullgame = CheckForFullGameAsync(token);
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type {NadekoBot.Config.CommandPrefixes.Gambling}jr to join the race.`");
|
||||
var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
|
||||
Started = true;
|
||||
cancelSource.Cancel();
|
||||
if (t == fullgame)
|
||||
{
|
||||
await raceChannel.SendMessage("🏁`Race full, starting right now!`");
|
||||
}
|
||||
else if (participants.Count > 1)
|
||||
{
|
||||
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " participants.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
await raceChannel.SendMessage("🏁`Race failed to start since there was not enough participants.`");
|
||||
var p = participants.FirstOrDefault();
|
||||
if (p != null)
|
||||
await FlowersHandler.AddFlowersAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false);
|
||||
End();
|
||||
return;
|
||||
}
|
||||
await Task.Run(StartRace);
|
||||
End();
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
|
||||
private void End()
|
||||
{
|
||||
AnimalRace throwaway;
|
||||
AnimalRaces.TryRemove(serverId, out throwaway);
|
||||
}
|
||||
|
||||
private async Task StartRace()
|
||||
{
|
||||
var rng = new Random();
|
||||
Participant winner = null;
|
||||
Message msg = null;
|
||||
int place = 1;
|
||||
try
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||
|
||||
while (!participants.All(p => p.Total >= 60))
|
||||
{
|
||||
//update the state
|
||||
participants.ForEach(p =>
|
||||
{
|
||||
|
||||
p.Total += 1 + rng.Next(0, 10);
|
||||
if (p.Total > 60)
|
||||
{
|
||||
p.Total = 60;
|
||||
if (winner == null)
|
||||
{
|
||||
winner = p;
|
||||
}
|
||||
if (p.Place == 0)
|
||||
p.Place = place++;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//draw the state
|
||||
|
||||
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
||||
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|
||||
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
||||
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
|
||||
{
|
||||
if (msg != null)
|
||||
try { await msg.Delete(); } catch { }
|
||||
msg = await raceChannel.SendMessage(text);
|
||||
messagesSinceGameStarted = 0;
|
||||
}
|
||||
else
|
||||
await msg.Edit(text);
|
||||
|
||||
await Task.Delay(2500);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||
}
|
||||
|
||||
if (winner.AmountBet > 0)
|
||||
{
|
||||
var wonAmount = winner.AmountBet * (participants.Count - 1);
|
||||
await FlowersHandler.AddFlowersAsync(winner.User, "Won a Race", wonAmount).ConfigureAwait(false);
|
||||
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{NadekoBot.Config.CurrencySign}!**");
|
||||
}
|
||||
else
|
||||
{
|
||||
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race!**");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Client_MessageReceived(object sender, MessageEventArgs e)
|
||||
{
|
||||
if (e.Message.IsAuthor || e.Channel.IsPrivate || e.Channel != raceChannel)
|
||||
return;
|
||||
messagesSinceGameStarted++;
|
||||
}
|
||||
|
||||
private async Task CheckForFullGameAsync(CancellationToken cancelToken)
|
||||
{
|
||||
while (animals.Count > 0)
|
||||
{
|
||||
await Task.Delay(100, cancelToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> JoinRace(User u, int amount = 0)
|
||||
{
|
||||
var animal = "";
|
||||
if (!animals.TryDequeue(out animal))
|
||||
{
|
||||
await raceChannel.SendMessage($"{u.Mention} `There is no running race on this server.`");
|
||||
return false;
|
||||
}
|
||||
var p = new Participant(u, animal, amount);
|
||||
if (participants.Contains(p))
|
||||
{
|
||||
await raceChannel.SendMessage($"{u.Mention} `You already joined this race.`");
|
||||
return false;
|
||||
}
|
||||
if (Started)
|
||||
{
|
||||
await raceChannel.SendMessage($"{u.Mention} `Race is already started`");
|
||||
return false;
|
||||
}
|
||||
participants.Add(p);
|
||||
await raceChannel.SendMessage($"{u.Mention} **joined the race as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {NadekoBot.Config.CurrencyName.SnPl(amount)}!**" : "**"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class Participant
|
||||
{
|
||||
public User User { get; set; }
|
||||
public string Animal { get; set; }
|
||||
public int AmountBet { get; set; }
|
||||
|
||||
public float Coeff { get; set; }
|
||||
public int Total { get; set; }
|
||||
|
||||
public int Place { get; set; } = 0;
|
||||
|
||||
public Participant(User u, string a, int amount)
|
||||
{
|
||||
this.User = u;
|
||||
this.Animal = a;
|
||||
this.AmountBet = amount;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return User.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var p = obj as Participant;
|
||||
return p == null ?
|
||||
false :
|
||||
p.User == User;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var str = new string('‣', Total) + Animal;
|
||||
if (Place == 0)
|
||||
return str;
|
||||
if (Place == 1)
|
||||
{
|
||||
return str + "🏆";
|
||||
}
|
||||
else if (Place == 2)
|
||||
{
|
||||
return str + "`2nd`";
|
||||
}
|
||||
else if (Place == 3)
|
||||
{
|
||||
return str + "`3rd`";
|
||||
}
|
||||
else
|
||||
{
|
||||
return str + $"`{Place}th`";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
internal class DiceRollCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public DiceRollCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "roll")
|
||||
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice." +
|
||||
$" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `{Prefix}roll` or `{Prefix}roll 7` or `{Prefix}roll 3d5`")
|
||||
.Parameter("num", ParameterType.Optional)
|
||||
.Do(RollFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "rolluo")
|
||||
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered)." +
|
||||
$" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `{Prefix}rolluo` or `{Prefix}rolluo 7` or `{Prefix}rolluo 3d5`")
|
||||
.Parameter("num", ParameterType.Optional)
|
||||
.Do(RollFunc(false));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "nroll")
|
||||
.Description($"Rolls in a given range. | `{Prefix}nroll 5` (rolls 0-5) or `{Prefix}nroll 5-15`")
|
||||
.Parameter("range", ParameterType.Required)
|
||||
.Do(NRollFunc());
|
||||
}
|
||||
|
||||
private Image GetDice(int num) => num != 10
|
||||
? Properties.Resources.ResourceManager.GetObject("_" + num) as Image
|
||||
: new[]
|
||||
{
|
||||
(Properties.Resources.ResourceManager.GetObject("_" + 1) as Image),
|
||||
(Properties.Resources.ResourceManager.GetObject("_" + 0) as Image),
|
||||
}.Merge();
|
||||
|
||||
|
||||
Regex dndRegex = new Regex(@"(?<n1>\d+)d(?<n2>\d+)", RegexOptions.Compiled);
|
||||
private Func<CommandEventArgs, Task> RollFunc(bool ordered = true)
|
||||
{
|
||||
var r = new Random();
|
||||
return async e =>
|
||||
{
|
||||
var arg = e.Args[0]?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
var gen = r.Next(0, 101);
|
||||
|
||||
var num1 = gen / 10;
|
||||
var num2 = gen % 10;
|
||||
|
||||
var imageStream = new Image[2] { GetDice(num1), GetDice(num2) }.Merge().ToStream(ImageFormat.Png);
|
||||
|
||||
await e.Channel.SendFile("dice.png", imageStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Match m;
|
||||
if ((m = dndRegex.Match(arg)).Length != 0)
|
||||
{
|
||||
int n1;
|
||||
int n2;
|
||||
if (int.TryParse(m.Groups["n1"].ToString(), out n1) &&
|
||||
int.TryParse(m.Groups["n2"].ToString(), out n2) &&
|
||||
n1 <= 50 && n2 <= 100000 && n1 > 0 && n2 > 0)
|
||||
{
|
||||
var arr = new int[n1];
|
||||
for (int i = 0; i < n1; i++)
|
||||
{
|
||||
arr[i] = r.Next(1, n2 + 1);
|
||||
}
|
||||
var elemCnt = 0;
|
||||
await e.Channel.SendMessage($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var num = int.Parse(e.Args[0]);
|
||||
if (num < 1) num = 1;
|
||||
if (num > 30)
|
||||
{
|
||||
await e.Channel.SendMessage("You can roll up to 30 dice at a time.").ConfigureAwait(false);
|
||||
num = 30;
|
||||
}
|
||||
var dices = new List<Image>(num);
|
||||
var values = new List<int>(num);
|
||||
for (var i = 0; i < num; i++)
|
||||
{
|
||||
var randomNumber = r.Next(1, 7);
|
||||
var toInsert = dices.Count;
|
||||
if (ordered)
|
||||
{
|
||||
if (randomNumber == 6 || dices.Count == 0)
|
||||
toInsert = 0;
|
||||
else if (randomNumber != 1)
|
||||
for (var j = 0; j < dices.Count; j++)
|
||||
{
|
||||
if (values[j] < randomNumber)
|
||||
{
|
||||
toInsert = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
toInsert = dices.Count;
|
||||
}
|
||||
dices.Insert(toInsert, GetDice(randomNumber));
|
||||
values.Insert(toInsert, randomNumber);
|
||||
}
|
||||
|
||||
var bitmap = dices.Merge();
|
||||
await e.Channel.SendMessage(values.Count + " Dice rolled. Total: **" + values.Sum() + "** Average: **" + (values.Sum() / (1.0f * values.Count)).ToString("N2") + "**").ConfigureAwait(false);
|
||||
await e.Channel.SendFile("dice.png", bitmap.ToStream(ImageFormat.Png)).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Please enter a number of dice to roll.").ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private Func<CommandEventArgs, Task> NRollFunc() =>
|
||||
async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int rolled;
|
||||
if (e.GetArg("range").Contains("-"))
|
||||
{
|
||||
var arr = e.GetArg("range").Split('-')
|
||||
.Take(2)
|
||||
.Select(int.Parse)
|
||||
.ToArray();
|
||||
if (arr[0] > arr[1])
|
||||
throw new ArgumentException("First argument should be bigger than the second one.");
|
||||
rolled = new Random().Next(arr[0], arr[1] + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rolled = new Random().Next(0, int.Parse(e.GetArg("range")) + 1);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage($"{e.User.Mention} rolled **{rolled}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($":anger: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Gambling.Helpers;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
internal class DrawCommand : DiscordCommand
|
||||
{
|
||||
public DrawCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "draw")
|
||||
.Description($"Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | `{Prefix}draw [x]`")
|
||||
.Parameter("count", ParameterType.Optional)
|
||||
.Do(DrawCardFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "shuffle")
|
||||
.Alias(Module.Prefix + "sh")
|
||||
.Description($"Reshuffles all cards back into the deck.|`{Prefix}shuffle`")
|
||||
.Do(ReshuffleTask());
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<Discord.Server, Cards> AllDecks = new ConcurrentDictionary<Discord.Server, Cards>();
|
||||
|
||||
private static Func<CommandEventArgs, Task> ReshuffleTask()
|
||||
{
|
||||
return async e =>
|
||||
{
|
||||
AllDecks.AddOrUpdate(e.Server,
|
||||
(s) => new Cards(),
|
||||
(s, c) =>
|
||||
{
|
||||
c.Restart();
|
||||
return c;
|
||||
});
|
||||
|
||||
await e.Channel.SendMessage("Deck reshuffled.").ConfigureAwait(false);
|
||||
};
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> DrawCardFunc() => async (e) =>
|
||||
{
|
||||
var cards = AllDecks.GetOrAdd(e.Server, (s) => new Cards());
|
||||
|
||||
try
|
||||
{
|
||||
var num = 1;
|
||||
var isParsed = int.TryParse(e.GetArg("count"), out num);
|
||||
if (!isParsed || num < 2)
|
||||
{
|
||||
var c = cards.DrawACard();
|
||||
await e.Channel.SendFile(c.Name + ".jpg", (Properties.Resources.ResourceManager.GetObject(c.Name) as Image).ToStream()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (num > 5)
|
||||
num = 5;
|
||||
|
||||
var images = new List<Image>();
|
||||
var cardObjects = new List<Cards.Card>();
|
||||
for (var i = 0; i < num; i++)
|
||||
{
|
||||
if (cards.CardPool.Count == 0 && i != 0)
|
||||
{
|
||||
await e.Channel.SendMessage("No more cards in a deck.").ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
var currentCard = cards.DrawACard();
|
||||
cardObjects.Add(currentCard);
|
||||
images.Add(Properties.Resources.ResourceManager.GetObject(currentCard.Name) as Image);
|
||||
}
|
||||
var bitmap = images.Merge();
|
||||
await e.Channel.SendFile(images.Count + " cards.jpg", bitmap.ToStream()).ConfigureAwait(false);
|
||||
if (cardObjects.Count == 5)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} `{Cards.GetHandValue(cardObjects)}`").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error drawing (a) card(s) " + ex.ToString());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
internal class FlipCoinCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public FlipCoinCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "flip")
|
||||
.Description($"Flips coin(s) - heads or tails, and shows an image. | `{Prefix}flip` or `{Prefix}flip 3`")
|
||||
.Parameter("count", ParameterType.Optional)
|
||||
.Do(FlipCoinFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "betflip")
|
||||
.Alias(Prefix+"bf")
|
||||
.Description($"Bet to guess will the result be heads or tails. Guessing award you double flowers you've bet. | `{Prefix}bf 5 heads` or `{Prefix}bf 3 t`")
|
||||
.Parameter("amount", ParameterType.Required)
|
||||
.Parameter("guess", ParameterType.Required)
|
||||
.Do(BetFlipCoinFunc());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private readonly Random rng = new Random();
|
||||
public Func<CommandEventArgs, Task> BetFlipCoinFunc() => async e =>
|
||||
{
|
||||
|
||||
var amountstr = e.GetArg("amount").Trim();
|
||||
|
||||
var guessStr = e.GetArg("guess").Trim().ToUpperInvariant();
|
||||
if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS")
|
||||
return;
|
||||
|
||||
int amount;
|
||||
if (!int.TryParse(amountstr, out amount) || amount < 1)
|
||||
return;
|
||||
|
||||
var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
|
||||
|
||||
if (userFlowers < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await FlowersHandler.RemoveFlowers(e.User, "Betflip Gamble", (int)amount, true).ConfigureAwait(false);
|
||||
//heads = true
|
||||
//tails = false
|
||||
|
||||
var guess = guessStr == "HEADS" || guessStr == "H";
|
||||
bool result = false;
|
||||
if (rng.Next(0, 2) == 1) {
|
||||
await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string str;
|
||||
if (guess == result)
|
||||
{
|
||||
str = $"{e.User.Mention}`You guessed it!` You won {amount * 2}{NadekoBot.Config.CurrencySign}";
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Betflip Gamble", amount * 2, true).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
else
|
||||
str = $"{e.User.Mention}`More luck next time.`";
|
||||
|
||||
await e.Channel.SendMessage(str).ConfigureAwait(false);
|
||||
};
|
||||
|
||||
public Func<CommandEventArgs, Task> FlipCoinFunc() => async e =>
|
||||
{
|
||||
|
||||
if (e.GetArg("count") == "")
|
||||
{
|
||||
if (rng.Next(0, 2) == 1)
|
||||
await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int result;
|
||||
if (int.TryParse(e.GetArg("count"), out result))
|
||||
{
|
||||
if (result > 10)
|
||||
result = 10;
|
||||
var imgs = new Image[result];
|
||||
for (var i = 0; i < result; i++)
|
||||
{
|
||||
imgs[i] = rng.Next(0, 2) == 0 ?
|
||||
Properties.Resources.tails :
|
||||
Properties.Resources.heads;
|
||||
}
|
||||
await e.Channel.SendFile($"{result} coins.png", imgs.Merge().ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage("Invalid number").ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Gambling.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
internal class GamblingModule : DiscordModule
|
||||
{
|
||||
public GamblingModule()
|
||||
{
|
||||
commands.Add(new DrawCommand(this));
|
||||
commands.Add(new FlipCoinCommand(this));
|
||||
commands.Add(new DiceRollCommand(this));
|
||||
commands.Add(new AnimalRacing(this));
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(com => com.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "raffle")
|
||||
.Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName`")
|
||||
.Parameter("role", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = string.IsNullOrWhiteSpace(e.GetArg("role")) ? "@everyone" : e.GetArg("role");
|
||||
var role = e.Server.FindRoles(arg).FirstOrDefault();
|
||||
if (role == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Role not found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var members = role.Members.Where(u => u.Status == UserStatus.Online); // only online
|
||||
var membersArray = members as User[] ?? members.ToArray();
|
||||
var usr = membersArray[new Random().Next(0, membersArray.Length)];
|
||||
await e.Channel.SendMessage($"**Raffled user:** {usr.Name} (id: {usr.Id})").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "$$")
|
||||
.Description(string.Format("Check how much {0}s a person has. (Defaults to yourself) |`{1}$$` or `{1}$$ @Someone`",
|
||||
NadekoBot.Config.CurrencyName, Prefix))
|
||||
.Parameter("all", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.Message.MentionedUsers.FirstOrDefault() ?? e.User;
|
||||
var pts = GetUserFlowers(usr.Id);
|
||||
var str = $"{usr.Name} has {pts} {NadekoBot.Config.CurrencySign}";
|
||||
await e.Channel.SendMessage(str).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "give")
|
||||
.Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)+ $"|`{Prefix}give 1 \"@SomeGuy\"`")
|
||||
.Parameter("amount", ParameterType.Required)
|
||||
.Parameter("receiver", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var amountStr = e.GetArg("amount")?.Trim();
|
||||
long amount;
|
||||
if (!long.TryParse(amountStr, out amount) || amount <= 0)
|
||||
return;
|
||||
|
||||
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
|
||||
u.Id != NadekoBot.Client.CurrentUser.Id &&
|
||||
u.Id != e.User.Id);
|
||||
if (mentionedUser == null)
|
||||
return;
|
||||
|
||||
var userFlowers = GetUserFlowers(e.User.Id);
|
||||
|
||||
if (userFlowers < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await FlowersHandler.RemoveFlowers(e.User, "Gift", (int)amount, true).ConfigureAwait(false);
|
||||
await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "award")
|
||||
.Description($"Gives someone a certain amount of flowers. **Bot Owner Only!** | `{Prefix}award 100 @person`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Parameter("amount", ParameterType.Required)
|
||||
.Parameter("receiver", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var amountStr = e.GetArg("amount")?.Trim();
|
||||
long amount;
|
||||
if (!long.TryParse(amountStr, out amount) || amount < 0)
|
||||
return;
|
||||
|
||||
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
|
||||
u.Id != NadekoBot.Client.CurrentUser.Id);
|
||||
if (mentionedUser == null)
|
||||
return;
|
||||
|
||||
await FlowersHandler.AddFlowersAsync(mentionedUser, $"Awarded by bot owner. ({e.User.Name}/{e.User.Id})", (int)amount).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage($"{e.User.Mention} successfully awarded {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "take")
|
||||
.Description($"Takes a certain amount of flowers from someone. **Bot Owner Only!** | `{Prefix}take 1 \"@someguy\"`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Parameter("amount", ParameterType.Required)
|
||||
.Parameter("rektperson", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var amountStr = e.GetArg("amount")?.Trim();
|
||||
long amount;
|
||||
if (!long.TryParse(amountStr, out amount) || amount < 0)
|
||||
return;
|
||||
|
||||
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
|
||||
u.Id != NadekoBot.Client.CurrentUser.Id);
|
||||
if (mentionedUser == null)
|
||||
return;
|
||||
|
||||
await FlowersHandler.RemoveFlowers(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount).ConfigureAwait(false);
|
||||
|
||||
await e.Channel.SendMessage($"{e.User.Mention} successfully took {amount} {NadekoBot.Config.CurrencyName}s from {mentionedUser.Mention}!").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "betroll")
|
||||
.Alias(Prefix + "br")
|
||||
.Description($"Bets a certain amount of {NadekoBot.Config.CurrencyName}s and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | `{Prefix}br 5`")
|
||||
.Parameter("amount",ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var amountstr = e.GetArg("amount").Trim();
|
||||
int amount;
|
||||
|
||||
if (!int.TryParse(amountstr, out amount) || amount < 1)
|
||||
return;
|
||||
|
||||
var userFlowers = GetUserFlowers(e.User.Id);
|
||||
|
||||
if (userFlowers < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await FlowersHandler.RemoveFlowers(e.User, "Betroll Gamble", (int)amount, true).ConfigureAwait(false);
|
||||
|
||||
var rng = new Random().Next(0, 101);
|
||||
var str = $"{e.User.Mention} `You rolled {rng}.` ";
|
||||
if (rng < 67)
|
||||
{
|
||||
str += "Better luck next time.";
|
||||
}
|
||||
else if (rng < 90)
|
||||
{
|
||||
str += $"Congratulations! You won {amount * 2}{NadekoBot.Config.CurrencySign} for rolling above 66";
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 2, true).ConfigureAwait(false);
|
||||
}
|
||||
else if (rng < 100)
|
||||
{
|
||||
str += $"Congratulations! You won {amount * 3}{NadekoBot.Config.CurrencySign} for rolling above 90.";
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 3, true).ConfigureAwait(false);
|
||||
}
|
||||
else {
|
||||
str += $"👑 Congratulations! You won {amount * 10}{NadekoBot.Config.CurrencySign} for rolling **100**. 👑";
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 10, true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(str).ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "leaderboard")
|
||||
.Alias(Prefix + "lb")
|
||||
.Description($"Displays bot currency leaderboard | `{Prefix}lb`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var richestTemp = DbHandler.Instance.GetTopRichest();
|
||||
var richest = richestTemp as CurrencyState[] ?? richestTemp.ToArray();
|
||||
if (richest.Length == 0)
|
||||
return;
|
||||
await e.Channel.SendMessage(
|
||||
richest.Aggregate(new StringBuilder(
|
||||
$@"```xl
|
||||
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
|
||||
┃ Id ┃ $$$ ┃
|
||||
"),
|
||||
(cur, cs) => cur.AppendLine(
|
||||
$@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫
|
||||
┃{(e.Server.Users.Where(u => u.Id == (ulong)cs.UserId).FirstOrDefault()?.Name.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs.Value,5} ┃")
|
||||
).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static long GetUserFlowers(ulong userId) =>
|
||||
Classes.DbHandler.Instance.GetStateByUserId((long)userId)?.Value ?? 0;
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
class BetrayGame : DiscordCommand
|
||||
{
|
||||
public BetrayGame(DiscordModule module) : base(module) { }
|
||||
|
||||
private enum Answers
|
||||
{
|
||||
Cooperate,
|
||||
Betray
|
||||
}
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "betray")
|
||||
.Description("BETRAY GAME. Betray nadeko next turn." +
|
||||
"If Nadeko cooperates - you get extra points, nadeko loses a LOT." +
|
||||
$"If Nadeko betrays - you both lose some points. | `{Prefix}betray`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await ReceiveAnswer(e, Answers.Betray).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "cooperate")
|
||||
.Description("BETRAY GAME. Cooperate with nadeko next turn." +
|
||||
"If Nadeko cooperates - you both get bonus points." +
|
||||
$"If Nadeko betrays - you lose A LOT, nadeko gets extra. | `{Prefix}cooperater`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
await ReceiveAnswer(e, Answers.Cooperate).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private int userPoints = 0;
|
||||
|
||||
private int UserPoints {
|
||||
get { return userPoints; }
|
||||
set {
|
||||
if (value < 0)
|
||||
userPoints = 0;
|
||||
userPoints = value;
|
||||
}
|
||||
}
|
||||
private int nadekoPoints = 0;
|
||||
private int NadekoPoints {
|
||||
get { return nadekoPoints; }
|
||||
set {
|
||||
if (value < 0)
|
||||
nadekoPoints = 0;
|
||||
nadekoPoints = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int round = 0;
|
||||
private Answers NextAnswer = Answers.Cooperate;
|
||||
private async Task ReceiveAnswer(CommandEventArgs e, Answers userAnswer)
|
||||
{
|
||||
var response = userAnswer == Answers.Betray
|
||||
? ":no_entry: `You betrayed nadeko` - you monster."
|
||||
: ":ok: `You cooperated with nadeko.` ";
|
||||
var currentAnswer = NextAnswer;
|
||||
var nadekoResponse = currentAnswer == Answers.Betray
|
||||
? ":no_entry: `aww Nadeko betrayed you` - she is so cute"
|
||||
: ":ok: `Nadeko cooperated.`";
|
||||
NextAnswer = userAnswer;
|
||||
if (userAnswer == Answers.Betray && currentAnswer == Answers.Betray)
|
||||
{
|
||||
NadekoPoints--;
|
||||
UserPoints--;
|
||||
}
|
||||
else if (userAnswer == Answers.Cooperate && currentAnswer == Answers.Cooperate)
|
||||
{
|
||||
NadekoPoints += 2;
|
||||
UserPoints += 2;
|
||||
}
|
||||
else if (userAnswer == Answers.Betray && currentAnswer == Answers.Cooperate)
|
||||
{
|
||||
NadekoPoints -= 3;
|
||||
UserPoints += 3;
|
||||
}
|
||||
else if (userAnswer == Answers.Cooperate && currentAnswer == Answers.Betray)
|
||||
{
|
||||
NadekoPoints += 3;
|
||||
UserPoints -= 3;
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage($"**ROUND {++round}**\n" +
|
||||
$"{response}\n" +
|
||||
$"{nadekoResponse}\n" +
|
||||
$"--------------------------------\n" +
|
||||
$"Nadeko has {NadekoPoints} points." +
|
||||
$"You have {UserPoints} points." +
|
||||
$"--------------------------------\n")
|
||||
.ConfigureAwait(false);
|
||||
if (round < 10) return;
|
||||
if (nadekoPoints == userPoints)
|
||||
await e.Channel.SendMessage("Its a draw").ConfigureAwait(false);
|
||||
else if (nadekoPoints > userPoints)
|
||||
await e.Channel.SendMessage("Nadeko won.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("You won.").ConfigureAwait(false);
|
||||
nadekoPoints = 0;
|
||||
userPoints = 0;
|
||||
round = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class BetraySetting
|
||||
{
|
||||
private string Story = $"{0} have robbed a bank and got captured by a police." +
|
||||
$"Investigators gave you a choice:\n" +
|
||||
$"You can either >COOPERATE with your friends and " +
|
||||
$"not tell them who's idea it was, OR you can >BETRAY your" +
|
||||
$"friends. Depending on their answers your penalty will vary.";
|
||||
|
||||
public int DoubleCoop = 1;
|
||||
public int DoubleBetray = -1;
|
||||
public int BetrayCoop_Betrayer = 3;
|
||||
public int BetrayCoop_Cooperater = -3;
|
||||
|
||||
public string GetStory(IEnumerable<string> names) => String.Format(Story, string.Join(", ", names));
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System.Text;
|
||||
using System.Timers;
|
||||
using static NadekoBot.Modules.Games.Commands.Bomberman;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
class Bomberman : DiscordCommand
|
||||
{
|
||||
public Field[,] board = new Field[15, 15];
|
||||
|
||||
public BombermanPlayer[] players = new BombermanPlayer[4];
|
||||
|
||||
public Channel gameChannel = null;
|
||||
|
||||
public Message godMsg = null;
|
||||
|
||||
public int curI = 5;
|
||||
public int curJ = 5;
|
||||
|
||||
|
||||
public Bomberman(DiscordModule module) : base(module)
|
||||
{
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
for (int j = 0; j < 15; j++)
|
||||
{
|
||||
board[i, j] = new Field();
|
||||
}
|
||||
}
|
||||
NadekoBot.Client.MessageReceived += (s, e) =>
|
||||
{
|
||||
if (e.Channel != gameChannel ||
|
||||
e.User.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
|
||||
if (e.Message.Text == "w")
|
||||
{
|
||||
board[curI - 1, curJ] = board[curI--, curJ];
|
||||
board[curI + 1, curJ].player = null;
|
||||
}
|
||||
else if (e.Message.Text == "s")
|
||||
{
|
||||
board[curI + 1, curJ] = board[curI++, curJ];
|
||||
board[curI - 1, curJ].player = null;
|
||||
}
|
||||
else if (e.Message.Text == "a")
|
||||
{
|
||||
board[curI, curJ - 1] = board[curI, curJ--];
|
||||
board[curI, curJ + 1].player = null;
|
||||
}
|
||||
else if (e.Message.Text == "d")
|
||||
{
|
||||
board[curI, curJ + 1] = board[curI, curJ++];
|
||||
board[curI, curJ - 1].player = null;
|
||||
}
|
||||
|
||||
e.Message.Delete();
|
||||
};
|
||||
|
||||
var t = new Timer();
|
||||
t.Elapsed += async (s, e) =>
|
||||
{
|
||||
if (gameChannel == null)
|
||||
return;
|
||||
|
||||
var boardStr = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
for (int j = 0; j < 15; j++)
|
||||
{
|
||||
boardStr.Append(board[i, j].ToString());
|
||||
}
|
||||
boardStr.AppendLine();
|
||||
}
|
||||
if (godMsg.Id != 0)
|
||||
await godMsg.Edit(boardStr.ToString()).ConfigureAwait(false);
|
||||
|
||||
};
|
||||
t.Interval = 1000;
|
||||
t.Start();
|
||||
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
//cgb.CreateCommand(Module.Prefix + "bomb")
|
||||
// .Description("Bomberman start")
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// if (gameChannel != null)
|
||||
// return;
|
||||
// godMsg = await e.Channel.SendMessage("GAME START IN 1 SECOND....").ConfigureAwait(false);
|
||||
// gameChannel = e.Channel;
|
||||
// players[0] = new BombermanPlayer
|
||||
// {
|
||||
// User = e.User,
|
||||
// };
|
||||
|
||||
// board[5, 5].player = players[0];
|
||||
// });
|
||||
}
|
||||
|
||||
public class BombermanPlayer
|
||||
{
|
||||
public User User = null;
|
||||
public string Icon = "👳";
|
||||
|
||||
internal void MoveLeft()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct Field
|
||||
{
|
||||
public BombermanPlayer player;
|
||||
|
||||
public override string ToString() => player?.Icon ?? "⬜";
|
||||
}
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Flower picking/planting idea is given to me by its
|
||||
/// inceptor Violent Crumble from Game Developers League discord server
|
||||
/// (he has !cookie and !nom) Thanks a lot Violent!
|
||||
/// Check out GDL (its a growing gamedev community):
|
||||
/// https://discord.gg/0TYNJfCU4De7YIk8
|
||||
/// </summary>
|
||||
class PlantPick : DiscordCommand
|
||||
{
|
||||
|
||||
private Random rng;
|
||||
public PlantPick(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<ulong, DateTime> plantpickCooldowns = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.Message.IsAuthor)
|
||||
return;
|
||||
var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
var now = DateTime.Now;
|
||||
int cd;
|
||||
DateTime lastSpawned;
|
||||
if (config.GenerateCurrencyChannels.TryGetValue(e.Channel.Id, out cd))
|
||||
if (!plantpickCooldowns.TryGetValue(e.Channel.Id, out lastSpawned) || (lastSpawned + new TimeSpan(0, cd, 0)) < now)
|
||||
{
|
||||
var rnd = Math.Abs(rng.Next(0,101));
|
||||
if (rnd == 0)
|
||||
{
|
||||
var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`") };
|
||||
plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msgs, (u, m) => { m.ForEach(async msgToDelete => { try { await msgToDelete.Delete(); } catch { } }); return msgs; });
|
||||
plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
//channelid/messageid pair
|
||||
ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>();
|
||||
|
||||
private SemaphoreSlim locker = new SemaphoreSlim(1,1);
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "pick")
|
||||
.Description($"Picks a flower planted in this channel. | `{Prefix}pick`")
|
||||
.Do(async e =>
|
||||
{
|
||||
IEnumerable<Message> msgs;
|
||||
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msgs))
|
||||
return;
|
||||
|
||||
foreach(var msgToDelete in msgs)
|
||||
await msgToDelete.Delete().ConfigureAwait(false);
|
||||
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false);
|
||||
var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false);
|
||||
ThreadPool.QueueUserWorkItem(async (state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
await msg.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "plant")
|
||||
.Description($"Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost) | `{Prefix}plant`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await locker.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
|
||||
{
|
||||
await e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var removed = await FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).ConfigureAwait(false);
|
||||
if (!removed)
|
||||
{
|
||||
await e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var file = GetRandomCurrencyImagePath();
|
||||
Message msg;
|
||||
if (file == null)
|
||||
msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false);
|
||||
else
|
||||
msg = await e.Channel.SendFile(file).ConfigureAwait(false);
|
||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
|
||||
var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false);
|
||||
plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
|
||||
}
|
||||
finally { locker.Release(); }
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "gencurrency")
|
||||
.Alias(Prefix + "gc")
|
||||
.Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `{Prefix}gc` or `{Prefix}gc 60`")
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Parameter("cd", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var cdStr = e.GetArg("cd");
|
||||
int cd = 2;
|
||||
if (!int.TryParse(cdStr, out cd) || cd < 0)
|
||||
{
|
||||
cd = 2;
|
||||
}
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
int throwaway;
|
||||
if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
|
||||
{
|
||||
await e.Channel.SendMessage("`Currency generation disabled on this channel.`").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
|
||||
await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private string GetRandomCurrencyImagePath() =>
|
||||
Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
|
||||
|
||||
int GetRandomNumber()
|
||||
{
|
||||
using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
|
||||
{
|
||||
byte[] rno = new byte[4];
|
||||
rg.GetBytes(rno);
|
||||
int randomvalue = BitConverter.ToInt32(rno, 0);
|
||||
return randomvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
internal class PollCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public static ConcurrentDictionary<Server, Poll> ActivePolls = new ConcurrentDictionary<Server, Poll>();
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "poll")
|
||||
.Description($"Creates a poll, only person who has manage server permission can do it. **Needs Manage Server Permissions**| `{Prefix}poll Question?;Answer1;Answ 2;A_3`")
|
||||
.Parameter("allargs", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageChannels)
|
||||
return;
|
||||
if (ActivePolls.ContainsKey(e.Server))
|
||||
return;
|
||||
var arg = e.GetArg("allargs");
|
||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
||||
return;
|
||||
var data = arg.Split(';');
|
||||
if (data.Length < 3)
|
||||
return;
|
||||
|
||||
var poll = new Poll(e, data[0], data.Skip(1));
|
||||
if (PollCommand.ActivePolls.TryAdd(e.Server, poll))
|
||||
{
|
||||
await poll.StartPoll().ConfigureAwait(false);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Module.Prefix + "pollend")
|
||||
.Description($"Stops active poll on this server and prints the results in this channel. | `{Prefix}pollend`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageChannels)
|
||||
return;
|
||||
if (!ActivePolls.ContainsKey(e.Server))
|
||||
return;
|
||||
await ActivePolls[e.Server].StopPoll(e.Channel).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
public PollCommand(DiscordModule module) : base(module) { }
|
||||
}
|
||||
|
||||
internal class Poll
|
||||
{
|
||||
private readonly CommandEventArgs e;
|
||||
private readonly string[] answers;
|
||||
private ConcurrentDictionary<User, int> participants = new ConcurrentDictionary<User, int>();
|
||||
private readonly string question;
|
||||
private DateTime started;
|
||||
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
|
||||
|
||||
public Poll(CommandEventArgs e, string question, IEnumerable<string> enumerable)
|
||||
{
|
||||
this.e = e;
|
||||
this.question = question;
|
||||
this.answers = enumerable as string[] ?? enumerable.ToArray();
|
||||
}
|
||||
|
||||
public async Task StartPoll()
|
||||
{
|
||||
started = DateTime.Now;
|
||||
NadekoBot.Client.MessageReceived += Vote;
|
||||
var msgToSend =
|
||||
$"📃**{e.User.Name}** from **{e.Server.Name}** server has created a poll which requires your attention:\n\n" +
|
||||
$"**{question}**\n";
|
||||
var num = 1;
|
||||
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
||||
await e.Channel.SendMessage(msgToSend).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task StopPoll(Channel ch)
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= Vote;
|
||||
Poll throwaway;
|
||||
PollCommand.ActivePolls.TryRemove(e.Server, out throwaway);
|
||||
try
|
||||
{
|
||||
var results = participants.GroupBy(kvp => kvp.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||
.OrderBy(kvp => kvp.Value);
|
||||
|
||||
var totalVotesCast = results.Sum(kvp => kvp.Value);
|
||||
if (totalVotesCast == 0)
|
||||
{
|
||||
await ch.SendMessage("📄 **No votes have been cast.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
|
||||
$"📄 , here are the results:\n";
|
||||
closeMessage = results.Aggregate(closeMessage, (current, kvp) => current + $"`{kvp.Key}.` **[{answers[kvp.Key - 1]}]**" +
|
||||
$" has {kvp.Value} votes." +
|
||||
$"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
|
||||
|
||||
await ch.SendMessage($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error in poll game {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void Vote(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!e.Channel.IsPrivate)
|
||||
return;
|
||||
if (participants.ContainsKey(e.User))
|
||||
return;
|
||||
|
||||
int vote;
|
||||
if (!int.TryParse(e.Message.Text, out vote)) return;
|
||||
if (vote < 1 || vote > answers.Length)
|
||||
return;
|
||||
if (participants.TryAdd(e.User, vote))
|
||||
{
|
||||
await e.User.SendMessage($"Thanks for voting **{e.User.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
|
||||
public static class SentencesProvider
|
||||
{
|
||||
internal static string GetRandomSentence()
|
||||
{
|
||||
var data = DbHandler.Instance.GetAllRows<TypingArticle>();
|
||||
try
|
||||
{
|
||||
return data.ToList()[new Random().Next(0, data.Count())].Text;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Failed retrieving data from parse. Owner didn't add any articles to type using `typeadd`.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TypingGame
|
||||
{
|
||||
public const float WORD_VALUE = 4.5f;
|
||||
private readonly Channel channel;
|
||||
public string CurrentSentence;
|
||||
public bool IsActive;
|
||||
private readonly Stopwatch sw;
|
||||
private readonly List<ulong> finishedUserIds;
|
||||
|
||||
public TypingGame(Channel channel)
|
||||
{
|
||||
this.channel = channel;
|
||||
IsActive = false;
|
||||
sw = new Stopwatch();
|
||||
finishedUserIds = new List<ulong>();
|
||||
}
|
||||
|
||||
public Channel Channell { get; internal set; }
|
||||
|
||||
internal async Task<bool> Stop()
|
||||
{
|
||||
if (!IsActive) return false;
|
||||
NadekoBot.Client.MessageReceived -= AnswerReceived;
|
||||
finishedUserIds.Clear();
|
||||
IsActive = false;
|
||||
sw.Stop();
|
||||
sw.Reset();
|
||||
await channel.Send("Typing contest stopped").ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task Start()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (IsActive) return; // can't start running game
|
||||
IsActive = true;
|
||||
CurrentSentence = SentencesProvider.GetRandomSentence();
|
||||
var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f);
|
||||
await channel.SendMessage($":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.").ConfigureAwait(false);
|
||||
|
||||
|
||||
var msg = await channel.SendMessage("Starting new typing contest in **3**...").ConfigureAwait(false);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
await msg.Edit("Starting new typing contest in **2**...").ConfigureAwait(false);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
await msg.Edit("Starting new typing contest in **1**...").ConfigureAwait(false);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
await msg.Edit($":book:**{CurrentSentence.Replace(" ", " \x200B")}**:book:").ConfigureAwait(false);
|
||||
sw.Start();
|
||||
HandleAnswers();
|
||||
|
||||
while (i > 0)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
i--;
|
||||
if (!IsActive)
|
||||
return;
|
||||
}
|
||||
|
||||
await Stop().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAnswers()
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += AnswerReceived;
|
||||
}
|
||||
|
||||
private async void AnswerReceived(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel == null || e.Channel.Id != channel.Id || e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
|
||||
var guess = e.Message.RawText;
|
||||
|
||||
var distance = CurrentSentence.LevenshteinDistance(guess);
|
||||
var decision = Judge(distance, guess.Length);
|
||||
if (decision && !finishedUserIds.Contains(e.User.Id))
|
||||
{
|
||||
finishedUserIds.Add(e.User.Id);
|
||||
await channel.Send($"{e.User.Mention} finished in **{sw.Elapsed.Seconds}** seconds with { distance } errors, **{ CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60 }** WPM!").ConfigureAwait(false);
|
||||
if (finishedUserIds.Count % 2 == 0)
|
||||
{
|
||||
await e.Channel.SendMessage($":exclamation: `A lot of people finished, here is the text for those still typing:`\n\n:book:**{CurrentSentence}**:book:").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private bool Judge(int errors, int textLength) => errors <= textLength / 25;
|
||||
|
||||
}
|
||||
|
||||
internal class SpeedTyping : DiscordCommand
|
||||
{
|
||||
|
||||
public static ConcurrentDictionary<ulong, TypingGame> RunningContests;
|
||||
|
||||
public SpeedTyping(DiscordModule module) : base(module)
|
||||
{
|
||||
RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
||||
}
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc() =>
|
||||
async e =>
|
||||
{
|
||||
var game = RunningContests.GetOrAdd(e.User.Server.Id, id => new TypingGame(e.Channel));
|
||||
|
||||
if (game.IsActive)
|
||||
{
|
||||
await e.Channel.SendMessage(
|
||||
$"Contest already running in " +
|
||||
$"{game.Channell.Mention} channel.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await game.Start().ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
|
||||
private Func<CommandEventArgs, Task> QuitFunc() =>
|
||||
async e =>
|
||||
{
|
||||
TypingGame game;
|
||||
if (RunningContests.TryRemove(e.User.Server.Id, out game))
|
||||
{
|
||||
await game.Stop().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage("No contest to stop on this channel.").ConfigureAwait(false);
|
||||
};
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "typestart")
|
||||
.Description($"Starts a typing contest. | `{Prefix}typestart`")
|
||||
.Do(DoFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "typestop")
|
||||
.Description($"Stops a typing contest on the current channel. | `{Prefix}typestop`")
|
||||
.Do(QuitFunc());
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "typeadd")
|
||||
.Description($"Adds a new article to the typing contest. Owner only. | `{Prefix}typeadd wordswords`")
|
||||
.Parameter("text", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id) || string.IsNullOrWhiteSpace(e.GetArg("text"))) return;
|
||||
|
||||
DbHandler.Instance.Connection.Insert(new TypingArticle
|
||||
{
|
||||
Text = e.GetArg("text"),
|
||||
DateAdded = DateTime.Now
|
||||
});
|
||||
|
||||
await e.Channel.SendMessage("Added new article for typing game.").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands.Trivia
|
||||
{
|
||||
internal class TriviaGame
|
||||
{
|
||||
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1);
|
||||
|
||||
private Server server { get; }
|
||||
private Channel channel { get; }
|
||||
|
||||
private int QuestionDurationMiliseconds { get; } = 30000;
|
||||
private int HintTimeoutMiliseconds { get; } = 6000;
|
||||
public bool ShowHints { get; set; } = true;
|
||||
private CancellationTokenSource triviaCancelSource { get; set; }
|
||||
|
||||
public TriviaQuestion CurrentQuestion { get; private set; }
|
||||
public HashSet<TriviaQuestion> oldQuestions { get; } = new HashSet<TriviaQuestion>();
|
||||
|
||||
public ConcurrentDictionary<User, int> Users { get; } = new ConcurrentDictionary<User, int>();
|
||||
|
||||
public bool GameActive { get; private set; } = false;
|
||||
public bool ShouldStopGame { get; private set; }
|
||||
|
||||
public int WinRequirement { get; } = 10;
|
||||
|
||||
public TriviaGame(CommandEventArgs e, bool showHints, int winReq = 10)
|
||||
{
|
||||
ShowHints = showHints;
|
||||
server = e.Server;
|
||||
channel = e.Channel;
|
||||
WinRequirement = winReq;
|
||||
Task.Run(StartGame);
|
||||
}
|
||||
|
||||
private async Task StartGame()
|
||||
{
|
||||
while (!ShouldStopGame)
|
||||
{
|
||||
// reset the cancellation source
|
||||
triviaCancelSource = new CancellationTokenSource();
|
||||
var token = triviaCancelSource.Token;
|
||||
// load question
|
||||
CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions);
|
||||
if (CurrentQuestion == null)
|
||||
{
|
||||
await channel.SendMessage($":exclamation: Failed loading a trivia question").ConfigureAwait(false);
|
||||
await End().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
oldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again
|
||||
//sendquestion
|
||||
await channel.SendMessage($":question: **{CurrentQuestion.Question}**").ConfigureAwait(false);
|
||||
|
||||
//receive messages
|
||||
NadekoBot.Client.MessageReceived += PotentialGuess;
|
||||
|
||||
//allow people to guess
|
||||
GameActive = true;
|
||||
|
||||
try
|
||||
{
|
||||
//hint
|
||||
await Task.Delay(HintTimeoutMiliseconds, token).ConfigureAwait(false);
|
||||
if (ShowHints)
|
||||
await channel.SendMessage($":exclamation:**Hint:** {CurrentQuestion.GetHint()}").ConfigureAwait(false);
|
||||
|
||||
//timeout
|
||||
await Task.Delay(QuestionDurationMiliseconds - HintTimeoutMiliseconds, token).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (TaskCanceledException) { } //means someone guessed the answer
|
||||
GameActive = false;
|
||||
if (!triviaCancelSource.IsCancellationRequested)
|
||||
await channel.Send($":clock2: :question: **Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false);
|
||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
||||
// load next question if game is still running
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
}
|
||||
await End().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task End()
|
||||
{
|
||||
ShouldStopGame = true;
|
||||
await channel.SendMessage("**Trivia game ended**\n" + GetLeaderboard()).ConfigureAwait(false);
|
||||
TriviaGame throwAwayValue;
|
||||
TriviaCommands.RunningTrivias.TryRemove(server.Id, out throwAwayValue);
|
||||
}
|
||||
|
||||
public async Task StopGame()
|
||||
{
|
||||
if (!ShouldStopGame)
|
||||
await channel.SendMessage(":exclamation: Trivia will stop after this question.").ConfigureAwait(false);
|
||||
ShouldStopGame = true;
|
||||
}
|
||||
|
||||
private async void PotentialGuess(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel.IsPrivate) return;
|
||||
if (e.Server != server) return;
|
||||
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
|
||||
var guess = false;
|
||||
await _guessLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested)
|
||||
{
|
||||
Users.TryAdd(e.User, 0); //add if not exists
|
||||
Users[e.User]++; //add 1 point to the winner
|
||||
guess = true;
|
||||
}
|
||||
}
|
||||
finally { _guessLock.Release(); }
|
||||
if (!guess) return;
|
||||
triviaCancelSource.Cancel();
|
||||
await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
|
||||
if (Users[e.User] != WinRequirement) return;
|
||||
ShouldStopGame = true;
|
||||
await channel.Send($":exclamation: We have a winner! It's {e.User.Mention}.").ConfigureAwait(false);
|
||||
// add points to the winner
|
||||
await FlowersHandler.AddFlowersAsync(e.User, "Won Trivia", 2).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public string GetLeaderboard()
|
||||
{
|
||||
if (Users.Count == 0)
|
||||
return "";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("**Leaderboard:**\n-----------\n");
|
||||
|
||||
foreach (var kvp in Users.OrderBy(kvp => kvp.Value))
|
||||
{
|
||||
sb.AppendLine($"**{kvp.Key.Name}** has {kvp.Value} points".ToString().SnPl(kvp.Value));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Games.Commands.Trivia;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
{
|
||||
internal class TriviaCommands : DiscordCommand
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||
|
||||
public TriviaCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "t")
|
||||
.Description($"Starts a game of trivia. You can add nohint to prevent hints." +
|
||||
"First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question." +
|
||||
$" |`{Module.Prefix}t nohint` or `{Module.Prefix}t 5 nohint`")
|
||||
.Parameter("args", ParameterType.Multiple)
|
||||
.Do(async e =>
|
||||
{
|
||||
TriviaGame trivia;
|
||||
if (!RunningTrivias.TryGetValue(e.Server.Id, out trivia))
|
||||
{
|
||||
var showHints = !e.Args.Contains("nohint");
|
||||
var number = e.Args.Select(s =>
|
||||
{
|
||||
int num;
|
||||
return new Tuple<bool, int>(int.TryParse(s, out num), num);
|
||||
}).Where(t => t.Item1).Select(t => t.Item2).FirstOrDefault();
|
||||
if (number < 3)
|
||||
{
|
||||
await e.Channel.SendMessage("Number too small.");
|
||||
return;
|
||||
}
|
||||
var triviaGame = new TriviaGame(e, showHints, number == 0 ? 10 : number);
|
||||
if (RunningTrivias.TryAdd(e.Server.Id, triviaGame))
|
||||
await e.Channel.SendMessage($"**Trivia game started! {triviaGame.WinRequirement} points needed to win.**").ConfigureAwait(false);
|
||||
else
|
||||
await triviaGame.StopGame().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "tl")
|
||||
.Description($"Shows a current trivia leaderboard. | `{Prefix}tl`")
|
||||
.Do(async e =>
|
||||
{
|
||||
TriviaGame trivia;
|
||||
if (RunningTrivias.TryGetValue(e.Server.Id, out trivia))
|
||||
await e.Channel.SendMessage(trivia.GetLeaderboard()).ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("No trivia is running on this server.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "tq")
|
||||
.Description($"Quits current trivia after current question. | `{Prefix}tq`")
|
||||
.Do(async e =>
|
||||
{
|
||||
TriviaGame trivia;
|
||||
if (RunningTrivias.TryGetValue(e.Server.Id, out trivia))
|
||||
{
|
||||
await trivia.StopGame().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage("No trivia is running on this server.").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Games.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Games
|
||||
{
|
||||
internal class GamesModule : DiscordModule
|
||||
{
|
||||
private readonly Random rng = new Random();
|
||||
|
||||
public GamesModule()
|
||||
{
|
||||
commands.Add(new TriviaCommands(this));
|
||||
commands.Add(new SpeedTyping(this));
|
||||
commands.Add(new PollCommand(this));
|
||||
commands.Add(new PlantPick(this));
|
||||
commands.Add(new Bomberman(this));
|
||||
commands.Add(new Leet(this));
|
||||
//commands.Add(new BetrayGame(this));
|
||||
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Games;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "choose")
|
||||
.Description($"Chooses a thing from a list of things | `{Prefix}choose Get up;Sleep;Sleep more`")
|
||||
.Parameter("list", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("list");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
var list = arg.Split(';');
|
||||
if (list.Count() < 2)
|
||||
return;
|
||||
await e.Channel.SendMessage(list[rng.Next(0, list.Length)]).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "8ball")
|
||||
.Description($"Ask the 8ball a yes/no question. | `{Prefix}8ball should i do something`")
|
||||
.Parameter("question", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var question = e.GetArg("question");
|
||||
if (string.IsNullOrWhiteSpace(question))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await e.Channel.SendMessage(
|
||||
$":question: `Question` __**{question}**__ \n🎱 `8Ball Answers` __**{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}**__")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rps")
|
||||
.Description($"Play a game of rocket paperclip scissors with Nadeko. | `{Prefix}rps scissors`")
|
||||
.Parameter("input", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var input = e.GetArg("input").Trim();
|
||||
int pick;
|
||||
switch (input)
|
||||
{
|
||||
case "r":
|
||||
case "rock":
|
||||
case "rocket":
|
||||
pick = 0;
|
||||
break;
|
||||
case "p":
|
||||
case "paper":
|
||||
case "paperclip":
|
||||
pick = 1;
|
||||
break;
|
||||
case "scissors":
|
||||
case "s":
|
||||
pick = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
var nadekoPick = new Random().Next(0, 3);
|
||||
var msg = "";
|
||||
if (pick == nadekoPick)
|
||||
msg = $"It's a draw! Both picked :{GetRPSPick(pick)}:";
|
||||
else if ((pick == 0 && nadekoPick == 1) ||
|
||||
(pick == 1 && nadekoPick == 2) ||
|
||||
(pick == 2 && nadekoPick == 0))
|
||||
msg = $"{NadekoBot.BotMention} won! :{GetRPSPick(nadekoPick)}: beats :{GetRPSPick(pick)}:";
|
||||
else
|
||||
msg = $"{e.User.Mention} won! :{GetRPSPick(pick)}: beats :{GetRPSPick(nadekoPick)}:";
|
||||
|
||||
await e.Channel.SendMessage(msg).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "linux")
|
||||
.Description($"Prints a customizable Linux interjection | `{Prefix}linux Spyware Windows`")
|
||||
.Parameter("gnu", ParameterType.Required)
|
||||
.Parameter("linux", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var guhnoo = e.Args[0];
|
||||
var loonix = e.Args[1];
|
||||
|
||||
await e.Channel.SendMessage(
|
||||
$@"
|
||||
I'd just like to interject for moment. What you're refering to as {loonix}, is in fact, {guhnoo}/{loonix}, or as I've recently taken to calling it, {guhnoo} plus {loonix}. {loonix} is not an operating system unto itself, but rather another free component of a fully functioning {guhnoo} system made useful by the {guhnoo} corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
|
||||
|
||||
Many computer users run a modified version of the {guhnoo} system every day, without realizing it. Through a peculiar turn of events, the version of {guhnoo} which is widely used today is often called {loonix}, and many of its users are not aware that it is basically the {guhnoo} system, developed by the {guhnoo} Project.
|
||||
|
||||
There really is a {loonix}, and these people are using it, but it is just a part of the system they use. {loonix} is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. {loonix} is normally used in combination with the {guhnoo} operating system: the whole system is basically {guhnoo} with {loonix} added, or {guhnoo}/{loonix}. All the so-called {loonix} distributions are really distributions of {guhnoo}/{loonix}.
|
||||
").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private string GetRPSPick(int i)
|
||||
{
|
||||
if (i == 0)
|
||||
return "rocket";
|
||||
else if (i == 1)
|
||||
return "paperclip";
|
||||
else
|
||||
return "scissors";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
//
|
||||
// _oo0oo_
|
||||
// o8888888o
|
||||
// 88" . "88
|
||||
// (| -_- |)
|
||||
// 0\ = /0
|
||||
// ___/`---'\___
|
||||
// .' \\| |// '.
|
||||
// / \\||| : |||// \
|
||||
// / _||||| -:- |||||- \
|
||||
// | | \\\ - /// | |
|
||||
// | \_| ''\---/'' |_/ |
|
||||
// \ .-\__ '-' ___/-. /
|
||||
// ___'. .' /--.--\ `. .'___
|
||||
// ."" '< `.___\_<|>_/___.' >' "".
|
||||
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
||||
// \ \ `_. \_ __\ /__ _/ .-` / /
|
||||
// =====`-.____`.___ \_____/___.-`___.-'=====
|
||||
// `=---='
|
||||
//
|
||||
//
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// 佛祖保佑 永无BUG
|
||||
//
|
||||
//
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes.Help.Commands
|
||||
{
|
||||
internal class HelpCommand : DiscordCommand
|
||||
{
|
||||
public Func<CommandEventArgs, Task> HelpFunc() => async e =>
|
||||
{
|
||||
var comToFind = e.GetArg("command")?.ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(comToFind))
|
||||
{
|
||||
await e.User.Send(HelpString).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var com = NadekoBot.Client.GetService<CommandService>().AllCommands
|
||||
.FirstOrDefault(c => c.Text.ToLowerInvariant().Equals(comToFind) ||
|
||||
c.Aliases.Select(a => a.ToLowerInvariant()).Contains(comToFind));
|
||||
|
||||
var str = "";
|
||||
var alias = com.Aliases.FirstOrDefault();
|
||||
if (alias != null)
|
||||
str = $" / `{ com.Aliases.FirstOrDefault()}`";
|
||||
if (com != null)
|
||||
await e.Channel.SendMessage($@"**__Help for:__ `{com.Text}`**" + str + $"\n**Desc:** {new Regex(@"\|").Replace(com.Description, "\n**Usage:**", 1)}").ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
};
|
||||
public static string HelpString {
|
||||
get {
|
||||
var str = !string.IsNullOrWhiteSpace(NadekoBot.Creds.ClientId) && !NadekoBot.Config.DontJoinServers
|
||||
? String.Format("To add me to your server, use this link -> <https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303>\n", NadekoBot.Creds.ClientId)
|
||||
: "";
|
||||
return str + String.Format(NadekoBot.Config.HelpString, NadekoBot.Config.CommandPrefixes.Help);
|
||||
}
|
||||
}
|
||||
|
||||
public static string DMHelpString => NadekoBot.Config.DMHelpString;
|
||||
|
||||
public Action<CommandEventArgs> DoGitFunc() => e =>
|
||||
{
|
||||
var helpstr = new StringBuilder();
|
||||
|
||||
var lastCategory = "";
|
||||
foreach (var com in NadekoBot.Client.GetService<CommandService>().AllCommands)
|
||||
{
|
||||
if (com.Category != lastCategory)
|
||||
{
|
||||
helpstr.AppendLine("\n### " + com.Category + " ");
|
||||
helpstr.AppendLine("Command and aliases | Description | Usage");
|
||||
helpstr.AppendLine("----------------|--------------|-------");
|
||||
lastCategory = com.Category;
|
||||
}
|
||||
helpstr.AppendLine($"`{com.Text}`{string.Concat(com.Aliases.Select(a => $", `{a}`"))} | {com.Description}");
|
||||
}
|
||||
helpstr = helpstr.Replace(NadekoBot.BotMention, "@BotName");
|
||||
#if DEBUG
|
||||
File.WriteAllText("../../../docs/Commands List.md", helpstr.ToString());
|
||||
#else
|
||||
File.WriteAllText("commandlist.md", helpstr.ToString());
|
||||
#endif
|
||||
};
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "h")
|
||||
.Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h")
|
||||
.Description($"Either shows a help for a single command, or PMs you help link if no arguments are specified. | `{Prefix}h !m q` or just `{Prefix}h` ")
|
||||
.Parameter("command", ParameterType.Unparsed)
|
||||
.Do(HelpFunc());
|
||||
cgb.CreateCommand(Module.Prefix + "hgit")
|
||||
.Description($"Generates the commandlist.md file. **Bot Owner Only!** | `{Prefix}hgit`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(DoGitFunc());
|
||||
cgb.CreateCommand(Module.Prefix + "readme")
|
||||
.Alias(Module.Prefix + "guide")
|
||||
.Description($"Sends a readme and a guide links to the channel. | `{Prefix}readme` or `{Prefix}guide`")
|
||||
.Do(async e =>
|
||||
await e.Channel.SendMessage(
|
||||
@"**LIST OF COMMANDS**: <http://nadekobot.readthedocs.io/en/latest/Commands%20List/>
|
||||
**Hosting Guides and docs can be found here**: <http://nadekobot.rtfd.io>").ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "donate")
|
||||
.Alias("~donate")
|
||||
.Description($"Instructions for helping the project! | `{Prefix}donate` or `~donate`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage(
|
||||
$@"You can support the project on patreon. <https://patreon.com/nadekobot> or
|
||||
You can send donations to `nadekodiscordbot@gmail.com`
|
||||
Don't forget to leave your discord name or id in the message.
|
||||
|
||||
**Thank you** ♥️").ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private static string PrintCommandHelp(Command com)
|
||||
{
|
||||
var str = "`" + com.Text + "`";
|
||||
str = com.Aliases.Aggregate(str, (current, a) => current + (", `" + a + "`"));
|
||||
str += " **Description:** " + com.Description + "\n";
|
||||
return str;
|
||||
}
|
||||
|
||||
public HelpCommand(DiscordModule module) : base(module) { }
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.Help.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Help
|
||||
{
|
||||
internal class HelpModule : DiscordModule
|
||||
{
|
||||
|
||||
public HelpModule()
|
||||
{
|
||||
commands.Add(new HelpCommand(this));
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Help;
|
||||
|
||||
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
commands.ForEach(com => com.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "modules")
|
||||
.Alias(".modules")
|
||||
.Description($"List all bot modules. | `{Prefix}modules` or `.modules`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage("`List of modules:` \n• " + string.Join("\n• ", NadekoBot.Client.GetService<ModuleService>().Modules.Select(m => m.Name)) + $"\n`Type \"{Prefix}commands module_name\" to get a list of commands in that module.`")
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "commands")
|
||||
.Alias(".commands")
|
||||
.Description($"List all of the bot's commands from a certain module. | `{Prefix}commands` or `.commands`")
|
||||
.Parameter("module", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var module = e.GetArg("module")?.Trim().ToLower();
|
||||
if (string.IsNullOrWhiteSpace(module))
|
||||
return;
|
||||
var cmds = NadekoBot.Client.GetService<CommandService>().AllCommands
|
||||
.Where(c => c.Category.ToLower() == module)
|
||||
.OrderBy(c=>c.Text)
|
||||
.AsEnumerable();
|
||||
var cmdsArray = cmds as Command[] ?? cmds.ToArray();
|
||||
if (!cmdsArray.Any())
|
||||
{
|
||||
await e.Channel.SendMessage("That module does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (module != "customreactions" && module != "conversations")
|
||||
{
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n" + SearchHelper.ShowInPrettyCode<Command>(cmdsArray,
|
||||
el => $"{el.Text,-15}{"[" + el.Aliases.FirstOrDefault() + "]",-8}"))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Text}")));
|
||||
}
|
||||
await e.Channel.SendMessage($"`You can type \"{Prefix}h command_name\" to see the help about that specific command.`").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 💩
|
||||
/// </summary>
|
||||
public class PoopyBuffer
|
||||
{
|
||||
|
||||
private readonly byte[] ringBuffer;
|
||||
|
||||
public int WritePosition { get; private set; } = 0;
|
||||
public int ReadPosition { get; private set; } = 0;
|
||||
|
||||
public int ContentLength => (WritePosition >= ReadPosition ?
|
||||
WritePosition - ReadPosition :
|
||||
(BufferSize - ReadPosition) + WritePosition);
|
||||
|
||||
public int BufferSize { get; }
|
||||
|
||||
private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public PoopyBuffer(int size)
|
||||
{
|
||||
if (size <= 0)
|
||||
throw new ArgumentException();
|
||||
BufferSize = size;
|
||||
ringBuffer = new byte[size];
|
||||
}
|
||||
|
||||
public Task<int> ReadAsync(byte[] buffer, int count)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (buffer.Length < count)
|
||||
throw new ArgumentException();
|
||||
//Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
|
||||
await readWriteLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
//read as much as you can if you're reading too much
|
||||
if (count > ContentLength)
|
||||
count = ContentLength;
|
||||
//if nothing to read, return 0
|
||||
if (WritePosition == ReadPosition)
|
||||
return 0;
|
||||
// if buffer is in the "normal" state, just read
|
||||
if (WritePosition > ReadPosition)
|
||||
{
|
||||
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
|
||||
ReadPosition += count;
|
||||
//Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]");
|
||||
return count;
|
||||
}
|
||||
//else ReadPos <Writepos
|
||||
// buffer is in its inverted state
|
||||
// A: if i can read as much as possible without hitting the buffer.length, read that
|
||||
|
||||
if (count + ReadPosition <= BufferSize)
|
||||
{
|
||||
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
|
||||
ReadPosition += count;
|
||||
//Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]");
|
||||
return count;
|
||||
}
|
||||
// B: if i can't read as much, read to the end,
|
||||
var readNormaly = BufferSize - ReadPosition;
|
||||
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly);
|
||||
|
||||
//Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]");
|
||||
//then read the remaining amount from the start
|
||||
|
||||
var readFromStart = count - readNormaly;
|
||||
Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart);
|
||||
//Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]");
|
||||
ReadPosition = readFromStart;
|
||||
return count;
|
||||
}
|
||||
finally { readWriteLock.Release(); }
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken)
|
||||
{
|
||||
if (count > buffer.Length)
|
||||
throw new ArgumentException();
|
||||
while (ContentLength + count > BufferSize)
|
||||
{
|
||||
await Task.Delay(20, cancelToken).ConfigureAwait(false);
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
}
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
//the while above assures that i cannot write past readposition with my write, so i don't have to check
|
||||
// *unless its multithreaded or task is not awaited
|
||||
await readWriteLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
// if i can just write without hitting buffer.length, do it
|
||||
if (WritePosition + count < BufferSize)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count);
|
||||
WritePosition += count;
|
||||
//Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]");
|
||||
return;
|
||||
}
|
||||
// otherwise, i have to write to the end, then write the rest from the start
|
||||
|
||||
var wroteNormaly = BufferSize - WritePosition;
|
||||
Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly);
|
||||
|
||||
//Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]");
|
||||
|
||||
var wroteFromStart = count - wroteNormaly;
|
||||
Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart);
|
||||
|
||||
//Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}");
|
||||
|
||||
WritePosition = wroteFromStart;
|
||||
}
|
||||
finally { readWriteLock.Release(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,900 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music
|
||||
{
|
||||
internal class MusicModule : DiscordModule
|
||||
{
|
||||
public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
|
||||
|
||||
public const string MusicDataPath = "data/musicdata";
|
||||
|
||||
public MusicModule()
|
||||
{
|
||||
//it can fail if its currenctly opened or doesn't exist. Either way i don't care
|
||||
try { Directory.Delete(MusicDataPath, true); } catch { }
|
||||
|
||||
Directory.CreateDirectory(MusicDataPath);
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
var client = NadekoBot.Client;
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "next")
|
||||
.Alias(Prefix + "n")
|
||||
.Alias(Prefix + "skip")
|
||||
.Description($"Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `{Prefix}n`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
|
||||
if (musicPlayer.PlaybackVoiceChannel == e.User.VoiceChannel)
|
||||
musicPlayer.Next();
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "stop")
|
||||
.Alias(Prefix + "s")
|
||||
.Description($"Stops the music and clears the playlist. Stays in the channel. | `{Prefix}s`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
{
|
||||
musicPlayer.Autoplay = false;
|
||||
musicPlayer.Stop();
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "destroy")
|
||||
.Alias(Prefix + "d")
|
||||
.Description("Completely stops the music and unbinds the bot from the channel. " +
|
||||
$"(may cause weird behaviour) | `{Prefix}d`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
musicPlayer.Destroy();
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "pause")
|
||||
.Alias(Prefix + "p")
|
||||
.Description($"Pauses or Unpauses the song. | `{Prefix}p`")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
musicPlayer.TogglePause();
|
||||
if (musicPlayer.Paused)
|
||||
await e.Channel.SendMessage("🎵`Music Player paused.`").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("🎵`Music Player unpaused.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "queue")
|
||||
.Alias(Prefix + "q")
|
||||
.Alias(Prefix + "yq")
|
||||
.Description("Queue a song using keywords or a link. Bot will join your voice channel." +
|
||||
$"**You must be in a voice channel**. | `{Prefix}q Dream Of Venice`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("query")).ConfigureAwait(false);
|
||||
if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "soundcloudqueue")
|
||||
.Alias(Prefix + "sq")
|
||||
.Description("Queue a soundcloud song using keywords. Bot will join your voice channel." +
|
||||
$"**You must be in a voice channel**. | `{Prefix}sq Dream Of Venice`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("query"), musicType: MusicType.Soundcloud).ConfigureAwait(false);
|
||||
if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "listqueue")
|
||||
.Alias(Prefix + "lq")
|
||||
.Description($"Lists 15 currently queued songs per page. Default page is 1. | `{Prefix}lq` or `{Prefix}lq 2`")
|
||||
.Parameter("page", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
{
|
||||
await e.Channel.SendMessage("🎵 No active music player.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int page;
|
||||
if (!int.TryParse(e.GetArg("page"), out page) || page <= 0)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
|
||||
var currentSong = musicPlayer.CurrentSong;
|
||||
if (currentSong == null)
|
||||
return;
|
||||
var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n";
|
||||
if (musicPlayer.RepeatSong)
|
||||
toSend += "🔂";
|
||||
else if (musicPlayer.RepeatPlaylist)
|
||||
toSend += "🔁";
|
||||
toSend += $" **{musicPlayer.Playlist.Count}** `tracks currently queued. Showing page {page}` ";
|
||||
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
|
||||
toSend += "**Song queue is full!**\n";
|
||||
else
|
||||
toSend += "\n";
|
||||
const int itemsPerPage = 15;
|
||||
int startAt = itemsPerPage * (page - 1);
|
||||
var number = 1 + startAt;
|
||||
await e.Channel.SendMessage(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "nowplaying")
|
||||
.Alias(Prefix + "np")
|
||||
.Description($"Shows the song currently playing. | `{Prefix}np`")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
var currentSong = musicPlayer.CurrentSong;
|
||||
if (currentSong == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
|
||||
$"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "volume")
|
||||
.Alias(Prefix + "vol")
|
||||
.Description($"Sets the music volume 0-100% | `{Prefix}vol 50`")
|
||||
.Parameter("val", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
var arg = e.GetArg("val");
|
||||
int volume;
|
||||
if (!int.TryParse(arg, out volume))
|
||||
{
|
||||
await e.Channel.SendMessage("Volume number invalid.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
volume = musicPlayer.SetVolume(volume);
|
||||
await e.Channel.SendMessage($"🎵 `Volume set to {volume}%`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "defvol")
|
||||
.Alias(Prefix + "dv")
|
||||
.Description("Sets the default music volume when music playback is started (0-100)." +
|
||||
$" Persists through restarts. | `{Prefix}dv 80`")
|
||||
.Parameter("val", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("val");
|
||||
float volume;
|
||||
if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100)
|
||||
{
|
||||
await e.Channel.SendMessage("Volume number invalid.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
conf.DefaultMusicVolume = volume / 100;
|
||||
await e.Channel.SendMessage($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "mute")
|
||||
.Alias(Prefix + "min")
|
||||
.Description($"Sets the music volume to 0% | `{Prefix}min`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
musicPlayer.SetVolume(0);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "max")
|
||||
.Description($"Sets the music volume to 100%. | `{Prefix}max`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
musicPlayer.SetVolume(100);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "half")
|
||||
.Description($"Sets the music volume to 50%. | `{Prefix}half`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
musicPlayer.SetVolume(50);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "shuffle")
|
||||
.Alias(Prefix + "sh")
|
||||
.Description($"Shuffles the current playlist. | `{Prefix}sh`")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
if (musicPlayer.Playlist.Count < 2)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
musicPlayer.Shuffle();
|
||||
await e.Channel.SendMessage("🎵 `Songs shuffled.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "playlist")
|
||||
.Alias(Prefix + "pl")
|
||||
.Description($"Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `{Prefix}pl playlist link or name`")
|
||||
.Parameter("playlist", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("playlist");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
if (e.User.VoiceChannel?.Server != e.Server)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var plId = await SearchHelper.GetPlaylistIdByKeyword(arg).ConfigureAwait(false);
|
||||
if (plId == null)
|
||||
{
|
||||
await e.Channel.SendMessage("No search results for that query.");
|
||||
return;
|
||||
}
|
||||
var ids = await SearchHelper.GetVideoIDs(plId, 500).ConfigureAwait(false);
|
||||
if (ids == null || ids.Count == 0)
|
||||
{
|
||||
await e.Channel.SendMessage($"🎵 `Failed to find any songs.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var idArray = ids as string[] ?? ids.ToArray();
|
||||
var count = idArray.Length;
|
||||
var msg =
|
||||
await e.Channel.SendMessage($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`").ConfigureAwait(false);
|
||||
foreach (var id in idArray)
|
||||
{
|
||||
try
|
||||
{
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, id, true).ConfigureAwait(false);
|
||||
}
|
||||
catch (PlaylistFullException)
|
||||
{ break; }
|
||||
catch { }
|
||||
}
|
||||
await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "soundcloudpl")
|
||||
.Alias(Prefix + "scpl")
|
||||
.Description($"Queue a soundcloud playlist using a link. | `{Prefix}scpl soundcloudseturl`")
|
||||
.Parameter("pl", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pl = e.GetArg("pl")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pl))
|
||||
return;
|
||||
|
||||
var scvids = JObject.Parse(await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Creds.SoundCloudClientID}").ConfigureAwait(false))["tracks"].ToObject<SoundCloudVideo[]>();
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false);
|
||||
|
||||
MusicPlayer mp;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out mp))
|
||||
return;
|
||||
|
||||
foreach (var svideo in scvids.Skip(1))
|
||||
{
|
||||
try
|
||||
{
|
||||
mp.AddSong(new Song(new Classes.SongInfo
|
||||
{
|
||||
Title = svideo.FullName,
|
||||
Provider = "SoundCloud",
|
||||
Uri = svideo.StreamLink,
|
||||
ProviderType = MusicType.Normal,
|
||||
Query = svideo.TrackLink,
|
||||
}), e.User.Name);
|
||||
}
|
||||
catch (PlaylistFullException) { break; }
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "localplaylst")
|
||||
.Alias(Prefix + "lopl")
|
||||
.Description($"Queues all songs from a directory. **Bot Owner Only!** | `{Prefix}lopl C:/music/classical`")
|
||||
.Parameter("directory", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("directory");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var fileEnum = new DirectoryInfo(arg).GetFiles()
|
||||
.Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
|
||||
foreach (var file in fileEnum)
|
||||
{
|
||||
try
|
||||
{
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
|
||||
}
|
||||
catch (PlaylistFullException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
await e.Channel.SendMessage("🎵 `Directory queue complete.`").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "radio").Alias(Prefix + "ra")
|
||||
.Description($"Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `{Prefix}ra radio link here`")
|
||||
.Parameter("radio_link", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (e.User.VoiceChannel?.Server != e.Server)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("radio_link"), musicType: MusicType.Radio).ConfigureAwait(false);
|
||||
if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
await e.Message.Delete().ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "local")
|
||||
.Alias(Prefix + "lo")
|
||||
.Description($"Queues a local file by specifying a full path. **Bot Owner Only!** | `{Prefix}lo C:/music/mysong.mp3`")
|
||||
.Parameter("path", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("path");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("path"), musicType: MusicType.Local).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "move")
|
||||
.Alias(Prefix + "mv")
|
||||
.Description($"Moves the bot to your voice channel. (works only if music is already playing) | `{Prefix}mv`")
|
||||
.Do(e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
var voiceChannel = e.User.VoiceChannel;
|
||||
if (voiceChannel == null || voiceChannel.Server != e.Server || !MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
musicPlayer.MoveToVoiceChannel(voiceChannel);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "remove")
|
||||
.Alias(Prefix + "rm")
|
||||
.Description($"Remove a song by its # in the queue, or 'all' to remove whole queue. | `{Prefix}rm 5`")
|
||||
.Parameter("num", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("num");
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
if (arg?.ToLower() == "all")
|
||||
{
|
||||
musicPlayer.ClearQueue();
|
||||
await e.Channel.SendMessage($"🎵`Queue cleared!`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
int num;
|
||||
if (!int.TryParse(arg, out num))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (num <= 0 || num > musicPlayer.Playlist.Count)
|
||||
return;
|
||||
var song = (musicPlayer.Playlist as List<Song>)?[num - 1];
|
||||
musicPlayer.RemoveSongAt(num - 1);
|
||||
await e.Channel.SendMessage($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
//var msRegex = new Regex(@"(?<n1>\d+)>(?<n2>\d+)", RegexOptions.Compiled);
|
||||
cgb.CreateCommand(Prefix + "movesong")
|
||||
.Alias(Prefix + "ms")
|
||||
.Description($"Moves a song from one position to another. | `{Prefix} ms 5>3`")
|
||||
.Parameter("fromto")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var fromto = e.GetArg("fromto").Trim();
|
||||
var fromtoArr = fromto.Split('>');
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
var playlist = musicPlayer.Playlist as List<Song> ?? musicPlayer.Playlist.ToList();
|
||||
|
||||
if (fromtoArr.Length != 2 || !int.TryParse(fromtoArr[0], out n1) ||
|
||||
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
|
||||
n1 > playlist.Count || n2 > playlist.Count)
|
||||
{
|
||||
await e.Channel.SendMessage("`Invalid input.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var s = playlist[n1 - 1];
|
||||
playlist.Insert(n2 - 1, s);
|
||||
var nn1 = n2 < n1 ? n1 : n1 - 1;
|
||||
playlist.RemoveAt(nn1);
|
||||
|
||||
await e.Channel.SendMessage($"🎵`Moved` {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "setmaxqueue")
|
||||
.Alias(Prefix + "smq")
|
||||
.Description($"Sets a maximum queue size. Supply 0 or no argument to have no limit. | `{Prefix}smq 50` or `{Prefix}smq`")
|
||||
.Parameter("size", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sizeStr = e.GetArg("size")?.Trim();
|
||||
uint size = 0;
|
||||
if (string.IsNullOrWhiteSpace(sizeStr) || !uint.TryParse(sizeStr, out size))
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
musicPlayer.MaxQueueSize = size;
|
||||
await e.Channel.SendMessage($"🎵 `Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}`");
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "cleanup")
|
||||
.Description($"Cleans up hanging voice connections. **Bot Owner Only!** | `{Prefix}cleanup`")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(e =>
|
||||
{
|
||||
foreach (var kvp in MusicPlayers)
|
||||
{
|
||||
var songs = kvp.Value.Playlist;
|
||||
var currentSong = kvp.Value.CurrentSong;
|
||||
if (songs.Count == 0 && currentSong == null)
|
||||
{
|
||||
MusicPlayer throwaway;
|
||||
MusicPlayers.TryRemove(kvp.Key, out throwaway);
|
||||
throwaway.Destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "reptcursong")
|
||||
.Alias(Prefix + "rcs")
|
||||
.Description($"Toggles repeat of current song. | `{Prefix}rcs`")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
var currentSong = musicPlayer.CurrentSong;
|
||||
if (currentSong == null)
|
||||
return;
|
||||
var currentValue = musicPlayer.ToggleRepeatSong();
|
||||
await e.Channel.SendMessage(currentValue ?
|
||||
$"🎵🔂`Repeating track:`{currentSong.PrettyName}" :
|
||||
$"🎵🔂`Current track repeat stopped.`")
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rpeatplaylst")
|
||||
.Alias(Prefix + "rpl")
|
||||
.Description($"Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `{Prefix}rpl`")
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
||||
await e.Channel.SendMessage($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "save")
|
||||
.Description($"Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `{Prefix}save classical1`")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name) ||
|
||||
name.Length > 20 ||
|
||||
name.Contains("-"))
|
||||
return;
|
||||
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
|
||||
//to avoid concurrency issues
|
||||
var currentPlaylist = new List<Song>(musicPlayer.Playlist);
|
||||
var curSong = musicPlayer.CurrentSong;
|
||||
if (curSong != null)
|
||||
currentPlaylist.Insert(0, curSong);
|
||||
|
||||
if (!currentPlaylist.Any())
|
||||
return;
|
||||
|
||||
|
||||
var songInfos = currentPlaylist.Select(s => new DataModels.SongInfo
|
||||
{
|
||||
Provider = s.SongInfo.Provider,
|
||||
ProviderType = (int)s.SongInfo.ProviderType,
|
||||
Title = s.SongInfo.Title,
|
||||
Uri = s.SongInfo.Uri,
|
||||
Query = s.SongInfo.Query,
|
||||
}).ToList();
|
||||
|
||||
var playlist = new MusicPlaylist
|
||||
{
|
||||
CreatorId = (long)e.User.Id,
|
||||
CreatorName = e.User.Name,
|
||||
Name = name.ToLowerInvariant(),
|
||||
};
|
||||
DbHandler.Instance.SaveAll(songInfos);
|
||||
DbHandler.Instance.Save(playlist);
|
||||
DbHandler.Instance.Connection.InsertAll(songInfos.Select(s => new PlaylistSongInfo
|
||||
{
|
||||
PlaylistId = playlist.Id.Value,
|
||||
SongInfoId = s.Id.Value
|
||||
}), typeof(PlaylistSongInfo));
|
||||
|
||||
await e.Channel.SendMessage($"🎵 `Saved playlist as {name}-{playlist.Id}`").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "load")
|
||||
.Description($"Loads a playlist under a certain name. | `{Prefix}load classical-1`")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var voiceCh = e.User.VoiceChannel;
|
||||
var textCh = e.Channel;
|
||||
if (voiceCh == null || voiceCh.Server != textCh.Server)
|
||||
{
|
||||
await textCh.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var name = e.GetArg("name")?.Trim().ToLowerInvariant();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
|
||||
var parts = name.Split('-');
|
||||
if (parts.Length != 2)
|
||||
return;
|
||||
var playlistName = parts[0];
|
||||
|
||||
int playlistNumber;
|
||||
if (!int.TryParse(parts[1], out playlistNumber))
|
||||
return;
|
||||
|
||||
var playlist = DbHandler.Instance.FindOne<MusicPlaylist>(
|
||||
p => p.Id == playlistNumber);
|
||||
|
||||
if (playlist == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Can't find playlist under that name.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var psis = DbHandler.Instance.FindAll<PlaylistSongInfo>(psi =>
|
||||
psi.PlaylistId == playlist.Id);
|
||||
|
||||
var songInfos = psis.Select(psi => DbHandler.Instance
|
||||
.FindOne<DataModels.SongInfo>(si => si.Id == psi.SongInfoId));
|
||||
|
||||
await e.Channel.SendMessage($"`Attempting to load {songInfos.Count()} songs`").ConfigureAwait(false);
|
||||
foreach (var si in songInfos)
|
||||
{
|
||||
try
|
||||
{
|
||||
await QueueSong(e.User, textCh, voiceCh, si.Query, true, (MusicType)si.ProviderType).ConfigureAwait(false);
|
||||
}
|
||||
catch (PlaylistFullException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed QueueSong in load playlist. {ex}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "playlists")
|
||||
.Alias(Prefix + "pls")
|
||||
.Description($"Lists all playlists. Paginated. 20 per page. Default page is 0. |`{Prefix}pls 1`")
|
||||
.Parameter("num", ParameterType.Optional)
|
||||
.Do(e =>
|
||||
{
|
||||
int num = 0;
|
||||
int.TryParse(e.GetArg("num"), out num);
|
||||
if (num < 0)
|
||||
return;
|
||||
var result = DbHandler.Instance.GetPlaylistData(num);
|
||||
if (result.Count == 0)
|
||||
e.Channel.SendMessage($"`No saved playlists found on page {num}`").ConfigureAwait(false);
|
||||
else
|
||||
e.Channel.SendMessage($"```js\n--- List of saved playlists ---\n\n" + string.Join("\n", result.Select(r => $"'{r.Name}-{r.Id}' by {r.Creator} ({r.SongCnt} songs)")) + $"\n\n --- Page {num} ---```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "deleteplaylist")
|
||||
.Alias(Prefix + "delpls")
|
||||
.Description($"Deletes a saved playlist. Only if you made it or if you are the bot owner. | `{Prefix}delpls animu-5`")
|
||||
.Parameter("pl", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pl = e.GetArg("pl").Trim().Split('-')[1];
|
||||
if (string.IsNullOrWhiteSpace(pl))
|
||||
return;
|
||||
var plnum = int.Parse(pl);
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
DbHandler.Instance.Delete<MusicPlaylist>(plnum);
|
||||
else
|
||||
DbHandler.Instance.DeleteWhere<MusicPlaylist>(mp => mp.Id == plnum && (long)e.User.Id == mp.CreatorId);
|
||||
await e.Channel.SendMessage("`Ok.` :ok:").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "goto")
|
||||
.Description($"Goes to a specific time in seconds in a song. | `{Prefix}goto 30`")
|
||||
.Parameter("time")
|
||||
.Do(async e =>
|
||||
{
|
||||
var skipToStr = e.GetArg("time")?.Trim();
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
if (e.User.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
int skipTo;
|
||||
if (!int.TryParse(skipToStr, out skipTo) || skipTo < 0)
|
||||
return;
|
||||
|
||||
var currentSong = musicPlayer.CurrentSong;
|
||||
|
||||
if (currentSong == null)
|
||||
return;
|
||||
|
||||
//currentSong.PrintStatusMessage = false;
|
||||
var gotoSong = currentSong.Clone();
|
||||
gotoSong.SkipTo = skipTo;
|
||||
musicPlayer.AddSong(gotoSong, 0);
|
||||
musicPlayer.Next();
|
||||
|
||||
var minutes = (skipTo / 60).ToString();
|
||||
var seconds = (skipTo % 60).ToString();
|
||||
|
||||
if (minutes.Length == 1)
|
||||
minutes = "0" + minutes;
|
||||
if (seconds.Length == 1)
|
||||
seconds = "0" + seconds;
|
||||
|
||||
await e.Channel.SendMessage($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "getlink")
|
||||
.Alias(Prefix + "gl")
|
||||
.Description($"Shows a link to the song in the queue by index, or the currently playing song by default. | `{Prefix}gl`")
|
||||
.Parameter("index", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
int index;
|
||||
string arg = e.GetArg("index")?.Trim();
|
||||
if (!string.IsNullOrEmpty(arg) && int.TryParse(arg, out index))
|
||||
{
|
||||
|
||||
var selSong = musicPlayer.Playlist.DefaultIfEmpty(null).ElementAtOrDefault(index - 1);
|
||||
if (selSong == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Could not select song, likely wrong index");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"🎶`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var curSong = musicPlayer.CurrentSong;
|
||||
if (curSong == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "autoplay")
|
||||
.Alias(Prefix + "ap")
|
||||
.Description($"Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `{Prefix}ap`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
|
||||
if (!musicPlayer.ToggleAutoplay())
|
||||
await e.Channel.SendMessage("🎶`Autoplay disabled.`").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("🎶`Autoplay enabled.`").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task QueueSong(User queuer, Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||
{
|
||||
if (voiceCh == null || voiceCh.Server != textCh.Server)
|
||||
{
|
||||
if (!silent)
|
||||
await textCh.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.").ConfigureAwait(false);
|
||||
throw new ArgumentNullException(nameof(voiceCh));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
|
||||
throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
|
||||
|
||||
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server =>
|
||||
{
|
||||
float vol = SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
||||
var mp = new MusicPlayer(voiceCh, vol);
|
||||
|
||||
|
||||
Message playingMessage = null;
|
||||
Message lastFinishedMessage = null;
|
||||
mp.OnCompleted += async (s, song) =>
|
||||
{
|
||||
if (song.PrintStatusMessage)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (lastFinishedMessage != null)
|
||||
await lastFinishedMessage.Delete().ConfigureAwait(false);
|
||||
if (playingMessage != null)
|
||||
await playingMessage.Delete().ConfigureAwait(false);
|
||||
lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
|
||||
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
|
||||
{
|
||||
await QueueSong(queuer.Server.CurrentUser, textCh, voiceCh, (await SearchHelper.GetRelatedVideoIds(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
mp.OnStarted += async (s, song) =>
|
||||
{
|
||||
if (song.PrintStatusMessage)
|
||||
{
|
||||
var sender = s as MusicPlayer;
|
||||
if (sender == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`";
|
||||
playingMessage = await textCh.SendMessage(msgTxt).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
};
|
||||
return mp;
|
||||
});
|
||||
Song resolvedSong;
|
||||
try
|
||||
{
|
||||
musicPlayer.ThrowIfQueueFull();
|
||||
resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
|
||||
|
||||
musicPlayer.AddSong(resolvedSong, queuer.Name);
|
||||
}
|
||||
catch (PlaylistFullException)
|
||||
{
|
||||
await textCh.SendMessage($"🎵 `Queue is full at {musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}.` ");
|
||||
throw;
|
||||
}
|
||||
if (!silent)
|
||||
{
|
||||
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await queuedMessage.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
internal class NSFWModule : DiscordModule
|
||||
{
|
||||
|
||||
private readonly Random rng = new Random();
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.NSFW;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
cgb.CreateCommand(Prefix + "hentai")
|
||||
.Description($"Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}hentai yuri+kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
|
||||
var links = await Task.WhenAll(SearchHelper.GetGelbooruImageLink("rating%3Aexplicit+" + tag), SearchHelper.GetDanbooruImageLink("rating%3Aexplicit+" + tag)).ConfigureAwait(false);
|
||||
|
||||
if (links.All(l => l == null))
|
||||
{
|
||||
await e.Channel.SendMessage("`No results.`");
|
||||
return;
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(String.Join("\n\n", links)).ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "danbooru")
|
||||
.Description($"Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}danbooru yuri+kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
var link = await SearchHelper.GetDanbooruImageLink(tag).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
await e.Channel.SendMessage("Search yielded no results ;(");
|
||||
else
|
||||
await e.Channel.SendMessage(link).ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "gelbooru")
|
||||
.Description($"Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}gelbooru yuri+kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
var link = await SearchHelper.GetGelbooruImageLink(tag).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
await e.Channel.SendMessage("Search yielded no results ;(");
|
||||
else
|
||||
await e.Channel.SendMessage(link).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rule34")
|
||||
.Description($"Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}rule34 yuri+kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
var link = await SearchHelper.GetRule34ImageLink(tag).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
await e.Channel.SendMessage("Search yielded no results ;(");
|
||||
else
|
||||
await e.Channel.SendMessage(link).ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "e621")
|
||||
.Description($"Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | `{Prefix}e621 yuri kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
await e.Channel.SendMessage(await SearchHelper.GetE621ImageLink(tag).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "cp")
|
||||
.Description($"We all know where this will lead you to. | `{Prefix}cp`")
|
||||
.Parameter("anything", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "boobs")
|
||||
.Description($"Real adult content. | `{Prefix}boobs`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.oboobs.ru/boobs/{rng.Next(0, 9380)}").ConfigureAwait(false))[0];
|
||||
await e.Channel.SendMessage($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "butts")
|
||||
.Alias(Prefix + "ass", Prefix + "butt")
|
||||
.Description($"Real adult content. | `{Prefix}butts` or `{Prefix}ass`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.obutts.ru/butts/{rng.Next(0, 3373)}").ConfigureAwait(false))[0];
|
||||
await e.Channel.SendMessage($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Commands.Permissions;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Classes
|
||||
{
|
||||
|
||||
internal class PermissionChecker : IPermissionChecker
|
||||
{
|
||||
public static PermissionChecker Instance { get; } = new PermissionChecker();
|
||||
|
||||
private ConcurrentDictionary<string, ulong> commandCooldowns = new ConcurrentDictionary<string, ulong>();
|
||||
private ConcurrentDictionary<ulong, bool> timeBlackList { get; } = new ConcurrentDictionary<ulong, bool>();
|
||||
|
||||
static PermissionChecker() { }
|
||||
private PermissionChecker()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
timeBlackList.Clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public bool CanRun(Command command, User user, Channel channel, out string error)
|
||||
{
|
||||
error = String.Empty;
|
||||
|
||||
if (!NadekoBot.Ready)
|
||||
return false;
|
||||
|
||||
if (channel.IsPrivate || channel.Server == null)
|
||||
return command.Category == "Help";
|
||||
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
if (ConfigHandler.IsUserBlacklisted(user.Id) ||
|
||||
(!channel.IsPrivate &&
|
||||
(ConfigHandler.IsServerBlacklisted(channel.Server.Id) || ConfigHandler.IsChannelBlacklisted(channel.Id))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (timeBlackList.ContainsKey(user.Id))
|
||||
return false;
|
||||
}
|
||||
catch { return false; }
|
||||
|
||||
if (!channel.IsPrivate && !channel.Server.CurrentUser.GetPermissions(channel).SendMessages)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
timeBlackList.TryAdd(user.Id, true);
|
||||
|
||||
ServerPermissions perms;
|
||||
PermissionsHandler.PermissionsDict.TryGetValue(user.Server.Id, out perms);
|
||||
|
||||
AddUserCooldown(user.Server.Id, user.Id, command.Text.ToLower());
|
||||
if (commandCooldowns.Keys.Contains(user.Server.Id + ":" + command.Text.ToLower()))
|
||||
{
|
||||
if (perms?.Verbose == true)
|
||||
error = $"{user.Mention} You have a cooldown on that command.";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//is it a permission command?
|
||||
// if it is, check if the user has the correct role
|
||||
// if yes return true, if no return false
|
||||
if (command.Category == "Permissions")
|
||||
{
|
||||
Discord.Role role = null;
|
||||
try
|
||||
{
|
||||
role = PermissionHelper.ValidateRole(user.Server,
|
||||
PermissionsHandler.GetServerPermissionsRoleName(user.Server));
|
||||
}
|
||||
catch { }
|
||||
if (user.Server.Owner.Id == user.Id || (role != null && user.HasRole(role)))
|
||||
return true;
|
||||
throw new Exception($"You don't have the necessary role (**{(perms?.PermissionsControllerRole ?? "Nadeko")}**) to change permissions.");
|
||||
}
|
||||
|
||||
var permissionType = PermissionsHandler.GetPermissionBanType(command, user, channel);
|
||||
|
||||
string msg;
|
||||
|
||||
if (permissionType == PermissionsHandler.PermissionBanType.ServerBanModule &&
|
||||
command.Category.ToLower() == "nsfw")
|
||||
msg = $"**{command.Category}** module has been banned from use on this **server**.\nNSFW module is disabled by default. Server owner can type `;sm nsfw enable` to enable it.";
|
||||
else
|
||||
switch (permissionType)
|
||||
{
|
||||
case PermissionsHandler.PermissionBanType.None:
|
||||
return true;
|
||||
case PermissionsHandler.PermissionBanType.ServerBanCommand:
|
||||
msg = $"**{command.Text}** command has been banned from use on this **server**.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.ServerBanModule:
|
||||
msg = $"**{command.Category}** module has been banned from use on this **server**.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.ChannelBanCommand:
|
||||
msg = $"**{command.Text}** command has been banned from use on this **channel**.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.ChannelBanModule:
|
||||
msg = $"**{command.Category}** module has been banned from use on this **channel**.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.RoleBanCommand:
|
||||
msg = $"You do not have a **role** which permits you the usage of **{command.Text}** command.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.RoleBanModule:
|
||||
msg = $"You do not have a **role** which permits you the usage of **{command.Category}** module.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.UserBanCommand:
|
||||
msg = $"{user.Mention}, You have been banned from using **{command.Text}** command.";
|
||||
break;
|
||||
case PermissionsHandler.PermissionBanType.UserBanModule:
|
||||
msg = $"{user.Mention}, You have been banned from using **{command.Category}** module.";
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
if (PermissionsHandler.PermissionsDict[user.Server.Id].Verbose) //if verbose - print errors
|
||||
error = msg;
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Exception in canrun: {ex}");
|
||||
try
|
||||
{
|
||||
if (perms != null && perms.Verbose)
|
||||
//if verbose - print errors
|
||||
error = ex.Message;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
Console.WriteLine($"SERIOUS PERMISSION ERROR {ex2}\n\nUser:{user} Server: {user?.Server?.Name}/{user?.Server?.Id}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddUserCooldown(ulong serverId, ulong userId, string commandName)
|
||||
{
|
||||
commandCooldowns.TryAdd(commandName, userId);
|
||||
var tosave = serverId + ":" + commandName;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
ServerPermissions perms;
|
||||
PermissionsHandler.PermissionsDict.TryGetValue(serverId, out perms);
|
||||
int cd;
|
||||
if (!perms.CommandCooldowns.TryGetValue(commandName, out cd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (commandCooldowns.TryAdd(tosave, userId))
|
||||
{
|
||||
await Task.Delay(cd * 1000);
|
||||
ulong throwaway;
|
||||
commandCooldowns.TryRemove(tosave, out throwaway);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Classes
|
||||
{
|
||||
internal static class PermissionHelper
|
||||
{
|
||||
public static bool ValidateBool(string passedArg)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(passedArg))
|
||||
{
|
||||
throw new ArgumentException("No value supplied! Missing argument");
|
||||
}
|
||||
switch (passedArg.ToLower())
|
||||
{
|
||||
case "1":
|
||||
case "t":
|
||||
case "true":
|
||||
case "enable":
|
||||
case "enabled":
|
||||
case "allow":
|
||||
case "unban":
|
||||
return true;
|
||||
case "0":
|
||||
case "f":
|
||||
case "false":
|
||||
case "disable":
|
||||
case "disabled":
|
||||
case "disallow":
|
||||
case "ban":
|
||||
return false;
|
||||
default:
|
||||
throw new ArgumentException("Did not receive a valid boolean value");
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ValidateModule(string mod)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mod))
|
||||
throw new ArgumentNullException(nameof(mod));
|
||||
|
||||
foreach (var m in NadekoBot.Client.GetService<ModuleService>().Modules)
|
||||
{
|
||||
if (m.Name.ToLower().Equals(mod.Trim().ToLower()))
|
||||
return m.Name;
|
||||
}
|
||||
throw new ArgumentException("That module does not exist.");
|
||||
}
|
||||
|
||||
internal static string ValidateCommand(string commandText)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(commandText))
|
||||
throw new ArgumentNullException(nameof(commandText));
|
||||
|
||||
var normalizedCmdTxt = commandText.Trim().ToUpperInvariant();
|
||||
|
||||
foreach (var com in NadekoBot.Client.GetService<CommandService>().AllCommands)
|
||||
{
|
||||
if (com.Text.ToUpperInvariant().Equals(normalizedCmdTxt) || com.Aliases.Select(c => c.ToUpperInvariant()).Contains(normalizedCmdTxt))
|
||||
return com.Text;
|
||||
}
|
||||
throw new NullReferenceException("That command does not exist.");
|
||||
}
|
||||
|
||||
internal static Role ValidateRole(Server server, string roleName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
throw new ArgumentNullException(nameof(roleName));
|
||||
|
||||
if (roleName.Trim() == "everyone")
|
||||
roleName = "@everyone";
|
||||
var role = server.FindRoles(roleName.Trim()).FirstOrDefault();
|
||||
if (role == null)
|
||||
throw new NullReferenceException("That role does not exist.");
|
||||
return role;
|
||||
}
|
||||
|
||||
internal static Channel ValidateChannel(Server server, string channelName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channelName))
|
||||
throw new ArgumentNullException(nameof(channelName));
|
||||
var channel = server.FindChannels(channelName.Trim(), ChannelType.Text).FirstOrDefault();
|
||||
if (channel == null)
|
||||
throw new NullReferenceException("That channel does not exist.");
|
||||
return channel;
|
||||
}
|
||||
|
||||
internal static User ValidateUser(Server server, string userName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
throw new ArgumentNullException(nameof(userName));
|
||||
var user = server.FindUsers(userName.Trim()).FirstOrDefault();
|
||||
if (user == null)
|
||||
throw new NullReferenceException("That user does not exist.");
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,577 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Classes
|
||||
{
|
||||
public static class PermissionsHandler
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, ServerPermissions> PermissionsDict =
|
||||
new ConcurrentDictionary<ulong, ServerPermissions>();
|
||||
|
||||
public enum PermissionBanType
|
||||
{
|
||||
None, ServerBanCommand, ServerBanModule,
|
||||
ChannelBanCommand, ChannelBanModule, RoleBanCommand,
|
||||
RoleBanModule, UserBanCommand, UserBanModule
|
||||
}
|
||||
|
||||
|
||||
public static Task Initialize() => Task.Run(() =>
|
||||
{
|
||||
Console.WriteLine("Reading from the permission files.");
|
||||
Directory.CreateDirectory("data/permissions");
|
||||
foreach (var file in Directory.EnumerateFiles("data/permissions/"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var strippedFileName = Path.GetFileNameWithoutExtension(file);
|
||||
if (string.IsNullOrWhiteSpace(strippedFileName)) continue;
|
||||
var id = ulong.Parse(strippedFileName);
|
||||
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<ServerPermissions>(File.ReadAllText(file));
|
||||
PermissionsDict.TryAdd(id, data);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
Console.WriteLine("Permission initialization complete.");
|
||||
});
|
||||
|
||||
internal static Permissions GetRolePermissionsById(Server server, ulong id)
|
||||
{
|
||||
ServerPermissions serverPerms;
|
||||
if (!PermissionsDict.TryGetValue(server.Id, out serverPerms))
|
||||
return null;
|
||||
|
||||
Permissions toReturn;
|
||||
serverPerms.RolePermissions.TryGetValue(id, out toReturn);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
internal static Permissions GetUserPermissionsById(Server server, ulong id)
|
||||
{
|
||||
ServerPermissions serverPerms;
|
||||
if (!PermissionsDict.TryGetValue(server.Id, out serverPerms))
|
||||
return null;
|
||||
|
||||
Permissions toReturn;
|
||||
serverPerms.UserPermissions.TryGetValue(id, out toReturn);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
internal static Permissions GetChannelPermissionsById(Server server, ulong id)
|
||||
{
|
||||
ServerPermissions serverPerms;
|
||||
if (!PermissionsDict.TryGetValue(server.Id, out serverPerms))
|
||||
return null;
|
||||
|
||||
Permissions toReturn;
|
||||
serverPerms.ChannelPermissions.TryGetValue(id, out toReturn);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
internal static Permissions GetServerPermissions(Server server)
|
||||
{
|
||||
ServerPermissions serverPerms;
|
||||
return !PermissionsDict.TryGetValue(server.Id, out serverPerms) ? null : serverPerms.Permissions;
|
||||
}
|
||||
|
||||
internal static PermissionBanType GetPermissionBanType(Command command, User user, Channel channel)
|
||||
{
|
||||
var server = user.Server;
|
||||
ServerPermissions serverPerms = PermissionsDict.GetOrAdd(server.Id, id => new ServerPermissions(id, server.Name));
|
||||
bool val;
|
||||
Permissions perm;
|
||||
//server
|
||||
if (serverPerms.Permissions.Modules.TryGetValue(command.Category, out val) && val == false)
|
||||
return PermissionBanType.ServerBanModule;
|
||||
if (serverPerms.Permissions.Commands.TryGetValue(command.Text, out val) && val == false)
|
||||
return PermissionBanType.ServerBanCommand;
|
||||
//channel
|
||||
if (serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perm) &&
|
||||
perm.Modules.TryGetValue(command.Category, out val) && val == false)
|
||||
return PermissionBanType.ChannelBanModule;
|
||||
if (serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perm) &&
|
||||
perm.Commands.TryGetValue(command.Text, out val) && val == false)
|
||||
return PermissionBanType.ChannelBanCommand;
|
||||
|
||||
//ROLE PART - TWO CASES
|
||||
// FIRST CASE:
|
||||
// IF EVERY ROLE USER HAS IS BANNED FROM THE MODULE,
|
||||
// THAT MEANS USER CANNOT RUN THIS COMMAND
|
||||
// IF AT LEAST ONE ROLE EXIST THAT IS NOT BANNED,
|
||||
// USER CAN RUN THE COMMAND
|
||||
var foundNotBannedRole = false;
|
||||
foreach (var role in user.Roles)
|
||||
{
|
||||
//if every role is banned from using the module -> rolebanmodule
|
||||
if (serverPerms.RolePermissions.TryGetValue(role.Id, out perm) &&
|
||||
perm.Modules.TryGetValue(command.Category, out val) && val == false)
|
||||
continue;
|
||||
foundNotBannedRole = true;
|
||||
break;
|
||||
}
|
||||
if (!foundNotBannedRole)
|
||||
return PermissionBanType.RoleBanModule;
|
||||
|
||||
// SECOND CASE:
|
||||
// IF EVERY ROLE USER HAS IS BANNED FROM THE COMMAND,
|
||||
// THAT MEANS USER CANNOT RUN THAT COMMAND
|
||||
// IF AT LEAST ONE ROLE EXISTS THAT IS NOT BANNED,
|
||||
// USER CAN RUN THE COMMAND
|
||||
foundNotBannedRole = false;
|
||||
foreach (var role in user.Roles)
|
||||
{
|
||||
//if every role is banned from using the module -> rolebanmodule
|
||||
if (serverPerms.RolePermissions.TryGetValue(role.Id, out perm) &&
|
||||
perm.Commands.TryGetValue(command.Text, out val) && val == false)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
foundNotBannedRole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundNotBannedRole)
|
||||
return PermissionBanType.RoleBanCommand;
|
||||
|
||||
//user
|
||||
if (serverPerms.UserPermissions.TryGetValue(user.Id, out perm) &&
|
||||
perm.Modules.TryGetValue(command.Category, out val) && val == false)
|
||||
return PermissionBanType.UserBanModule;
|
||||
if (serverPerms.UserPermissions.TryGetValue(user.Id, out perm) &&
|
||||
perm.Commands.TryGetValue(command.Text, out val) && val == false)
|
||||
return PermissionBanType.UserBanCommand;
|
||||
|
||||
return PermissionBanType.None;
|
||||
}
|
||||
|
||||
private static Task WriteServerToJson(ServerPermissions serverPerms) => Task.Run(() =>
|
||||
{
|
||||
string pathToFile = $"data/permissions/{serverPerms.Id}.json";
|
||||
File.WriteAllText(pathToFile,
|
||||
Newtonsoft.Json.JsonConvert.SerializeObject(serverPerms, Newtonsoft.Json.Formatting.Indented));
|
||||
});
|
||||
|
||||
public static Task WriteToJson() => Task.Run(() =>
|
||||
{
|
||||
Directory.CreateDirectory("data/permissions/");
|
||||
foreach (var kvp in PermissionsDict)
|
||||
{
|
||||
WriteServerToJson(kvp.Value);
|
||||
}
|
||||
});
|
||||
|
||||
public static string GetServerPermissionsRoleName(Server server)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
return serverPerms.PermissionsControllerRole;
|
||||
}
|
||||
|
||||
internal static async Task SetPermissionsRole(Server server, string roleName)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
serverPerms.PermissionsControllerRole = roleName;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task SetVerbosity(Server server, bool val)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
serverPerms.Verbose = val;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task CopyRolePermissions(Role fromRole, Role toRole)
|
||||
{
|
||||
var server = fromRole.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
var from = GetRolePermissionsById(server, fromRole.Id);
|
||||
if (from == null)
|
||||
serverPerms.RolePermissions.Add(fromRole.Id, from = new Permissions(fromRole.Name));
|
||||
var to = GetRolePermissionsById(server, toRole.Id);
|
||||
if (to == null)
|
||||
serverPerms.RolePermissions.Add(toRole.Id, to = new Permissions(toRole.Name));
|
||||
|
||||
to.CopyFrom(from);
|
||||
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task CopyChannelPermissions(Channel fromChannel, Channel toChannel)
|
||||
{
|
||||
var server = fromChannel.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
var from = GetChannelPermissionsById(server, fromChannel.Id);
|
||||
if (from == null)
|
||||
serverPerms.ChannelPermissions.Add(fromChannel.Id, from = new Permissions(fromChannel.Name));
|
||||
var to = GetChannelPermissionsById(server, toChannel.Id);
|
||||
if (to == null)
|
||||
serverPerms.ChannelPermissions.Add(toChannel.Id, to = new Permissions(toChannel.Name));
|
||||
|
||||
to.CopyFrom(from);
|
||||
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task CopyUserPermissions(User fromUser, User toUser)
|
||||
{
|
||||
var server = fromUser.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
var from = GetUserPermissionsById(server, fromUser.Id);
|
||||
if (from == null)
|
||||
serverPerms.UserPermissions.Add(fromUser.Id, from = new Permissions(fromUser.Name));
|
||||
var to = GetUserPermissionsById(server, toUser.Id);
|
||||
if (to == null)
|
||||
serverPerms.UserPermissions.Add(toUser.Id, to = new Permissions(toUser.Name));
|
||||
|
||||
to.CopyFrom(from);
|
||||
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetServerModulePermission(Server server, string moduleName, bool value)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
var modules = serverPerms.Permissions.Modules;
|
||||
if (modules.ContainsKey(moduleName))
|
||||
modules[moduleName] = value;
|
||||
else
|
||||
modules.TryAdd(moduleName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetServerCommandPermission(Server server, string commandName, bool value)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
var commands = serverPerms.Permissions.Commands;
|
||||
if (commands.ContainsKey(commandName))
|
||||
commands[commandName] = value;
|
||||
else
|
||||
commands.TryAdd(commandName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetChannelModulePermission(Channel channel, string moduleName, bool value)
|
||||
{
|
||||
var server = channel.Server;
|
||||
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.ChannelPermissions.ContainsKey(channel.Id))
|
||||
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
|
||||
|
||||
var modules = serverPerms.ChannelPermissions[channel.Id].Modules;
|
||||
|
||||
if (modules.ContainsKey(moduleName))
|
||||
modules[moduleName] = value;
|
||||
else
|
||||
modules.TryAdd(moduleName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetChannelCommandPermission(Channel channel, string commandName, bool value)
|
||||
{
|
||||
var server = channel.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.ChannelPermissions.ContainsKey(channel.Id))
|
||||
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
|
||||
|
||||
var commands = serverPerms.ChannelPermissions[channel.Id].Commands;
|
||||
|
||||
if (commands.ContainsKey(commandName))
|
||||
commands[commandName] = value;
|
||||
else
|
||||
commands.TryAdd(commandName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetRoleModulePermission(Role role, string moduleName, bool value)
|
||||
{
|
||||
var server = role.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.RolePermissions.ContainsKey(role.Id))
|
||||
serverPerms.RolePermissions.Add(role.Id, new Permissions(role.Name));
|
||||
|
||||
var modules = serverPerms.RolePermissions[role.Id].Modules;
|
||||
|
||||
if (modules.ContainsKey(moduleName))
|
||||
modules[moduleName] = value;
|
||||
else
|
||||
modules.TryAdd(moduleName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetRoleCommandPermission(Role role, string commandName, bool value)
|
||||
{
|
||||
var server = role.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.RolePermissions.ContainsKey(role.Id))
|
||||
serverPerms.RolePermissions.Add(role.Id, new Permissions(role.Name));
|
||||
|
||||
var commands = serverPerms.RolePermissions[role.Id].Commands;
|
||||
|
||||
if (commands.ContainsKey(commandName))
|
||||
commands[commandName] = value;
|
||||
else
|
||||
commands.TryAdd(commandName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetUserModulePermission(User user, string moduleName, bool value)
|
||||
{
|
||||
var server = user.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.UserPermissions.ContainsKey(user.Id))
|
||||
serverPerms.UserPermissions.Add(user.Id, new Permissions(user.Name));
|
||||
|
||||
var modules = serverPerms.UserPermissions[user.Id].Modules;
|
||||
|
||||
if (modules.ContainsKey(moduleName))
|
||||
modules[moduleName] = value;
|
||||
else
|
||||
modules.TryAdd(moduleName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetUserCommandPermission(User user, string commandName, bool value)
|
||||
{
|
||||
var server = user.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
if (!serverPerms.UserPermissions.ContainsKey(user.Id))
|
||||
serverPerms.UserPermissions.Add(user.Id, new Permissions(user.Name));
|
||||
|
||||
var commands = serverPerms.UserPermissions[user.Id].Commands;
|
||||
|
||||
if (commands.ContainsKey(commandName))
|
||||
commands[commandName] = value;
|
||||
else
|
||||
commands.TryAdd(commandName, value);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetServerWordPermission(Server server, bool value)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
serverPerms.Permissions.FilterWords = value;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetChannelWordPermission(Channel channel, bool value)
|
||||
{
|
||||
var server = channel.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.ChannelPermissions.ContainsKey(channel.Id))
|
||||
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
|
||||
|
||||
serverPerms.ChannelPermissions[channel.Id].FilterWords = value;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetServerFilterInvitesPermission(Server server, bool value)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
serverPerms.Permissions.FilterInvites = value;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetChannelFilterInvitesPermission(Channel channel, bool value)
|
||||
{
|
||||
var server = channel.Server;
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
|
||||
if (!serverPerms.ChannelPermissions.ContainsKey(channel.Id))
|
||||
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
|
||||
|
||||
serverPerms.ChannelPermissions[channel.Id].FilterInvites = value;
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task SetCommandCooldown(Server server, string commandName, int value)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
if (value == 0)
|
||||
{
|
||||
int throwaway;
|
||||
serverPerms.CommandCooldowns.TryRemove(commandName, out throwaway);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverPerms.CommandCooldowns.AddOrUpdate(commandName, value, (str, v) => value);
|
||||
}
|
||||
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task AddFilteredWord(Server server, string word)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
if (serverPerms.Words.Contains(word))
|
||||
throw new InvalidOperationException("That word is already banned.");
|
||||
serverPerms.Words.Add(word);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
public static async Task RemoveFilteredWord(Server server, string word)
|
||||
{
|
||||
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
|
||||
new ServerPermissions(server.Id, server.Name));
|
||||
if (!serverPerms.Words.Contains(word))
|
||||
throw new InvalidOperationException("That word is not banned.");
|
||||
serverPerms.Words.Remove(word);
|
||||
await WriteServerToJson(serverPerms).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Holds a permission list
|
||||
/// </summary>
|
||||
public class Permissions
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the parent object whose permissions these are
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Module name with allowed/disallowed
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, bool> Modules { get; set; }
|
||||
/// <summary>
|
||||
/// Command name with allowed/disallowed
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, bool> Commands { get; set; }
|
||||
/// <summary>
|
||||
/// Should the bot filter invites to other discord servers (and ref links in the future)
|
||||
/// </summary>
|
||||
public bool FilterInvites { get; set; }
|
||||
/// <summary>
|
||||
/// Should the bot filter words which are specified in the Words hashset
|
||||
/// </summary>
|
||||
public bool FilterWords { get; set; }
|
||||
|
||||
public Permissions(string name)
|
||||
{
|
||||
Name = name;
|
||||
Modules = new ConcurrentDictionary<string, bool>();
|
||||
Commands = new ConcurrentDictionary<string, bool>();
|
||||
FilterInvites = false;
|
||||
FilterWords = false;
|
||||
}
|
||||
|
||||
public void CopyFrom(Permissions other)
|
||||
{
|
||||
Modules.Clear();
|
||||
foreach (var mp in other.Modules)
|
||||
Modules.AddOrUpdate(mp.Key, mp.Value, (s, b) => mp.Value);
|
||||
Commands.Clear();
|
||||
foreach (var cp in other.Commands)
|
||||
Commands.AddOrUpdate(cp.Key, cp.Value, (s, b) => cp.Value);
|
||||
FilterInvites = other.FilterInvites;
|
||||
FilterWords = other.FilterWords;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var toReturn = "";
|
||||
var bannedModules = Modules.Where(kvp => kvp.Value == false);
|
||||
var bannedModulesArray = bannedModules as KeyValuePair<string, bool>[] ?? bannedModules.ToArray();
|
||||
if (bannedModulesArray.Any())
|
||||
{
|
||||
toReturn += "`Banned Modules:`\n";
|
||||
toReturn = bannedModulesArray.Aggregate(toReturn, (current, m) => current + $"\t`[x] {m.Key}`\n");
|
||||
}
|
||||
var bannedCommands = Commands.Where(kvp => kvp.Value == false);
|
||||
var bannedCommandsArr = bannedCommands as KeyValuePair<string, bool>[] ?? bannedCommands.ToArray();
|
||||
if (bannedCommandsArr.Any())
|
||||
{
|
||||
toReturn += "`Banned Commands:`\n";
|
||||
toReturn = bannedCommandsArr.Aggregate(toReturn, (current, c) => current + $"\t`[x] {c.Key}`\n");
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerPermissions
|
||||
{
|
||||
/// <summary>
|
||||
/// The guy who can edit the permissions
|
||||
/// </summary>
|
||||
public string PermissionsControllerRole { get; set; }
|
||||
/// <summary>
|
||||
/// Does it print the error when a restriction occurs
|
||||
/// </summary>
|
||||
public bool Verbose { get; set; }
|
||||
/// <summary>
|
||||
/// The id of the thing (user/server/channel)
|
||||
/// </summary>
|
||||
public ulong Id { get; set; } //a string because of the role name.
|
||||
/// <summary>
|
||||
/// Permission object bound to the id of something/role name
|
||||
/// </summary>
|
||||
public Permissions Permissions { get; set; }
|
||||
/// <summary>
|
||||
/// Banned words, usually profanities, like word "java"
|
||||
/// </summary>
|
||||
public HashSet<string> Words { get; set; }
|
||||
|
||||
public Dictionary<ulong, Permissions> UserPermissions { get; set; }
|
||||
public Dictionary<ulong, Permissions> ChannelPermissions { get; set; }
|
||||
public Dictionary<ulong, Permissions> RolePermissions { get; set; }
|
||||
/// <summary>
|
||||
/// Dictionary of command names with their respective cooldowns
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, int> CommandCooldowns { get; set; }
|
||||
|
||||
public ServerPermissions(ulong id, string name)
|
||||
{
|
||||
Id = id;
|
||||
PermissionsControllerRole = "Nadeko";
|
||||
Verbose = true;
|
||||
|
||||
Permissions = new Permissions(name);
|
||||
Permissions.Modules.TryAdd("NSFW", false);
|
||||
UserPermissions = new Dictionary<ulong, Permissions>();
|
||||
ChannelPermissions = new Dictionary<ulong, Permissions>();
|
||||
RolePermissions = new Dictionary<ulong, Permissions>();
|
||||
CommandCooldowns = new ConcurrentDictionary<string, int>();
|
||||
Words = new HashSet<string>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Commands.Permissions;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Classes
|
||||
{
|
||||
public static class SimpleCheckers
|
||||
{
|
||||
public static ManageRoles CanManageRoles { get; } = new ManageRoles();
|
||||
|
||||
public static Func<Command, User, Channel, bool> OwnerOnly() =>
|
||||
(com, user, ch) => NadekoBot.IsOwner(user.Id);
|
||||
|
||||
public static Func<Command, User, Channel, bool> ManageMessages() =>
|
||||
(com, user, ch) => user.ServerPermissions.ManageMessages;
|
||||
|
||||
public static Func<Command, User, Channel, bool> ManageChannels() =>
|
||||
(com, user, ch) => user.ServerPermissions.ManageChannels;
|
||||
|
||||
public static Func<Command, User, Channel, bool> ManageServer() =>
|
||||
(com, user, ch) => user.ServerPermissions.ManageServer;
|
||||
|
||||
public class ManageRoles : IPermissionChecker
|
||||
{
|
||||
public bool CanRun(Command command, User user, Channel channel, out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
if (user.ServerPermissions.ManageRoles)
|
||||
return true;
|
||||
error = "You do not have a permission to manage roles.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Commands
|
||||
{
|
||||
internal class FilterInvitesCommand : DiscordCommand
|
||||
{
|
||||
private readonly Regex filterRegex = new Regex(@"(?:discord(?:\.gg|app\.com\/invite)\/(?<id>([\w]{16}|(?:[\w]+-?){3})))");
|
||||
|
||||
|
||||
public FilterInvitesCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () => NadekoBot.Client.MessageReceived += async (sender, args) =>
|
||||
{
|
||||
if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
try
|
||||
{
|
||||
Classes.ServerPermissions serverPerms;
|
||||
if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return;
|
||||
|
||||
if (filterRegex.IsMatch(args.Message.RawText))
|
||||
{
|
||||
await args.Message.Delete().ConfigureAwait(false);
|
||||
IncidentsHandler.Add(args.Server.Id, args.Channel.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"INVITE LINK in [{args.Channel.Name}/{args.Channel.Id}] channel.\n" +
|
||||
$"`Full message:` {args.Message.Text}");
|
||||
if (serverPerms.Verbose)
|
||||
await args.Channel.SendMessage($"{args.User.Mention} Invite links are not " +
|
||||
$"allowed on this channel.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsChannelOrServerFiltering(Channel channel, out Classes.ServerPermissions serverPerms)
|
||||
{
|
||||
if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false;
|
||||
|
||||
if (serverPerms.Permissions.FilterInvites)
|
||||
return true;
|
||||
|
||||
Classes.Permissions perms;
|
||||
return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterInvites;
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "chnlfilterinv")
|
||||
.Alias(Module.Prefix + "cfi")
|
||||
.Description("Enables or disables automatic deleting of invites on the channel." +
|
||||
"If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." +
|
||||
$" | `{Prefix}cfi enable #general-chat`")
|
||||
.Parameter("bool")
|
||||
.Parameter("channel", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var chanStr = e.GetArg("channel");
|
||||
|
||||
if (chanStr?.ToLowerInvariant().Trim() != "all")
|
||||
{
|
||||
|
||||
var chan = string.IsNullOrWhiteSpace(chanStr)
|
||||
? e.Channel
|
||||
: PermissionHelper.ValidateChannel(e.Server, chanStr);
|
||||
await PermissionsHandler.SetChannelFilterInvitesPermission(chan, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.")
|
||||
.ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//all channels
|
||||
|
||||
foreach (var curChannel in e.Server.TextChannels)
|
||||
{
|
||||
await PermissionsHandler.SetChannelFilterInvitesPermission(curChannel, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "srvrfilterinv")
|
||||
.Alias(Module.Prefix + "sfi")
|
||||
.Description($"Enables or disables automatic deleting of invites on the server. | `{Prefix}sfi disable`")
|
||||
.Parameter("bool")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
await PermissionsHandler.SetServerFilterInvitesPermission(e.Server, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for this server.")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Commands
|
||||
{
|
||||
internal class FilterWords : DiscordCommand
|
||||
{
|
||||
public FilterWords(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.OnReady += () => NadekoBot.Client.MessageReceived += async (sender, args) =>
|
||||
{
|
||||
if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
try
|
||||
{
|
||||
Classes.ServerPermissions serverPerms;
|
||||
if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return;
|
||||
|
||||
var wordsInMessage = args.Message.RawText.ToLowerInvariant().Split(' ');
|
||||
if (serverPerms.Words.Any(w => wordsInMessage.Contains(w)))
|
||||
{
|
||||
await args.Message.Delete().ConfigureAwait(false);
|
||||
IncidentsHandler.Add(args.Server.Id, args.Channel.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel.\n" +
|
||||
$"`Full message:` {args.Message.Text}");
|
||||
if (serverPerms.Verbose)
|
||||
await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " +
|
||||
$"in that sentence are not allowed here.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsChannelOrServerFiltering(Channel channel, out Classes.ServerPermissions serverPerms)
|
||||
{
|
||||
if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false;
|
||||
|
||||
if (serverPerms.Permissions.FilterWords)
|
||||
return true;
|
||||
|
||||
Classes.Permissions perms;
|
||||
return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords;
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "chnlfilterwords")
|
||||
.Alias(Module.Prefix + "cfw")
|
||||
.Description("Enables or disables automatic deleting of messages containing banned words on the channel." +
|
||||
"If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." +
|
||||
$" | `{Prefix}cfw enable #general-chat`")
|
||||
.Parameter("bool")
|
||||
.Parameter("channel", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim();
|
||||
|
||||
if (chanStr != "all")
|
||||
{
|
||||
var chan = string.IsNullOrWhiteSpace(chanStr)
|
||||
? e.Channel
|
||||
: PermissionHelper.ValidateChannel(e.Server, chanStr);
|
||||
await PermissionsHandler.SetChannelWordPermission(chan, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//all channels
|
||||
|
||||
foreach (var curChannel in e.Server.TextChannels)
|
||||
{
|
||||
await PermissionsHandler.SetChannelWordPermission(curChannel, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "addfilterword")
|
||||
.Alias(Module.Prefix + "afw")
|
||||
.Description("Adds a new word to the list of filtered words" +
|
||||
$" | `{Prefix}afw poop`")
|
||||
.Parameter("word", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var word = e.GetArg("word");
|
||||
if (string.IsNullOrWhiteSpace(word))
|
||||
return;
|
||||
await PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully added new filtered word.").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "rmvfilterword")
|
||||
.Alias(Module.Prefix + "rfw")
|
||||
.Description("Removes the word from the list of filtered words" +
|
||||
$" | `{Prefix}rw poop`")
|
||||
.Parameter("word", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var word = e.GetArg("word");
|
||||
if (string.IsNullOrWhiteSpace(word))
|
||||
return;
|
||||
await PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Successfully removed filtered word.").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "lstfilterwords")
|
||||
.Alias(Module.Prefix + "lfw")
|
||||
.Description("Shows a list of filtered words" +
|
||||
$" | `{Prefix}lfw`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Classes.ServerPermissions serverPerms;
|
||||
if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms))
|
||||
return;
|
||||
await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" +
|
||||
string.Join("\n", serverPerms.Words)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "srvrfilterwords")
|
||||
.Alias(Module.Prefix + "sfw")
|
||||
.Description($"Enables or disables automatic deleting of messages containing forbidden words on the server. | `{Prefix}sfw disable`")
|
||||
.Parameter("bool")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
await PermissionsHandler.SetServerWordPermission(e.Server, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error: {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,839 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Games.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Permissions.Commands;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
internal class PermissionModule : DiscordModule
|
||||
{
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Permissions;
|
||||
|
||||
public PermissionModule()
|
||||
{
|
||||
commands.Add(new FilterInvitesCommand(this));
|
||||
commands.Add(new FilterWords(this));
|
||||
}
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "permrole")
|
||||
.Alias(Prefix + "pr")
|
||||
.Description($"Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `{Prefix}pr role`")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("role")))
|
||||
{
|
||||
await e.Channel.SendMessage($"Current permissions role is `{PermissionsHandler.GetServerPermissionsRoleName(e.Server)}`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var arg = e.GetArg("role");
|
||||
Discord.Role role = null;
|
||||
try
|
||||
{
|
||||
role = PermissionHelper.ValidateRole(e.Server, arg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
await e.Channel.SendMessage($"Role `{arg}` probably doesn't exist. Create the role with that name first.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await PermissionsHandler.SetPermissionsRole(e.Server, role.Name).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Role `{role.Name}` is now required in order to change permissions.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rolepermscopy")
|
||||
.Alias(Prefix + "rpc")
|
||||
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another. |`{Prefix}rpc Some Role ~ Some other role`")
|
||||
.Parameter("from_to", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("from_to")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains('~'))
|
||||
return;
|
||||
var args = arg.Split('~').Select(a => a.Trim()).ToArray();
|
||||
if (args.Length > 2)
|
||||
{
|
||||
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var fromRole = PermissionHelper.ValidateRole(e.Server, args[0]);
|
||||
var toRole = PermissionHelper.ValidateRole(e.Server, args[1]);
|
||||
|
||||
await PermissionsHandler.CopyRolePermissions(fromRole, toRole).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢{ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "chnlpermscopy")
|
||||
.Alias(Prefix + "cpc")
|
||||
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one channel to another. |`{Prefix}cpc Some Channel ~ Some other channel`")
|
||||
.Parameter("from_to", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("from_to")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains('~'))
|
||||
return;
|
||||
var args = arg.Split('~').Select(a => a.Trim()).ToArray();
|
||||
if (args.Length > 2)
|
||||
{
|
||||
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var fromChannel = PermissionHelper.ValidateChannel(e.Server, args[0]);
|
||||
var toChannel = PermissionHelper.ValidateChannel(e.Server, args[1]);
|
||||
|
||||
await PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢{ex.Message}");
|
||||
}
|
||||
});
|
||||
cgb.CreateCommand(Prefix + "usrpermscopy")
|
||||
.Alias(Prefix + "upc")
|
||||
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another. |`{Prefix}upc @SomeUser ~ @SomeOtherUser`")
|
||||
.Parameter("from_to", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("from_to")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains('~'))
|
||||
return;
|
||||
var args = arg.Split('~').Select(a => a.Trim()).ToArray();
|
||||
if (args.Length > 2)
|
||||
{
|
||||
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var fromUser = PermissionHelper.ValidateUser(e.Server, args[0]);
|
||||
var toUser = PermissionHelper.ValidateUser(e.Server, args[1]);
|
||||
|
||||
await PermissionsHandler.CopyUserPermissions(fromUser, toUser).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢{ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "verbose")
|
||||
.Alias(Prefix + "v")
|
||||
.Description($"Sets whether to show when a command/module is blocked. | `{Prefix}verbose true`")
|
||||
.Parameter("arg", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("arg");
|
||||
var val = PermissionHelper.ValidateBool(arg);
|
||||
await PermissionsHandler.SetVerbosity(e.Server, val).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Verbosity set to {val}.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "srvrperms")
|
||||
.Alias(Prefix + "sp")
|
||||
.Description($"Shows banned permissions for this server. | `{Prefix}sp`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var perms = PermissionsHandler.GetServerPermissions(e.Server);
|
||||
if (string.IsNullOrWhiteSpace(perms?.ToString()))
|
||||
await e.Channel.SendMessage("No permissions set for this server.").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(perms.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "roleperms")
|
||||
.Alias(Prefix + "rp")
|
||||
.Description($"Shows banned permissions for a certain role. No argument means for everyone. | `{Prefix}rp AwesomeRole`")
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("role");
|
||||
var role = e.Server.EveryoneRole;
|
||||
if (!string.IsNullOrWhiteSpace(arg))
|
||||
try
|
||||
{
|
||||
role = PermissionHelper.ValidateRole(e.Server, arg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Error: " + ex.Message).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var perms = PermissionsHandler.GetRolePermissionsById(e.Server, role.Id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(perms?.ToString()))
|
||||
await e.Channel.SendMessage($"No permissions set for **{role.Name}** role.").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(perms.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "chnlperms")
|
||||
.Alias(Prefix + "cp")
|
||||
.Description($"Shows banned permissions for a certain channel. No argument means for this channel. | `{Prefix}cp #dev`")
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("channel");
|
||||
var channel = e.Channel;
|
||||
if (!string.IsNullOrWhiteSpace(arg))
|
||||
try
|
||||
{
|
||||
channel = PermissionHelper.ValidateChannel(e.Server, arg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Error: " + ex.Message).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var perms = PermissionsHandler.GetChannelPermissionsById(e.Server, channel.Id);
|
||||
if (string.IsNullOrWhiteSpace(perms?.ToString()))
|
||||
await e.Channel.SendMessage($"No permissions set for **{channel.Name}** channel.").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(perms.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "userperms")
|
||||
.Alias(Prefix + "up")
|
||||
.Description($"Shows banned permissions for a certain user. No argument means for yourself. | `{Prefix}up Kwoth`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var user = e.User;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
try
|
||||
{
|
||||
user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Error: " + ex.Message).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var perms = PermissionsHandler.GetUserPermissionsById(e.Server, user.Id);
|
||||
if (string.IsNullOrWhiteSpace(perms?.ToString()))
|
||||
await e.Channel.SendMessage($"No permissions set for user **{user.Name}**.").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(perms.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "srvrmdl")
|
||||
.Alias(Prefix + "sm")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Description($"Sets a module's permission at the server level. | `{Prefix}sm \"module name\" enable`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
await PermissionsHandler.SetServerModulePermission(e.Server, module, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc")
|
||||
.Parameter("command", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Description($"Sets a command's permission at the server level. | `{Prefix}sc \"command name\" disable`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
await PermissionsHandler.SetServerCommandPermission(e.Server, command, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rolemdl").Alias(Prefix + "rm")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Description($"Sets a module's permission at the role level. | `{Prefix}rm \"module name\" enable MyRole`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
if (e.GetArg("role")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var role in e.Server.Roles)
|
||||
{
|
||||
await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
|
||||
|
||||
await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "rolecmd").Alias(Prefix + "rc")
|
||||
.Parameter("command", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Description($"Sets a command's permission at the role level. | `{Prefix}rc \"command name\" disable MyRole`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
if (e.GetArg("role")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var role in e.Server.Roles)
|
||||
{
|
||||
await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
|
||||
|
||||
await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "chnlmdl").Alias(Prefix + "cm")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Description($"Sets a module's permission at the channel level. | `{Prefix}cm \"module name\" enable SomeChannel`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var channelArg = e.GetArg("channel");
|
||||
if (channelArg?.ToLower() == "all")
|
||||
{
|
||||
foreach (var channel in e.Server.TextChannels)
|
||||
{
|
||||
await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(channelArg))
|
||||
{
|
||||
await PermissionsHandler.SetChannelModulePermission(e.Channel, module, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{e.Channel.Name}** channel.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var channel = PermissionHelper.ValidateChannel(e.Server, channelArg);
|
||||
|
||||
await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "chnlcmd").Alias(Prefix + "cc")
|
||||
.Parameter("command", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Description($"Sets a command's permission at the channel level. | `{Prefix}cc \"command name\" enable SomeChannel`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
if (e.GetArg("channel")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var channel in e.Server.TextChannels)
|
||||
{
|
||||
await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
|
||||
|
||||
await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "usrmdl").Alias(Prefix + "um")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Description($"Sets a module's permission at the user level. | `{Prefix}um \"module name\" enable SomeUsername`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
|
||||
|
||||
await PermissionsHandler.SetUserModulePermission(user, module, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "usrcmd").Alias(Prefix + "uc")
|
||||
.Parameter("command", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Description($"Sets a command's permission at the user level. | `{Prefix}uc \"command name\" enable SomeUsername`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
|
||||
|
||||
await PermissionsHandler.SetUserCommandPermission(user, command, state).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm")
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Description($"Sets permissions for all modules at the server level. | `{Prefix}asm [enable/disable]`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
|
||||
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
|
||||
{
|
||||
await PermissionsHandler.SetServerModulePermission(e.Server, module.Name, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Description($"Sets permissions for all commands from a certain module at the server level. | `{Prefix}asc \"module name\" [enable/disable]`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
|
||||
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
|
||||
{
|
||||
await PermissionsHandler.SetServerCommandPermission(e.Server, command.Text, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm")
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Description($"Sets permissions for all modules at the channel level. | `{Prefix}acm [enable/disable] SomeChannel`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var chArg = e.GetArg("channel");
|
||||
var channel = string.IsNullOrWhiteSpace(chArg) ? e.Channel : PermissionHelper.ValidateChannel(e.Server, chArg);
|
||||
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
|
||||
{
|
||||
await PermissionsHandler.SetChannelModulePermission(channel, module.Name, state).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allchnlcmds").Alias(Prefix + "acc")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Description($"Sets permissions for all commands from a certain module at the channel level. | `{Prefix}acc \"module name\" [enable/disable] SomeChannel`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
|
||||
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
|
||||
{
|
||||
await PermissionsHandler.SetChannelCommandPermission(channel, command.Text, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm")
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Description($"Sets permissions for all modules at the role level. | `{Prefix}arm [enable/disable] MyRole`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
|
||||
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
|
||||
{
|
||||
await PermissionsHandler.SetRoleModulePermission(role, module.Name, state).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allrolecmds").Alias(Prefix + "arc")
|
||||
.Parameter("module", ParameterType.Required)
|
||||
.Parameter("bool", ParameterType.Required)
|
||||
.Parameter("role", ParameterType.Unparsed)
|
||||
.Description($"Sets permissions for all commands from a certain module at the role level. | `{Prefix}arc \"module name\" [enable/disable] MyRole`")
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
|
||||
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
|
||||
if (e.GetArg("role")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var role in e.Server.Roles)
|
||||
{
|
||||
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
|
||||
{
|
||||
await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **all roles** role.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
|
||||
|
||||
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
|
||||
{
|
||||
await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ubl")
|
||||
.Description($"Blacklists a mentioned user. **Bot Owner Only!**| `{Prefix}ubl [user_mention]`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.Message.MentionedUsers.Any()) return;
|
||||
var usr = e.Message.MentionedUsers.First();
|
||||
NadekoBot.Config.UserBlacklist.Add(usr.Id);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "uubl")
|
||||
.Description($"Unblacklists a mentioned user. **Bot Owner Only!** | `{Prefix}uubl [user_mention]`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.Message.MentionedUsers.Any()) return;
|
||||
var usr = e.Message.MentionedUsers.First();
|
||||
if (NadekoBot.Config.UserBlacklist.Contains(usr.Id))
|
||||
{
|
||||
NadekoBot.Config.UserBlacklist.Remove(usr.Id);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Sucessfully unblacklisted user {usr.Name}`").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"`{usr.Name} was not in blacklist`").ConfigureAwait(false);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "cbl")
|
||||
.Description($"Blacklists a mentioned channel (#general for example). | `{Prefix}cbl #some_channel`")
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.Message.MentionedChannels.Any()) return;
|
||||
var ch = e.Message.MentionedChannels.First();
|
||||
NadekoBot.Config.ChannelBlacklist.Add(ch.Id);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "cubl")
|
||||
.Description($"Unblacklists a mentioned channel (#general for example). | `{Prefix}cubl #some_channel`")
|
||||
.Parameter("channel", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.Message.MentionedChannels.Any()) return;
|
||||
var ch = e.Message.MentionedChannels.First();
|
||||
if (NadekoBot.Config.ChannelBlacklist.Contains(ch.Id))
|
||||
{
|
||||
NadekoBot.Config.ChannelBlacklist.Remove(ch.Id);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Sucessfully unblacklisted channel {ch.Name}`").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage($"`{ch.Name} was not in blacklist`").ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "sbl")
|
||||
.Description($"Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | `{Prefix}sbl [servername/serverid]`")
|
||||
.Parameter("server", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var arg = e.GetArg("server")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
var server = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id.ToString() == arg) ??
|
||||
NadekoBot.Client.FindServers(arg.Trim()).FirstOrDefault();
|
||||
if (server == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Cannot find that server").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var serverId = server.Id;
|
||||
NadekoBot.Config.ServerBlacklist.Add(serverId);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
//cleanup trivias and typeracing
|
||||
Modules.Games.Commands.Trivia.TriviaGame trivia;
|
||||
TriviaCommands.RunningTrivias.TryRemove(serverId, out trivia);
|
||||
TypingGame typeracer;
|
||||
SpeedTyping.RunningContests.TryRemove(serverId, out typeracer);
|
||||
|
||||
await e.Channel.SendMessage($"`Sucessfully blacklisted server {server.Name}`").ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "cmdcooldown")
|
||||
.Alias(Prefix+ "cmdcd")
|
||||
.Description($"Sets a cooldown per user for a command. Set 0 to clear. **Needs Manager Messages Permissions**| `{Prefix}cmdcd \"some cmd\" 5`")
|
||||
.Parameter("command", ParameterType.Required)
|
||||
.Parameter("secs",ParameterType.Required)
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
|
||||
var secsStr = e.GetArg("secs").Trim();
|
||||
int secs;
|
||||
if (!int.TryParse(secsStr, out secs) || secs < 0 || secs > 3600)
|
||||
throw new ArgumentOutOfRangeException("secs", "Invalid second parameter. (Must be a number between 0 and 3600)");
|
||||
|
||||
|
||||
await PermissionsHandler.SetCommandCooldown(e.Server, command, secs).ConfigureAwait(false);
|
||||
if(secs == 0)
|
||||
await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage($"Command **{command}** now has a **{secs} {(secs==1 ? "second" : "seconds")}** cooldown.").ConfigureAwait(false);
|
||||
}
|
||||
catch (ArgumentException exArg)
|
||||
{
|
||||
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "allcmdcooldowns")
|
||||
.Alias(Prefix + "acmdcds")
|
||||
.Description($"Shows a list of all commands and their respective cooldowns. | `{Prefix}acmdcds`")
|
||||
.Do(async e =>
|
||||
{
|
||||
ServerPermissions perms;
|
||||
PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out perms);
|
||||
if (perms == null)
|
||||
return;
|
||||
|
||||
if (!perms.CommandCooldowns.Any())
|
||||
{
|
||||
await e.Channel.SendMessage("`No command cooldowns set.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(SearchHelper.ShowInPrettyCode(perms.CommandCooldowns.Select(c=>c.Key+ ": "+c.Value+" secs"),s=>$"{s,-30}",2)).ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
class PokeStats
|
||||
{
|
||||
//Health left
|
||||
public int Hp { get; set; } = 500;
|
||||
public int MaxHp { get; } = 500;
|
||||
//Amount of moves made since last time attacked
|
||||
public int MovesMade { get; set; } = 0;
|
||||
//Last people attacked
|
||||
public List<ulong> LastAttacked { get; set; } = new List<ulong>();
|
||||
}
|
||||
}
|
@ -1,339 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
class PokemonModule : DiscordModule
|
||||
{
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Pokemon;
|
||||
|
||||
private ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>();
|
||||
|
||||
public PokemonModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private int GetDamage(PokemonType usertype, PokemonType targetType)
|
||||
{
|
||||
var rng = new Random();
|
||||
int damage = rng.Next(40, 60);
|
||||
foreach (PokemonMultiplier Multiplier in usertype.Multipliers)
|
||||
{
|
||||
if (Multiplier.Type == targetType.Name)
|
||||
{
|
||||
var multiplier = Multiplier.Multiplication;
|
||||
damage = (int)(damage * multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
private PokemonType GetPokeType(ulong id)
|
||||
{
|
||||
|
||||
var db = DbHandler.Instance.GetAllRows<UserPokeTypes>();
|
||||
Dictionary<long, string> setTypes = db.ToDictionary(x => x.UserId, y => y.type);
|
||||
if (setTypes.ContainsKey((long)id))
|
||||
{
|
||||
return stringToPokemonType(setTypes[(long)id]);
|
||||
}
|
||||
int count = NadekoBot.Config.PokemonTypes.Count;
|
||||
|
||||
int remainder = Math.Abs((int)(id % (ulong)count));
|
||||
|
||||
return NadekoBot.Config.PokemonTypes[remainder];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PokemonType stringToPokemonType(string v)
|
||||
{
|
||||
var str = v.ToUpperInvariant();
|
||||
var list = NadekoBot.Config.PokemonTypes;
|
||||
foreach (PokemonType p in list)
|
||||
{
|
||||
if (str == p.Name)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "attack")
|
||||
.Description($"Attacks a target with the given move. Use `{Prefix}movelist` to see a list of moves your type can use. | `{Prefix}attack \"vine whip\" @someguy`")
|
||||
.Parameter("move", ParameterType.Required)
|
||||
.Parameter("target", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var move = e.GetArg("move");
|
||||
var targetStr = e.GetArg("target")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(targetStr))
|
||||
return;
|
||||
var target = e.Server.FindUsers(targetStr).FirstOrDefault();
|
||||
if (target == null)
|
||||
{
|
||||
await e.Channel.SendMessage("No such person.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else if (target == e.User)
|
||||
{
|
||||
await e.Channel.SendMessage("You can't attack yourself.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
// Checking stats first, then move
|
||||
//Set up the userstats
|
||||
PokeStats userStats;
|
||||
userStats = Stats.GetOrAdd(e.User.Id, new PokeStats());
|
||||
|
||||
//Check if able to move
|
||||
//User not able if HP < 0, has made more than 4 attacks
|
||||
if (userStats.Hp < 0)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} has fainted and was not able to move!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (userStats.MovesMade >= 5)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} has used too many moves in a row and was not able to move!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (userStats.LastAttacked.Contains(target.Id))
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} can't attack again without retaliation!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//get target stats
|
||||
PokeStats targetStats;
|
||||
targetStats = Stats.GetOrAdd(target.Id, new PokeStats());
|
||||
|
||||
//If target's HP is below 0, no use attacking
|
||||
if (targetStats.Hp <= 0)
|
||||
{
|
||||
await e.Channel.SendMessage($"{target.Mention} has already fainted!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Check whether move can be used
|
||||
PokemonType userType = GetPokeType(e.User.Id);
|
||||
|
||||
var enabledMoves = userType.Moves;
|
||||
if (!enabledMoves.Contains(move.ToLowerInvariant()))
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} was not able to use **{move}**, use `{Prefix}ml` to see moves you can use").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//get target type
|
||||
PokemonType targetType = GetPokeType(target.Id);
|
||||
//generate damage
|
||||
int damage = GetDamage(userType, targetType);
|
||||
//apply damage to target
|
||||
targetStats.Hp -= damage;
|
||||
|
||||
var response = $"{e.User.Mention} used **{move}**{userType.Icon} on {target.Mention}{targetType.Icon} for **{damage}** damage";
|
||||
|
||||
//Damage type
|
||||
if (damage < 40)
|
||||
{
|
||||
response += "\nIt's not effective..";
|
||||
}
|
||||
else if (damage > 60)
|
||||
{
|
||||
response += "\nIt's super effective!";
|
||||
}
|
||||
else
|
||||
{
|
||||
response += "\nIt's somewhat effective";
|
||||
}
|
||||
|
||||
//check fainted
|
||||
|
||||
if (targetStats.Hp <= 0)
|
||||
{
|
||||
response += $"\n**{target.Name}** has fainted!";
|
||||
}
|
||||
else
|
||||
{
|
||||
response += $"\n**{target.Name}** has {targetStats.Hp} HP remaining";
|
||||
}
|
||||
|
||||
//update other stats
|
||||
userStats.LastAttacked.Add(target.Id);
|
||||
userStats.MovesMade++;
|
||||
targetStats.MovesMade = 0;
|
||||
if (targetStats.LastAttacked.Contains(e.User.Id))
|
||||
{
|
||||
targetStats.LastAttacked.Remove(e.User.Id);
|
||||
}
|
||||
|
||||
//update dictionary
|
||||
//This can stay the same right?
|
||||
Stats[e.User.Id] = userStats;
|
||||
Stats[target.Id] = targetStats;
|
||||
|
||||
await e.Channel.SendMessage(response).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "movelist")
|
||||
.Alias(Prefix + "ml")
|
||||
.Description($"Lists the moves you are able to use | `{Prefix}ml`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var userType = GetPokeType(e.User.Id);
|
||||
var movesList = userType.Moves;
|
||||
var str = $"**Moves for `{userType.Name}` type.**";
|
||||
foreach (string m in movesList)
|
||||
{
|
||||
str += $"\n{userType.Icon}{m}";
|
||||
}
|
||||
await e.Channel.SendMessage(str).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "heal")
|
||||
.Description($"Heals someone. Revives those who fainted. Costs a {NadekoBot.Config.CurrencyName} | `{Prefix}heal @someone`")
|
||||
.Parameter("target", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var targetStr = e.GetArg("target")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(targetStr))
|
||||
return;
|
||||
var usr = e.Server.FindUsers(targetStr).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("No such person.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (Stats.ContainsKey(usr.Id))
|
||||
{
|
||||
|
||||
var targetStats = Stats[usr.Id];
|
||||
int HP = targetStats.Hp;
|
||||
if (targetStats.Hp == targetStats.MaxHp)
|
||||
{
|
||||
await e.Channel.SendMessage($"{usr.Name} already has full HP!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//Payment~
|
||||
var amount = 1;
|
||||
var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;
|
||||
if (pts < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} you don't have enough {NadekoBot.Config.CurrencyName}s! \nYou still need {amount - pts} {NadekoBot.Config.CurrencySign} to be able to do this!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name;
|
||||
await FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount).ConfigureAwait(false);
|
||||
//healing
|
||||
targetStats.Hp = targetStats.MaxHp;
|
||||
if (HP < 0)
|
||||
{
|
||||
//Could heal only for half HP?
|
||||
Stats[usr.Id].Hp = (targetStats.MaxHp / 2);
|
||||
await e.Channel.SendMessage($"{e.User.Name} revived {usr.Name} with one {NadekoBot.Config.CurrencySign}").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
|
||||
await e.Channel.SendMessage($"{e.User.Name} healed {usr.Name} for {targetStats.MaxHp - HP} HP with {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencySign}").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"{usr.Name} already has full HP!").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "type")
|
||||
.Description($"Get the poketype of the target. | `{Prefix}type @someone`")
|
||||
.Parameter("target", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usrStr = e.GetArg("target")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(usrStr))
|
||||
return;
|
||||
var usr = e.Server.FindUsers(usrStr).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("No such person.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var pType = GetPokeType(usr.Id);
|
||||
await e.Channel.SendMessage($"Type of {usr.Name} is **{pType.Name.ToLowerInvariant()}**{pType.Icon}").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "settype")
|
||||
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}. | `{Prefix}settype fire`")
|
||||
.Parameter("targetType", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var targetTypeStr = e.GetArg("targetType")?.ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(targetTypeStr))
|
||||
return;
|
||||
var targetType = stringToPokemonType(targetTypeStr);
|
||||
if (targetType == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Invalid type specified. Type must be one of:\n" + string.Join(", ", NadekoBot.Config.PokemonTypes.Select(t => t.Name.ToUpperInvariant()))).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (targetType == GetPokeType(e.User.Id))
|
||||
{
|
||||
await e.Channel.SendMessage($"Your type is already {targetType.Name.ToLowerInvariant()}{targetType.Icon}").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Payment~
|
||||
var amount = 1;
|
||||
var pts = DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;
|
||||
if (pts < amount)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} you don't have enough {NadekoBot.Config.CurrencyName}s! \nYou still need {amount - pts} {NadekoBot.Config.CurrencySign} to be able to do this!").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount).ConfigureAwait(false);
|
||||
//Actually changing the type here
|
||||
var preTypes = DbHandler.Instance.GetAllRows<UserPokeTypes>();
|
||||
Dictionary<long, int> Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id.Value);
|
||||
if (Dict.ContainsKey((long)e.User.Id))
|
||||
{
|
||||
//delete previous type
|
||||
DbHandler.Instance.Delete<UserPokeTypes>(Dict[(long)e.User.Id]);
|
||||
}
|
||||
|
||||
DbHandler.Instance.Connection.Insert(new UserPokeTypes
|
||||
{
|
||||
UserId = (long)e.User.Id,
|
||||
type = targetType.Name
|
||||
}, typeof(UserPokeTypes));
|
||||
|
||||
//Now for the response
|
||||
|
||||
await e.Channel.SendMessage($"Set type of {e.User.Mention} to {targetTypeStr}{targetType.Icon} for a {NadekoBot.Config.CurrencySign}").ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,92 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// I have no idea what am i doing
|
||||
/// </summary>
|
||||
namespace NadekoBot.Modules.Programming.Commands
|
||||
{
|
||||
class HaskellRepl : DiscordCommand
|
||||
{
|
||||
ConcurrentQueue<KeyValuePair<string, Channel>> commandQueue = new ConcurrentQueue<KeyValuePair<string, Channel>>();
|
||||
|
||||
Thread haskellThread;
|
||||
|
||||
public HaskellRepl(DiscordModule module) : base(module)
|
||||
{
|
||||
//start haskell interpreter
|
||||
|
||||
haskellThread = new Thread(new ThreadStart(() =>
|
||||
{
|
||||
var p = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "stack", //shouldn't use repl, but a Language.Haskell.Interpreter somehow
|
||||
Arguments = "repl",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true,
|
||||
});
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (commandQueue.Count == 0)
|
||||
await Task.Delay(100);
|
||||
|
||||
//read from queue
|
||||
KeyValuePair<string, Channel> com;
|
||||
if (!commandQueue.TryDequeue(out com))
|
||||
{
|
||||
await Task.Delay(100);
|
||||
continue;
|
||||
}
|
||||
//var bytes = Encoding.ASCII.GetBytes(com.Key);
|
||||
|
||||
//send the command to the process
|
||||
p.StandardInput.WriteLine(com.Key);
|
||||
|
||||
//wait 50 ms for execution
|
||||
await Task.Delay(50);
|
||||
|
||||
//read everything from the output
|
||||
var outBuffer = new byte[1500];
|
||||
|
||||
p.StandardOutput.BaseStream.Read(outBuffer, 0, 1500);
|
||||
|
||||
var outStr = Encoding.ASCII.GetString(outBuffer);
|
||||
//send to channel
|
||||
await com.Value.SendMessage($"```hs\nPrelude> {com.Key}\n" + outStr + "\n```");
|
||||
}
|
||||
});
|
||||
|
||||
}));
|
||||
haskellThread.Start();
|
||||
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "hs")
|
||||
.Description("Executes a haskell express with LAMBDABOT")
|
||||
.Parameter("command", ParameterType.Unparsed)
|
||||
.Do(e =>
|
||||
{
|
||||
var com = e.GetArg("command")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(com))
|
||||
return;
|
||||
|
||||
//send a command and a channel to the queue
|
||||
commandQueue.Enqueue(new KeyValuePair<string, Channel>(com, e.Channel));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Programming.Commands;
|
||||
|
||||
namespace NadekoBot.Modules.Programming
|
||||
{
|
||||
class ProgrammingModule : DiscordModule
|
||||
{
|
||||
public override string Prefix => NadekoBot.Config.CommandPrefixes.Programming;
|
||||
|
||||
public ProgrammingModule()
|
||||
{
|
||||
commands.Add(new HaskellRepl(this));
|
||||
}
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
commands.ForEach(c => c.Init(cgb));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using ScaredFingers.UnitsConversion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class ConverterCommand : DiscordCommand
|
||||
{
|
||||
|
||||
public ConverterCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
if (unitTables == null)
|
||||
{
|
||||
CultureInfo ci = new CultureInfo("en-US");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
unitTables = new List<UnitTable>();
|
||||
unitTables.Add(UnitTable.LengthTable);
|
||||
unitTables.Add(UnitTable.TemperatureTable);
|
||||
unitTables.Add(UnitTable.VolumeTable);
|
||||
unitTables.Add(UnitTable.WeightTable);
|
||||
reInitCurrencyConverterTable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "convert")
|
||||
.Description($"Convert quantities from>to. | `{Prefix}convert m>km 1000`")
|
||||
.Parameter("from-to", ParameterType.Required)
|
||||
.Parameter("quantity", ParameterType.Optional)
|
||||
.Do(ConvertFunc());
|
||||
cgb.CreateCommand(Module.Prefix + "convertlist")
|
||||
.Description("List of the convertable dimensions and currencies.")
|
||||
.Do(ConvertListFunc());
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> ConvertListFunc() =>
|
||||
async e =>
|
||||
{
|
||||
reInitCurrencyConverterTable();
|
||||
string msg = "";
|
||||
foreach (var tmpTable in unitTables)
|
||||
{
|
||||
int i = 1;
|
||||
while (tmpTable.IsKnownUnit(i))
|
||||
{
|
||||
msg += tmpTable.GetUnitName(i) + " (" + tmpTable.GetUnitSymbol(i) + "); ";
|
||||
i++;
|
||||
}
|
||||
msg += "\n";
|
||||
}
|
||||
foreach (var curr in exchangeRateProvider.Currencies)
|
||||
{
|
||||
msg += curr + "; ";
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(msg).ConfigureAwait(false);
|
||||
};
|
||||
|
||||
private Func<CommandEventArgs, Task> ConvertFunc() =>
|
||||
async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
|
||||
string from = e.GetArg("from-to").ToLowerInvariant().Split('>')[0];
|
||||
string to = e.GetArg("from-to").ToLowerInvariant().Split('>')[1];
|
||||
|
||||
float quantity = 1.0f;
|
||||
if (!float.TryParse(e.GetArg("quantity"), out quantity))
|
||||
{
|
||||
quantity = 1.0f;
|
||||
}
|
||||
|
||||
int fromCode, toCode = 0;
|
||||
UnitTable table = null;
|
||||
ResolveUnitCodes(from, to, out table, out fromCode, out toCode);
|
||||
|
||||
if (table != null)
|
||||
{
|
||||
Unit inUnit = new Unit(fromCode, quantity, table);
|
||||
Unit outUnit = inUnit.Convert(toCode);
|
||||
await e.Channel.SendMessage(inUnit.ToString() + " = " + outUnit.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CultureInfo ci = new CultureInfo("en-US");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
reInitCurrencyConverterTable();
|
||||
Unit inUnit = currTable.CreateUnit(quantity, from.ToUpperInvariant());
|
||||
Unit outUnit = inUnit.Convert(currTable.CurrencyCode(to.ToUpperInvariant()));
|
||||
await e.Channel.SendMessage(inUnit.ToString() + " = " + outUnit.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch //(Exception ex)
|
||||
{
|
||||
//Console.WriteLine(ex.ToString());
|
||||
await e.Channel.SendMessage("Bad input format, or sth went wrong... Try to list them with `" + Module.Prefix + "`convertlist").ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
|
||||
private void reInitCurrencyConverterTable()
|
||||
{
|
||||
if (lastChanged == null || lastChanged.DayOfYear != DateTime.Now.DayOfYear)
|
||||
{
|
||||
try
|
||||
{
|
||||
exchangeRateProvider = new WebExchangeRatesProvider();
|
||||
currTable = new CurrencyExchangeTable(exchangeRateProvider);
|
||||
lastChanged = DateTime.Now;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Error with the currency download.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveUnitCodes(string from, string to, out UnitTable table, out int fromCode, out int toCode)
|
||||
{
|
||||
foreach (var tmpTable in unitTables)
|
||||
{
|
||||
int f = LookupUnit(tmpTable, from);
|
||||
int t = LookupUnit(tmpTable, to);
|
||||
if (f > 0 && t > 0)
|
||||
{
|
||||
table = tmpTable;
|
||||
fromCode = f;
|
||||
toCode = t;
|
||||
return;
|
||||
}
|
||||
}
|
||||
table = null;
|
||||
fromCode = 0;
|
||||
toCode = 0;
|
||||
}
|
||||
|
||||
private int LookupUnit(UnitTable table, string lookup)
|
||||
{
|
||||
string wellformedLookup = lookup.ToLowerInvariant().Replace("°", "");
|
||||
int i = 1;
|
||||
while (table.IsKnownUnit(i))
|
||||
{
|
||||
if (wellformedLookup == table.GetUnitName(i).ToLowerInvariant().Replace("°", "") ||
|
||||
wellformedLookup == table.GetUnitPlural(i).ToLowerInvariant().Replace("°", "") ||
|
||||
wellformedLookup == table.GetUnitSymbol(i).ToLowerInvariant().Replace("°", ""))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static List<UnitTable> unitTables;
|
||||
|
||||
private static CurrencyExchangeRatesProvider exchangeRateProvider;
|
||||
|
||||
private static CurrencyExchangeTable currTable;
|
||||
|
||||
private static DateTime lastChanged;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Mathos.Parser;
|
||||
using NadekoBot.Classes;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class CalcCommand : DiscordCommand
|
||||
{
|
||||
public CalcCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "calculate")
|
||||
.Alias(Module.Prefix + "calc")
|
||||
.Description($"Evaluate a mathematical expression. | `{Prefix}calc 1+1`")
|
||||
.Parameter("expression", ParameterType.Unparsed)
|
||||
.Do(EvalFunc());
|
||||
}
|
||||
|
||||
|
||||
private CustomParser parser = new CustomParser();
|
||||
private Func<CommandEventArgs, Task> EvalFunc() => async e =>
|
||||
{
|
||||
string expression = e.GetArg("expression")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string answer = Evaluate(expression);
|
||||
if (answer == null)
|
||||
{
|
||||
await e.Channel.SendMessage($"Expression {expression} failed to evaluate");
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage($"⚙ `{answer}`");
|
||||
};
|
||||
|
||||
private string Evaluate(string expression)
|
||||
{
|
||||
//check for factorial
|
||||
expression = Regex.Replace(expression, @"\d+!", x => x.Value + "0");
|
||||
try
|
||||
{
|
||||
string result = parser.Parse(expression).ToString();
|
||||
return result;
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return $"Overflow error on {expression}";
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return $"\"{expression}\" was not formatted correctly";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CustomParser : MathParser
|
||||
{
|
||||
public CustomParser() : base()
|
||||
{
|
||||
OperatorList.Add("!");
|
||||
OperatorAction.Add("!", (x, y) => Factorial(x));
|
||||
}
|
||||
|
||||
static decimal Factorial(decimal x)
|
||||
{
|
||||
decimal y = x - 1;
|
||||
while (y > 0)
|
||||
{
|
||||
x = x * y--;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using NadekoBot.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Web;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands.IMDB
|
||||
{
|
||||
public class ImdbMovie
|
||||
{
|
||||
public bool Status { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string OriginalTitle { get; set; }
|
||||
public string Year { get; set; }
|
||||
public string Rating { get; set; }
|
||||
public string Plot { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
//public ArrayList Directors { get; set; }
|
||||
//public ArrayList Writers { get; set; }
|
||||
//public ArrayList Cast { get; set; }
|
||||
//public ArrayList Producers { get; set; }
|
||||
//public ArrayList Musicians { get; set; }
|
||||
//public ArrayList Cinematographers { get; set; }
|
||||
//public ArrayList Editors { get; set; }
|
||||
//public string MpaaRating { get; set; }
|
||||
//public string ReleaseDate { get; set; }
|
||||
//public ArrayList PlotKeywords { get; set; }
|
||||
//public string PosterLarge { get; set; }
|
||||
//public string PosterFull { get; set; }
|
||||
//public string Runtime { get; set; }
|
||||
//public string Top250 { get; set; }
|
||||
//public string Oscars { get; set; }
|
||||
//public string Awards { get; set; }
|
||||
//public string Nominations { get; set; }
|
||||
//public string Storyline { get; set; }
|
||||
//public string Tagline { get; set; }
|
||||
//public string Votes { get; set; }
|
||||
//public ArrayList Languages { get; set; }
|
||||
//public ArrayList Countries { get; set; }
|
||||
//public Dictionary<string, string> ReleaseDates { get; set; }
|
||||
//public ArrayList MediaImages { get; set; }
|
||||
//public ArrayList RecommendedTitles { get; set; }
|
||||
public string ImdbURL { get; set; }
|
||||
|
||||
public Dictionary<string, string> Aka { get; set; }
|
||||
|
||||
public override string ToString() =>
|
||||
$@"`Title:` {HttpUtility.HtmlDecode(Title)} {(string.IsNullOrEmpty(OriginalTitle) ? "" : $"({OriginalTitle})")}
|
||||
`Year:` {Year}
|
||||
`Rating:` {Rating}
|
||||
`Genre:` {GenresAsString}
|
||||
`Link:` <{ImdbURL}>
|
||||
`Plot:` {System.Net.WebUtility.HtmlDecode(Plot.TrimTo(500))}
|
||||
`img:` " + Poster.ShortenUrl().Result;
|
||||
|
||||
//public string EnglishTitle => Aka.ContainsKey("USA") ? Aka["USA"] :
|
||||
// (Aka.ContainsKey("UK") ? Aka["UK"] :
|
||||
// (Aka.ContainsKey("(original title)") ? Aka["(original title)"] :
|
||||
// (Aka.ContainsKey("(original)") ? Aka["(original)"] : OriginalTitle)));
|
||||
public string GenresAsString =>
|
||||
string.Join(", ", Genres);
|
||||
}
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/*******************************************************************************
|
||||
* Free ASP.net IMDb Scraper API for the new IMDb Template.
|
||||
* Author: Abhinay Rathore
|
||||
* Website: http://www.AbhinayRathore.com
|
||||
* Blog: http://web3o.blogspot.com
|
||||
* More Info: http://web3o.blogspot.com/2010/11/aspnetc-imdb-scraping-api.html
|
||||
|
||||
* Updated By: Gergo Torcsvari
|
||||
* Last Updated: Feb, 2016
|
||||
*******************************************************************************/
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands.IMDB
|
||||
{
|
||||
public static class ImdbScraper
|
||||
{
|
||||
//Search Engine URLs
|
||||
private static string GoogleSearch = "https://www.google.com/search?q=imdb+";
|
||||
private static string BingSearch = "http://www.bing.com/search?q=imdb+";
|
||||
private static string AskSearch = "http://www.ask.com/web?q=imdb+";
|
||||
//Constructor
|
||||
public static ImdbMovie ImdbScrape(string MovieName, bool GetExtraInfo = true)
|
||||
{
|
||||
ImdbMovie mov = new ImdbMovie();
|
||||
string imdbUrl = GetIMDbUrl(System.Uri.EscapeUriString(MovieName));
|
||||
mov.Status = false;
|
||||
if (!string.IsNullOrWhiteSpace(imdbUrl))
|
||||
{
|
||||
ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
|
||||
}
|
||||
|
||||
return mov;
|
||||
}
|
||||
|
||||
public static ImdbMovie ImdbScrapeFromId(string imdbId, bool GetExtraInfo = true)
|
||||
{
|
||||
ImdbMovie mov = new ImdbMovie();
|
||||
string imdbUrl = "http://www.imdb.com/title/" + imdbId + "/";
|
||||
mov.Status = false;
|
||||
ParseIMDbPage(imdbUrl, GetExtraInfo, mov);
|
||||
return mov;
|
||||
}
|
||||
|
||||
public static string GetIMDBId(string MovieName)
|
||||
{
|
||||
string imdbUrl = GetIMDbUrl(System.Uri.EscapeUriString(MovieName));
|
||||
return match(@"http://www.imdb.com/title/(tt\d{7})", imdbUrl);
|
||||
}
|
||||
//Get IMDb URL from search results
|
||||
private static string GetIMDbUrl(string MovieName, string searchEngine = "google")
|
||||
{
|
||||
string url = GoogleSearch + MovieName; //default to Google search
|
||||
if (searchEngine.ToLower().Equals("bing")) url = BingSearch + MovieName;
|
||||
if (searchEngine.ToLower().Equals("ask")) url = AskSearch + MovieName;
|
||||
string html = GetUrlData(url);
|
||||
ArrayList imdbUrls = MatchAll(@"<a href=""(http://www.imdb.com/title/tt\d{7}/)"".*?>.*?</a>", html);
|
||||
if (imdbUrls.Count > 0)
|
||||
return (string)imdbUrls[0]; //return first IMDb result
|
||||
else if (searchEngine.ToLower().Equals("google")) //if Google search fails
|
||||
return GetIMDbUrl(MovieName, "bing"); //search using Bing
|
||||
else if (searchEngine.ToLower().Equals("bing")) //if Bing search fails
|
||||
return GetIMDbUrl(MovieName, "ask"); //search using Ask
|
||||
else //search fails
|
||||
return string.Empty;
|
||||
}
|
||||
//Parse IMDb page data
|
||||
private static void ParseIMDbPage(string imdbUrl, bool GetExtraInfo, ImdbMovie mov)
|
||||
{
|
||||
string html = GetUrlData(imdbUrl + "combined");
|
||||
mov.Id = match(@"<link rel=""canonical"" href=""http://www.imdb.com/title/(tt\d{7})/combined"" />", html);
|
||||
if (!string.IsNullOrEmpty(mov.Id))
|
||||
{
|
||||
mov.Status = true;
|
||||
mov.Title = match(@"<title>(IMDb \- )*(.*?) \(.*?</title>", html, 2);
|
||||
mov.OriginalTitle = match(@"title-extra"">(.*?)<", html);
|
||||
mov.Year = match(@"<title>.*?\(.*?(\d{4}).*?\).*?</title>", match(@"(<title>.*?</title>)", html));
|
||||
mov.Rating = match(@"<b>(\d.\d)/10</b>", html);
|
||||
mov.Genres = MatchAll(@"<a.*?>(.*?)</a>", match(@"Genre.?:(.*?)(</div>|See more)", html)).Cast<string>().ToList();
|
||||
mov.Plot = match(@"Plot:</h5>.*?<div class=""info-content"">(.*?)(<a|</div)", html);
|
||||
//mov.Directors = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Directed by</a></h5>(.*?)</table>", html));
|
||||
//mov.Writers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Writing credits</a></h5>(.*?)</table>", html));
|
||||
//mov.Producers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Produced by</a></h5>(.*?)</table>", html));
|
||||
//mov.Musicians = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Original Music by</a></h5>(.*?)</table>", html));
|
||||
//mov.Cinematographers = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Cinematography by</a></h5>(.*?)</table>", html));
|
||||
//mov.Editors = matchAll(@"<td valign=""top""><a.*?href=""/name/.*?/"">(.*?)</a>", match(@"Film Editing by</a></h5>(.*?)</table>", html));
|
||||
//mov.Cast = matchAll(@"<td class=""nm""><a.*?href=""/name/.*?/"".*?>(.*?)</a>", match(@"<h3>Cast</h3>(.*?)</table>", html));
|
||||
//mov.PlotKeywords = matchAll(@"<a.*?>(.*?)</a>", match(@"Plot Keywords:</h5>.*?<div class=""info-content"">(.*?)</div", html));
|
||||
//mov.ReleaseDate = match(@"Release Date:</h5>.*?<div class=""info-content"">.*?(\d{1,2} (January|February|March|April|May|June|July|August|September|October|November|December) (19|20)\d{2})", html);
|
||||
//mov.Runtime = match(@"Runtime:</h5><div class=""info-content"">(\d{1,4}) min[\s]*.*?</div>", html);
|
||||
//mov.Top250 = match(@"Top 250: #(\d{1,3})<", html);
|
||||
//mov.Oscars = match(@"Won (\d+) Oscars?\.", html);
|
||||
//if (string.IsNullOrEmpty(mov.Oscars) && "Won Oscar.".Equals(match(@"(Won Oscar\.)", html))) mov.Oscars = "1";
|
||||
//mov.Awards = match(@"(\d{1,4}) wins", html);
|
||||
//mov.Nominations = match(@"(\d{1,4}) nominations", html);
|
||||
//mov.Tagline = match(@"Tagline:</h5>.*?<div class=""info-content"">(.*?)(<a|</div)", html);
|
||||
//mov.MpaaRating = match(@"MPAA</a>:</h5><div class=""info-content"">Rated (G|PG|PG-13|PG-14|R|NC-17|X) ", html);
|
||||
//mov.Votes = match(@">(\d+,?\d*) votes<", html);
|
||||
//mov.Languages = matchAll(@"<a.*?>(.*?)</a>", match(@"Language.?:(.*?)(</div>|>.?and )", html));
|
||||
//mov.Countries = matchAll(@"<a.*?>(.*?)</a>", match(@"Country:(.*?)(</div>|>.?and )", html));
|
||||
mov.Poster = match(@"<div class=""photo"">.*?<a name=""poster"".*?><img.*?src=""(.*?)"".*?</div>", html);
|
||||
if (!string.IsNullOrEmpty(mov.Poster) && mov.Poster.IndexOf("media-imdb.com") > 0)
|
||||
{
|
||||
mov.Poster = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY200.jpg");
|
||||
//mov.PosterLarge = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY500.jpg");
|
||||
//mov.PosterFull = Regex.Replace(mov.Poster, @"_V1.*?.jpg", "_V1._SY0.jpg");
|
||||
}
|
||||
else
|
||||
{
|
||||
mov.Poster = string.Empty;
|
||||
//mov.PosterLarge = string.Empty;
|
||||
//mov.PosterFull = string.Empty;
|
||||
}
|
||||
mov.ImdbURL = "http://www.imdb.com/title/" + mov.Id + "/";
|
||||
if (GetExtraInfo)
|
||||
{
|
||||
string plotHtml = GetUrlData(imdbUrl + "plotsummary");
|
||||
//mov.Storyline = match(@"<p class=""plotpar"">(.*?)(<i>|</p>)", plotHtml);
|
||||
GetReleaseDatesAndAka(mov);
|
||||
//mov.MediaImages = getMediaImages(mov);
|
||||
//mov.RecommendedTitles = getRecommendedTitles(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Get all release dates and aka-s
|
||||
private static void GetReleaseDatesAndAka(ImdbMovie mov)
|
||||
{
|
||||
Dictionary<string, string> release = new Dictionary<string, string>();
|
||||
string releasehtml = GetUrlData("http://www.imdb.com/title/" + mov.Id + "/releaseinfo");
|
||||
foreach (string r in MatchAll(@"<tr class="".*?"">(.*?)</tr>", match(@"<table id=""release_dates"" class=""subpage_data spFirst"">\n*?(.*?)</table>", releasehtml)))
|
||||
{
|
||||
Match rd = new Regex(@"<td>(.*?)</td>\n*?.*?<td class=.*?>(.*?)</td>", RegexOptions.Multiline).Match(r);
|
||||
release[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
|
||||
}
|
||||
//mov.ReleaseDates = release;
|
||||
|
||||
Dictionary<string, string> aka = new Dictionary<string, string>();
|
||||
ArrayList list = MatchAll(@".*?<tr class="".*?"">(.*?)</tr>", match(@"<table id=""akas"" class=.*?>\n*?(.*?)</table>", releasehtml));
|
||||
foreach (string r in list)
|
||||
{
|
||||
Match rd = new Regex(@"\n*?.*?<td>(.*?)</td>\n*?.*?<td>(.*?)</td>", RegexOptions.Multiline).Match(r);
|
||||
aka[StripHTML(rd.Groups[1].Value.Trim())] = StripHTML(rd.Groups[2].Value.Trim());
|
||||
}
|
||||
mov.Aka = aka;
|
||||
|
||||
|
||||
|
||||
}
|
||||
//Get all media images
|
||||
private static ArrayList GetMediaImages(ImdbMovie mov)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
string mediaurl = "http://www.imdb.com/title/" + mov.Id + "/mediaindex";
|
||||
string mediahtml = GetUrlData(mediaurl);
|
||||
int pagecount = MatchAll(@"<a href=""\?page=(.*?)"">", match(@"<span style=""padding: 0 1em;"">(.*?)</span>", mediahtml)).Count;
|
||||
for (int p = 1; p <= pagecount + 1; p++)
|
||||
{
|
||||
mediahtml = GetUrlData(mediaurl + "?page=" + p);
|
||||
foreach (Match m in new Regex(@"src=""(.*?)""", RegexOptions.Multiline).Matches(match(@"<div class=""thumb_list"" style=""font-size: 0px;"">(.*?)</div>", mediahtml)))
|
||||
{
|
||||
String image = m.Groups[1].Value;
|
||||
list.Add(Regex.Replace(image, @"_V1\..*?.jpg", "_V1._SY0.jpg"));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
//Get Recommended Titles
|
||||
private static ArrayList GetRecommendedTitles(ImdbMovie mov)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
string recUrl = "http://www.imdb.com/widget/recommendations/_ajax/get_more_recs?specs=p13nsims%3A" + mov.Id;
|
||||
string json = GetUrlData(recUrl);
|
||||
list = MatchAll(@"title=\\""(.*?)\\""", json);
|
||||
HashSet<String> set = new HashSet<string>();
|
||||
foreach (String rec in list) set.Add(rec);
|
||||
return new ArrayList(set.ToList());
|
||||
}
|
||||
/*******************************[ Helper Methods ]********************************/
|
||||
//Match single instance
|
||||
private static string match(string regex, string html, int i = 1)
|
||||
{
|
||||
return new Regex(regex, RegexOptions.Multiline).Match(html).Groups[i].Value.Trim();
|
||||
}
|
||||
//Match all instances and return as ArrayList
|
||||
private static ArrayList MatchAll(string regex, string html, int i = 1)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
foreach (Match m in new Regex(regex, RegexOptions.Multiline).Matches(html))
|
||||
list.Add(m.Groups[i].Value.Trim());
|
||||
return list;
|
||||
}
|
||||
//Strip HTML Tags
|
||||
private static string StripHTML(string inputString)
|
||||
{
|
||||
return Regex.Replace(inputString, @"<.*?>", string.Empty);
|
||||
}
|
||||
//Get URL Data
|
||||
private static string GetUrlData(string url)
|
||||
{
|
||||
WebClient client = new WebClient();
|
||||
Random r = new Random();
|
||||
//Random IP Address
|
||||
//client.Headers["X-Forwarded-For"] = r.Next(0, 255) + "." + r.Next(0, 255) + "." + r.Next(0, 255) + "." + r.Next(0, 255);
|
||||
//Random User-Agent
|
||||
client.Headers["User-Agent"] = "Mozilla/" + r.Next(3, 5) + ".0 (Windows NT " + r.Next(3, 5) + "." + r.Next(0, 2) + "; rv:37.0) Gecko/20100101 Firefox/" + r.Next(30, 37) + "." + r.Next(0, 5);
|
||||
Stream datastream = client.OpenRead(url);
|
||||
StreamReader reader = new StreamReader(datastream);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
//TODO: Coud be reader error must catch and drop!!!
|
||||
while (!reader.EndOfStream)
|
||||
sb.Append(reader.ReadLine());
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,383 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class LoLCommands : DiscordCommand
|
||||
{
|
||||
|
||||
private class CachedChampion
|
||||
{
|
||||
public System.IO.Stream ImageStream { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
private class ChampionNameComparer : IEqualityComparer<JToken>
|
||||
{
|
||||
public bool Equals(JToken a, JToken b) => a["name"].ToString() == b["name"].ToString();
|
||||
|
||||
public int GetHashCode(JToken obj) =>
|
||||
obj["name"].GetHashCode();
|
||||
}
|
||||
|
||||
private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>();
|
||||
|
||||
private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer();
|
||||
public LoLCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
clearTimer.Interval = new TimeSpan(0, 10, 0).TotalMilliseconds;
|
||||
clearTimer.Start();
|
||||
clearTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
CachedChampionImages = CachedChampionImages
|
||||
.Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private readonly string[] trashTalk = { "Better ban your counters. You are going to carry the game anyway.",
|
||||
"Go with the flow. Don't think. Just ban one of these.",
|
||||
"DONT READ BELOW! Ban Urgot mid OP 100%. Im smurf Diamond 1.",
|
||||
"Ask your teammates what would they like to play, and ban that.",
|
||||
"If you consider playing teemo, do it. If you consider teemo, you deserve him.",
|
||||
"Doesn't matter what you ban really. Enemy will ban your main and you will lose." };
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private class MatchupModel
|
||||
{
|
||||
public int Games { get; set; }
|
||||
public float WinRate { get; set; }
|
||||
[Newtonsoft.Json.JsonProperty("key")]
|
||||
public string Name { get; set; }
|
||||
public float StatScore { get; set; }
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "lolchamp")
|
||||
.Description($"Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. |`{Prefix}lolchamp Riven` or `{Prefix}lolchamp Annie sup`")
|
||||
.Parameter("champ", ParameterType.Required)
|
||||
.Parameter("position", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
//get role
|
||||
var role = ResolvePos(e.GetArg("position"));
|
||||
var resolvedRole = role;
|
||||
var name = e.GetArg("champ").Replace(" ", "").ToLower();
|
||||
CachedChampion champ = null;
|
||||
|
||||
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
|
||||
if (champ != null)
|
||||
{
|
||||
champ.ImageStream.Position = 0;
|
||||
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}").ConfigureAwait(false));
|
||||
JToken data = null;
|
||||
if (role != null)
|
||||
{
|
||||
for (var i = 0; i < allData.Count; i++)
|
||||
{
|
||||
if (allData[i]["role"].ToString().Equals(role))
|
||||
{
|
||||
data = allData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data == null)
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Data for that role does not exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = allData[0];
|
||||
role = allData[0]["role"].ToString();
|
||||
resolvedRole = ResolvePos(role);
|
||||
}
|
||||
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
|
||||
if (champ != null)
|
||||
{
|
||||
champ.ImageStream.Position = 0;
|
||||
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//name = data["title"].ToString();
|
||||
// get all possible roles, and "select" the shown one
|
||||
var roles = new string[allData.Count];
|
||||
for (var i = 0; i < allData.Count; i++)
|
||||
{
|
||||
roles[i] = allData[i]["role"].ToString();
|
||||
if (roles[i] == role)
|
||||
roles[i] = ">" + roles[i] + "<";
|
||||
}
|
||||
var general = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.champion.gg/stats/" +
|
||||
$"champs/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")
|
||||
.ConfigureAwait(false))
|
||||
.FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
||||
if (general == null)
|
||||
{
|
||||
Console.WriteLine("General is null.");
|
||||
return;
|
||||
}
|
||||
//get build data for this role
|
||||
var buildData = data["items"]["mostGames"]["items"];
|
||||
var items = new string[6];
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
items[i] = buildData[i]["id"].ToString();
|
||||
}
|
||||
|
||||
//get matchup data to show counters and countered champions
|
||||
var matchupDataIE = data["matchups"].ToObject<List<MatchupModel>>();
|
||||
|
||||
var matchupData = matchupDataIE.OrderBy(m => m.StatScore).ToArray();
|
||||
|
||||
var countered = new[] { matchupData[0].Name, matchupData[1].Name, matchupData[2].Name };
|
||||
var counters = new[] { matchupData[matchupData.Length - 1].Name, matchupData[matchupData.Length - 2].Name, matchupData[matchupData.Length - 3].Name };
|
||||
|
||||
//get runes data
|
||||
var runesJArray = data["runes"]["mostGames"]["runes"] as JArray;
|
||||
var runes = string.Join("\n", runesJArray.OrderBy(jt => int.Parse(jt["number"].ToString())).Select(jt => jt["number"].ToString() + "x" + jt["name"]));
|
||||
|
||||
// get masteries data
|
||||
|
||||
var masteries = (data["masteries"]["mostGames"]["masteries"] as JArray);
|
||||
|
||||
//get skill order data<API_KEY>
|
||||
|
||||
var orderArr = (data["skills"]["mostGames"]["order"] as JArray);
|
||||
|
||||
var img = Image.FromFile("data/lol/bg.png");
|
||||
using (var g = Graphics.FromImage(img))
|
||||
{
|
||||
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
||||
//g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
|
||||
const int margin = 5;
|
||||
const int imageSize = 75;
|
||||
var normalFont = new Font("Monaco", 8, FontStyle.Regular);
|
||||
var smallFont = new Font("Monaco", 7, FontStyle.Regular);
|
||||
//draw champ image
|
||||
var champName = data["key"].ToString().Replace(" ", "");
|
||||
|
||||
g.DrawImage(GetImage(champName), new Rectangle(margin, margin, imageSize, imageSize));
|
||||
//draw champ name
|
||||
if (champName == "MonkeyKing")
|
||||
champName = "Wukong";
|
||||
g.DrawString($"{champName}", new Font("Times New Roman", 24, FontStyle.Regular), Brushes.WhiteSmoke, margin + imageSize + margin, margin);
|
||||
//draw champ surname
|
||||
|
||||
//draw skill order
|
||||
if (orderArr.Count != 0)
|
||||
{
|
||||
float orderFormula = 120 / orderArr.Count;
|
||||
const float orderVerticalSpacing = 10;
|
||||
for (var i = 0; i < orderArr.Count; i++)
|
||||
{
|
||||
var orderX = margin + margin + imageSize + orderFormula * i + i;
|
||||
float orderY = margin + 35;
|
||||
var spellName = orderArr[i].ToString().ToLowerInvariant();
|
||||
|
||||
switch (spellName)
|
||||
{
|
||||
case "w":
|
||||
orderY += orderVerticalSpacing;
|
||||
break;
|
||||
case "e":
|
||||
orderY += orderVerticalSpacing * 2;
|
||||
break;
|
||||
case "r":
|
||||
orderY += orderVerticalSpacing * 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g.DrawString(spellName.ToUpperInvariant(), new Font("Monaco", 7), Brushes.LimeGreen, orderX, orderY);
|
||||
}
|
||||
}
|
||||
//draw roles
|
||||
g.DrawString("Roles: " + string.Join(", ", roles), normalFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin);
|
||||
|
||||
//draw average stats
|
||||
g.DrawString(
|
||||
$@" Average Stats
|
||||
|
||||
Kills: {general["kills"]} CS: {general["minionsKilled"]}
|
||||
Deaths: {general["deaths"]} Win: {general["winPercent"]}%
|
||||
Assists: {general["assists"]} Ban: {general["banRate"]}%
|
||||
", normalFont, Brushes.WhiteSmoke, img.Width - 150, margin);
|
||||
//draw masteries
|
||||
g.DrawString($"Masteries: {string.Join(" / ", masteries?.Select(jt => jt["total"]))}", normalFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin + 20);
|
||||
//draw runes
|
||||
g.DrawString($"{runes}", smallFont, Brushes.WhiteSmoke, margin, margin + imageSize + margin + 40);
|
||||
//draw counters
|
||||
g.DrawString($"Best against", smallFont, Brushes.WhiteSmoke, margin, img.Height - imageSize + margin);
|
||||
var smallImgSize = 50;
|
||||
|
||||
for (var i = 0; i < counters.Length; i++)
|
||||
{
|
||||
g.DrawImage(GetImage(counters[i]),
|
||||
new Rectangle(i * (smallImgSize + margin) + margin, img.Height - smallImgSize - margin,
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
//draw countered by
|
||||
g.DrawString($"Worst against", smallFont, Brushes.WhiteSmoke, img.Width - 3 * (smallImgSize + margin), img.Height - imageSize + margin);
|
||||
|
||||
for (var i = 0; i < countered.Length; i++)
|
||||
{
|
||||
var j = countered.Length - i;
|
||||
g.DrawImage(GetImage(countered[i]),
|
||||
new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), img.Height - smallImgSize - margin,
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
//draw item build
|
||||
g.DrawString("Popular build", normalFont, Brushes.WhiteSmoke, img.Width - (3 * (smallImgSize + margin) + margin), 77);
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
var inverseI = 5 - i;
|
||||
var j = inverseI % 3 + 1;
|
||||
var k = inverseI / 3;
|
||||
g.DrawImage(GetImage(items[i], GetImageType.Item),
|
||||
new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), 92 + k * (smallImgSize + margin),
|
||||
smallImgSize,
|
||||
smallImgSize));
|
||||
}
|
||||
}
|
||||
var cachedChamp = new CachedChampion { AddedAt = DateTime.Now, ImageStream = img.ToStream(System.Drawing.Imaging.ImageFormat.Png), Name = name.ToLower() + "_" + resolvedRole };
|
||||
CachedChampionImages.Add(cachedChamp.Name, cachedChamp);
|
||||
await e.Channel.SendFile(data["title"] + "_stats.png", cachedChamp.ImageStream).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
await e.Channel.SendMessage("💢 Failed retreiving data for that champion.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "lolban")
|
||||
.Description($"Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time. | `{Prefix}lolban`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var showCount = 8;
|
||||
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
|
||||
try
|
||||
{
|
||||
var data = JObject.Parse(
|
||||
await Classes
|
||||
.SearchHelper
|
||||
.GetResponseStringAsync($"http://api.champion.gg/stats/champs/mostBanned?" +
|
||||
$"api_key={NadekoBot.Creds.LOLAPIKey}&page=1&" +
|
||||
$"limit={showCount}")
|
||||
.ConfigureAwait(false))["data"] as JArray;
|
||||
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"**Showing {showCount} top banned champions.**");
|
||||
sb.AppendLine($"`{trashTalk[new Random().Next(0, trashTalk.Length)]}`");
|
||||
for (var i = 0; i < dataList.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0 && i != 0)
|
||||
sb.AppendLine();
|
||||
sb.Append($"`{i + 1}.` **{dataList[i]["name"]}** ");
|
||||
//sb.AppendLine($" ({dataList[i]["general"]["banRate"]}%)");
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await e.Channel.SendMessage($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private enum GetImageType
|
||||
{
|
||||
Champion,
|
||||
Item
|
||||
}
|
||||
private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (imageType)
|
||||
{
|
||||
case GetImageType.Champion:
|
||||
return Image.FromFile($"data/lol/champions/{id}.png");
|
||||
case GetImageType.Item:
|
||||
default:
|
||||
return Image.FromFile($"data/lol/items/{id}.png");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Image.FromFile("data/lol/_ERROR.png");
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolvePos(string pos)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pos))
|
||||
return null;
|
||||
switch (pos.ToLowerInvariant())
|
||||
{
|
||||
case "m":
|
||||
case "mid":
|
||||
case "midorfeed":
|
||||
case "midd":
|
||||
case "middle":
|
||||
return "Middle";
|
||||
case "top":
|
||||
case "topp":
|
||||
case "t":
|
||||
case "toporfeed":
|
||||
return "Top";
|
||||
case "j":
|
||||
case "jun":
|
||||
case "jungl":
|
||||
case "jungle":
|
||||
return "Jungle";
|
||||
case "a":
|
||||
case "ad":
|
||||
case "adc":
|
||||
case "carry":
|
||||
case "ad carry":
|
||||
case "adcarry":
|
||||
case "c":
|
||||
return "ADC";
|
||||
case "s":
|
||||
case "sup":
|
||||
case "supp":
|
||||
case "support":
|
||||
return "Support";
|
||||
default:
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class MemegenCommands : DiscordCommand
|
||||
{
|
||||
public MemegenCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "memelist")
|
||||
.Description($"Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `{Prefix}memelist`")
|
||||
.Do(async e =>
|
||||
{
|
||||
int i = 0;
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n```xl\n" +
|
||||
string.Join("\n", JsonConvert.DeserializeObject<Dictionary<string, string>>(await SearchHelper.GetResponseStringAsync("http://memegen.link/templates/"))
|
||||
.Select(kvp => Path.GetFileName(kvp.Value))
|
||||
.GroupBy(item => (i++) / 4)
|
||||
.Select(ig => string.Concat(ig.Select(el => $"{el,-17}"))))
|
||||
+ $"\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "memegen")
|
||||
.Description($"Generates a meme from memelist with top and bottom text. | `{Prefix}memegen biw \"gets iced coffee\" \"in the winter\"`")
|
||||
.Parameter("meme", ParameterType.Required)
|
||||
.Parameter("toptext", ParameterType.Required)
|
||||
.Parameter("bottext", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var meme = e.GetArg("meme");
|
||||
var top = Uri.EscapeDataString(e.GetArg("toptext").Replace(' ', '-'));
|
||||
var bot = Uri.EscapeDataString(e.GetArg("bottext").Replace(' ', '-'));
|
||||
await e.Channel.SendMessage($"http://memegen.link/{meme}/{top}/{bot}.jpg");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class OsuCommands : DiscordCommand
|
||||
{
|
||||
public OsuCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "osu")
|
||||
.Description($"Shows osu stats for a player. | `{Prefix}osu Name` or `{Prefix}osu Name taiko`")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
return;
|
||||
|
||||
using (WebClient cl = new WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
cl.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
|
||||
cl.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.2; Win64; x64)");
|
||||
cl.DownloadDataAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ e.GetArg("usr") }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}"));
|
||||
cl.DownloadDataCompleted += async (s, cle) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendFile($"{e.GetArg("usr")}.png", new MemoryStream(cle.Result)).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Profile Link:`https://osu.ppy.sh/u/{Uri.EscapeDataString(e.GetArg("usr"))}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Failed retrieving osu signature :\\").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu b")
|
||||
.Description($"Shows information about an osu beatmap. |`{Prefix}osu b https://osu.ppy.sh/s/127712`")
|
||||
.Parameter("map", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("map")))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var mapId = ResolveMap(e.GetArg("map"));
|
||||
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&{mapId}";
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false))[0];
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2);
|
||||
var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss");
|
||||
sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}");
|
||||
sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu top5")
|
||||
.Description($"Displays a user's top 5 plays. |`{Prefix}osu top5 Name`")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Please provide a username.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
var reqString = $"https://osu.ppy.sh/api/get_user_best?k={NadekoBot.Creds.OsuAPIKey}&u={Uri.EscapeDataString(e.GetArg("usr"))}&type=string&limit=5&m={m}";
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
var sb = new System.Text.StringBuilder($"`Top 5 plays for {e.GetArg("usr")}:`\n```xl" + Environment.NewLine);
|
||||
foreach (var item in obj)
|
||||
{
|
||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&b={item["beatmap_id"]}";
|
||||
var map = JArray.Parse(await SearchHelper.GetResponseStringAsync(mapReqString).ConfigureAwait(false))[0];
|
||||
var pp = Math.Round(Double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2);
|
||||
var acc = CalculateAcc(item, m);
|
||||
var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}"));
|
||||
if (mods != "+")
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | **{mods,-10}** | /b/{item["beatmap_id"]}");
|
||||
else
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | /b/{item["beatmap_id"]}");
|
||||
}
|
||||
sb.Append("```");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//https://osu.ppy.sh/wiki/Accuracy
|
||||
private static Double CalculateAcc(JToken play, int mode)
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["count300"]}") * 300;
|
||||
var totalHits = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countmiss"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["countmiss"]}") * 0 + Double.Parse($"{play["count100"]}") * 0.5 + Double.Parse($"{play["count300"]}") * 1;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
hitPoints *= 300;
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
var fruitsCaught = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
var totalFruits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countkatu"]}");
|
||||
return Math.Round(fruitsCaught / totalFruits * 100, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["countkatu"]}") * 200 + (Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}")) * 300;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["countkatu"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveMap(string mapLink)
|
||||
{
|
||||
Match s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
if (s.Success)
|
||||
{
|
||||
var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3);
|
||||
return $"s={mapId}";
|
||||
}
|
||||
else if (b.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("/b/") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3)}";
|
||||
}
|
||||
else if (p.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("?b=") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"s={mapLink}"; //just a default incase an ID number was provided by itself (non-url)?
|
||||
}
|
||||
}
|
||||
|
||||
private static int ResolveGameMode(string mode)
|
||||
{
|
||||
switch (mode.ToLower())
|
||||
{
|
||||
case "std":
|
||||
case "standard":
|
||||
return 0;
|
||||
case "taiko":
|
||||
return 1;
|
||||
case "ctb":
|
||||
case "catchthebeat":
|
||||
return 2;
|
||||
case "mania":
|
||||
case "osu!mania":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/ppy/osu-api/wiki#mods
|
||||
private static string ResolveMods(int mods)
|
||||
{
|
||||
var modString = $"+";
|
||||
|
||||
if (IsBitSet(mods, 0))
|
||||
modString += "NF";
|
||||
if (IsBitSet(mods, 1))
|
||||
modString += "EZ";
|
||||
if (IsBitSet(mods, 8))
|
||||
modString += "HT";
|
||||
|
||||
if (IsBitSet(mods, 3))
|
||||
modString += "HD";
|
||||
if (IsBitSet(mods, 4))
|
||||
modString += "HR";
|
||||
if (IsBitSet(mods, 6) && !IsBitSet(mods, 9))
|
||||
modString += "DT";
|
||||
if (IsBitSet(mods, 9))
|
||||
modString += "NC";
|
||||
if (IsBitSet(mods, 10))
|
||||
modString += "FL";
|
||||
|
||||
if (IsBitSet(mods, 5))
|
||||
modString += "SD";
|
||||
if (IsBitSet(mods, 14))
|
||||
modString += "PF";
|
||||
|
||||
if (IsBitSet(mods, 7))
|
||||
modString += "RX";
|
||||
if (IsBitSet(mods, 11))
|
||||
modString += "AT";
|
||||
if (IsBitSet(mods, 12))
|
||||
modString += "SO";
|
||||
return modString;
|
||||
}
|
||||
|
||||
private static bool IsBitSet(int mods, int pos)
|
||||
{
|
||||
return (mods & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class PokemonSearchCommands : DiscordCommand
|
||||
{
|
||||
private static Dictionary<string, SearchPokemon> pokemons;
|
||||
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities;
|
||||
|
||||
public PokemonSearchCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
pokemons = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemon>>(File.ReadAllText("data/pokemon/pokemon_list.json"));
|
||||
pokemonAbilities = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemonAbility>>(File.ReadAllText("data/pokemon/pokemon_abilities.json"));
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "pokemon")
|
||||
.Alias(Prefix + "poke")
|
||||
.Description($"Searches for a pokemon. | `{Prefix}poke Sylveon`")
|
||||
.Parameter("pokemon", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pok = e.GetArg("pokemon")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(pok))
|
||||
return;
|
||||
|
||||
foreach (var kvp in pokemons)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == pok.ToUpperInvariant())
|
||||
{
|
||||
await e.Channel.SendMessage($"`Stats for \"{kvp.Key}\" pokemon:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage("`No pokemon found.`");
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "pokemonability")
|
||||
.Alias(Prefix + "pokeab")
|
||||
.Description($"Searches for a pokemon ability. | `{Prefix}pokeab \"water gun\"`")
|
||||
.Parameter("abil", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var ab = e.GetArg("abil")?.Trim().ToUpperInvariant().Replace(" ", "");
|
||||
if (string.IsNullOrWhiteSpace(ab))
|
||||
return;
|
||||
foreach (var kvp in pokemonAbilities)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == ab)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Info for \"{kvp.Key}\" ability:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage("`No ability found.`");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchPokemon
|
||||
{
|
||||
public class GenderRatioClass
|
||||
{
|
||||
public float M { get; set; }
|
||||
public float F { get; set; }
|
||||
}
|
||||
public class BaseStatsClass
|
||||
{
|
||||
public int HP { get; set; }
|
||||
public int ATK { get; set; }
|
||||
public int DEF { get; set; }
|
||||
public int SPA { get; set; }
|
||||
public int SPD { get; set; }
|
||||
public int SPE { get; set; }
|
||||
|
||||
public override string ToString() => $@"
|
||||
**HP:** {HP,-4} **ATK:** {ATK,-4} **DEF:** {DEF,-4}
|
||||
**SPA:** {SPA,-4} **SPD:** {SPD,-4} **SPE:** {SPE,-4}";
|
||||
}
|
||||
public int Id { get; set; }
|
||||
public string Species { get; set; }
|
||||
public string[] Types { get; set; }
|
||||
public GenderRatioClass GenderRatio { get; set; }
|
||||
public BaseStatsClass BaseStats { get; set; }
|
||||
public Dictionary<string, string> Abilities { get; set; }
|
||||
public float HeightM { get; set; }
|
||||
public float WeightKg { get; set; }
|
||||
public string Color { get; set; }
|
||||
public string[] Evos { get; set; }
|
||||
public string[] EggGroups { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` {Species}
|
||||
`Types:` {string.Join(", ", Types)}
|
||||
`Stats:` {BaseStats}
|
||||
`Height:` {HeightM,4}m `Weight:` {WeightKg}kg
|
||||
`Abilities:` {string.Join(", ", Abilities.Values)}";
|
||||
|
||||
}
|
||||
|
||||
public class SearchPokemonAbility
|
||||
{
|
||||
public string Desc { get; set; }
|
||||
public string Name { get; set; }
|
||||
public float Rating { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` : {Name}
|
||||
`Rating:` {Rating}
|
||||
`Description:` {Desc}";
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class RedditCommand : DiscordCommand
|
||||
{
|
||||
public RedditCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,373 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class StreamNotifications : DiscordCommand
|
||||
{
|
||||
private ConcurrentDictionary<string, Tuple<bool, string>> cachedStatuses = new ConcurrentDictionary<string, Tuple<bool, string>>();
|
||||
private bool FirstPass { get; set; } = true;
|
||||
|
||||
public StreamNotifications(DiscordModule module) : base(module)
|
||||
{
|
||||
//start checking only after ready, because we need all servers to be initialized
|
||||
NadekoBot.OnReady += () =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(60000);
|
||||
while (true)
|
||||
{
|
||||
cachedStatuses.Clear();
|
||||
try
|
||||
{
|
||||
var streams = SpecificConfigurations.Default.AllConfigs.SelectMany(c => c.ObservingStreams);
|
||||
if (!streams.Any()) return;
|
||||
#if NADEKO_RELEASE
|
||||
var clr = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
Console.WriteLine($"Getting {streams.Count()} streams.");
|
||||
Console.ForegroundColor = clr;
|
||||
#endif
|
||||
foreach (var stream in streams)
|
||||
{
|
||||
Tuple<bool, string> data;
|
||||
try
|
||||
{
|
||||
data = await GetStreamStatus(stream).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.Item1 != stream.LastStatus)
|
||||
{
|
||||
stream.LastStatus = data.Item1;
|
||||
if (FirstPass)
|
||||
continue;
|
||||
var server = NadekoBot.Client.GetServer(stream.ServerId);
|
||||
var channel = server?.GetChannel(stream.ChannelId);
|
||||
if (channel == null)
|
||||
continue;
|
||||
var msg = $"`{stream.Username}`'s stream is now " +
|
||||
$"**{(data.Item1 ? "ONLINE" : "OFFLINE")}** with " +
|
||||
$"**{data.Item2}** viewers.";
|
||||
if (stream.LastStatus)
|
||||
if (stream.Type == StreamNotificationConfig.StreamType.Hitbox)
|
||||
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.Twitch)
|
||||
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.Beam)
|
||||
msg += $"\n`Here is the Link:`【 http://www.beam.pro/{stream.Username}/ 】";
|
||||
else if (stream.Type == StreamNotificationConfig.StreamType.YoutubeGaming)
|
||||
msg += $"\n`Here is the Link:`【 not implemented yet - {stream.Username} 】";
|
||||
await channel.SendMessage(msg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
FirstPass = false;
|
||||
#if NADEKO_RELEASE
|
||||
clr = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
Console.WriteLine($"Done getting streams.");
|
||||
Console.ForegroundColor = clr;
|
||||
#endif
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(60));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
private async Task<Tuple<bool, string>> GetStreamStatus(StreamNotificationConfig stream, bool checkCache = true)
|
||||
{
|
||||
bool isLive;
|
||||
string response;
|
||||
JObject data;
|
||||
Tuple<bool, string> result;
|
||||
switch (stream.Type)
|
||||
{
|
||||
case StreamNotificationConfig.StreamType.Hitbox:
|
||||
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username}";
|
||||
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(hitboxUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = data["media_is_live"].ToString() == "1";
|
||||
result = new Tuple<bool, string>(isLive, data["media_views"].ToString());
|
||||
cachedStatuses.TryAdd(hitboxUrl, result);
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Twitch:
|
||||
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
|
||||
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(twitchUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = !string.IsNullOrWhiteSpace(data["stream"].ToString());
|
||||
result = new Tuple<bool, string>(isLive, isLive ? data["stream"]["viewers"].ToString() : stream.Username);
|
||||
cachedStatuses.TryAdd(twitchUrl, result);
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Beam:
|
||||
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}";
|
||||
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(beamUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
isLive = data["online"].ToObject<bool>() == true;
|
||||
result = new Tuple<bool, string>(isLive, data["viewersCurrent"].ToString());
|
||||
cachedStatuses.TryAdd(beamUrl, result);
|
||||
return result;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new Tuple<bool, string>(false, "NOT_FOUND");
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "hitbox")
|
||||
.Alias(Module.Prefix + "hb")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}hitbox SomeStreamer`")
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Hitbox));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "twitch")
|
||||
.Alias(Module.Prefix + "tw")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}twitch SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Twitch));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "beam")
|
||||
.Alias(Module.Prefix + "bm")
|
||||
.Description("Notifies this channel when a certain user starts streaming." +
|
||||
$" | `{Prefix}beam SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Beam));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkhitbox")
|
||||
.Alias(Module.Prefix + "chhb")
|
||||
.Description("Checks if a certain user is streaming on the hitbox platform." +
|
||||
$" | `{Prefix}chhb SomeStreamer`")
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Hitbox
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is online with {streamStatus.Item2} viewers.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is offline.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checktwitch")
|
||||
.Alias(Module.Prefix + "chtw")
|
||||
.Description("Checks if a certain user is streaming on the twitch platform." +
|
||||
$" | `{Prefix}chtw SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Twitch
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is online with {streamStatus.Item2} viewers.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is offline.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkbeam")
|
||||
.Alias(Module.Prefix + "chbm")
|
||||
.Description("Checks if a certain user is streaming on the beam platform." +
|
||||
$" | `{Prefix}chbm SomeStreamer`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Beam
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is online with {streamStatus.Item2} viewers.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {stream} is offline.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "removestream")
|
||||
.Alias(Module.Prefix + "rms")
|
||||
.Description("Removes notifications of a certain streamer on this channel." +
|
||||
$" | `{Prefix}rms SomeGuy`")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var username = e.GetArg("username")?.ToLower().Trim();
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
return;
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var toRemove = config.ObservingStreams
|
||||
.FirstOrDefault(snc => snc.ChannelId == e.Channel.Id &&
|
||||
snc.Username.ToLower().Trim() == username);
|
||||
if (toRemove == null)
|
||||
{
|
||||
await e.Channel.SendMessage(":anger: No such stream.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
config.ObservingStreams.Remove(toRemove);
|
||||
await ConfigHandler.SaveConfig().ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "liststreams")
|
||||
.Alias(Module.Prefix + "ls")
|
||||
.Description("Lists all streams you are following on this server." +
|
||||
$" | `{Prefix}ls`")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var streams = config.ObservingStreams.Where(snc =>
|
||||
snc.ServerId == e.Server.Id);
|
||||
|
||||
var streamsArray = streams as StreamNotificationConfig[] ?? streams.ToArray();
|
||||
|
||||
if (streamsArray.Length == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("You are not following any streams on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var text = string.Join("\n", streamsArray.Select(snc =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return $"`{snc.Username}`'s stream on **{e.Server.GetChannel(e.Channel.Id).Name}** channel. 【`{snc.Type.ToString()}`】";
|
||||
}
|
||||
catch { }
|
||||
return "";
|
||||
}));
|
||||
|
||||
await e.Channel.SendMessage($"You are following **{streamsArray.Length}** streams on this server.\n\n" + text).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> TrackStream(StreamNotificationConfig.StreamType type) =>
|
||||
async e =>
|
||||
{
|
||||
var username = e.GetArg("username")?.ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
return;
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
|
||||
var stream = new StreamNotificationConfig
|
||||
{
|
||||
ServerId = e.Server.Id,
|
||||
ChannelId = e.Channel.Id,
|
||||
Username = username,
|
||||
Type = type,
|
||||
};
|
||||
var exists = config.ObservingStreams.Contains(stream);
|
||||
if (exists)
|
||||
{
|
||||
await e.Channel.SendMessage(":anger: I am already notifying that stream on this channel.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Tuple<bool, string> data;
|
||||
try
|
||||
{
|
||||
data = await GetStreamStatus(stream).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage(":anger: Stream probably doesn't exist.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var msg = $"Stream is currently **{(data.Item1 ? "ONLINE" : "OFFLINE")}** with **{data.Item2}** viewers";
|
||||
if (data.Item1)
|
||||
if (type == StreamNotificationConfig.StreamType.Hitbox)
|
||||
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.Twitch)
|
||||
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.Beam)
|
||||
msg += $"\n`Here is the Link:`【 https://beam.pro/{stream.Username}/ 】";
|
||||
else if (type == StreamNotificationConfig.StreamType.YoutubeGaming)
|
||||
msg += $"\n`Here is the Link:` not implemented yet - {stream.Username}";
|
||||
stream.LastStatus = data.Item1;
|
||||
if (!exists)
|
||||
msg = $":ok: I will notify this channel when status changes.\n{msg}";
|
||||
await e.Channel.SendMessage(msg).ConfigureAwait(false);
|
||||
config.ObservingStreams.Add(stream);
|
||||
};
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class WowJokeCommand : DiscordCommand
|
||||
{
|
||||
|
||||
List<WoWJoke> jokes = new List<WoWJoke>();
|
||||
|
||||
public WowJokeCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "wowjoke")
|
||||
.Description($"Get one of Kwoth's penultimate WoW jokes. | `{Prefix}wowjoke`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!jokes.Any())
|
||||
{
|
||||
jokes = JsonConvert.DeserializeObject<List<WoWJoke>>(File.ReadAllText("data/wowjokes.json"));
|
||||
}
|
||||
await e.Channel.SendMessage(jokes[new Random().Next(0, jokes.Count)].ToString());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,522 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Searches.Commands;
|
||||
using NadekoBot.Modules.Searches.Commands.IMDB;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Web;
|
||||
|
||||
namespace NadekoBot.Modules.Searches
|
||||
{
|
||||
internal class SearchesModule : DiscordModule
|
||||
{
|
||||
private readonly Random rng;
|
||||
public SearchesModule()
|
||||
{
|
||||
commands.Add(new LoLCommands(this));
|
||||
commands.Add(new StreamNotifications(this));
|
||||
commands.Add(new ConverterCommand(this));
|
||||
commands.Add(new RedditCommand(this));
|
||||
commands.Add(new WowJokeCommand(this));
|
||||
commands.Add(new CalcCommand(this));
|
||||
commands.Add(new OsuCommands(this));
|
||||
commands.Add(new PokemonSearchCommands(this));
|
||||
commands.Add(new MemegenCommands(this));
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Searches;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "we")
|
||||
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `{Prefix}we Moscow RF`")
|
||||
.Parameter("city", ParameterType.Required)
|
||||
.Parameter("country", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var city = e.GetArg("city").Replace(" ", "");
|
||||
var country = e.GetArg("country").Replace(" ", "");
|
||||
var response = await SearchHelper.GetResponseStringAsync($"http://api.ninetales.us/nadekobot/weather/?city={city}&country={country}").ConfigureAwait(false);
|
||||
|
||||
var obj = JObject.Parse(response)["weather"];
|
||||
|
||||
await e.Channel.SendMessage(
|
||||
$@"🌍 **Weather for** 【{obj["target"]}】
|
||||
📏 **Lat,Long:** ({obj["latitude"]}, {obj["longitude"]}) ☁ **Condition:** {obj["condition"]}
|
||||
😓 **Humidity:** {obj["humidity"]}% 💨 **Wind Speed:** {obj["windspeedk"]}km/h / {obj["windspeedm"]}mph
|
||||
🔆 **Temperature:** {obj["centigrade"]}°C / {obj["fahrenheit"]}°F 🔆 **Feels like:** {obj["feelscentigrade"]}°C / {obj["feelsfahrenheit"]}°F
|
||||
🌄 **Sunrise:** {obj["sunrise"]} 🌇 **Sunset:** {obj["sunset"]}").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "yt")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Description($"Searches youtubes and shows the first result | `{Prefix}yt query`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
|
||||
var link = await SearchHelper.FindYoutubeUrlByKeywords(e.GetArg("query")).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
{
|
||||
await e.Channel.SendMessage("No results found for that query.");
|
||||
return;
|
||||
}
|
||||
var shortUrl = await SearchHelper.ShortenUrl(link).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(shortUrl).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ani")
|
||||
.Alias(Prefix + "anime", Prefix + "aq")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Description($"Queries anilist for an anime and shows the first result. | `{Prefix}aq aquarion evol`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = (await SearchHelper.GetAnimeData(e.GetArg("query")).ConfigureAwait(false)).ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to find that anime.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(result.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "imdb")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Description($"Queries imdb for movies or series, show first result. | `{Prefix}imdb Batman vs Superman`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
string result;
|
||||
try
|
||||
{
|
||||
var movie = ImdbScraper.ImdbScrape(e.GetArg("query"), true);
|
||||
if (movie.Status) result = movie.ToString();
|
||||
else result = "Failed to find that movie.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to find that movie.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage(result.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "mang")
|
||||
.Alias(Prefix + "manga").Alias(Prefix + "mq")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Description($"Queries anilist for a manga and shows the first result. | `{Prefix}mq Shingeki no kyojin`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = (await SearchHelper.GetMangaData(e.GetArg("query")).ConfigureAwait(false)).ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Failed to find that anime.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(result).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "randomcat")
|
||||
.Alias(Prefix + "meow")
|
||||
.Description($"Shows a random cat image. | `{Prefix}meow`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage(JObject.Parse(
|
||||
await SearchHelper.GetResponseStringAsync("http://www.random.cat/meow").ConfigureAwait(false))["file"].ToString())
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "randomdog")
|
||||
.Alias(Prefix + "woof")
|
||||
.Description($"Shows a random dog image. | `{Prefix}woof`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage("http://random.dog/" + await SearchHelper.GetResponseStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "i")
|
||||
.Description($"Pulls the first image found using a search parameter. Use ~ir for different results. | `{Prefix}i cute kitten`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("query")))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&fields=items%2Flink&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
var obj = JObject.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
await e.Channel.SendMessage(obj["items"][0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await e.Channel.SendMessage("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ir")
|
||||
.Description($"Pulls a random image using a search parameter. | `{Prefix}ir cute kitten`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("query")))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&start={ rng.Next(1, 50) }&fields=items%2Flink&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
var obj = JObject.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
var items = obj["items"] as JArray;
|
||||
await e.Channel.SendMessage(items[0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await e.Channel.SendMessage("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "lmgtfy")
|
||||
.Description($"Google something for an idiot. | `{Prefix}lmgtfy query`")
|
||||
.Parameter("ffs", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (e.GetArg("ffs") == null || e.GetArg("ffs").Length < 1) return;
|
||||
await e.Channel.SendMessage(await $"http://lmgtfy.com/?q={ Uri.EscapeUriString(e.GetArg("ffs").ToString()) }".ShortenUrl())
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "google")
|
||||
.Alias(Prefix + "g")
|
||||
.Description($"Get a google search link for some terms. | `{Prefix}google query`")
|
||||
.Parameter("terms", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var terms = e.GetArg("terms")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(terms))
|
||||
return;
|
||||
await e.Channel.SendMessage($"https://google.com/search?q={ HttpUtility.UrlEncode(terms).Replace(' ', '+') }")
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "hs")
|
||||
.Description($"Searches for a Hearthstone card and shows its image. Takes a while to complete. | `{Prefix}hs Ysera`")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("name");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Please enter a card name to search for.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
var headers = new Dictionary<string, string> { { "X-Mashape-Key", NadekoBot.Creds.MashapeKey } };
|
||||
var res = await SearchHelper.GetResponseStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}", headers)
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JArray.Parse(res);
|
||||
var images = new List<Image>();
|
||||
if (items == null)
|
||||
throw new KeyNotFoundException("Cannot find a card by that name");
|
||||
var cnt = 0;
|
||||
items.Shuffle();
|
||||
foreach (var item in items.TakeWhile(item => cnt++ < 4).Where(item => item.HasValues && item["img"] != null))
|
||||
{
|
||||
images.Add(
|
||||
Image.FromStream(await SearchHelper.GetResponseStreamAsync(item["img"].ToString()).ConfigureAwait(false)));
|
||||
}
|
||||
if (items.Count > 4)
|
||||
{
|
||||
await e.Channel.SendMessage("⚠ Found over 4 images. Showing random 4.").ConfigureAwait(false);
|
||||
}
|
||||
await e.Channel.SendFile(arg + ".png", (await images.MergeAsync()).ToStream(System.Drawing.Imaging.ImageFormat.Png))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage($"💢 Error {ex.Message}").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ud")
|
||||
.Description($"Searches Urban Dictionary for a word. | `{Prefix}ud Pineapple`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("query");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Please enter a search term.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
var headers = new Dictionary<string, string> { { "X-Mashape-Key", NadekoBot.Creds.MashapeKey } };
|
||||
var res = await SearchHelper.GetResponseStringAsync($"https://mashape-community-urban-dictionary.p.mashape.com/define?term={Uri.EscapeUriString(arg)}", headers).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JObject.Parse(res);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var item = items["list"][0];
|
||||
sb.AppendLine($"`Term:` {item["word"].ToString()}");
|
||||
sb.AppendLine($"`Definition:` {item["definition"].ToString()}");
|
||||
sb.Append($"`Link:` <{item["permalink"].ToString()}>");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Failed finding a definition for that term.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
// thanks to Blaubeerwald
|
||||
cgb.CreateCommand(Prefix + "#")
|
||||
.Description($"Searches Tagdef.com for a hashtag. | `{Prefix}# ff`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("query");
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Please enter a search term.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
var headers = new Dictionary<string, string> { { "X-Mashape-Key", NadekoBot.Creds.MashapeKey } };
|
||||
var res = await SearchHelper.GetResponseStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(arg)}.json", headers).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JObject.Parse(res);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine($"`Hashtag:` {items["defs"]["def"]["hashtag"].ToString()}");
|
||||
sb.AppendLine($"`Definition:` {items["defs"]["def"]["text"].ToString()}");
|
||||
sb.Append($"`Link:` <{await items["defs"]["def"]["uri"].ToString().ShortenUrl().ConfigureAwait(false)}>");
|
||||
await e.Channel.SendMessage(sb.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Failed finidng a definition for that tag.").ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "quote")
|
||||
.Description($"Shows a random quote. | `{Prefix}quote`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
|
||||
await e.Channel.SendMessage(quote).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "catfact")
|
||||
.Description($"Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `{Prefix}catfact`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var response = await SearchHelper.GetResponseStringAsync("http://catfacts-api.appspot.com/api/facts").ConfigureAwait(false);
|
||||
if (response == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"🐈 `{JObject.Parse(response)["facts"][0].ToString()}`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "yomama")
|
||||
.Alias(Prefix + "ym")
|
||||
.Description($"Shows a random joke from <http://api.yomomma.info/> | `{Prefix}ym`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var response = await SearchHelper.GetResponseStringAsync("http://api.yomomma.info/").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage("`" + JObject.Parse(response)["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "randjoke")
|
||||
.Alias(Prefix + "rj")
|
||||
.Description($"Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `{Prefix}rj`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var response = await SearchHelper.GetResponseStringAsync("http://tambal.azurewebsites.net/joke/random").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage("`" + JObject.Parse(response)["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "chucknorris")
|
||||
.Alias(Prefix + "cn")
|
||||
.Description($"Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `{Prefix}cn`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var response = await SearchHelper.GetResponseStringAsync("http://api.icndb.com/jokes/random/").ConfigureAwait(false);
|
||||
await e.Channel.SendMessage("`" + JObject.Parse(response)["value"]["joke"].ToString() + "` 😆").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "magicitem")
|
||||
.Alias(Prefix + "mi")
|
||||
.Description($"Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `{Prefix}mi`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
|
||||
var item = magicItems[rng.Next(0, magicItems.Count)].ToString();
|
||||
|
||||
await e.Channel.SendMessage(item).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "revav")
|
||||
.Description($"Returns a google reverse image search for someone's avatar. | `{Prefix}revav \"@SomeGuy\"`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usrStr = e.GetArg("user")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(usrStr))
|
||||
return;
|
||||
|
||||
var usr = e.Server.FindUsers(usrStr).FirstOrDefault();
|
||||
|
||||
if (usr == null || string.IsNullOrWhiteSpace(usr.AvatarUrl))
|
||||
return;
|
||||
await e.Channel.SendMessage($"https://images.google.com/searchbyimage?image_url={usr.AvatarUrl}").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "revimg")
|
||||
.Description($"Returns a google reverse image search for an image from a link. | `{Prefix}revav Image link`")
|
||||
.Parameter("image", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var imgLink = e.GetArg("image")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(imgLink))
|
||||
return;
|
||||
await e.Channel.SendMessage($"https://images.google.com/searchbyimage?image_url={imgLink}").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "safebooru")
|
||||
.Description($"Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}safebooru yuri+kissing`")
|
||||
.Parameter("tag", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var tag = e.GetArg("tag")?.Trim() ?? "";
|
||||
var link = await SearchHelper.GetSafebooruImageLink(tag).ConfigureAwait(false);
|
||||
if (link == null)
|
||||
await e.Channel.SendMessage("`No results.`");
|
||||
else
|
||||
await e.Channel.SendMessage(link).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "wiki")
|
||||
.Description($"Gives you back a wikipedia link | `{Prefix}wiki query`")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var query = e.GetArg("query");
|
||||
var result = await SearchHelper.GetResponseStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query));
|
||||
var data = JsonConvert.DeserializeObject<WikipediaApiModel>(result);
|
||||
if (data.Query.Pages[0].Missing)
|
||||
await e.Channel.SendMessage("`That page could not be found.`");
|
||||
else
|
||||
await e.Channel.SendMessage(data.Query.Pages[0].FullUrl);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "clr")
|
||||
.Description($"Shows you what color corresponds to that hex. | `{Prefix}clr 00ff00`")
|
||||
.Parameter("color", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg1 = e.GetArg("color")?.Trim()?.Replace("#", "");
|
||||
if (string.IsNullOrWhiteSpace(arg1))
|
||||
return;
|
||||
var img = new Bitmap(50, 50);
|
||||
|
||||
var red = Convert.ToInt32(arg1.Substring(0, 2), 16);
|
||||
var green = Convert.ToInt32(arg1.Substring(2, 2), 16);
|
||||
var blue = Convert.ToInt32(arg1.Substring(4, 2), 16);
|
||||
var brush = new SolidBrush(System.Drawing.Color.FromArgb(red, green, blue));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(img))
|
||||
{
|
||||
g.FillRectangle(brush, 0, 0, 50, 50);
|
||||
g.Flush();
|
||||
}
|
||||
|
||||
await e.Channel.SendFile("arg1.png", img.ToStream());
|
||||
});
|
||||
|
||||
|
||||
cgb.CreateCommand(Prefix + "videocall")
|
||||
.Description($"Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `{Prefix}videocall \"@SomeGuy\"`")
|
||||
.Parameter("arg", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var allUsrs = e.Message.MentionedUsers.Union(new User[] { e.User });
|
||||
var allUsrsArray = allUsrs as User[] ?? allUsrs.ToArray();
|
||||
var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Name[0].ToString()));
|
||||
str += new Random().Next();
|
||||
foreach (var usr in allUsrsArray)
|
||||
{
|
||||
await usr.SendMessage(str).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "av")
|
||||
.Alias(Prefix + "avatar")
|
||||
.Parameter("mention", ParameterType.Required)
|
||||
.Description($"Shows a mentioned person's avatar. | `{Prefix}av \"@SomeGuy\"`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Invalid user specified.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(await usr.AvatarUrl.ShortenUrl()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Translator.Helpers;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
class TranslateCommand : DiscordCommand
|
||||
{
|
||||
public TranslateCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "translate")
|
||||
.Alias(Module.Prefix + "trans")
|
||||
.Description($"Translates from>to text. From the given language to the destiation language. | `{Module.Prefix}trans en>fr Hello`")
|
||||
.Parameter("langs", ParameterType.Required)
|
||||
.Parameter("text", ParameterType.Unparsed)
|
||||
.Do(TranslateFunc());
|
||||
}
|
||||
private GoogleTranslator t = new GoogleTranslator();
|
||||
private Func<CommandEventArgs, Task> TranslateFunc() => async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
string from = e.GetArg("langs").ToLowerInvariant().Split('>')[0];
|
||||
string to = e.GetArg("langs").ToLowerInvariant().Split('>')[1];
|
||||
var text = e.GetArg("text")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
string translation = await t.Translate(text, from, to).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(translation).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
await e.Channel.SendMessage("Bad input format, or something went wrong...").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
internal class TranslatorModule : DiscordModule
|
||||
{
|
||||
public TranslatorModule()
|
||||
{
|
||||
commands.Add(new TranslateCommand(this));
|
||||
commands.Add(new ValidLanguagesCommand(this));
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Searches;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Translator.Helpers;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Translator
|
||||
{
|
||||
class ValidLanguagesCommand : DiscordCommand
|
||||
{
|
||||
public ValidLanguagesCommand(DiscordModule module) : base(module) { }
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "translangs")
|
||||
.Description($"List the valid languages for translation. | `{Prefix}translangs` or `{Prefix}translangs language`")
|
||||
.Parameter("search", ParameterType.Optional)
|
||||
.Do(ListLanguagesFunc());
|
||||
}
|
||||
private Func<CommandEventArgs, Task> ListLanguagesFunc() => async e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
GoogleTranslator.EnsureInitialized();
|
||||
string s = e.GetArg("search");
|
||||
string ret = "";
|
||||
foreach (string key in GoogleTranslator._languageModeMap.Keys)
|
||||
{
|
||||
if (!s.Equals(""))
|
||||
{
|
||||
if (key.ToLower().Contains(s))
|
||||
{
|
||||
ret += " " + key + ";";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += " " + key + ";";
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage(ret).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Bad input format, or sth went wrong...").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
using Discord.Modules;
|
||||
using Manatee.Trello;
|
||||
using Manatee.Trello.ManateeJson;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
using Action = Manatee.Trello.Action;
|
||||
|
||||
namespace NadekoBot.Modules.Trello
|
||||
{
|
||||
internal class TrelloModule : DiscordModule
|
||||
{
|
||||
private readonly Timer t = new Timer { Interval = 2000 };
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Trello;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
|
||||
var client = manager.Client;
|
||||
|
||||
var serializer = new ManateeSerializer();
|
||||
TrelloConfiguration.Serializer = serializer;
|
||||
TrelloConfiguration.Deserializer = serializer;
|
||||
TrelloConfiguration.JsonFactory = new ManateeFactory();
|
||||
TrelloConfiguration.RestClientProvider = new Manatee.Trello.WebApi.WebApiClientProvider();
|
||||
TrelloAuthorization.Default.AppKey = NadekoBot.Creds.TrelloAppKey;
|
||||
//TrelloAuthorization.Default.UserToken = "[your user token]";
|
||||
|
||||
Discord.Channel bound = null;
|
||||
Board board = null;
|
||||
|
||||
List<string> last5ActionIDs = null;
|
||||
t.Elapsed += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (board == null || bound == null)
|
||||
return; //do nothing if there is no bound board
|
||||
|
||||
board.Refresh();
|
||||
var cur5Actions = board.Actions.Take(board.Actions.Count() < 5 ? board.Actions.Count() : 5);
|
||||
var cur5ActionsArray = cur5Actions as Action[] ?? cur5Actions.ToArray();
|
||||
|
||||
if (last5ActionIDs == null)
|
||||
{
|
||||
last5ActionIDs = cur5ActionsArray.Select(a => a.Id).ToList();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var a in cur5ActionsArray.Where(ca => !last5ActionIDs.Contains(ca.Id)))
|
||||
{
|
||||
await bound.Send("**--TRELLO NOTIFICATION--**\n" + a.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
last5ActionIDs.Clear();
|
||||
last5ActionIDs.AddRange(cur5ActionsArray.Select(a => a.Id));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Timer failed " + ex.ToString());
|
||||
}
|
||||
};
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
cgb.CreateCommand(Prefix + "bind")
|
||||
.Description("Bind a trello bot to a single channel. " +
|
||||
"You will receive notifications from your board when something is added or edited." +
|
||||
$" **Bot Owner Only!**| `{Prefix}bind [board_id]`")
|
||||
.Parameter("board_id", Discord.Commands.ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id)) return;
|
||||
if (bound != null) return;
|
||||
try
|
||||
{
|
||||
bound = e.Channel;
|
||||
board = new Board(e.GetArg("board_id").Trim());
|
||||
board.Refresh();
|
||||
await e.Channel.SendMessage("Successfully bound to this channel and board " + board.Name);
|
||||
t.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Failed to join the board. " + ex.ToString());
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "unbind")
|
||||
.Description($"Unbinds a bot from the channel and board. **Bot Owner Only!**| `{Prefix}unbind`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id)) return;
|
||||
if (bound == null || bound != e.Channel) return;
|
||||
t.Stop();
|
||||
bound = null;
|
||||
board = null;
|
||||
await e.Channel.SendMessage("Successfully unbound trello from this channel.").ConfigureAwait(false);
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "lists")
|
||||
.Alias(Prefix + "list")
|
||||
.Description($"Lists all lists, yo ;) **Bot Owner Only!**| `{Prefix}list`")
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id)) return;
|
||||
if (bound == null || board == null || bound != e.Channel) return;
|
||||
await e.Channel.SendMessage("Lists for a board '" + board.Name + "'\n" + string.Join("\n", board.Lists.Select(l => "**• " + l.ToString() + "**")))
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "cards")
|
||||
.Description($"Lists all cards from the supplied list. You can supply either a name or an index. **Bot Owner Only!**| `{Prefix}cards index`")
|
||||
.Parameter("list_name", Discord.Commands.ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!NadekoBot.IsOwner(e.User.Id)) return;
|
||||
if (bound == null || board == null || bound != e.Channel || e.GetArg("list_name") == null) return;
|
||||
|
||||
int num;
|
||||
var success = int.TryParse(e.GetArg("list_name"), out num);
|
||||
List list = null;
|
||||
if (success && num <= board.Lists.Count() && num > 0)
|
||||
list = board.Lists[num - 1];
|
||||
else
|
||||
list = board.Lists.FirstOrDefault(l => l.Name == e.GetArg("list_name"));
|
||||
|
||||
|
||||
if (list != null)
|
||||
await e.Channel.SendMessage("There are " + list.Cards.Count() + " cards in a **" + list.Name + "** list\n" + string.Join("\n", list.Cards.Select(c => "**• " + c.ToString() + "**")))
|
||||
.ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("No such list.")
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Utility.Commands
|
||||
{
|
||||
class InfoCommands : DiscordCommand
|
||||
{
|
||||
public InfoCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "serverinfo")
|
||||
.Alias(Module.Prefix + "sinfo")
|
||||
.Description($"Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. |`{Module.Prefix}sinfo Some Server`")
|
||||
.Parameter("server", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
var servText = e.GetArg("server")?.Trim();
|
||||
var server = string.IsNullOrWhiteSpace(servText)
|
||||
? e.Server
|
||||
: NadekoBot.Client.FindServers(servText).FirstOrDefault();
|
||||
if (server == null)
|
||||
return;
|
||||
var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(server.Id >> 22);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"`Name:` **#{server.Name}**");
|
||||
sb.AppendLine($"`Owner:` **{server.Owner}**");
|
||||
sb.AppendLine($"`Id:` **{server.Id}**");
|
||||
sb.AppendLine($"`Icon Url:` **{await server.IconUrl.ShortenUrl().ConfigureAwait(false)}**");
|
||||
sb.AppendLine($"`TextChannels:` **{server.TextChannels.Count()}** `VoiceChannels:` **{server.VoiceChannels.Count()}**");
|
||||
sb.AppendLine($"`Members:` **{server.UserCount}** `Online:` **{server.Users.Count(u => u.Status == UserStatus.Online)}** (may be incorrect)");
|
||||
sb.AppendLine($"`Roles:` **{server.Roles.Count()}**");
|
||||
sb.AppendLine($"`Created At:` **{createdAt}**");
|
||||
if (server.CustomEmojis.Count() > 0)
|
||||
sb.AppendLine($"`Custom Emojis:` **{string.Join(", ", server.CustomEmojis.Select(em => em.Name))}**");
|
||||
if (server.Features.Count() > 0)
|
||||
sb.AppendLine($"`Features:` **{string.Join(", ", server.Features)}**");
|
||||
if (!string.IsNullOrWhiteSpace(server.SplashId))
|
||||
sb.AppendLine($"`Region:` **{server.Region.Name}**");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "channelinfo")
|
||||
.Alias(Module.Prefix + "cinfo")
|
||||
.Description($"Shows info about the channel. If no channel is supplied, it defaults to current one. |`{Module.Prefix}cinfo #some-channel`")
|
||||
.Parameter("channel", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
var chText = e.GetArg("channel")?.Trim();
|
||||
var ch = string.IsNullOrWhiteSpace(chText)
|
||||
? e.Channel
|
||||
: e.Server.FindChannels(chText, Discord.ChannelType.Text).FirstOrDefault();
|
||||
if (ch == null)
|
||||
return;
|
||||
var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(ch.Id >> 22);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"`Name:` **#{ch.Name}**");
|
||||
sb.AppendLine($"`Id:` **{ch.Id}**");
|
||||
sb.AppendLine($"`Created At:` **{createdAt}**");
|
||||
sb.AppendLine($"`Topic:` **{ch.Topic}**");
|
||||
sb.AppendLine($"`Users:` **{ch.Users.Count()}**");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "userinfo")
|
||||
.Alias(Module.Prefix + "uinfo")
|
||||
.Description($"Shows info about the user. If no user is supplied, it defaults a user running the command. |`{Module.Prefix}uinfo @SomeUser`")
|
||||
.Parameter("user", ParameterType.Optional)
|
||||
.Do(async e =>
|
||||
{
|
||||
var userText = e.GetArg("user")?.Trim();
|
||||
var user = string.IsNullOrWhiteSpace(userText)
|
||||
? e.User
|
||||
: e.Server.FindUsers(userText).FirstOrDefault();
|
||||
if (user == null)
|
||||
return;
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"`Name#Discrim:` **#{user.Name}#{user.Discriminator}**");
|
||||
if (!string.IsNullOrWhiteSpace(user.Nickname))
|
||||
sb.AppendLine($"`Nickname:` **{user.Nickname}**");
|
||||
sb.AppendLine($"`Id:` **{user.Id}**");
|
||||
sb.AppendLine($"`Current Game:` **{(user.CurrentGame?.Name == null ? "-" : user.CurrentGame.Value.Name)}**");
|
||||
if (user.LastOnlineAt != null)
|
||||
sb.AppendLine($"`Last Online:` **{user.LastOnlineAt:HH:mm:ss}**");
|
||||
sb.AppendLine($"`Joined At:` **{user.JoinedAt}**");
|
||||
sb.AppendLine($"`Roles:` **({user.Roles.Count()}) - {string.Join(", ", user.Roles.Select(r => r.Name))}**");
|
||||
sb.AppendLine($"`AvatarUrl:` **{await user.AvatarUrl.ShortenUrl().ConfigureAwait(false)}**");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot.Modules.Utility.Commands
|
||||
{
|
||||
class Remind : DiscordCommand
|
||||
{
|
||||
|
||||
Regex regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
List<Timer> reminders = new List<Timer>();
|
||||
|
||||
IDictionary<string, Func<Reminder, string>> replacements = new Dictionary<string, Func<Reminder, string>>
|
||||
{
|
||||
{ "%message%" , (r) => r.Message },
|
||||
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
||||
{ "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
||||
};
|
||||
|
||||
public Remind(DiscordModule module) : base(module)
|
||||
{
|
||||
var remList = DbHandler.Instance.GetAllRows<Reminder>();
|
||||
|
||||
NadekoBot.OnReady += () => reminders = remList.Select(StartNewReminder).ToList();
|
||||
}
|
||||
|
||||
private Timer StartNewReminder(Reminder r)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var twoMins = new TimeSpan(0, 2, 0);
|
||||
TimeSpan time = (r.When - now) < twoMins
|
||||
? twoMins //if the time is less than 2 minutes,
|
||||
: r.When - now; //it will send the message 2 minutes after start
|
||||
//To account for high bot startup times
|
||||
if (time.TotalMilliseconds > int.MaxValue)
|
||||
return null;
|
||||
var t = new Timer(time.TotalMilliseconds);
|
||||
t.Elapsed += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Channel ch;
|
||||
if (r.IsPrivate)
|
||||
{
|
||||
ch = NadekoBot.Client.PrivateChannels.FirstOrDefault(c => (long)c.Id == r.ChannelId);
|
||||
if (ch == null)
|
||||
ch = await NadekoBot.Client.CreatePrivateChannel((ulong)r.ChannelId).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
ch = NadekoBot.Client.GetServer((ulong)r.ServerId)?.GetChannel((ulong)r.ChannelId);
|
||||
|
||||
if (ch == null)
|
||||
return;
|
||||
|
||||
await ch.SendMessage(
|
||||
replacements.Aggregate(NadekoBot.Config.RemindMessageFormat,
|
||||
(cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
||||
).ConfigureAwait(false); //it works trust me
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Timer error! {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
DbHandler.Instance.Delete<Reminder>(r.Id.Value);
|
||||
t.Stop();
|
||||
t.Dispose();
|
||||
}
|
||||
};
|
||||
t.Start();
|
||||
return t;
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "remind")
|
||||
.Description("Sends a message to you or a channel after certain amount of time. " +
|
||||
"First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. " +
|
||||
"Third argument is a (multiword)message. " +
|
||||
$" | `{Prefix}remind me 1d5h Do something` or `{Prefix}remind #general Start now!`")
|
||||
.Parameter("meorchannel", ParameterType.Required)
|
||||
.Parameter("time", ParameterType.Required)
|
||||
.Parameter("message", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var meorchStr = e.GetArg("meorchannel").ToUpperInvariant();
|
||||
Channel ch;
|
||||
bool isPrivate = false;
|
||||
if (meorchStr == "ME")
|
||||
{
|
||||
isPrivate = true;
|
||||
ch = await e.User.CreatePMChannel().ConfigureAwait(false);
|
||||
}
|
||||
else if (meorchStr == "HERE")
|
||||
{
|
||||
ch = e.Channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = e.Server.FindChannels(meorchStr).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (ch == null)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var timeStr = e.GetArg("time");
|
||||
|
||||
var m = regex.Match(timeStr);
|
||||
|
||||
if (m.Length == 0)
|
||||
{
|
||||
await e.Channel.SendMessage("Not a valid time format blablabla").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
string output = "";
|
||||
var namesAndValues = new Dictionary<string, int>();
|
||||
|
||||
foreach (var groupName in regex.GetGroupNames())
|
||||
{
|
||||
if (groupName == "0") continue;
|
||||
int value = 0;
|
||||
int.TryParse(m.Groups[groupName].Value, out value);
|
||||
|
||||
if (string.IsNullOrEmpty(m.Groups[groupName].Value))
|
||||
{
|
||||
namesAndValues[groupName] = 0;
|
||||
continue;
|
||||
}
|
||||
else if (value < 1 ||
|
||||
(groupName == "months" && value > 1) ||
|
||||
(groupName == "weeks" && value > 4) ||
|
||||
(groupName == "days" && value >= 7) ||
|
||||
(groupName == "hours" && value > 23) ||
|
||||
(groupName == "minutes" && value > 59))
|
||||
{
|
||||
await e.Channel.SendMessage($"Invalid {groupName} value.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
namesAndValues[groupName] = value;
|
||||
output += m.Groups[groupName].Value + " " + groupName + " ";
|
||||
}
|
||||
var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] +
|
||||
7 * namesAndValues["weeks"] +
|
||||
namesAndValues["days"],
|
||||
namesAndValues["hours"],
|
||||
namesAndValues["minutes"],
|
||||
0);
|
||||
|
||||
var rem = new Reminder
|
||||
{
|
||||
ChannelId = (long)ch.Id,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = e.GetArg("message"),
|
||||
UserId = (long)e.User.Id,
|
||||
ServerId = (long)e.Server.Id
|
||||
};
|
||||
DbHandler.Instance.Connection.Insert(rem);
|
||||
|
||||
reminders.Add(StartNewReminder(rem));
|
||||
|
||||
await e.Channel.SendMessage($"⏰ I will remind \"{ch.Name}\" to \"{e.GetArg("message").ToString()}\" in {output}. ({time:d.M.yyyy.} at {time:HH:mm})").ConfigureAwait(false);
|
||||
});
|
||||
cgb.CreateCommand(Module.Prefix + "remindmsg")
|
||||
.Description("Sets message for when the remind is triggered. " +
|
||||
" Available placeholders are %user% - user who ran the command, %message% -" +
|
||||
$" Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!** | `{Prefix}remindmsg do something else`")
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var arg = e.GetArg("msg")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
|
||||
NadekoBot.Config.RemindMessageFormat = arg;
|
||||
await e.Channel.SendMessage("`New remind message set.`");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Utility.Commands;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
internal class UtilityModule : DiscordModule
|
||||
{
|
||||
public UtilityModule()
|
||||
{
|
||||
commands.Add(new Remind(this));
|
||||
commands.Add(new InfoCommands(this));
|
||||
}
|
||||
|
||||
public override string Prefix => NadekoBot.Config.CommandPrefixes.Utility;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
var client = manager.Client;
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "whoplays")
|
||||
.Description($"Shows a list of users who are playing the specified game. | `{Prefix}whoplays Overwatch`")
|
||||
.Parameter("game", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var game = e.GetArg("game")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
var en = e.Server.Users
|
||||
.Where(u => u.CurrentGame?.Name?.ToUpperInvariant() == game)
|
||||
.Select(u => u.Name);
|
||||
|
||||
var arr = en as string[] ?? en.ToArray();
|
||||
|
||||
int i = 0;
|
||||
if (arr.Length == 0)
|
||||
await e.Channel.SendMessage("Nobody. (not 100% sure)").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Concat(ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "inrole")
|
||||
.Description($"Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `{Prefix}inrole Role`")
|
||||
.Parameter("roles", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
|
||||
string send = $"`Here is a list of users in a specfic role:`";
|
||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@everyone" && str != "everyone"))
|
||||
{
|
||||
var role = e.Server.FindRoles(roleStr).FirstOrDefault();
|
||||
if (role == null) continue;
|
||||
send += $"\n`{role.Name}`\n";
|
||||
send += string.Join(", ", role.Members.Select(r => "**" + r.Name + "**#" + r.Discriminator));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageMessages)
|
||||
{
|
||||
await e.Channel.SendMessage($"{e.User.Mention} you are not allowed to use this command on roles with a lot of users in them to prevent abuse.");
|
||||
return;
|
||||
}
|
||||
var curstr = send.Substring(0, 2000);
|
||||
await
|
||||
e.Channel.Send(curstr.Substring(0,
|
||||
curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
send.Substring(2000);
|
||||
}
|
||||
await e.Channel.Send(send).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "checkmyperms")
|
||||
.Description($"Checks your userspecific permissions on this channel. | `{Prefix}checkmyperms`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var output = "```\n";
|
||||
foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
||||
{
|
||||
output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n";
|
||||
}
|
||||
output += "```";
|
||||
await e.User.SendMessage(output).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "stats")
|
||||
.Description($"Shows some basic stats for Nadeko. | `{Prefix}stats`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "dysyd")
|
||||
.Description($"Shows some basic stats for Nadeko. | `{Prefix}dysyd`")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
|
||||
.Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.User;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"Id of the user { usr.Name } is { usr.Id }").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
|
||||
.Description($"Shows current channel ID. | `{Prefix}cid`")
|
||||
.Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
|
||||
.Description($"Shows current server ID. | `{Prefix}sid`")
|
||||
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "roles")
|
||||
.Description($"List all roles on this server or a single user if specified. | `{Prefix}roles`")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
{
|
||||
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null) return;
|
||||
|
||||
await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
|
||||
cgb.CreateCommand(Prefix + "channeltopic")
|
||||
.Alias(Prefix + "ct")
|
||||
.Description($"Sends current channel's topic as a message. | `{Prefix}ct`")
|
||||
.Do(async e =>
|
||||
{
|
||||
var topic = e.Channel.Topic;
|
||||
if (string.IsNullOrWhiteSpace(topic))
|
||||
return;
|
||||
await e.Channel.SendMessage(topic).ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,301 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Audio;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.Help.Commands;
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Modules.Administration;
|
||||
using NadekoBot.Modules.ClashOfClans;
|
||||
using NadekoBot.Modules.Conversations;
|
||||
using NadekoBot.Modules.CustomReactions;
|
||||
using NadekoBot.Modules.Gambling;
|
||||
using NadekoBot.Modules.Games;
|
||||
using NadekoBot.Modules.Games.Commands;
|
||||
using NadekoBot.Modules.Help;
|
||||
#if !NADEKO_RELEASE
|
||||
using NadekoBot.Modules.Music;
|
||||
#endif
|
||||
using NadekoBot.Modules.NSFW;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Pokemon;
|
||||
using NadekoBot.Modules.Searches;
|
||||
using NadekoBot.Modules.Translator;
|
||||
using NadekoBot.Modules.Trello;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
public class NadekoBot
|
||||
{
|
||||
public static DiscordClient Client { get; private set; }
|
||||
public static Credentials Creds { get; set; }
|
||||
public static Configuration Config { get; set; }
|
||||
public static LocalizedStrings Locale { get; set; } = new LocalizedStrings();
|
||||
public static string BotMention { get; set; } = "";
|
||||
public static bool Ready { get; set; } = false;
|
||||
public static Action OnReady { get; set; } = delegate { };
|
||||
|
||||
private static List<Channel> OwnerPrivateChannels { get; set; }
|
||||
|
||||
private static void Main()
|
||||
{
|
||||
Console.OutputEncoding = Encoding.Unicode;
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText("data/config_example.json", JsonConvert.SerializeObject(new Configuration(), Formatting.Indented));
|
||||
if (!File.Exists("data/config.json"))
|
||||
File.Copy("data/config_example.json", "data/config.json");
|
||||
File.WriteAllText("credentials_example.json", JsonConvert.SerializeObject(new Credentials(), Formatting.Indented));
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Failed writing credentials_example.json or data/config_example.json");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Config = JsonConvert.DeserializeObject<Configuration>(File.ReadAllText("data/config.json"));
|
||||
Config.Quotes = JsonConvert.DeserializeObject<List<Quote>>(File.ReadAllText("data/quotes.json"));
|
||||
Config.PokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText("data/PokemonTypes.json"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Failed loading configuration.");
|
||||
Console.WriteLine(ex);
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//load credentials from credentials.json
|
||||
Creds = JsonConvert.DeserializeObject<Credentials>(File.ReadAllText("credentials.json"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load stuff from credentials.json, RTFM\n{ex.Message}");
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
//if password is not entered, prompt for password
|
||||
if (string.IsNullOrWhiteSpace(Creds.Token))
|
||||
{
|
||||
Console.WriteLine("Token blank. Please enter your bot's token:\n");
|
||||
Creds.Token = Console.ReadLine();
|
||||
}
|
||||
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.GoogleAPIKey)
|
||||
? "No google api key found. You will not be able to use music and links won't be shortened."
|
||||
: "Google API key provided.");
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.TrelloAppKey)
|
||||
? "No trello appkey found. You will not be able to use trello commands."
|
||||
: "Trello app key provided.");
|
||||
Console.WriteLine(Config.ForwardMessages != true
|
||||
? "Not forwarding messages."
|
||||
: "Forwarding private messages to owner.");
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.SoundCloudClientID)
|
||||
? "No soundcloud Client ID found. Soundcloud streaming is disabled."
|
||||
: "SoundCloud streaming enabled.");
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.OsuAPIKey)
|
||||
? "No osu! api key found. Song & top score lookups will not work. User lookups still available."
|
||||
: "osu! API key provided.");
|
||||
|
||||
BotMention = $"<@{Creds.BotId}>";
|
||||
|
||||
//create new discord client and log
|
||||
Client = new DiscordClient(new DiscordConfigBuilder()
|
||||
{
|
||||
MessageCacheSize = 10,
|
||||
ConnectionTimeout = int.MaxValue,
|
||||
LogLevel = LogSeverity.Warning,
|
||||
LogHandler = (s, e) =>
|
||||
Console.WriteLine($"Severity: {e.Severity}" +
|
||||
$"ExceptionMessage: {e.Exception?.Message ?? "-"}" +
|
||||
$"Message: {e.Message}"),
|
||||
});
|
||||
|
||||
//create a command service
|
||||
var commandService = new CommandService(new CommandServiceConfigBuilder
|
||||
{
|
||||
AllowMentionPrefix = false,
|
||||
CustomPrefixHandler = m => 0,
|
||||
HelpMode = HelpMode.Disabled,
|
||||
ErrorHandler = async (s, e) =>
|
||||
{
|
||||
if (e.ErrorType != CommandErrorType.BadPermissions)
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(e.Exception?.Message))
|
||||
return;
|
||||
try
|
||||
{
|
||||
await e.Channel.SendMessage(e.Exception.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
|
||||
//add command service
|
||||
Client.AddService<CommandService>(commandService);
|
||||
|
||||
//create module service
|
||||
var modules = Client.AddService<ModuleService>(new ModuleService());
|
||||
|
||||
//add audio service
|
||||
Client.AddService<AudioService>(new AudioService(new AudioServiceConfigBuilder()
|
||||
{
|
||||
Channels = 2,
|
||||
EnableEncryption = false,
|
||||
Bitrate = 128,
|
||||
}));
|
||||
|
||||
//install modules
|
||||
modules.Add(new HelpModule(), "Help", ModuleFilter.None);
|
||||
modules.Add(new AdministrationModule(), "Administration", ModuleFilter.None);
|
||||
modules.Add(new UtilityModule(), "Utility", ModuleFilter.None);
|
||||
modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None);
|
||||
modules.Add(new Conversations(), "Conversations", ModuleFilter.None);
|
||||
modules.Add(new GamblingModule(), "Gambling", ModuleFilter.None);
|
||||
modules.Add(new GamesModule(), "Games", ModuleFilter.None);
|
||||
#if !NADEKO_RELEASE
|
||||
modules.Add(new MusicModule(), "Music", ModuleFilter.None);
|
||||
#endif
|
||||
modules.Add(new SearchesModule(), "Searches", ModuleFilter.None);
|
||||
modules.Add(new NSFWModule(), "NSFW", ModuleFilter.None);
|
||||
modules.Add(new ClashOfClansModule(), "ClashOfClans", ModuleFilter.None);
|
||||
modules.Add(new PokemonModule(), "Pokegame", ModuleFilter.None);
|
||||
modules.Add(new TranslatorModule(), "Translator", ModuleFilter.None);
|
||||
modules.Add(new CustomReactionsModule(), "Customreactions", ModuleFilter.None);
|
||||
if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey))
|
||||
modules.Add(new TrelloModule(), "Trello", ModuleFilter.None);
|
||||
|
||||
//run the bot
|
||||
Client.ExecuteAndWait(async () =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Console.WriteLine("Specific config started initializing.");
|
||||
var x = SpecificConfigurations.Default;
|
||||
Console.WriteLine("Specific config done initializing.");
|
||||
});
|
||||
|
||||
await PermissionsHandler.Initialize();
|
||||
|
||||
try
|
||||
{
|
||||
await Client.Connect(Creds.Token, TokenType.Bot).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Token is wrong. Don't set a token if you don't have an official BOT account.");
|
||||
Console.WriteLine(ex);
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
#if NADEKO_RELEASE
|
||||
await Task.Delay(300000).ConfigureAwait(false);
|
||||
#else
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
Console.WriteLine("-----------------");
|
||||
Console.WriteLine(await NadekoStats.Instance.GetStats().ConfigureAwait(false));
|
||||
Console.WriteLine("-----------------");
|
||||
|
||||
|
||||
OwnerPrivateChannels = new List<Channel>(Creds.OwnerIds.Length);
|
||||
foreach (var id in Creds.OwnerIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
OwnerPrivateChannels.Add(await Client.CreatePrivateChannel(id).ConfigureAwait(false));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine($"Failed creating private channel with the owner {id} listed in credentials.json");
|
||||
}
|
||||
}
|
||||
Client.ClientAPI.SendingRequest += (s, e) =>
|
||||
{
|
||||
var request = e.Request as Discord.API.Client.Rest.SendMessageRequest;
|
||||
if (request == null) return;
|
||||
// meew0 is magic
|
||||
request.Content = request.Content?.Replace("@everyone", "@everyοne").Replace("@here", "@һere") ?? "_error_";
|
||||
if (string.IsNullOrWhiteSpace(request.Content))
|
||||
e.Cancel = true;
|
||||
};
|
||||
#if NADEKO_RELEASE
|
||||
Client.ClientAPI.SentRequest += (s, e) =>
|
||||
{
|
||||
Console.WriteLine($"[Request of type {e.Request.GetType()} sent in {e.Milliseconds}]");
|
||||
|
||||
var request = e.Request as Discord.API.Client.Rest.SendMessageRequest;
|
||||
if (request == null) return;
|
||||
|
||||
Console.WriteLine($"[Content: { request.Content }");
|
||||
};
|
||||
#endif
|
||||
NadekoBot.Ready = true;
|
||||
NadekoBot.OnReady();
|
||||
Console.WriteLine("Ready!");
|
||||
//reply to personal messages and forward if enabled.
|
||||
Client.MessageReceived += Client_MessageReceived;
|
||||
});
|
||||
Console.WriteLine("Exiting...");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
public static bool IsOwner(ulong id) => Creds.OwnerIds.Contains(id);
|
||||
|
||||
public static async Task SendMessageToOwner(string message)
|
||||
{
|
||||
if (Config.ForwardMessages && OwnerPrivateChannels.Any())
|
||||
if (Config.ForwardToAllOwners)
|
||||
OwnerPrivateChannels.ForEach(async c =>
|
||||
{
|
||||
try { await c.SendMessage(message).ConfigureAwait(false); } catch { }
|
||||
});
|
||||
else
|
||||
{
|
||||
var c = OwnerPrivateChannels.FirstOrDefault();
|
||||
if (c != null)
|
||||
await c.SendMessage(message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool repliedRecently = false;
|
||||
private static async void Client_MessageReceived(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server != null || e.User.Id == Client.CurrentUser.Id) return;
|
||||
if (PollCommand.ActivePolls.SelectMany(kvp => kvp.Key.Users.Select(u => u.Id)).Contains(e.User.Id)) return;
|
||||
if (ConfigHandler.IsBlackListed(e))
|
||||
return;
|
||||
|
||||
if (Config.ForwardMessages && !NadekoBot.Creds.OwnerIds.Contains(e.User.Id) && OwnerPrivateChannels.Any())
|
||||
await SendMessageToOwner(e.User + ": ```\n" + e.Message.Text + "\n```").ConfigureAwait(false);
|
||||
|
||||
if (repliedRecently) return;
|
||||
|
||||
repliedRecently = true;
|
||||
if (e.Message.RawText != NadekoBot.Config.CommandPrefixes.Help + "h")
|
||||
await e.Channel.SendMessage(HelpCommand.DMHelpString).ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
repliedRecently = false;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,568 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NadekoBot</RootNamespace>
|
||||
<AssemblyName>NadekoBot</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
<PublishUrl>C:\Users\Master\Desktop\NadekoBot\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<WebPage>publish.htm</WebPage>
|
||||
<AutorunEnabled>true</AutorunEnabled>
|
||||
<ApplicationRevision>1</ApplicationRevision>
|
||||
<ApplicationVersion>0.5.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<NoWarn>
|
||||
</NoWarn>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\PRIVATE\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'NadekoRelease|AnyCPU'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NADEKO_RELEASE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\PRIVATE\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'NadekoRelease|x64'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NADEKO_RELEASE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="libvideo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\VideoLibrary.1.3.3\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\libvideo.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Manatee.Json, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c267f67a39449c62, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Manatee.Json.3.2.1\lib\net45\Manatee.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Manatee.StateMachine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=15909d91027a225e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Manatee.StateMachine.1.1.2\lib\net45\Manatee.StateMachine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Manatee.Trello, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Manatee.Trello.1.8.2\lib\net45\Manatee.Trello.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Manatee.Trello.ManateeJson, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Manatee.Trello.ManateeJson.1.4.0\lib\net45\Manatee.Trello.ManateeJson.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Manatee.Trello.WebApi, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Manatee.Trello.WebApi.1.0.1\lib\net45\Manatee.Trello.WebApi.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MathParser, Version=1.0.10.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MathosParser.1.0.10.1\lib\MathParser.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net452\RestSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ScaredFingers.UnitsConversion, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>lib\ScaredFingers.UnitsConversion.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="sqlite3">
|
||||
<HintPath>Classes\lib\sqlite3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Classes\ObservableConcurrentDictionary.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\AutoAssignRole.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\CustomReactionsCommands.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\SelfCommands.cs" />
|
||||
<Compile Include="Modules\ClashOfClans\ClashOfClans.cs" />
|
||||
<Compile Include="Classes\DBHandler.cs" />
|
||||
<Compile Include="Classes\FlowersHandler.cs" />
|
||||
<Compile Include="Modules\Conversations\Commands\RipCommand.cs" />
|
||||
<Compile Include="Modules\CustomReactions\CustomReactions.cs" />
|
||||
<Compile Include="Modules\Gambling\Commands\AnimalRacing.cs" />
|
||||
<Compile Include="Modules\Music\Classes\PlaylistFullException.cs" />
|
||||
<Compile Include="Modules\Programming\Commands\HaskellRepl.cs" />
|
||||
<Compile Include="Modules\Programming\ProgrammingModule.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\EvalCommand.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\IMDB\ImdbMovie.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\IMDB\ImdbScraper.cs" />
|
||||
<Compile Include="Classes\IncidentsHandler.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\MemegenCommands.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\OsuCommands.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\PokemonSearchCommands.cs" />
|
||||
<Compile Include="Modules\Utility\UtilityModule.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SQLite.cs" />
|
||||
<Compile Include="_Models\DataModels\TestDataModel.cs" />
|
||||
<Compile Include="_Models\DataModels\Incident.cs" />
|
||||
<Compile Include="_Models\JSONModels\AnimeResult.cs" />
|
||||
<Compile Include="_Models\JSONModels\Configuration.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\WowJokes.cs" />
|
||||
<Compile Include="_Models\JSONModels\LocalizedStrings.cs" />
|
||||
<Compile Include="_Models\JSONModels\MagicItem.cs" />
|
||||
<Compile Include="_Models\JSONModels\MangaResult.cs" />
|
||||
<Compile Include="_Models\JSONModels\PokemonType.cs" />
|
||||
<Compile Include="_Models\JSONModels\_JSONModels.cs" />
|
||||
<Compile Include="Modules\Games\Commands\Leet.cs" />
|
||||
<Compile Include="Modules\Music\Classes\MusicControls.cs" />
|
||||
<Compile Include="Modules\Music\Classes\PoopyBuffer.cs" />
|
||||
<Compile Include="Modules\Music\Classes\Song.cs" />
|
||||
<Compile Include="Modules\Music\Classes\SongBuffer.cs" />
|
||||
<Compile Include="Modules\Music\Classes\SoundCloud.cs" />
|
||||
<Compile Include="Modules\Permissions\Classes\PermissionChecker.cs" />
|
||||
<Compile Include="Modules\Permissions\Classes\PermissionHelper.cs" />
|
||||
<Compile Include="Modules\Permissions\Classes\PermissionsHandler.cs" />
|
||||
<Compile Include="Modules\Permissions\Classes\SimpleCheckers.cs" />
|
||||
<Compile Include="Classes\SearchHelper.cs" />
|
||||
<Compile Include="Classes\ServerSpecificConfig.cs" />
|
||||
<Compile Include="_Models\DataModels\AnnouncementModel.cs" />
|
||||
<Compile Include="_Models\DataModels\CommandModel.cs" />
|
||||
<Compile Include="_Models\DataModels\CurrencyStateModel.cs" />
|
||||
<Compile Include="_Models\DataModels\CurrencyTransactionModel.cs" />
|
||||
<Compile Include="_Models\DataModels\Donator.cs" />
|
||||
<Compile Include="_Models\DataModels\IDataModel.cs" />
|
||||
<Compile Include="_Models\DataModels\MusicPlaylist.cs" />
|
||||
<Compile Include="_Models\DataModels\PlaylistSongInfo.cs" />
|
||||
<Compile Include="_Models\DataModels\PokeTypes.cs" />
|
||||
<Compile Include="_Models\DataModels\Reminder.cs" />
|
||||
<Compile Include="_Models\DataModels\RequestModel.cs" />
|
||||
<Compile Include="_Models\DataModels\SongInfo.cs" />
|
||||
<Compile Include="_Models\DataModels\StatsModel.cs" />
|
||||
<Compile Include="_Models\DataModels\TypingArticleModel.cs" />
|
||||
<Compile Include="_Models\DataModels\UserQuoteModel.cs" />
|
||||
<Compile Include="Modules\Games\Commands\BetrayGame.cs" />
|
||||
<Compile Include="Modules\DiscordCommand.cs" />
|
||||
<Compile Include="Modules\Games\Commands\PlantPick.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\CrossServerTextChannel.cs" />
|
||||
<Compile Include="Modules\Utility\Commands\InfoCommands.cs" />
|
||||
<Compile Include="Modules\Utility\Commands\Remind.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\IncidentsCommands.cs" />
|
||||
<Compile Include="Modules\ClashOfClans\ClashOfClansModule.cs" />
|
||||
<Compile Include="Modules\Permissions\Commands\FilterWordsCommand.cs" />
|
||||
<Compile Include="Modules\Permissions\Commands\FilterInvitesCommand.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\LogCommand.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\LoLCommands.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\MessageRepeater.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\PlayingRotate.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\StreamNotifications.cs" />
|
||||
<Compile Include="Modules\Games\Commands\TriviaCommand.cs" />
|
||||
<Compile Include="Modules\Games\Commands\Trivia\TriviaGame.cs" />
|
||||
<Compile Include="Modules\Games\Commands\Trivia\TriviaQuestion.cs" />
|
||||
<Compile Include="Modules\Games\Commands\Trivia\TriviaQuestionPool.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\ServerGreetCommand.cs" />
|
||||
<Compile Include="Modules\Games\Commands\SpeedTyping.cs" />
|
||||
<Compile Include="Modules\Gambling\Helpers\Cards.cs" />
|
||||
<Compile Include="Classes\Extensions.cs" />
|
||||
<Compile Include="Modules\Gambling\DiceRollCommand.cs" />
|
||||
<Compile Include="Modules\Gambling\DrawCommand.cs" />
|
||||
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
|
||||
<Compile Include="Modules\Help\Commands\HelpCommand.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" />
|
||||
<Compile Include="Modules\Administration\AdministrationModule.cs" />
|
||||
<Compile Include="Modules\Conversations\Conversations.cs" />
|
||||
<Compile Include="Modules\DiscordModule.cs" />
|
||||
<Compile Include="Modules\Gambling\GamblingModule.cs" />
|
||||
<Compile Include="Modules\Games\Commands\Bomberman.cs" />
|
||||
<Compile Include="Modules\Games\GamesModule.cs" />
|
||||
<Compile Include="Modules\Help\HelpModule.cs" />
|
||||
<Compile Include="Modules\Music\MusicModule.cs" />
|
||||
<Compile Include="Modules\Games\Commands\PollCommand.cs" />
|
||||
<Compile Include="Modules\NSFW\NSFWModule.cs" />
|
||||
<Compile Include="Modules\Permissions\PermissionsModule.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
|
||||
<Compile Include="Modules\Pokemon\PokemonModule.cs" />
|
||||
<Compile Include="Modules\Pokemon\PokeStats.cs" />
|
||||
<Compile Include="Modules\Searches\SearchesModule.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\ConverterCommand.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\RedditCommand.cs" />
|
||||
<Compile Include="Modules\Translator\Helpers\GoogleTranslator.cs" />
|
||||
<Compile Include="Modules\Translator\TranslateCommand.cs" />
|
||||
<Compile Include="Modules\Translator\TranslatorModule.cs" />
|
||||
<Compile Include="Modules\Translator\ValidLanguagesCommand.cs" />
|
||||
<Compile Include="Modules\Trello\TrelloModule.cs" />
|
||||
<Compile Include="NadekoBot.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Classes\NadekoStats.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\rip.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\6.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\7.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\8.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\9.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\0.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\1.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\3.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\4.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\dice\5.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\coins\tails.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\coins\heads.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\2_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\2_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\2_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\3_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\3_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\3_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\3_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\4_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\4_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\4_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\4_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\5_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\5_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\5_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\5_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\6_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\6_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\6_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\6_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\7_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\7_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\7_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\7_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\8_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\8_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\8_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\8_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\9_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\9_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\9_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\9_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\10_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\10_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\10_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\10_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\ace_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\ace_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\ace_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\ace_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\black_joker.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\jack_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\jack_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\jack_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\jack_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\king_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\king_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\king_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\king_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\queen_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\queen_of_diamonds.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\queen_of_hearts.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\queen_of_spades.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\red_joker.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\images\cards\2_of_clubs.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\discord.net\src\Discord.Net.Audio.Net45\Discord.Net.Audio.csproj">
|
||||
<Project>{7bfef748-b934-4621-9b11-6302e3a9f6b3}</Project>
|
||||
<Name>Discord.Net.Audio</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\discord.net\src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj">
|
||||
<Project>{1b5603b4-6f8f-4289-b945-7baae523d740}</Project>
|
||||
<Name>Discord.Net.Commands</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\discord.net\src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj">
|
||||
<Project>{3091164f-66ae-4543-a63d-167c1116241d}</Project>
|
||||
<Name>Discord.Net.Modules</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\discord.net\src\Discord.Net.Net45\Discord.Net.csproj">
|
||||
<Project>{8d71a857-879a-4a10-859e-5ff824ed6688}</Project>
|
||||
<Name>Discord.Net</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Classes\lib\ScaredFingers.UnitsConversion.dll" />
|
||||
<None Include="resources\images\rose_overlay.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,34 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyDescription("Discord bot written in C#.")]
|
||||
[assembly: AssemblyCompany("Kwoth")]
|
||||
[assembly: AssemblyCopyright("Copyright © Kwoth 2015-2016")]
|
||||
[assembly: AssemblyProduct("NadekoBot")]
|
||||
[assembly: AssemblyVersion("0.9.*")]
|
||||
[assembly: AssemblyTitle("NadekoBot")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("27a886f5-cdda-4f4a-81ee-6dafcce9de46")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
743
NadekoBot/Properties/Resources.Designer.cs
generated
743
NadekoBot/Properties/Resources.Designer.cs
generated
@ -1,743 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace NadekoBot.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NadekoBot.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _10_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_10_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _10_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_10_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _10_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_10_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _10_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_10_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _2_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_2_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _2_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_2_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _2_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_2_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _2_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_2_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _3_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_3_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _3_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_3_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _3_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_3_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _3_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_3_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _4_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_4_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _4_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_4_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _4_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_4_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _4_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_4_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _5 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_5", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _5_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_5_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _5_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_5_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _5_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_5_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _5_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_5_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _6 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_6", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _6_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_6_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _6_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_6_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _6_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_6_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _6_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_6_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _7 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_7", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _7_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_7_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _7_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_7_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _7_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_7_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _7_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_7_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _8 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_8", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _8_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_8_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _8_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_8_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _8_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_8_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _8_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_8_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _9 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_9", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _9_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_9_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _9_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_9_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _9_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_9_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap _9_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("_9_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap ace_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ace_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap ace_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ace_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap ace_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ace_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap ace_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ace_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap black_joker {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("black_joker", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap heads {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("heads", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap jack_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("jack_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap jack_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("jack_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap jack_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("jack_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap jack_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("jack_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap king_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("king_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap king_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("king_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap king_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("king_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap king_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("king_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap queen_of_clubs {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("queen_of_clubs", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap queen_of_diamonds {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("queen_of_diamonds", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap queen_of_hearts {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("queen_of_hearts", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap queen_of_spades {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("queen_of_spades", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap red_joker {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("red_joker", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap rip {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("rip", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap rose_overlay {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("rose_overlay", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap tails {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("tails", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,325 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="ace_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\ace_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ace_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\ace_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ace_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\ace_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ace_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\ace_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="black_joker" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\black_joker.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="heads" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\coins\heads.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="jack_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\jack_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="jack_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\jack_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="jack_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\jack_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="jack_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\jack_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="king_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\king_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="king_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\king_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="king_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\king_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="king_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\king_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="queen_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\queen_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="queen_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\queen_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="queen_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\queen_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="queen_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\queen_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="red_joker" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\red_joker.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="rip" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\rip.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="tails" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\coins\tails.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_10_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\10_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_10_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\10_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_10_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\10_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_10_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\10_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_2_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\2_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_2_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\2_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_2_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\2_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_2_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\2_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_3_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\3_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_3_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\3_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_3_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\3_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_3_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\3_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_4_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\4_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_4_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\4_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_4_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\4_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_4_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\4_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_5_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\5_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_5_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\5_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_5_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\5_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_5_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\5_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_6" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_6_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\6_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_6_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\6_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_6_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\6_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_6_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\6_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_7" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\7.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_7_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\7_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_7_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\7_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_7_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\7_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_7_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\7_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_8" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\8.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_8_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\8_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_8_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\8_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_8_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\8_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_8_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\8_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_9" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\dice\9.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_9_of_clubs" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\9_of_clubs.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_9_of_diamonds" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\9_of_diamonds.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_9_of_hearts" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\9_of_hearts.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="_9_of_spades" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\cards\9_of_spades.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="rose_overlay" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\images\rose_overlay.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
3278
NadekoBot/SQLite.cs
3278
NadekoBot/SQLite.cs
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
internal class Announcement : IDataModel
|
||||
{
|
||||
public long ServerId { get; set; } = 0;
|
||||
public bool Greet { get; set; } = false;
|
||||
public bool GreetPM { get; set; } = false;
|
||||
[JsonProperty("greetChannel")]
|
||||
public long GreetChannelId { get; set; } = 0;
|
||||
public string GreetText { get; set; } = "Welcome %user%!";
|
||||
public bool Bye { get; set; } = false;
|
||||
public bool ByePM { get; set; } = false;
|
||||
[JsonProperty("byeChannel")]
|
||||
public long ByeChannelId { get; set; } = 0;
|
||||
public string ByeText { get; set; } = "%user% has left the server.";
|
||||
public bool DeleteGreetMessages { get; set; } = true;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class Command : IDataModel {
|
||||
public long UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public long ServerId { get; set; }
|
||||
public string ServerName { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
public string ChannelName { get; set; }
|
||||
public string CommandName { get; set; }
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class CurrencyState : IDataModel {
|
||||
public long Value { get; set; }
|
||||
[SQLite.Unique]
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class CurrencyTransaction : IDataModel {
|
||||
public string Reason { get; set; }
|
||||
public int Value { get; set; }
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class Donator : IDataModel {
|
||||
public long UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using SQLite;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
internal abstract class IDataModel
|
||||
{
|
||||
[PrimaryKey, AutoIncrement]
|
||||
public int? Id { get; set; }
|
||||
[Newtonsoft.Json.JsonProperty("createdAt")]
|
||||
public DateTime DateAdded { get; set; } = DateTime.Now;
|
||||
public IDataModel() { }
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
class Incident : IDataModel
|
||||
{
|
||||
public long ServerId { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
public string Text { get; set; }
|
||||
public bool Read { get; set; } = false;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user