commit
17d642805f
@ -1 +1 @@
|
||||
Subproject commit fa2568bc312ba35f1518e47601c62fccdb949731
|
||||
Subproject commit b9f767337d2b7c07ed76eb83c3bc5030109d5238
|
@ -12,8 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "NadekoBot", "src\NadekoBot\NadekoBot.xproj", "{45EC1473-C678-4857-A544-07DFE0D0B478}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.API", "discord.net\src\Discord.Net.API\Discord.Net.API.xproj", "{834C70DF-1230-4AAA-9C13-48AB232E8D76}"
|
||||
EndProject
|
||||
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
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Core", "discord.net\src\Discord.Net.Core\Discord.Net.Core.xproj", "{E5F4786F-58F3-469E-8C87-1908A95436B7}"
|
||||
@ -35,12 +33,6 @@ Global
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.Build.0 = Release|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
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{834C70DF-1230-4AAA-9C13-48AB232E8D76}.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 = Debug|Any CPU
|
||||
|
@ -18,8 +18,63 @@ You can support the project on patreon: <https://patreon.com/nadekobot> or paypa
|
||||
### Administration
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms`
|
||||
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd`
|
||||
`.voice+text` `.v+t` | 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. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.voice+text`
|
||||
`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t`
|
||||
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
|
||||
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
|
||||
`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.`
|
||||
`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm`
|
||||
`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`.
|
||||
`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye`
|
||||
`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.`
|
||||
`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30`
|
||||
`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331`
|
||||
`.die` | Shuts the bot down. **Bot Owner only.** | `.die`
|
||||
`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName`
|
||||
`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle`
|
||||
`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg`
|
||||
`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes`
|
||||
`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello`
|
||||
`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message`
|
||||
`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam`
|
||||
`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm`
|
||||
`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer`
|
||||
`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar`
|
||||
`.lsar` | Lists all self-assignable roles. | `.lsar`
|
||||
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar`
|
||||
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer`
|
||||
`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer`
|
||||
`.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode`
|
||||
`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl`
|
||||
`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl`
|
||||
`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl`
|
||||
`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl`
|
||||
`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced`
|
||||
`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone`
|
||||
`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone`
|
||||
`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone`
|
||||
`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone`
|
||||
`.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone`
|
||||
`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy`
|
||||
`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata`
|
||||
`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1`
|
||||
`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2`
|
||||
`.repeat` | Repeat a message every X minutes in the current channel. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
|
||||
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
|
||||
`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable`
|
||||
`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore`
|
||||
`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents`
|
||||
`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned`
|
||||
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs`
|
||||
`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall`
|
||||
`.scsc` | 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.** | `.scsc`
|
||||
`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere`
|
||||
`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc`
|
||||
`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable
|
||||
`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick`
|
||||
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban`
|
||||
`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms`
|
||||
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd`
|
||||
`.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest`
|
||||
`.removerole` `.rr` | Removes a role from a given user. **Requires ManageRoles server permission.** | `.rr @User Admin`
|
||||
`.renamerole` `.renr` | Renames a role. Roles you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole`
|
||||
@ -38,62 +93,10 @@ Command and aliases | Description | Usage
|
||||
`.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic`
|
||||
`.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName`
|
||||
`.prune` `.clr` | `.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. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
|
||||
`.die` | Shuts the bot down. **Bot Owner only.** | `.die`
|
||||
`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName`
|
||||
`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg`
|
||||
`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes`
|
||||
`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello`
|
||||
`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message`
|
||||
`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam`
|
||||
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150`
|
||||
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150`
|
||||
`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName`
|
||||
`.donators` | List of lovely people who donated to keep this project alive. | `.donators`
|
||||
`.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount`
|
||||
`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick`
|
||||
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban`
|
||||
`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable
|
||||
`.scsc` | 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.** | `.scsc`
|
||||
`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere`
|
||||
`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc`
|
||||
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs`
|
||||
`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall`
|
||||
`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable`
|
||||
`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore`
|
||||
`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents`
|
||||
`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned`
|
||||
`.repeatinvoke` `.repinv` | Immediately shows the repeat message and restarts the timer. **Requires ManageMessages server permission.** | `.repinv`
|
||||
`.repeat` | Repeat a message every X minutes. If no parameters are specified, repeat is disabled. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
|
||||
`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata`
|
||||
`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced`
|
||||
`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone`
|
||||
`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone`
|
||||
`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone`
|
||||
`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone`
|
||||
`.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone`
|
||||
`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy`
|
||||
`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl`
|
||||
`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl`
|
||||
`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl`
|
||||
`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl`
|
||||
`.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode`
|
||||
`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm`
|
||||
`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer`
|
||||
`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar`
|
||||
`.lsar` | Lists all self-assignable roles. | `.lsar`
|
||||
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar`
|
||||
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer`
|
||||
`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer`
|
||||
`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331`
|
||||
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
|
||||
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
|
||||
`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.`
|
||||
`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm`
|
||||
`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`.
|
||||
`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye`
|
||||
`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.`
|
||||
`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30`
|
||||
`.voice+text` `.v+t` | 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. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.voice+text`
|
||||
`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t`
|
||||
`.donators` | List of lovely people who donated to keep this project alive. | `.donators`
|
||||
`.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
@ -120,59 +123,60 @@ Command and aliases | Description | Usage
|
||||
`.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1`
|
||||
`.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1`
|
||||
`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5`
|
||||
`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. | `.crstatsclear` or `.crstatsclear rng`
|
||||
`.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3`
|
||||
`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner only.** | `.crstatsclear` or `.crstatsclear rng`
|
||||
`.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
### Gambling
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
|
||||
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
|
||||
`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. | `$bf 5 heads` or `$bf 3 t`
|
||||
`$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
|
||||
`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh`
|
||||
`$roll` | 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. Y can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF`
|
||||
`$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
|
||||
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
|
||||
`$race` | Starts a new animal race. | `$race`
|
||||
`$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
|
||||
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
|
||||
`$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
|
||||
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
||||
`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner only.** | `$award 100 @person` or `$award 5 Role Of Gamblers`
|
||||
`$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"`
|
||||
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
||||
`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner only.** | `$award 100 @person` or `$award 5 Role Of Gamblers`
|
||||
`$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"`
|
||||
`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. | `$br 5`
|
||||
`$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb`
|
||||
`$race` | Starts a new animal race. | `$race`
|
||||
`$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
|
||||
`$roll` | 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. Y can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF`
|
||||
`$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
|
||||
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
|
||||
`$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
|
||||
`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh`
|
||||
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
|
||||
`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. | `$bf 5 heads` or `$bf 3 t`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
### Games
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
|
||||
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something`
|
||||
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
|
||||
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
||||
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
||||
`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3`
|
||||
`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3`
|
||||
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
||||
`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30`
|
||||
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot`
|
||||
`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist`
|
||||
`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies`
|
||||
`>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick`
|
||||
`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant`
|
||||
`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc`
|
||||
`>typestart` | Starts a typing contest. | `>typestart`
|
||||
`>typestop` | Stops a typing contest on the current channel. | `>typestop`
|
||||
`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords`
|
||||
`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3`
|
||||
`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3`
|
||||
`>trivia` `>t` | 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. | `>t` or `>t 5 nohint`
|
||||
`>tl` | Shows a current trivia leaderboard. | `>tl`
|
||||
`>tq` | Quits current trivia after current question. | `>tq`
|
||||
`>tl` | Shows a current trivia leaderboard. | `>tl`
|
||||
`>tq` | Quits current trivia after current question. | `>tq`
|
||||
`>typestart` | Starts a typing contest. | `>typestart`
|
||||
`>typestop` | Stops a typing contest on the current channel. | `>typestop`
|
||||
`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords`
|
||||
`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3`
|
||||
`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3`
|
||||
`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3`
|
||||
`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3`
|
||||
`>pollstats` | Shows the poll results without stopping the poll on this server. **Requires ManageMessages server permission.** | `>pollstats`
|
||||
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
||||
`>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick`
|
||||
`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant`
|
||||
`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc`
|
||||
`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist`
|
||||
`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies`
|
||||
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot`
|
||||
`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30`
|
||||
`>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
|
||||
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something`
|
||||
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
|
||||
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
||||
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
@ -182,9 +186,9 @@ Command and aliases | Description | Usage
|
||||
`-modules` `-mdls` | Lists all bot modules. | `-modules`
|
||||
`-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. | `-commands Administration` or `-cmds Admin`
|
||||
`-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h !!q` or `-h`
|
||||
`-hgit` | Generates the commandlist.md file. **Bot Owner only.** | `-hgit`
|
||||
`-hgit` | Generates the commandlist.md file. **Bot Owner only.** | `-hgit`
|
||||
`-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide`
|
||||
`-donate` | Instructions for helping the project financially. | `-donate`
|
||||
`-donate` | Instructions for helping the project financially. | `-donate`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
@ -215,11 +219,11 @@ Command and aliases | Description | Usage
|
||||
`!!setmaxplaytime` `!!smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `!!smp 0` or `!!smp 270`
|
||||
`!!reptcursong` `!!rcs` | Toggles repeat of current song. | `!!rcs`
|
||||
`!!rpeatplaylst` `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl`
|
||||
`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!!save classical1`
|
||||
`!!load` | Loads a saved playlist using it's ID. Use `!!pls` to list all saved playlists and !!save to save new ones. | `!!load 5`
|
||||
`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!!save classical1`
|
||||
`!!load` | Loads a saved playlist using it's ID. Use `!!pls` to list all saved playlists and !!save to save new ones. | `!!load 5`
|
||||
`!!playlists` `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1`
|
||||
`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
|
||||
`!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
|
||||
`!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
|
||||
`!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `!!ap`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
@ -227,17 +231,17 @@ Command and aliases | Description | Usage
|
||||
### NSFW
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri`
|
||||
`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. | `~autohentai 30 yuri|tail|long_hair` or `~autohentai`
|
||||
`~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri`
|
||||
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing`
|
||||
`~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2`
|
||||
`~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri`
|
||||
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
|
||||
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing`
|
||||
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing`
|
||||
`~cp` | We all know where this will lead you to. | `~cp`
|
||||
`~boobs` | Real adult content. | `~boobs`
|
||||
`~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri`
|
||||
`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. | `~autohentai 30 yuri|tail|long_hair` or `~autohentai`
|
||||
`~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri`
|
||||
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing`
|
||||
`~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2`
|
||||
`~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri`
|
||||
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
|
||||
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing`
|
||||
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing`
|
||||
`~cp` | We all know where this will lead you to. | `~cp`
|
||||
`~boobs` | Real adult content. | `~boobs`
|
||||
`~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
@ -245,6 +249,17 @@ Command and aliases | Description | Usage
|
||||
### Permissions
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi`
|
||||
`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi`
|
||||
`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw`
|
||||
`;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw`
|
||||
`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop`
|
||||
`;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw`
|
||||
`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5`
|
||||
`;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds`
|
||||
`;ubl` | Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. **Bot Owner only.** | `;ubl add @SomeUser` or `;ubl rem 12312312313`
|
||||
`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312`
|
||||
`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer`
|
||||
`;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
|
||||
`;permrole` `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role`
|
||||
`;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3`
|
||||
@ -262,120 +277,111 @@ Command and aliases | Description | Usage
|
||||
`;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole`
|
||||
`;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone`
|
||||
`;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]`
|
||||
`;ubl` | Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. **Bot Owner only.** | `;ubl add @SomeUser` or `;ubl rem 12312312313`
|
||||
`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312`
|
||||
`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer`
|
||||
`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5`
|
||||
`;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds`
|
||||
`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi`
|
||||
`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi`
|
||||
`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw`
|
||||
`;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw`
|
||||
`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop`
|
||||
`;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
### Pokemon
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
|
||||
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
|
||||
`>movelist` `>ml` | Lists the moves you are able to use | `>ml`
|
||||
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | `>heal @someone`
|
||||
`>type` | Get the poketype of the target. | `>type @someone`
|
||||
`>settype` | Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. | `>settype fire` or `>settype`
|
||||
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | `>heal @someone`
|
||||
`>type` | Get the poketype of the target. | `>type @someone`
|
||||
`>settype` | Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. | `>settype fire` or `>settype`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
### Searches
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU`
|
||||
`~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query`
|
||||
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
|
||||
`~randomcat` `~meow` | Shows a random cat image. | `~meow`
|
||||
`~randomdog` `~woof` | Shows a random dog image. | `~woof`
|
||||
`~img` `~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | `~i cute kitten`
|
||||
`~ir` | Pulls a random image using a search parameter. | `~ir cute kitten`
|
||||
`~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
|
||||
`~shorten` | Attempts to shorten an URL, if it fails, returns the input URL. | `~shorten https://google.com`
|
||||
`~google` `~g` | Get a google search link for some terms. | `~google query`
|
||||
`~magicthegathering` `~mtg` | Searches for a Magic The Gathering card. | `~magicthegathering about face` or `~mtg about face`
|
||||
`~hearthstone` `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
|
||||
`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | ~yodify I was once an adventurer like you` or `~yoda my feelings hurt`
|
||||
`~urbandict` `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
|
||||
`~define` `~def` | Finds a definition of a word. | `~def heresy`
|
||||
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
|
||||
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `~catfact`
|
||||
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"`
|
||||
`~revimg` | Returns a google reverse image search for an image from a link. | `~revimg Image link`
|
||||
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~safebooru yuri+kissing`
|
||||
`~wikipedia` `~wiki` | Gives you back a wikipedia link | `~wiki query`
|
||||
`~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
|
||||
`~videocall` | 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. | `~videocall "@SomeGuy"`
|
||||
`~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"`
|
||||
`~wikia` | Gives you back a wikia link | `~wikia mtg Vigilance` or `~wikia mlp Dashy`
|
||||
`~minecraftping` `~mcping` | Pings a minecraft server. | `~mcping 127.0.0.1:25565`
|
||||
`~minecraftquery` `~mcq` | Finds information about a minecraft server. | `~mcq server:ip`
|
||||
`~lolban` | Shows top banned champions ordered by ban rate. | `~lolban`
|
||||
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`
|
||||
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
||||
`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol`
|
||||
`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin`
|
||||
`~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
|
||||
`~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
|
||||
`~chucknorris` `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn`
|
||||
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
|
||||
`~magicitem` `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
|
||||
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
|
||||
`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712`
|
||||
`~osu5` | Displays a user's top 5 plays. | `~osu5 Name`
|
||||
`~overwatch` `~ow` | Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` | `~ow us Battletag#1337` or `~overwatch eu Battletag#2016`
|
||||
`~placelist` | Shows the list of available tags for the `~place` command. | `~placelist`
|
||||
`~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400`
|
||||
`~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon`
|
||||
`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow`
|
||||
`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest`
|
||||
`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello`
|
||||
`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del`
|
||||
`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value.
|
||||
`~translangs` | Lists the valid languages for translation. | `~translangs`
|
||||
`~hitbox` `~hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~hitbox SomeStreamer`
|
||||
`~twitch` `~tw` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~twitch SomeStreamer`
|
||||
`~beam` `~bm` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~beam SomeStreamer`
|
||||
`~liststreams` `~ls` | Lists all streams you are following on this server. | `~ls`
|
||||
`~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy`
|
||||
`~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer`
|
||||
`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello`
|
||||
`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del`
|
||||
`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value.
|
||||
`~translangs` | Lists the valid languages for translation. | `~translangs`
|
||||
`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest`
|
||||
`~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon`
|
||||
`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow`
|
||||
`~placelist` | Shows the list of available tags for the `~place` command. | `~placelist`
|
||||
`~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400`
|
||||
`~overwatch` `~ow` | Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` | `~ow us Battletag#1337` or `~overwatch eu Battletag#2016`
|
||||
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
|
||||
`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712`
|
||||
`~osu5` | Displays a user's top 5 plays. | `~osu5 Name`
|
||||
`~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
|
||||
`~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
|
||||
`~chucknorris` `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn`
|
||||
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
|
||||
`~magicitem` `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
|
||||
`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol`
|
||||
`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin`
|
||||
`~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU`
|
||||
`~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query`
|
||||
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
|
||||
`~randomcat` `~meow` | Shows a random cat image. | `~meow`
|
||||
`~randomdog` `~woof` | Shows a random dog image. | `~woof`
|
||||
`~image` `~img` | Pulls the first image found using a search parameter. Use ~rimg for different results. | `~img cute kitten`
|
||||
`~randomimage` `~rimg` | Pulls a random image using a search parameter. | `~rimg cute kitten`
|
||||
`~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
|
||||
`~shorten` | Attempts to shorten an URL, if it fails, returns the input URL. | `~shorten https://google.com`
|
||||
`~google` `~g` | Get a google search link for some terms. | `~google query`
|
||||
`~magicthegathering` `~mtg` | Searches for a Magic The Gathering card. | `~magicthegathering about face` or `~mtg about face`
|
||||
`~hearthstone` `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
|
||||
`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | ~yodify I was once an adventurer like you` or `~yoda my feelings hurt`
|
||||
`~urbandict` `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
|
||||
`~define` `~def` | Finds a definition of a word. | `~def heresy`
|
||||
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
|
||||
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `~catfact`
|
||||
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"`
|
||||
`~revimg` | Returns a google reverse image search for an image from a link. | `~revimg Image link`
|
||||
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~safebooru yuri+kissing`
|
||||
`~wikipedia` `~wiki` | Gives you back a wikipedia link | `~wiki query`
|
||||
`~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
|
||||
`~videocall` | 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. | `~videocall "@SomeGuy"`
|
||||
`~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"`
|
||||
`~wikia` | Gives you back a wikia link | `~wikia mtg Vigilance` or `~wikia mlp Dashy`
|
||||
`~minecraftping` `~mcping` | Pings a minecraft server. | `~mcping 127.0.0.1:25565`
|
||||
`~minecraftquery` `~mcq` | Finds information about a minecraft server. | `~mcq server:ip`
|
||||
`~lolban` | Shows top banned champions ordered by ban rate. | `~lolban`
|
||||
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`
|
||||
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
||||
|
||||
###### [Back to TOC](#table-of-contents)
|
||||
|
||||
### Utility
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`.togethertube` `.totube` | Creates a new room on <https://togethertube.com> and shows the link in the chat. | `.totube`
|
||||
`.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch`
|
||||
`.inrole` | 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. | `.inrole Role`
|
||||
`.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms`
|
||||
`.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
|
||||
`.channelid` `.cid` | Shows current channel ID. | `.cid`
|
||||
`.serverid` `.sid` | Shows current server ID. | `.sid`
|
||||
`.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone`
|
||||
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
||||
`.stats` | Shows some basic stats for Nadeko. | `.stats`
|
||||
`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis`
|
||||
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3`
|
||||
`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1`
|
||||
`.calcops` | Shows all available operations in .calc command | `.calcops`
|
||||
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
|
||||
`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000`
|
||||
`.remind` | 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. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!`
|
||||
`.remindtemplate` | 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.** | `.remindtemplate %user%, do %message%!`
|
||||
`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page.
|
||||
`...` | Shows a random quote with a specified name. | `... abc`
|
||||
`..` | Adds a new quote with the specified name and message. | `.. sayhi Hi`
|
||||
`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc`
|
||||
`.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek`
|
||||
`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server`
|
||||
`.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel`
|
||||
`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser`
|
||||
`.activity` | Checks for spammers. **Bot Owner only.** | `.activity`
|
||||
`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page.
|
||||
`...` | Shows a random quote with a specified name. | `... abc`
|
||||
`..` | Adds a new quote with the specified name and message. | `.. sayhi Hi`
|
||||
`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc`
|
||||
`.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek`
|
||||
`.remind` | 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. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!`
|
||||
`.remindtemplate` | 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.** | `.remindtemplate %user%, do %message%!`
|
||||
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
|
||||
`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000`
|
||||
`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1`
|
||||
`.calcops` | Shows all available operations in .calc command | `.calcops`
|
||||
`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole`
|
||||
`.togethertube` `.totube` | Creates a new room on <https://togethertube.com> and shows the link in the chat. | `.totube`
|
||||
`.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch`
|
||||
`.inrole` | 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. | `.inrole Role`
|
||||
`.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms`
|
||||
`.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
|
||||
`.channelid` `.cid` | Shows current channel ID. | `.cid`
|
||||
`.serverid` `.sid` | Shows current server ID. | `.sid`
|
||||
`.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone`
|
||||
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
||||
`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv`
|
||||
`.stats` | Shows some basic stats for Nadeko. | `.stats`
|
||||
`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis`
|
||||
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3`
|
||||
`.activity` | Checks for spammers. **Bot Owner only.** | `.activity`
|
||||
|
@ -40,7 +40,7 @@ There are currently three different placeholders which we will look at, with mor
|
||||
|
||||
| Placeholder | Description | Example Usage | Usage |
|
||||
|:-----------:|-------------|---------------|-------|
|
||||
|`%mention`|The `%mention%` placeholder is triggered when you type `@BotName` - It's important to note that if you've given the bot a custom nickname, this trigger won't work!|```.acr "Hello %mention%" I, %mention%, also say hello!```|Input: "Hello @BotName" Output: "I, @BotName, also say hello!"|
|
||||
|`%mention%`|The `%mention%` placeholder is triggered when you type `@BotName` - It's important to note that if you've given the bot a custom nickname, this trigger won't work!|```.acr "Hello %mention%" I, %mention%, also say hello!```|Input: "Hello @BotName" Output: "I, @BotName, also say hello!"|
|
||||
|`%user%`|The `%user%` placeholder mentions the person who said the command|`.acr "Who am I?" You are %user%!`|Input: "Who am I?" Output: "You are @Username!"|
|
||||
|`%rng%`|The `%rng%` placeholder generates a random number between 0 and 10. You can also specify a custom range (%rng1-100%) even with negative numbers: `%rng-9--1%` (from -9 to -1) . |`.acr "Random number" %rng%`|Input: "Random number" Output: "2"|
|
||||
|`%rnduser%`|The `%rnduser%` placeholder mentions a random user from the server. |`.acr "Random user" %rnduser%`|Input: "Random number" Output: @SomeUser|
|
||||
|
@ -43,7 +43,7 @@ Commonly Asked Questions
|
||||
---------------
|
||||
|
||||
###How do I create a music DJ?
|
||||
To allow users to only see the current song and have a DJ role for queuing follow these five steps:
|
||||
To allow users to only see the current song and have a DJ role for queuing follow these steps:
|
||||
|
||||
1. `;sm Music disable`
|
||||
|
||||
@ -53,17 +53,13 @@ To allow users to only see the current song and have a DJ role for queuing follo
|
||||
|
||||
* Enables the "nowplaying" command for everyone
|
||||
|
||||
3. `;sc !!getlink enable`
|
||||
|
||||
* Enables the "getlink" command for everyone
|
||||
|
||||
4. `;sc !!listqueue enable`
|
||||
3. `;sc !!listqueue enable`
|
||||
|
||||
* Enables the "listqueue" command for everyone
|
||||
|
||||
5. `;rm Music enable DJ`
|
||||
4. `;rm Music enable DJ`
|
||||
|
||||
* Enables all the music commands only for the DJ role
|
||||
* Enables all music commands only for the DJ role
|
||||
|
||||
|
||||
###How do I create a NSFW channel?
|
||||
|
@ -1,34 +1,58 @@
|
||||
# NadekoBot a Discord bot
|
||||
Nadeko is written in C# and Discord.net for more information visit https://github.com/Kwoth/NadekoBot
|
||||
Nadeko is written in C# and Discord.net for more information visit <https://github.com/Kwoth/NadekoBot>
|
||||
|
||||
## Install Docker
|
||||
Follow the respective guide for your operating system found here https://docs.docker.com/engine/installation/
|
||||
Follow the respective guide for your operating system found here [Docker Engine Install Guide](https://docs.docker.com/engine/installation/)
|
||||
|
||||
## Nadeko Setup Guide
|
||||
For this guide we will be using the folder /nadeko as our config root folder.
|
||||
|
||||
```
|
||||
docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json kwoth/nadeko:dev
|
||||
```bash
|
||||
docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko
|
||||
```
|
||||
-If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder.
|
||||
|
||||
-If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder
|
||||
http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/
|
||||
-If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/)
|
||||
|
||||
Next start the docker up with
|
||||
|
||||
```docker start nadeko; docker logs -f nadeko```
|
||||
`docker start nadeko; docker logs -f nadeko`
|
||||
|
||||
The docker will start and the log file will start scrolling past. Depending on hardware the bot start can take up to 5 minutes on a small DigitalOcean droplet.
|
||||
Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is ready and can be invited to your server. Ctrl+C at this point to stop viewing the logs.
|
||||
|
||||
After a few moments you should be able to invite Nadeko to your server. If you cannot check the log file for errors
|
||||
|
||||
## Updates / Monitoring
|
||||
## Monitoring
|
||||
|
||||
* Upgrade to the latest version of Nadeko simply `docker restart nadeko`.
|
||||
* Monitor the logs of the container in realtime `docker logs -f nadeko`.
|
||||
|
||||
## Updates
|
||||
|
||||
# Manual
|
||||
Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko.
|
||||
The following commands are required for the default options
|
||||
|
||||
`docker pull uirel/nadeko:latest`
|
||||
|
||||
`docker stop nadeko; docker rm nadeko`
|
||||
|
||||
`docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko`
|
||||
|
||||
`docker start nadeko`
|
||||
|
||||
|
||||
# Automatic Updates
|
||||
Automatic update are now handled by watchertower [WatchTower GitHub](https://github.com/CenturyLinkLabs/watchtower)
|
||||
To setup watchtower to keep Nadeko up-to-date for you with the default settings use the following command
|
||||
|
||||
```bash
|
||||
docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko
|
||||
```
|
||||
|
||||
This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the `--interval X` command to change the interval, where X is the amount of time in seconds to wait. eg 21600 for 6 hours.
|
||||
|
||||
|
||||
If you have any issues with the docker setup, please ask in #help but indicate you are using the docker.
|
||||
|
||||
For information about configuring your bot or its functionality, please check the http://nadekobot.readthedocs.io/en/latest guides.
|
||||
For information about configuring your bot or its functionality, please check the <http://nadekobot.readthedocs.io/en/latest> guides.
|
||||
|
@ -11,6 +11,9 @@ NadekoBot is an open source project, and it can be found on our [GitHub][GitHub]
|
||||
Here you can read current [Issues][Issues].
|
||||
|
||||
If you want to contribute, be sure to PR on the **[dev][dev]** branch.
|
||||
|
||||
**NadekoBot 1.1 release currently does not support x86/32bit architecture.**
|
||||
|
||||
##Content
|
||||
- [About](about.md)
|
||||
- Guides
|
||||
@ -34,14 +37,3 @@ If you want to contribute, be sure to PR on the **[dev][dev]** branch.
|
||||
[GitHub]: https://github.com/Kwoth/NadekoBot
|
||||
[Issues]: https://github.com/Kwoth/NadekoBot/issues
|
||||
[dev]: https://github.com/Kwoth/NadekoBot/tree/dev
|
||||
|
||||
[Italian]: http://i.imgur.com/SsaTwOF.png?1
|
||||
[Russian]: http://i.imgur.com/wf9bc5G.png?1
|
||||
[German]: http://i.imgur.com/EM5qPzf.png?1
|
||||
[Chinese]: http://i.imgur.com/MVCNOjT.png?1
|
||||
[English]: http://i.imgur.com/jHTyZFS.png?1
|
||||
[Spanish]: http://i.imgur.com/9BsusB6.png?1
|
||||
[French]: http://i.imgur.com/g2ARPF6.png?1
|
||||
[Dutch]: http://i.imgur.com/SadddLj.png?1
|
||||
[Norwegian]: http://i.imgur.com/TCVa0V8.png?1
|
||||
[Serbian]: http://i.imgur.com/5evoUbU.png
|
||||
|
24
src/NadekoBot/DataStructures/ExecuteCommandResult.cs
Normal file
24
src/NadekoBot/DataStructures/ExecuteCommandResult.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using Discord.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static NadekoBot.Modules.Permissions.Permissions;
|
||||
|
||||
namespace NadekoBot.DataStructures
|
||||
{
|
||||
public struct ExecuteCommandResult
|
||||
{
|
||||
public readonly CommandInfo CommandInfo;
|
||||
public readonly PermissionCache PermissionCache;
|
||||
public readonly IResult Result;
|
||||
|
||||
public ExecuteCommandResult(CommandInfo commandInfo, PermissionCache cache, IResult result)
|
||||
{
|
||||
this.CommandInfo = commandInfo;
|
||||
this.PermissionCache = cache;
|
||||
this.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
834
src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs
generated
Normal file
834
src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs
generated
Normal file
@ -0,0 +1,834 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
[DbContext(typeof(NadekoContext))]
|
||||
[Migration("20170110111159_repeater-drop")]
|
||||
partial class repeaterdrop
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<ulong>("ItemId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("BlacklistItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("BufferSize");
|
||||
|
||||
b.Property<float>("CurrencyGenerationChance");
|
||||
|
||||
b.Property<int>("CurrencyGenerationCooldown");
|
||||
|
||||
b.Property<string>("CurrencyName");
|
||||
|
||||
b.Property<string>("CurrencyPluralName");
|
||||
|
||||
b.Property<string>("CurrencySign");
|
||||
|
||||
b.Property<string>("DMHelpString");
|
||||
|
||||
b.Property<bool>("ForwardMessages");
|
||||
|
||||
b.Property<bool>("ForwardToAllOwners");
|
||||
|
||||
b.Property<string>("HelpString");
|
||||
|
||||
b.Property<int>("MigrationVersion");
|
||||
|
||||
b.Property<string>("RemindMessageFormat");
|
||||
|
||||
b.Property<bool>("RotatingStatuses");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BotConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("BaseDestroyed");
|
||||
|
||||
b.Property<string>("CallUser");
|
||||
|
||||
b.Property<int>("ClashWarId");
|
||||
|
||||
b.Property<int?>("SequenceNumber");
|
||||
|
||||
b.Property<int>("Stars");
|
||||
|
||||
b.Property<DateTime>("TimeAdded");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClashWarId");
|
||||
|
||||
b.ToTable("ClashCallers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<string>("EnemyClan");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Size");
|
||||
|
||||
b.Property<DateTime>("StartedAt");
|
||||
|
||||
b.Property<int>("WarState");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ClashOfClans");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("CommandName");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int>("Seconds");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("CommandCooldown");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("InternalTrigger");
|
||||
|
||||
b.Property<decimal>("Modifier");
|
||||
|
||||
b.Property<string>("UnitType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ConversionUnits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<string>("Reason");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CurrencyTransactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong?>("GuildId");
|
||||
|
||||
b.Property<bool>("IsRegex");
|
||||
|
||||
b.Property<bool>("OwnerOnly");
|
||||
|
||||
b.Property<string>("Response");
|
||||
|
||||
b.Property<string>("Trigger");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CustomReactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Amount");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Donators");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("EightBallResponses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int?>("GuildConfigId1");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.HasIndex("GuildConfigId1");
|
||||
|
||||
b.ToTable("FilterChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<string>("Word");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FilteredWord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Username");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FollowedStream");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GCChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AutoAssignRoleId");
|
||||
|
||||
b.Property<bool>("AutoDeleteByeMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteByeMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteGreetMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteGreetMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
|
||||
|
||||
b.Property<ulong>("ByeMessageChannelId");
|
||||
|
||||
b.Property<string>("ChannelByeMessageText");
|
||||
|
||||
b.Property<string>("ChannelGreetMessageText");
|
||||
|
||||
b.Property<bool>("CleverbotEnabled");
|
||||
|
||||
b.Property<float>("DefaultMusicVolume");
|
||||
|
||||
b.Property<bool>("DeleteMessageOnCommand");
|
||||
|
||||
b.Property<string>("DmGreetMessageText");
|
||||
|
||||
b.Property<bool>("ExclusiveSelfAssignedRoles");
|
||||
|
||||
b.Property<bool>("FilterInvites");
|
||||
|
||||
b.Property<bool>("FilterWords");
|
||||
|
||||
b.Property<ulong>("GreetMessageChannelId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.Property<string>("MuteRoleName");
|
||||
|
||||
b.Property<string>("PermissionRole");
|
||||
|
||||
b.Property<int?>("RootPermissionId");
|
||||
|
||||
b.Property<bool>("SendChannelByeMessage");
|
||||
|
||||
b.Property<bool>("SendChannelGreetMessage");
|
||||
|
||||
b.Property<bool>("SendDmGreetMessage");
|
||||
|
||||
b.Property<bool>("VerbosePermissions");
|
||||
|
||||
b.Property<bool>("VoicePlusTextEnabled");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.HasIndex("RootPermissionId");
|
||||
|
||||
b.ToTable("GuildConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredLogChannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredVoicePresenceCHannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("ChannelCreated");
|
||||
|
||||
b.Property<ulong?>("ChannelCreatedId");
|
||||
|
||||
b.Property<bool>("ChannelDestroyed");
|
||||
|
||||
b.Property<ulong?>("ChannelDestroyedId");
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("ChannelUpdated");
|
||||
|
||||
b.Property<ulong?>("ChannelUpdatedId");
|
||||
|
||||
b.Property<bool>("IsLogging");
|
||||
|
||||
b.Property<ulong?>("LogOtherId");
|
||||
|
||||
b.Property<bool>("LogUserPresence");
|
||||
|
||||
b.Property<ulong?>("LogUserPresenceId");
|
||||
|
||||
b.Property<bool>("LogVoicePresence");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceId");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceTTSId");
|
||||
|
||||
b.Property<bool>("MessageDeleted");
|
||||
|
||||
b.Property<ulong?>("MessageDeletedId");
|
||||
|
||||
b.Property<bool>("MessageUpdated");
|
||||
|
||||
b.Property<ulong?>("MessageUpdatedId");
|
||||
|
||||
b.Property<bool>("UserBanned");
|
||||
|
||||
b.Property<ulong?>("UserBannedId");
|
||||
|
||||
b.Property<bool>("UserJoined");
|
||||
|
||||
b.Property<ulong?>("UserJoinedId");
|
||||
|
||||
b.Property<bool>("UserLeft");
|
||||
|
||||
b.Property<ulong?>("UserLeftId");
|
||||
|
||||
b.Property<ulong?>("UserMutedId");
|
||||
|
||||
b.Property<ulong>("UserPresenceChannelId");
|
||||
|
||||
b.Property<bool>("UserUnbanned");
|
||||
|
||||
b.Property<ulong?>("UserUnbannedId");
|
||||
|
||||
b.Property<bool>("UserUpdated");
|
||||
|
||||
b.Property<ulong?>("UserUpdatedId");
|
||||
|
||||
b.Property<ulong>("VoicePresenceChannelId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("LogSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("ModuleName");
|
||||
|
||||
b.Property<string>("Prefix");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("ModulePrefixes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MusicPlaylists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("MutedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("NextId");
|
||||
|
||||
b.Property<int>("PrimaryTarget");
|
||||
|
||||
b.Property<ulong>("PrimaryTargetId");
|
||||
|
||||
b.Property<int>("SecondaryTarget");
|
||||
|
||||
b.Property<string>("SecondaryTargetName");
|
||||
|
||||
b.Property<bool>("State");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NextId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Permission");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("PlayingStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("MusicPlaylistId");
|
||||
|
||||
b.Property<string>("Provider");
|
||||
|
||||
b.Property<int>("ProviderType");
|
||||
|
||||
b.Property<string>("Query");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uri");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MusicPlaylistId");
|
||||
|
||||
b.ToTable("PlaylistSong");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<string>("Keyword")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Quotes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Icon");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("RaceAnimals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("IsPrivate");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<ulong>("ServerId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Reminders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<ulong>("RoleId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId", "RoleId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SelfAssignableRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<string>("type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("PokeGame");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
|
||||
.WithMany("Bases")
|
||||
.HasForeignKey("ClashWarId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("EightBallResponses")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId1");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission")
|
||||
.WithMany()
|
||||
.HasForeignKey("RootPermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredVoicePresenceChannelIds")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("ModulePrefixes")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next")
|
||||
.WithOne("Previous")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RotatingStatusMessages")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist")
|
||||
.WithMany("Songs")
|
||||
.HasForeignKey("MusicPlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RaceAnimals")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
40
src/NadekoBot/Migrations/20170110111159_repeater-drop.cs
Normal file
40
src/NadekoBot/Migrations/20170110111159_repeater-drop.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class repeaterdrop : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Repeaters");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Repeaters",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ChannelId = table.Column<ulong>(nullable: false),
|
||||
GuildId = table.Column<ulong>(nullable: false),
|
||||
Interval = table.Column<TimeSpan>(nullable: false),
|
||||
Message = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Repeaters", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Repeaters_ChannelId",
|
||||
table: "Repeaters",
|
||||
column: "ChannelId",
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
863
src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs
generated
Normal file
863
src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs
generated
Normal file
@ -0,0 +1,863 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
[DbContext(typeof(NadekoContext))]
|
||||
[Migration("20170110111302_repeater-new")]
|
||||
partial class repeaternew
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<ulong>("ItemId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("BlacklistItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("BufferSize");
|
||||
|
||||
b.Property<float>("CurrencyGenerationChance");
|
||||
|
||||
b.Property<int>("CurrencyGenerationCooldown");
|
||||
|
||||
b.Property<string>("CurrencyName");
|
||||
|
||||
b.Property<string>("CurrencyPluralName");
|
||||
|
||||
b.Property<string>("CurrencySign");
|
||||
|
||||
b.Property<string>("DMHelpString");
|
||||
|
||||
b.Property<bool>("ForwardMessages");
|
||||
|
||||
b.Property<bool>("ForwardToAllOwners");
|
||||
|
||||
b.Property<string>("HelpString");
|
||||
|
||||
b.Property<int>("MigrationVersion");
|
||||
|
||||
b.Property<string>("RemindMessageFormat");
|
||||
|
||||
b.Property<bool>("RotatingStatuses");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BotConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("BaseDestroyed");
|
||||
|
||||
b.Property<string>("CallUser");
|
||||
|
||||
b.Property<int>("ClashWarId");
|
||||
|
||||
b.Property<int?>("SequenceNumber");
|
||||
|
||||
b.Property<int>("Stars");
|
||||
|
||||
b.Property<DateTime>("TimeAdded");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClashWarId");
|
||||
|
||||
b.ToTable("ClashCallers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<string>("EnemyClan");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Size");
|
||||
|
||||
b.Property<DateTime>("StartedAt");
|
||||
|
||||
b.Property<int>("WarState");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ClashOfClans");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("CommandName");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int>("Seconds");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("CommandCooldown");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("InternalTrigger");
|
||||
|
||||
b.Property<decimal>("Modifier");
|
||||
|
||||
b.Property<string>("UnitType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ConversionUnits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<string>("Reason");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CurrencyTransactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong?>("GuildId");
|
||||
|
||||
b.Property<bool>("IsRegex");
|
||||
|
||||
b.Property<bool>("OwnerOnly");
|
||||
|
||||
b.Property<string>("Response");
|
||||
|
||||
b.Property<string>("Trigger");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CustomReactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Amount");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Donators");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("EightBallResponses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int?>("GuildConfigId1");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.HasIndex("GuildConfigId1");
|
||||
|
||||
b.ToTable("FilterChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<string>("Word");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FilteredWord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Username");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FollowedStream");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GCChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AutoAssignRoleId");
|
||||
|
||||
b.Property<bool>("AutoDeleteByeMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteByeMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteGreetMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteGreetMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
|
||||
|
||||
b.Property<ulong>("ByeMessageChannelId");
|
||||
|
||||
b.Property<string>("ChannelByeMessageText");
|
||||
|
||||
b.Property<string>("ChannelGreetMessageText");
|
||||
|
||||
b.Property<bool>("CleverbotEnabled");
|
||||
|
||||
b.Property<float>("DefaultMusicVolume");
|
||||
|
||||
b.Property<bool>("DeleteMessageOnCommand");
|
||||
|
||||
b.Property<string>("DmGreetMessageText");
|
||||
|
||||
b.Property<bool>("ExclusiveSelfAssignedRoles");
|
||||
|
||||
b.Property<bool>("FilterInvites");
|
||||
|
||||
b.Property<bool>("FilterWords");
|
||||
|
||||
b.Property<ulong>("GreetMessageChannelId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.Property<string>("MuteRoleName");
|
||||
|
||||
b.Property<string>("PermissionRole");
|
||||
|
||||
b.Property<int?>("RootPermissionId");
|
||||
|
||||
b.Property<bool>("SendChannelByeMessage");
|
||||
|
||||
b.Property<bool>("SendChannelGreetMessage");
|
||||
|
||||
b.Property<bool>("SendDmGreetMessage");
|
||||
|
||||
b.Property<bool>("VerbosePermissions");
|
||||
|
||||
b.Property<bool>("VoicePlusTextEnabled");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.HasIndex("RootPermissionId");
|
||||
|
||||
b.ToTable("GuildConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<TimeSpan>("Interval");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GuildRepeater");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredLogChannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredVoicePresenceCHannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("ChannelCreated");
|
||||
|
||||
b.Property<ulong?>("ChannelCreatedId");
|
||||
|
||||
b.Property<bool>("ChannelDestroyed");
|
||||
|
||||
b.Property<ulong?>("ChannelDestroyedId");
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("ChannelUpdated");
|
||||
|
||||
b.Property<ulong?>("ChannelUpdatedId");
|
||||
|
||||
b.Property<bool>("IsLogging");
|
||||
|
||||
b.Property<ulong?>("LogOtherId");
|
||||
|
||||
b.Property<bool>("LogUserPresence");
|
||||
|
||||
b.Property<ulong?>("LogUserPresenceId");
|
||||
|
||||
b.Property<bool>("LogVoicePresence");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceId");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceTTSId");
|
||||
|
||||
b.Property<bool>("MessageDeleted");
|
||||
|
||||
b.Property<ulong?>("MessageDeletedId");
|
||||
|
||||
b.Property<bool>("MessageUpdated");
|
||||
|
||||
b.Property<ulong?>("MessageUpdatedId");
|
||||
|
||||
b.Property<bool>("UserBanned");
|
||||
|
||||
b.Property<ulong?>("UserBannedId");
|
||||
|
||||
b.Property<bool>("UserJoined");
|
||||
|
||||
b.Property<ulong?>("UserJoinedId");
|
||||
|
||||
b.Property<bool>("UserLeft");
|
||||
|
||||
b.Property<ulong?>("UserLeftId");
|
||||
|
||||
b.Property<ulong?>("UserMutedId");
|
||||
|
||||
b.Property<ulong>("UserPresenceChannelId");
|
||||
|
||||
b.Property<bool>("UserUnbanned");
|
||||
|
||||
b.Property<ulong?>("UserUnbannedId");
|
||||
|
||||
b.Property<bool>("UserUpdated");
|
||||
|
||||
b.Property<ulong?>("UserUpdatedId");
|
||||
|
||||
b.Property<ulong>("VoicePresenceChannelId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("LogSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("ModuleName");
|
||||
|
||||
b.Property<string>("Prefix");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("ModulePrefixes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MusicPlaylists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("MutedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("NextId");
|
||||
|
||||
b.Property<int>("PrimaryTarget");
|
||||
|
||||
b.Property<ulong>("PrimaryTargetId");
|
||||
|
||||
b.Property<int>("SecondaryTarget");
|
||||
|
||||
b.Property<string>("SecondaryTargetName");
|
||||
|
||||
b.Property<bool>("State");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NextId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Permission");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("PlayingStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("MusicPlaylistId");
|
||||
|
||||
b.Property<string>("Provider");
|
||||
|
||||
b.Property<int>("ProviderType");
|
||||
|
||||
b.Property<string>("Query");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uri");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MusicPlaylistId");
|
||||
|
||||
b.ToTable("PlaylistSong");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<string>("Keyword")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Quotes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Icon");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("RaceAnimals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("IsPrivate");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<ulong>("ServerId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Reminders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<ulong>("RoleId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId", "RoleId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SelfAssignableRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<string>("type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("PokeGame");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
|
||||
.WithMany("Bases")
|
||||
.HasForeignKey("ClashWarId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("EightBallResponses")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId1");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission")
|
||||
.WithMany()
|
||||
.HasForeignKey("RootPermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GuildRepeaters")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredVoicePresenceChannelIds")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("ModulePrefixes")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next")
|
||||
.WithOne("Previous")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RotatingStatusMessages")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist")
|
||||
.WithMany("Songs")
|
||||
.HasForeignKey("MusicPlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RaceAnimals")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
46
src/NadekoBot/Migrations/20170110111302_repeater-new.cs
Normal file
46
src/NadekoBot/Migrations/20170110111302_repeater-new.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class repeaternew : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GuildRepeater",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ChannelId = table.Column<ulong>(nullable: false),
|
||||
GuildConfigId = table.Column<int>(nullable: true),
|
||||
GuildId = table.Column<ulong>(nullable: false),
|
||||
Interval = table.Column<TimeSpan>(nullable: false),
|
||||
Message = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_GuildRepeater", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_GuildRepeater_GuildConfigs_GuildConfigId",
|
||||
column: x => x.GuildConfigId,
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_GuildRepeater_GuildConfigId",
|
||||
table: "GuildRepeater",
|
||||
column: "GuildConfigId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "GuildRepeater");
|
||||
}
|
||||
}
|
||||
}
|
942
src/NadekoBot/Migrations/20170110180534_protection.Designer.cs
generated
Normal file
942
src/NadekoBot/Migrations/20170110180534_protection.Designer.cs
generated
Normal file
@ -0,0 +1,942 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
[DbContext(typeof(NadekoContext))]
|
||||
[Migration("20170110180534_protection")]
|
||||
partial class protection
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Action");
|
||||
|
||||
b.Property<int>("GuildConfigId");
|
||||
|
||||
b.Property<int>("Seconds");
|
||||
|
||||
b.Property<int>("UserThreshold");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AntiRaidSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("AntiSpamSettingId");
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AntiSpamSettingId");
|
||||
|
||||
b.ToTable("AntiSpamIgnore");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Action");
|
||||
|
||||
b.Property<int>("GuildConfigId");
|
||||
|
||||
b.Property<int>("MessageThreshold");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AntiSpamSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<ulong>("ItemId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("BlacklistItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("BufferSize");
|
||||
|
||||
b.Property<float>("CurrencyGenerationChance");
|
||||
|
||||
b.Property<int>("CurrencyGenerationCooldown");
|
||||
|
||||
b.Property<string>("CurrencyName");
|
||||
|
||||
b.Property<string>("CurrencyPluralName");
|
||||
|
||||
b.Property<string>("CurrencySign");
|
||||
|
||||
b.Property<string>("DMHelpString");
|
||||
|
||||
b.Property<bool>("ForwardMessages");
|
||||
|
||||
b.Property<bool>("ForwardToAllOwners");
|
||||
|
||||
b.Property<string>("HelpString");
|
||||
|
||||
b.Property<int>("MigrationVersion");
|
||||
|
||||
b.Property<string>("RemindMessageFormat");
|
||||
|
||||
b.Property<bool>("RotatingStatuses");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("BotConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("BaseDestroyed");
|
||||
|
||||
b.Property<string>("CallUser");
|
||||
|
||||
b.Property<int>("ClashWarId");
|
||||
|
||||
b.Property<int?>("SequenceNumber");
|
||||
|
||||
b.Property<int>("Stars");
|
||||
|
||||
b.Property<DateTime>("TimeAdded");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClashWarId");
|
||||
|
||||
b.ToTable("ClashCallers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<string>("EnemyClan");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Size");
|
||||
|
||||
b.Property<DateTime>("StartedAt");
|
||||
|
||||
b.Property<int>("WarState");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ClashOfClans");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("CommandName");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int>("Seconds");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("CommandCooldown");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("InternalTrigger");
|
||||
|
||||
b.Property<decimal>("Modifier");
|
||||
|
||||
b.Property<string>("UnitType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ConversionUnits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("Amount");
|
||||
|
||||
b.Property<string>("Reason");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CurrencyTransactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong?>("GuildId");
|
||||
|
||||
b.Property<bool>("IsRegex");
|
||||
|
||||
b.Property<bool>("OwnerOnly");
|
||||
|
||||
b.Property<string>("Response");
|
||||
|
||||
b.Property<string>("Trigger");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CustomReactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Amount");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Donators");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("EightBallResponses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<int?>("GuildConfigId1");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.HasIndex("GuildConfigId1");
|
||||
|
||||
b.ToTable("FilterChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<string>("Word");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FilteredWord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Username");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("FollowedStream");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GCChannelId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AutoAssignRoleId");
|
||||
|
||||
b.Property<bool>("AutoDeleteByeMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteByeMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteGreetMessages");
|
||||
|
||||
b.Property<int>("AutoDeleteGreetMessagesTimer");
|
||||
|
||||
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
|
||||
|
||||
b.Property<ulong>("ByeMessageChannelId");
|
||||
|
||||
b.Property<string>("ChannelByeMessageText");
|
||||
|
||||
b.Property<string>("ChannelGreetMessageText");
|
||||
|
||||
b.Property<bool>("CleverbotEnabled");
|
||||
|
||||
b.Property<float>("DefaultMusicVolume");
|
||||
|
||||
b.Property<bool>("DeleteMessageOnCommand");
|
||||
|
||||
b.Property<string>("DmGreetMessageText");
|
||||
|
||||
b.Property<bool>("ExclusiveSelfAssignedRoles");
|
||||
|
||||
b.Property<bool>("FilterInvites");
|
||||
|
||||
b.Property<bool>("FilterWords");
|
||||
|
||||
b.Property<ulong>("GreetMessageChannelId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.Property<string>("MuteRoleName");
|
||||
|
||||
b.Property<string>("PermissionRole");
|
||||
|
||||
b.Property<int?>("RootPermissionId");
|
||||
|
||||
b.Property<bool>("SendChannelByeMessage");
|
||||
|
||||
b.Property<bool>("SendChannelGreetMessage");
|
||||
|
||||
b.Property<bool>("SendDmGreetMessage");
|
||||
|
||||
b.Property<bool>("VerbosePermissions");
|
||||
|
||||
b.Property<bool>("VoicePlusTextEnabled");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.HasIndex("RootPermissionId");
|
||||
|
||||
b.ToTable("GuildConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<TimeSpan>("Interval");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GuildRepeater");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredLogChannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LogSettingId");
|
||||
|
||||
b.ToTable("IgnoredVoicePresenceCHannels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("ChannelCreated");
|
||||
|
||||
b.Property<ulong?>("ChannelCreatedId");
|
||||
|
||||
b.Property<bool>("ChannelDestroyed");
|
||||
|
||||
b.Property<ulong?>("ChannelDestroyedId");
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("ChannelUpdated");
|
||||
|
||||
b.Property<ulong?>("ChannelUpdatedId");
|
||||
|
||||
b.Property<bool>("IsLogging");
|
||||
|
||||
b.Property<ulong?>("LogOtherId");
|
||||
|
||||
b.Property<bool>("LogUserPresence");
|
||||
|
||||
b.Property<ulong?>("LogUserPresenceId");
|
||||
|
||||
b.Property<bool>("LogVoicePresence");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceId");
|
||||
|
||||
b.Property<ulong?>("LogVoicePresenceTTSId");
|
||||
|
||||
b.Property<bool>("MessageDeleted");
|
||||
|
||||
b.Property<ulong?>("MessageDeletedId");
|
||||
|
||||
b.Property<bool>("MessageUpdated");
|
||||
|
||||
b.Property<ulong?>("MessageUpdatedId");
|
||||
|
||||
b.Property<bool>("UserBanned");
|
||||
|
||||
b.Property<ulong?>("UserBannedId");
|
||||
|
||||
b.Property<bool>("UserJoined");
|
||||
|
||||
b.Property<ulong?>("UserJoinedId");
|
||||
|
||||
b.Property<bool>("UserLeft");
|
||||
|
||||
b.Property<ulong?>("UserLeftId");
|
||||
|
||||
b.Property<ulong?>("UserMutedId");
|
||||
|
||||
b.Property<ulong>("UserPresenceChannelId");
|
||||
|
||||
b.Property<bool>("UserUnbanned");
|
||||
|
||||
b.Property<ulong?>("UserUnbannedId");
|
||||
|
||||
b.Property<bool>("UserUpdated");
|
||||
|
||||
b.Property<ulong?>("UserUpdatedId");
|
||||
|
||||
b.Property<ulong>("VoicePresenceChannelId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("LogSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("ModuleName");
|
||||
|
||||
b.Property<string>("Prefix");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("ModulePrefixes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MusicPlaylists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("MutedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("NextId");
|
||||
|
||||
b.Property<int>("PrimaryTarget");
|
||||
|
||||
b.Property<ulong>("PrimaryTargetId");
|
||||
|
||||
b.Property<int>("SecondaryTarget");
|
||||
|
||||
b.Property<string>("SecondaryTargetName");
|
||||
|
||||
b.Property<bool>("State");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NextId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Permission");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("PlayingStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("MusicPlaylistId");
|
||||
|
||||
b.Property<string>("Provider");
|
||||
|
||||
b.Property<int>("ProviderType");
|
||||
|
||||
b.Property<string>("Query");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uri");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MusicPlaylistId");
|
||||
|
||||
b.ToTable("PlaylistSong");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("AuthorId");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<string>("Keyword")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Quotes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("BotConfigId");
|
||||
|
||||
b.Property<string>("Icon");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BotConfigId");
|
||||
|
||||
b.ToTable("RaceAnimals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<bool>("IsPrivate");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<ulong>("ServerId");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Reminders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<ulong>("RoleId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId", "RoleId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SelfAssignableRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<string>("type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("PokeGame");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
||||
.WithOne("AntiRaidSetting")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting")
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("AntiSpamSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
||||
.WithOne("AntiSpamSetting")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("Blacklist")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
|
||||
.WithMany("Bases")
|
||||
.HasForeignKey("ClashWarId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("CommandCooldowns")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("EightBallResponses")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterInvitesChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilterWordsChannelIds")
|
||||
.HasForeignKey("GuildConfigId1");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FilteredWords")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("FollowedStreams")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GenerateCurrencyChannelIds")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany()
|
||||
.HasForeignKey("LogSettingId");
|
||||
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission")
|
||||
.WithMany()
|
||||
.HasForeignKey("RootPermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GuildRepeaters")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
.WithMany("IgnoredVoicePresenceChannelIds")
|
||||
.HasForeignKey("LogSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("ModulePrefixes")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("MutedUsers")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next")
|
||||
.WithOne("Previous")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RotatingStatusMessages")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist")
|
||||
.WithMany("Songs")
|
||||
.HasForeignKey("MusicPlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
.WithMany("RaceAnimals")
|
||||
.HasForeignKey("BotConfigId");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
104
src/NadekoBot/Migrations/20170110180534_protection.cs
Normal file
104
src/NadekoBot/Migrations/20170110180534_protection.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class protection : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AntiRaidSetting",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Action = table.Column<int>(nullable: false),
|
||||
GuildConfigId = table.Column<int>(nullable: false),
|
||||
Seconds = table.Column<int>(nullable: false),
|
||||
UserThreshold = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AntiRaidSetting", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId",
|
||||
column: x => x.GuildConfigId,
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AntiSpamSetting",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Action = table.Column<int>(nullable: false),
|
||||
GuildConfigId = table.Column<int>(nullable: false),
|
||||
MessageThreshold = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AntiSpamSetting", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId",
|
||||
column: x => x.GuildConfigId,
|
||||
principalTable: "GuildConfigs",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AntiSpamIgnore",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
AntiSpamSettingId = table.Column<int>(nullable: true),
|
||||
ChannelId = table.Column<ulong>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AntiSpamIgnore", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId",
|
||||
column: x => x.AntiSpamSettingId,
|
||||
principalTable: "AntiSpamSetting",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AntiRaidSetting_GuildConfigId",
|
||||
table: "AntiRaidSetting",
|
||||
column: "GuildConfigId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AntiSpamIgnore_AntiSpamSettingId",
|
||||
table: "AntiSpamIgnore",
|
||||
column: "AntiSpamSettingId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AntiSpamSetting_GuildConfigId",
|
||||
table: "AntiSpamSetting",
|
||||
column: "GuildConfigId",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AntiRaidSetting");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AntiSpamIgnore");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AntiSpamSetting");
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,10 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
@ -14,6 +17,62 @@ namespace NadekoBot.Migrations
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Action");
|
||||
|
||||
b.Property<int>("GuildConfigId");
|
||||
|
||||
b.Property<int>("Seconds");
|
||||
|
||||
b.Property<int>("UserThreshold");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AntiRaidSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("AntiSpamSettingId");
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AntiSpamSettingId");
|
||||
|
||||
b.ToTable("AntiSpamIgnore");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Action");
|
||||
|
||||
b.Property<int>("GuildConfigId");
|
||||
|
||||
b.Property<int>("MessageThreshold");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AntiSpamSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -381,6 +440,28 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("GuildConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<int?>("GuildConfigId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<TimeSpan>("Interval");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildConfigId");
|
||||
|
||||
b.ToTable("GuildRepeater");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -663,27 +744,6 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("Reminders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<ulong>("ChannelId");
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<TimeSpan>("Interval");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChannelId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Repeaters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -718,6 +778,29 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("PokeGame");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
||||
.WithOne("AntiRaidSetting")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting")
|
||||
.WithMany("IgnoredChannels")
|
||||
.HasForeignKey("AntiSpamSettingId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
||||
.WithOne("AntiSpamSetting")
|
||||
.HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||
@ -790,6 +873,13 @@ namespace NadekoBot.Migrations
|
||||
.HasForeignKey("RootPermissionId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||
.WithMany("GuildRepeaters")
|
||||
.HasForeignKey("GuildConfigId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b =>
|
||||
{
|
||||
b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting")
|
||||
|
@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Administration
|
||||
NadekoBot.CommandHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
||||
|
||||
DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static async Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd)
|
||||
@ -202,7 +202,7 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
}
|
||||
var roleName = args[0].ToUpperInvariant();
|
||||
var role = Context.Guild.Roles.Where(r=>r.Name.ToUpperInvariant() == roleName).FirstOrDefault();
|
||||
var role = Context.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleName).FirstOrDefault();
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
@ -217,7 +217,7 @@ namespace NadekoBot.Modules.Administration
|
||||
var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16));
|
||||
var green = Convert.ToByte(rgb ? int.Parse(args[2]) : Convert.ToInt32(arg1.Substring(2, 2), 16));
|
||||
var blue = Convert.ToByte(rgb ? int.Parse(args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16));
|
||||
|
||||
|
||||
await role.ModifyAsync(r => r.Color = new Color(red, green, blue)).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"☑️ Role **{role.Name}'s** color has been changed.").ConfigureAwait(false);
|
||||
}
|
||||
@ -236,18 +236,22 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
msg = "❗️No reason provided.";
|
||||
}
|
||||
if (Context.User.Id != user.Guild.OwnerId && ((IGuildUser)Context.User).GetRoles().Select(r=>r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||
if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
await (await user.CreateDMChannelAsync()).SendErrorAsync($"⛔️ **You have been BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await (await user.CreateDMChannelAsync()).SendErrorAsync($"⛔️ **You have been BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
@ -275,13 +279,18 @@ namespace NadekoBot.Modules.Administration
|
||||
await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
await user.SendErrorAsync($"☣ **You have been SOFT-BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync($"☣ **You have been SOFT-BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
@ -439,7 +448,7 @@ namespace NadekoBot.Modules.Administration
|
||||
public async Task Prune()
|
||||
{
|
||||
var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
|
||||
|
||||
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable();
|
||||
enumerable = enumerable.Where(x => x.Author.Id == user.Id);
|
||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||
@ -451,6 +460,9 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
public async Task Prune(int count)
|
||||
{
|
||||
if (count < 1)
|
||||
return;
|
||||
count += 1;
|
||||
await Context.Message.DeleteAsync().ConfigureAwait(false);
|
||||
int limit = (count < 100) ? count : 100;
|
||||
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false));
|
||||
@ -463,45 +475,17 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
public async Task Prune(IGuildUser user, int count = 100)
|
||||
{
|
||||
if (count < 1)
|
||||
return;
|
||||
|
||||
if (user.Id == Context.User.Id)
|
||||
count += 1;
|
||||
|
||||
int limit = (count < 100) ? count : 100;
|
||||
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user);
|
||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task SaveChat(int cnt)
|
||||
{
|
||||
ulong? lastmsgId = null;
|
||||
var sb = new StringBuilder();
|
||||
var msgs = new List<IMessage>(cnt);
|
||||
while (cnt > 0)
|
||||
{
|
||||
var dlcnt = cnt < 100 ? cnt : 100;
|
||||
IEnumerable<IMessage> dledMsgs;
|
||||
if (lastmsgId == null)
|
||||
dledMsgs = await Context.Channel.GetMessagesAsync(cnt).Flatten().ConfigureAwait(false);
|
||||
else
|
||||
dledMsgs = await Context.Channel.GetMessagesAsync(lastmsgId.Value, Direction.Before, dlcnt).Flatten().ConfigureAwait(false);
|
||||
|
||||
if (!dledMsgs.Any())
|
||||
break;
|
||||
|
||||
msgs.AddRange(dledMsgs);
|
||||
lastmsgId = msgs[msgs.Count - 1].Id;
|
||||
cnt -= 100;
|
||||
}
|
||||
var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt";
|
||||
var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}")
|
||||
.Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) });
|
||||
await (Context.User as IGuildUser).SendFileAsync(
|
||||
await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false),
|
||||
title, title).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.MentionEveryone)]
|
||||
@ -511,7 +495,7 @@ title, title).ConfigureAwait(false);
|
||||
foreach (var role in roles)
|
||||
{
|
||||
send += $"\n**{role.Name}**\n";
|
||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Distinct().Select(u=>u.Mention));
|
||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Distinct().Select(u => u.Mention));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
@ -536,7 +520,7 @@ title, title).ConfigureAwait(false);
|
||||
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("Thanks to the people listed below for making this project happen!", string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
||||
|
||||
|
||||
nadekoSupportServer = nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850);
|
||||
|
||||
if (nadekoSupportServer == null)
|
||||
|
@ -1,272 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
public enum PunishmentAction
|
||||
{
|
||||
Mute,
|
||||
Kick,
|
||||
Ban,
|
||||
}
|
||||
|
||||
public enum ProtectionType
|
||||
{
|
||||
Raiding,
|
||||
Spamming,
|
||||
}
|
||||
|
||||
private class AntiRaidSetting
|
||||
{
|
||||
public int UserThreshold { get; set; }
|
||||
public int Seconds { get; set; }
|
||||
public PunishmentAction Action { get; set; }
|
||||
public int UsersCount { get; set; }
|
||||
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
||||
}
|
||||
|
||||
private class AntiSpamSetting
|
||||
{
|
||||
public PunishmentAction Action { get; set; }
|
||||
public int MessageThreshold { get; set; } = 3;
|
||||
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
||||
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
||||
}
|
||||
|
||||
private class UserSpamStats
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public string LastMessage { get; set; }
|
||||
|
||||
public UserSpamStats(string msg)
|
||||
{
|
||||
Count = 1;
|
||||
LastMessage = msg.ToUpperInvariant();
|
||||
}
|
||||
|
||||
public void ApplyNextMessage(string message)
|
||||
{
|
||||
var upperMsg = message.ToUpperInvariant();
|
||||
if (upperMsg == LastMessage)
|
||||
Count++;
|
||||
else
|
||||
{
|
||||
LastMessage = upperMsg;
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Group]
|
||||
public class AntiRaidCommands : ModuleBase
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, AntiRaidSetting> antiRaidGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiRaidSetting>();
|
||||
// guildId | (userId|messages)
|
||||
private static ConcurrentDictionary<ulong, AntiSpamSetting> antiSpamGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiSpamSetting>();
|
||||
|
||||
private static Logger _log { get; }
|
||||
|
||||
static AntiRaidCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
NadekoBot.Client.MessageReceived += async (imsg) =>
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var msg = imsg as IUserMessage;
|
||||
if (msg == null || msg.Author.IsBot)
|
||||
return;
|
||||
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
AntiSpamSetting spamSettings;
|
||||
if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings))
|
||||
return;
|
||||
|
||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
||||
(id, old) => { old.ApplyNextMessage(msg.Content); return old; });
|
||||
|
||||
if (stats.Count >= spamSettings.MessageThreshold)
|
||||
{
|
||||
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
||||
{
|
||||
await PunishUsers(spamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
|
||||
NadekoBot.Client.UserJoined += async (usr) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (usr.IsBot)
|
||||
return;
|
||||
AntiRaidSetting settings;
|
||||
if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
||||
return;
|
||||
if (!settings.RaidUsers.Add(usr))
|
||||
return;
|
||||
|
||||
++settings.UsersCount;
|
||||
|
||||
if (settings.UsersCount >= settings.UserThreshold)
|
||||
{
|
||||
var users = settings.RaidUsers.ToArray();
|
||||
settings.RaidUsers.Clear();
|
||||
|
||||
await PunishUsers(settings.Action, ProtectionType.Raiding, users).ConfigureAwait(false);
|
||||
}
|
||||
await Task.Delay(1000 * settings.Seconds).ConfigureAwait(false);
|
||||
|
||||
settings.RaidUsers.TryRemove(usr);
|
||||
--settings.UsersCount;
|
||||
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
||||
{
|
||||
foreach (var gu in gus)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PunishmentAction.Mute:
|
||||
try
|
||||
{
|
||||
await MuteCommands.MuteUser(gu).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||
break;
|
||||
case PunishmentAction.Kick:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
// try it twice, really don't want to ban user if
|
||||
// only kick has been specified as the punishement
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
case PunishmentAction.Ban:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntiRaid(int userThreshold, int seconds, PunishmentAction action)
|
||||
{
|
||||
if (userThreshold < 2 || userThreshold > 30)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (seconds < 2 || seconds > 300)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
var setting = new AntiRaidSetting()
|
||||
{
|
||||
Action = action,
|
||||
Seconds = seconds,
|
||||
UserThreshold = userThreshold,
|
||||
};
|
||||
antiRaidGuilds.AddOrUpdate(Context.Guild.Id, setting, (id, old) => setting);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ {Context.User.Mention} If **{userThreshold}** or more users join within **{seconds}** seconds, I will **{action}** them.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntiSpam(int messageCount=3, PunishmentAction action = PunishmentAction.Mute)
|
||||
{
|
||||
if (messageCount < 2 || messageCount > 10)
|
||||
return;
|
||||
|
||||
AntiSpamSetting throwaway;
|
||||
if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("🆗 **Anti-Spam feature** has been **disabled** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (antiSpamGuilds.TryAdd(Context.Guild.Id, new AntiSpamSetting()
|
||||
{
|
||||
Action = action,
|
||||
MessageThreshold = messageCount,
|
||||
}))
|
||||
await Context.Channel.SendConfirmAsync("✅ **Anti-Spam feature** has been **enabled** on this server.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,14 +23,17 @@ namespace NadekoBot.Modules.Administration
|
||||
[Group]
|
||||
public class LogCommands : ModuleBase
|
||||
{
|
||||
private const string clockEmojiUrl = "https://cdn.discordapp.com/attachments/155726317222887425/258309524966866945/clock.png";
|
||||
|
||||
private static ShardedDiscordClient _client { get; }
|
||||
private static Logger _log { get; }
|
||||
|
||||
private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
|
||||
private static string currentTime = $"{DateTime.Now:HH:mm:ss}";
|
||||
|
||||
public static ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
|
||||
|
||||
private static ConcurrentDictionary<ITextChannel, List<string>> UserPresenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
|
||||
private static ConcurrentDictionary<ITextChannel, List<string>> PresenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
|
||||
private static Timer timerReference { get; }
|
||||
private IGoogleApiService _google { get; }
|
||||
|
||||
@ -50,20 +53,20 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
var keys = UserPresenceUpdates.Keys.ToList();
|
||||
var keys = PresenceUpdates.Keys.ToList();
|
||||
|
||||
await Task.WhenAll(keys.Select(async key =>
|
||||
{
|
||||
List<string> messages;
|
||||
if (UserPresenceUpdates.TryRemove(key, out messages))
|
||||
try { await key.SendMessageAsync(string.Join(Environment.NewLine, messages)); } catch { }
|
||||
if (PresenceUpdates.TryRemove(key, out messages))
|
||||
try { await key.SendConfirmAsync("Presence Updates", string.Join(Environment.NewLine, messages)); } catch { }
|
||||
}));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}, null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
|
||||
}, null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
|
||||
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
@ -78,7 +81,10 @@ namespace NadekoBot.Modules.Administration
|
||||
_client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
||||
_client.GuildUserUpdated += _client_GuildUserUpdated;
|
||||
#if !GLOBAL_NADEKO
|
||||
_client.UserUpdated += _client_UserUpdated;
|
||||
#endif
|
||||
|
||||
_client.ChannelCreated += _client_ChannelCreated;
|
||||
_client.ChannelDestroyed += _client_ChannelDestroyed;
|
||||
@ -88,6 +94,74 @@ namespace NadekoBot.Modules.Administration
|
||||
MuteCommands.UserUnmuted += MuteCommands_UserUnmuted;
|
||||
}
|
||||
|
||||
private static async void _client_UserUpdated(SocketUser before, SocketUser uAfter)
|
||||
{
|
||||
try
|
||||
{
|
||||
var after = uAfter as SocketGuildUser;
|
||||
|
||||
if (after == null)
|
||||
return;
|
||||
|
||||
var g = after.Guild;
|
||||
|
||||
LogSetting logSetting;
|
||||
if (!GuildLogSettings.TryGetValue(g.Id, out logSetting)
|
||||
|| (logSetting.UserUpdatedId == null))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) == null)
|
||||
return;
|
||||
|
||||
var embed = new EmbedBuilder();
|
||||
|
||||
|
||||
if (before.Username != after.Username)
|
||||
{
|
||||
embed.WithTitle("👥 Username Changed")
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true))
|
||||
.WithFooter(fb => fb.WithText(currentTime))
|
||||
.WithOkColor();
|
||||
}
|
||||
else if (before.AvatarUrl != after.AvatarUrl)
|
||||
{
|
||||
embed.WithTitle("👥 Avatar Changed")
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithThumbnailUrl(before.AvatarUrl)
|
||||
.WithImageUrl(after.AvatarUrl)
|
||||
.WithFooter(fb => fb.WithText(currentTime))
|
||||
.WithOkColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
||||
//var guildsMemberOf = NadekoBot.Client.GetGuilds().Where(g => g.Users.Select(u => u.Id).Contains(before.Id)).ToList();
|
||||
//foreach (var g in guildsMemberOf)
|
||||
//{
|
||||
// LogSetting logSetting;
|
||||
// if (!GuildLogSettings.TryGetValue(g.Id, out logSetting)
|
||||
// || (logSetting.UserUpdatedId == null))
|
||||
// return;
|
||||
|
||||
// ITextChannel logChannel;
|
||||
// if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) == null)
|
||||
// return;
|
||||
|
||||
// try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch { }
|
||||
//}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
private static async void _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
||||
{
|
||||
try
|
||||
@ -111,7 +185,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTTS)) == null)
|
||||
return;
|
||||
|
||||
string str = null;
|
||||
var str = "";
|
||||
if (beforeVch?.Guild == afterVch?.Guild)
|
||||
{
|
||||
str = $"{usr.Username} moved from {beforeVch.Name} to {afterVch.Name}";
|
||||
@ -155,9 +229,15 @@ namespace NadekoBot.Modules.Administration
|
||||
mutes = "text and voice chat";
|
||||
break;
|
||||
}
|
||||
await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔇 **| User muted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔇 User Muted from " + mutes))
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(fb => fb.WithText(currentTime))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void MuteCommands_UserUnmuted(IGuildUser usr, MuteCommands.MuteType muteType)
|
||||
@ -186,9 +266,15 @@ namespace NadekoBot.Modules.Administration
|
||||
mutes = "text and voice chat";
|
||||
break;
|
||||
}
|
||||
await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔊 **| User unmuted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔊 User Unmuted from " + mutes))
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(fb => fb.WithText($"{currentTime}"))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static async Task TriggeredAntiProtection(IGuildUser[] users, PunishmentAction action, ProtectionType protection)
|
||||
@ -210,35 +296,31 @@ namespace NadekoBot.Modules.Administration
|
||||
if (action == PunishmentAction.Mute)
|
||||
{
|
||||
punishment = "🔇 MUTED";
|
||||
//punishment = "MUTED";
|
||||
}
|
||||
else if (action == PunishmentAction.Kick)
|
||||
{
|
||||
punishment = "☣ SOFT-BANNED (KICKED)";
|
||||
//punishment = "KICKED";
|
||||
}
|
||||
else if (action == PunishmentAction.Ban)
|
||||
{
|
||||
punishment = "⛔️ BANNED";
|
||||
//punishment = "BANNED";
|
||||
}
|
||||
await logChannel.SendMessageAsync(String.Join("\n", users.Select(user => $"‼️ {Format.Bold(user.ToString())} got **{punishment}** due to __**{protection}**__ protection on **{user.Guild.Name}** server.")))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}"))
|
||||
.WithTitle($"Users " + punishment)
|
||||
.WithDescription(String.Join("\n", users.Select(u => u.ToString())))
|
||||
.WithFooter(fb => fb.WithText($"{currentTime}"))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_UserUpdated(SocketUser uBefore, SocketUser uAfter)
|
||||
private static async void _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after)
|
||||
{
|
||||
try
|
||||
{
|
||||
var before = uBefore as SocketGuildUser;
|
||||
if (before == null)
|
||||
return;
|
||||
var after = uAfter as SocketGuildUser;
|
||||
if (after == null)
|
||||
return;
|
||||
|
||||
LogSetting logSetting;
|
||||
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
|
||||
|| (logSetting.UserUpdatedId == null))
|
||||
@ -247,32 +329,35 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
|
||||
return;
|
||||
string str = $"🕔`{prettyCurrentTime}`";
|
||||
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(currentTime))
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
||||
if (before.Nickname != after.Nickname)
|
||||
{
|
||||
embed.WithAuthor(eab => eab.WithName("👥 Nickname Changed"))
|
||||
|
||||
if (before.Username != after.Username)
|
||||
str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Name Changed |** 🆔 `{before.Id}`\n\t\t`New:` **{after.ToString()}**";
|
||||
else if (before.Nickname != after.Nickname)
|
||||
str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Nickname Changed |** 🆔 `{before.Id}`\n\t\t`Old:` **{before.Nickname}#{before.Discriminator}**\n\t\t`New:` **{after.Nickname}#{after.Discriminator}**";
|
||||
else if (before.AvatarUrl != after.AvatarUrl)
|
||||
str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Avatar Changed |** 🆔 `{before.Id}`\n\t🖼 {await NadekoBot.Google.ShortenUrl(before.AvatarUrl)} `=>` {await NadekoBot.Google.ShortenUrl(after.AvatarUrl)}";
|
||||
.AddField(efb => efb.WithName("Old Nickname").WithValue($"{before.Nickname}#{before.Discriminator}"))
|
||||
.AddField(efb => efb.WithName("New Nickname").WithValue($"{after.Nickname}#{after.Discriminator}"));
|
||||
}
|
||||
else if (!before.RoleIds.SequenceEqual(after.RoleIds))
|
||||
{
|
||||
if (before.RoleIds.Count < after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => "**" + before.Guild.GetRole(r).Name + "**");
|
||||
str += $"👤__**{before.ToString()}**__ **| User's Role Added |** 🆔 `{before.Id}`\n\t✅ {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ User's Role Added"))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
}
|
||||
else if (before.RoleIds.Count > after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => "**" + before.Guild.GetRole(r).Name + "**");
|
||||
str += $"👤__**{before.ToString()}**__ **| User's Role Removed |** 🆔 `{before.Id}`\n\t🚮 {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ User's Role Removed"))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
|
||||
@ -293,16 +378,29 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
|
||||
return;
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(currentTime));
|
||||
|
||||
var beforeTextChannel = cbefore as ITextChannel;
|
||||
var afterTextChannel = cafter as ITextChannel;
|
||||
|
||||
if (before.Name != after.Name)
|
||||
await logChannel.SendMessageAsync($@"🕓`{prettyCurrentTime}`ℹ️ **| Channel Name Changed |** #⃣ `{after.Name} ({after.Id})`
|
||||
`Old:` {before.Name}
|
||||
**`New:`** {after.Name}").ConfigureAwait(false);
|
||||
else if ((before as ITextChannel).Topic != (after as ITextChannel).Topic)
|
||||
await logChannel.SendMessageAsync($@"🕘`{prettyCurrentTime}`ℹ️ **| Channel Topic Changed |** #⃣ `{after.Name} ({after.Id})`
|
||||
`Old:` {((ITextChannel)before).Topic}
|
||||
**`New:`** {((ITextChannel)after).Topic}").ConfigureAwait(false);
|
||||
{
|
||||
embed.WithTitle("ℹ️ Channel Name Changed")
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(efb => efb.WithName("Old Name").WithValue(before.Name));
|
||||
}
|
||||
else if (beforeTextChannel?.Topic != afterTextChannel?.Topic)
|
||||
{
|
||||
embed.WithTitle("ℹ️ Channel Topic Changed")
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(efb => efb.WithName("Old Topic").WithValue(beforeTextChannel.Topic))
|
||||
.AddField(efb => efb.WithName("New Topic").WithValue(afterTextChannel.Topic));
|
||||
}
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_ChannelDestroyed(IChannel ich)
|
||||
@ -323,9 +421,13 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) == null)
|
||||
return;
|
||||
|
||||
await logChannel.SendMessageAsync($"🕕`{prettyCurrentTime}`🗑 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Deleted #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false);
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Destroyed")
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_ChannelCreated(IChannel ich)
|
||||
@ -345,7 +447,11 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) == null)
|
||||
return;
|
||||
|
||||
await logChannel.SendMessageAsync($"🕓`{prettyCurrentTime}`🆕 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Created: #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false);
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Created")
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
@ -387,19 +493,16 @@ namespace NadekoBot.Modules.Administration
|
||||
str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has left **{beforeVch.Name}** voice channel.";
|
||||
}
|
||||
if (str != null)
|
||||
UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = optGuild.IsSpecified ? optGuild.Value : null;
|
||||
var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild;
|
||||
|
||||
if (guild == null)
|
||||
return;
|
||||
@ -413,13 +516,18 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null)
|
||||
return;
|
||||
string str;
|
||||
string str = "";
|
||||
if (before.Status != after.Status)
|
||||
str = $"🔵`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**.";
|
||||
else
|
||||
str = $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game}**.";
|
||||
str = $"🎭`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**.";
|
||||
|
||||
UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
//if (before.Game?.Name != after.Game?.Name)
|
||||
//{
|
||||
// if (str != "")
|
||||
// str += "\n";
|
||||
// str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
|
||||
//}
|
||||
|
||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
@ -436,7 +544,14 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
|
||||
return;
|
||||
await logChannel.SendMessageAsync($"❗️🕛`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__❌ **| USER LEFT |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("❌ User Left")
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
@ -454,7 +569,13 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
|
||||
return;
|
||||
|
||||
await logChannel.SendMessageAsync($"❕🕓`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__✅ **| USER JOINED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("✅ User Joined")
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription($"{usr}")
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
@ -472,7 +593,13 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
|
||||
return;
|
||||
|
||||
await logChannel.SendMessageAsync($"❕🕘`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__♻️ **| USER UN-BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("♻️ User Unbanned")
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
@ -489,7 +616,13 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
|
||||
return;
|
||||
await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🚫 **| USER BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🚫 User Banned")
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
@ -516,13 +649,19 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) == null || logChannel.Id == msg.Id)
|
||||
return;
|
||||
var str = $@"🕔`{prettyCurrentTime}`👤__**{msg.Author.Username}#{msg.Author.Discriminator}**__ **| Deleted Message |** 🆔 `{msg.Author.Id}` #⃣ `{channel.Name}`
|
||||
🗑 {msg.Resolve(userHandling: TagHandling.FullName)}";
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle($"🗑 Message Deleted in {((ITextChannel)msg.Channel).Mention}")
|
||||
.WithDescription($"{msg.Author}")
|
||||
.AddField(efb => efb.WithName("Content").WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
||||
.WithFooter(efb => efb.WithText(currentTime));
|
||||
if (msg.Attachments.Any())
|
||||
str += $"{Environment.NewLine}📎 {string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))}";
|
||||
await logChannel.SendMessageAsync(str.SanitizeMentions()).ConfigureAwait(false);
|
||||
embed.AddField(efb => efb.WithName("Attachments").WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false));
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async void _client_MessageUpdated(Optional<SocketMessage> optmsg, SocketMessage imsg2)
|
||||
@ -553,11 +692,19 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) == null || logChannel.Id == after.Channel.Id)
|
||||
return;
|
||||
await logChannel.SendMessageAsync($@"🕔`{prettyCurrentTime}`👤__**{before.Author.Username}#{before.Author.Discriminator}**__ **| 📝 Edited Message |** 🆔 `{before.Author.Id}` #⃣ `{channel.Name}`
|
||||
`Old:` {before.Resolve(userHandling: TagHandling.FullName).SanitizeMentions()}
|
||||
**`New:`** {after.Resolve(userHandling: TagHandling.FullName).SanitizeMentions()}").ConfigureAwait(false);
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle($"📝 Message Updated in {((ITextChannel)after.Channel).Mention}")
|
||||
.WithDescription(after.Author.ToString())
|
||||
.AddField(efb => efb.WithName("Old Message").WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("New Message").WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
||||
.WithFooter(efb => efb.WithText(currentTime));
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
public enum LogType
|
||||
@ -740,14 +887,15 @@ namespace NadekoBot.Modules.Administration
|
||||
logSetting.ChannelUpdatedId =
|
||||
logSetting.LogUserPresenceId =
|
||||
logSetting.LogVoicePresenceId =
|
||||
logSetting.UserMutedId =
|
||||
logSetting.LogVoicePresenceTTSId = (action.Value ? channel.Id : (ulong?)null);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (action.Value)
|
||||
await channel.SendMessageAsync("✅ Logging all events on this channel.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync("Logging all events in this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync("ℹ️ Logging disabled.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync("Logging disabled.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -774,9 +922,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
await channel.SendMessageAsync($"🆗 Logging will **now ignore** #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging will IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync($"ℹ️ Logging will **no longer ignore** #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging will NOT IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -853,9 +1001,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (channelId != null)
|
||||
await channel.SendMessageAsync($"✅ Logging `{type}` event in #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging **{type}** event in this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync($"ℹ️ Stopped logging `{type}` event.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Stopped logging **{type}** event.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,173 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class RepeatCommands : ModuleBase
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, RepeatRunner> repeaters { get; }
|
||||
|
||||
public class RepeatRunner
|
||||
{
|
||||
private Logger _log { get; }
|
||||
|
||||
private CancellationTokenSource source { get; set; }
|
||||
private CancellationToken token { get; set; }
|
||||
public Repeater Repeater { get; }
|
||||
public ITextChannel Channel { get; }
|
||||
|
||||
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.Repeater = repeater;
|
||||
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult();
|
||||
if (Channel == null)
|
||||
return;
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
IUserMessage oldMsg = null;
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var toSend = "🔄 " + Repeater.Message;
|
||||
await Task.Delay(Repeater.Interval, token).ConfigureAwait(false);
|
||||
|
||||
//var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault();
|
||||
// if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel
|
||||
// continue;
|
||||
|
||||
if (oldMsg != null)
|
||||
try { await oldMsg.DeleteAsync(); } catch { }
|
||||
try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
source.Cancel();
|
||||
var t = Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
source.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
static RepeatCommands()
|
||||
{
|
||||
var _log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
repeaters = new ConcurrentDictionary<ulong, RepeatRunner>(uow.Repeaters.GetAll().Select(r => new RepeatRunner(r)).Where(r => r != null).ToDictionary(r => r.Repeater.ChannelId));
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task RepeatInvoke()
|
||||
{
|
||||
RepeatRunner rep;
|
||||
if (!repeaters.TryGetValue(Context.Channel.Id, out rep))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
rep.Reset();
|
||||
await Context.Channel.SendMessageAsync("🔄 " + rep.Repeater.Message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Repeat()
|
||||
{
|
||||
RepeatRunner rep;
|
||||
if (repeaters.TryRemove(Context.Channel.Id, out rep))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
uow.Repeaters.Remove(rep.Repeater);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
rep.Stop();
|
||||
await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ **No message is repeating.**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Repeat(int minutes, [Remainder] string message)
|
||||
{
|
||||
if (minutes < 1 || minutes > 10080)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return;
|
||||
|
||||
RepeatRunner rep;
|
||||
|
||||
rep = repeaters.AddOrUpdate(Context.Channel.Id, (cid) =>
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var localRep = new Repeater
|
||||
{
|
||||
ChannelId = Context.Channel.Id,
|
||||
GuildId = Context.Guild.Id,
|
||||
Interval = TimeSpan.FromMinutes(minutes),
|
||||
Message = message,
|
||||
};
|
||||
uow.Repeaters.Add(localRep);
|
||||
uow.Complete();
|
||||
return new RepeatRunner(localRep, (ITextChannel)Context.Channel);
|
||||
}
|
||||
}, (cid, old) =>
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
old.Repeater.Message = message;
|
||||
old.Repeater.Interval = TimeSpan.FromMinutes(minutes);
|
||||
uow.Repeaters.Update(old.Repeater);
|
||||
uow.Complete();
|
||||
}
|
||||
old.Reset();
|
||||
return old;
|
||||
});
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -71,8 +71,8 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
|
||||
new Dictionary<string, Func<string>> {
|
||||
{"%servers%", () => NadekoBot.Client.GetGuilds().Count().ToString()},
|
||||
{"%users%", () => NadekoBot.Client.GetGuilds().Select(s => s.Users.Count).Sum().ToString()},
|
||||
{"%servers%", () => NadekoBot.Client.GetGuildsCount().ToString()},
|
||||
{"%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()},
|
||||
{"%playing%", () => {
|
||||
var cnt = Music.Music.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
||||
if (cnt != 1) return cnt.ToString();
|
||||
|
@ -0,0 +1,425 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
public enum ProtectionType
|
||||
{
|
||||
Raiding,
|
||||
Spamming,
|
||||
}
|
||||
|
||||
public class AntiRaidStats
|
||||
{
|
||||
public AntiRaidSetting AntiRaidSettings { get; set; }
|
||||
public int UsersCount { get; set; } = 0;
|
||||
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
||||
|
||||
public override string ToString() =>
|
||||
$"If **{AntiRaidSettings.UserThreshold}** or more users join within **{AntiRaidSettings.Seconds}** seconds," +
|
||||
$" I will **{AntiRaidSettings.Action}** them.";
|
||||
}
|
||||
|
||||
public class AntiSpamStats
|
||||
{
|
||||
public AntiSpamSetting AntiSpamSettings { get; set; }
|
||||
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
||||
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var ignoredString = string.Join(", ", AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ignoredString))
|
||||
ignoredString = "none";
|
||||
return $"If a user posts **{AntiSpamSettings.MessageThreshold}** same messages in a row, I will **{AntiSpamSettings.Action}** them."
|
||||
+ $"\n\t__IgnoredChannels__: {ignoredString}";
|
||||
}
|
||||
}
|
||||
|
||||
public class UserSpamStats
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public string LastMessage { get; set; }
|
||||
|
||||
public UserSpamStats(string msg)
|
||||
{
|
||||
Count = 1;
|
||||
LastMessage = msg.ToUpperInvariant();
|
||||
}
|
||||
|
||||
public void ApplyNextMessage(string message)
|
||||
{
|
||||
var upperMsg = message.ToUpperInvariant();
|
||||
if (upperMsg == LastMessage)
|
||||
Count++;
|
||||
else
|
||||
{
|
||||
LastMessage = upperMsg;
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Group]
|
||||
public class ProtectionCommands : ModuleBase
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, AntiRaidStats> antiRaidGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiRaidStats>();
|
||||
// guildId | (userId|messages)
|
||||
private static ConcurrentDictionary<ulong, AntiSpamStats> antiSpamGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiSpamStats>();
|
||||
|
||||
private static Logger _log { get; }
|
||||
|
||||
static ProtectionCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
foreach (var gc in NadekoBot.AllGuildConfigs)
|
||||
{
|
||||
var raid = gc.AntiRaidSetting;
|
||||
var spam = gc.AntiSpamSetting;
|
||||
|
||||
if (raid != null)
|
||||
{
|
||||
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
||||
antiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
||||
}
|
||||
|
||||
if (spam != null)
|
||||
antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||
}
|
||||
|
||||
NadekoBot.Client.MessageReceived += async (imsg) =>
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var msg = imsg as IUserMessage;
|
||||
if (msg == null || msg.Author.IsBot)
|
||||
return;
|
||||
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
AntiSpamStats spamSettings;
|
||||
if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
}))
|
||||
return;
|
||||
|
||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
||||
(id, old) => { old.ApplyNextMessage(msg.Content); return old; });
|
||||
|
||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||
{
|
||||
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
||||
{
|
||||
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
|
||||
NadekoBot.Client.UserJoined += async (usr) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (usr.IsBot)
|
||||
return;
|
||||
AntiRaidStats settings;
|
||||
if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
||||
return;
|
||||
if (!settings.RaidUsers.Add(usr))
|
||||
return;
|
||||
|
||||
++settings.UsersCount;
|
||||
|
||||
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
||||
{
|
||||
var users = settings.RaidUsers.ToArray();
|
||||
settings.RaidUsers.Clear();
|
||||
|
||||
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false);
|
||||
}
|
||||
await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false);
|
||||
|
||||
settings.RaidUsers.TryRemove(usr);
|
||||
--settings.UsersCount;
|
||||
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
||||
{
|
||||
foreach (var gu in gus)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PunishmentAction.Mute:
|
||||
try
|
||||
{
|
||||
await MuteCommands.MuteUser(gu).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||
break;
|
||||
case PunishmentAction.Kick:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||
// try it twice, really don't want to ban user if
|
||||
// only kick has been specified as the punishement
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
case PunishmentAction.Ban:
|
||||
try
|
||||
{
|
||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntiRaid(int userThreshold = 5, int seconds = 10, PunishmentAction action = PunishmentAction.Mute)
|
||||
{
|
||||
if (userThreshold < 2 || userThreshold > 30)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (seconds < 2 || seconds > 300)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
AntiRaidStats throwaway;
|
||||
if (antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||
|
||||
gc.AntiRaidSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("**Anti-Raid** feature has been **disabled** on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
var stats = new AntiRaidStats()
|
||||
{
|
||||
AntiRaidSettings = new AntiRaidSetting()
|
||||
{
|
||||
Action = action,
|
||||
Seconds = seconds,
|
||||
UserThreshold = userThreshold,
|
||||
}
|
||||
};
|
||||
|
||||
antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||
|
||||
gc.AntiRaidSetting = stats.AntiRaidSettings;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Anti-Raid Enabled", $"{Context.User.Mention} {stats.ToString()}")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task AntiSpam(int messageCount = 3, PunishmentAction action = PunishmentAction.Mute)
|
||||
{
|
||||
if (messageCount < 2 || messageCount > 10)
|
||||
return;
|
||||
|
||||
AntiSpamStats throwaway;
|
||||
if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels));
|
||||
|
||||
gc.AntiSpamSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("**Anti-Spam** has been **disabled** on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
var stats = new AntiSpamStats
|
||||
{
|
||||
AntiSpamSettings = new AntiSpamSetting()
|
||||
{
|
||||
Action = action,
|
||||
MessageThreshold = messageCount,
|
||||
}
|
||||
};
|
||||
|
||||
antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting));
|
||||
|
||||
gc.AntiSpamSetting = stats.AntiSpamSettings;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam Enabled", $"{Context.User.Mention} {stats.ToString()}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AntispamIgnore()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
var obj = new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
};
|
||||
bool added;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||
var spam = gc.AntiSpamSetting;
|
||||
if (spam == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (spam.IgnoredChannels.Add(obj))
|
||||
{
|
||||
AntiSpamStats temp;
|
||||
if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Add(obj);
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
spam.IgnoredChannels.Remove(obj);
|
||||
AntiSpamStats temp;
|
||||
if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Remove(obj);
|
||||
added = false;
|
||||
}
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (added)
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam will ignore this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam will no longer ignore this channel.").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AntiList()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
AntiSpamStats spam;
|
||||
antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
||||
|
||||
AntiRaidStats raid;
|
||||
antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
||||
|
||||
if (spam == null && raid == null)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("No protections enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("Protections Enabled");
|
||||
|
||||
if (spam != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Spam")
|
||||
.WithValue(spam.ToString())
|
||||
.WithIsInline(true));
|
||||
|
||||
if (raid != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Raid")
|
||||
.WithValue(raid.ToString())
|
||||
.WithIsInline(true));
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Administration
|
||||
public async Task Leave([Remainder] string guildStr)
|
||||
{
|
||||
guildStr = guildStr.Trim().ToUpperInvariant();
|
||||
var server = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == guildStr) ??
|
||||
var server = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Id.ToString() == guildStr) ??
|
||||
NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||
|
||||
if (server == null)
|
||||
@ -59,7 +59,16 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await NadekoBot.Client.CurrentUser().ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Successfully changed name to **{newName}**").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"Bot name changed to **{newName}**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task SetStatus([Remainder] SettableUserStatus status)
|
||||
{
|
||||
await NadekoBot.Client.SetStatus(status);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Bot status changed to **{status}**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -88,8 +97,6 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public async Task SetGame([Remainder] string game = null)
|
||||
{
|
||||
game = game ?? "";
|
||||
|
||||
await NadekoBot.Client.SetGame(game).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("👾 **New game set.**").ConfigureAwait(false);
|
||||
|
@ -145,13 +145,17 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync(
|
||||
$"Page {page} of custom reactions:",
|
||||
string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
|
||||
.Skip((page - 1) * 20)
|
||||
{
|
||||
var lastPage = customReactions.Count / 20;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
|
||||
new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("Custom reactions")
|
||||
.WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
|
||||
.Skip((curPage - 1) * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}")))
|
||||
.Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}"))), lastPage)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public enum All
|
||||
@ -200,14 +204,22 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync($"Page {page} of custom reactions (grouped):",
|
||||
string.Join("\r\n", customReactions
|
||||
.GroupBy(cr => cr.Trigger)
|
||||
.OrderBy(cr => cr.Key)
|
||||
.Skip((page - 1) * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"**{cr.Key.Trim().ToLowerInvariant()}** `x{cr.Count()}`")))
|
||||
{
|
||||
var ordered = customReactions
|
||||
.GroupBy(cr => cr.Trigger)
|
||||
.OrderBy(cr => cr.Key)
|
||||
.ToList();
|
||||
|
||||
var lastPage = ordered.Count / 20;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) =>
|
||||
new EmbedBuilder().WithOkColor()
|
||||
.WithTitle($"Custom Reactions (grouped)")
|
||||
.WithDescription(string.Join("\r\n", ordered
|
||||
.Skip((curPage - 1) * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"**{cr.Key.Trim().ToLowerInvariant()}** `x{cr.Count()}`"))), lastPage)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -300,13 +312,14 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
if (page < 1)
|
||||
return;
|
||||
await Context.Channel.EmbedAsync(ReactionStats.OrderByDescending(x => x.Value)
|
||||
.Skip((page - 1) * 9)
|
||||
.Take(9)
|
||||
.Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction stats page #{page}"),
|
||||
(agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true)))
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList();
|
||||
var lastPage = ordered.Count / 9;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page,
|
||||
(curPage) => ordered.Skip((curPage - 1) * 9)
|
||||
.Take(9)
|
||||
.Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction Stats"),
|
||||
(agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))), lastPage)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -164,12 +164,15 @@ namespace NadekoBot.Modules.Gambling
|
||||
var arr = new int[n1];
|
||||
for (int i = 0; i < n1; i++)
|
||||
{
|
||||
arr[i] = rng.Next(1, n2 + 1) + add - sub;
|
||||
arr[i] = rng.Next(1, n2 + 1);
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}` +`{add}` -`{sub}`")
|
||||
.AddField(efb => efb.WithName(Format.Bold("Result"))
|
||||
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))));
|
||||
var sum = arr.Sum();
|
||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}`")
|
||||
.AddField(efb => efb.WithName(Format.Bold("Rolls"))
|
||||
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Sum"))
|
||||
.WithValue(sum + " + " + add + " - " + sub + " = " + (sum + add - sub)));
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (count == 1)
|
||||
{
|
||||
if (rng.Next(0, 2) == 1)
|
||||
await Context.Channel.SendFileAsync(headsPath, $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(headsPath, FileMode.OpenOrCreate), "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendFileAsync(tailsPath, $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(tailsPath, FileMode.OpenOrCreate), "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (count > 10 || count < 1)
|
||||
@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
str = $"{Context.User.Mention}`Better luck next time.`";
|
||||
}
|
||||
|
||||
await Context.Channel.SendFileAsync(imgPathToSend, str).ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), "coin.jpg", str).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Cleverbot()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
@ -12,37 +12,15 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
{
|
||||
public class HangmanModel
|
||||
{
|
||||
public List<HangmanObject> All { get; set; }
|
||||
public List<HangmanObject> Animals { get; set; }
|
||||
public List<HangmanObject> Countries { get; set; }
|
||||
public List<HangmanObject> Movies { get; set; }
|
||||
public List<HangmanObject> Things { get; set; }
|
||||
}
|
||||
|
||||
public class HangmanTermPool
|
||||
{
|
||||
public enum HangmanTermType
|
||||
{
|
||||
All,
|
||||
Animals,
|
||||
Countries,
|
||||
Movies,
|
||||
Things
|
||||
}
|
||||
|
||||
const string termsPath = "data/hangman.json";
|
||||
public static HangmanModel data { get; }
|
||||
public static IReadOnlyDictionary<string, HangmanObject[]> data { get; }
|
||||
static HangmanTermPool()
|
||||
{
|
||||
try
|
||||
{
|
||||
data = JsonConvert.DeserializeObject<HangmanModel>(File.ReadAllText(termsPath));
|
||||
data.All = data.Animals.Concat(data.Countries)
|
||||
.Concat(data.Movies)
|
||||
.Concat(data.Things)
|
||||
.ToList();
|
||||
data = JsonConvert.DeserializeObject<Dictionary<string, HangmanObject[]>>(File.ReadAllText(termsPath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -50,27 +28,31 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
}
|
||||
}
|
||||
|
||||
public static HangmanObject GetTerm(HangmanTermType type)
|
||||
public static HangmanObject GetTerm(string type)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type))
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
type = type.Trim();
|
||||
|
||||
var rng = new NadekoRandom();
|
||||
switch (type)
|
||||
{
|
||||
case HangmanTermType.Animals:
|
||||
return data.Animals[rng.Next(0, data.Animals.Count)];
|
||||
case HangmanTermType.Countries:
|
||||
return data.Countries[rng.Next(0, data.Countries.Count)];
|
||||
case HangmanTermType.Movies:
|
||||
return data.Movies[rng.Next(0, data.Movies.Count)];
|
||||
case HangmanTermType.Things:
|
||||
return data.Things[rng.Next(0, data.Things.Count)];
|
||||
default:
|
||||
return data.All[rng.Next(0, data.All.Count)];
|
||||
|
||||
if (type == "All") {
|
||||
var keys = data.Keys.ToArray();
|
||||
type = keys[rng.Next(0, keys.Length)];
|
||||
}
|
||||
|
||||
HangmanObject[] termTypes;
|
||||
data.TryGetValue(type, out termTypes);
|
||||
|
||||
if (termTypes.Length == 0)
|
||||
return null;
|
||||
|
||||
return termTypes[rng.Next(0, termTypes.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
public class HangmanGame
|
||||
public class HangmanGame: IDisposable
|
||||
{
|
||||
private readonly Logger _log;
|
||||
|
||||
@ -95,20 +77,23 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
||||
.Where(c => char.IsLetter(c) || char.IsDigit(c)));
|
||||
|
||||
public HangmanTermPool.HangmanTermType TermType { get; }
|
||||
public string TermType { get; }
|
||||
|
||||
public event Action<HangmanGame> OnEnded;
|
||||
|
||||
public HangmanGame(IMessageChannel channel, HangmanTermPool.HangmanTermType type)
|
||||
public HangmanGame(IMessageChannel channel, string type)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.GameChannel = channel;
|
||||
this.TermType = type;
|
||||
this.TermType = type.ToTitleCase();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
this.Term = HangmanTermPool.GetTerm(TermType);
|
||||
|
||||
if (this.Term == null)
|
||||
throw new KeyNotFoundException("Can't find a term with that type. Use hangmanlist command.");
|
||||
// start listening for answers when game starts
|
||||
NadekoBot.Client.MessageReceived += PotentialGuess;
|
||||
}
|
||||
@ -211,5 +196,11 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
{(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} |
|
||||
{(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} |
|
||||
/-\";
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
||||
OnEnded = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Games
|
||||
static HangmanCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", Enum.GetNames(typeof(HangmanTermPool.HangmanTermType)));
|
||||
typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", HangmanTermPool.data.Keys);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Hangman(HangmanTermPool.HangmanTermType type = HangmanTermPool.HangmanTermType.All)
|
||||
public async Task Hangman([Remainder]string type = "All")
|
||||
{
|
||||
var hm = new HangmanGame(Context.Channel, type);
|
||||
|
||||
@ -48,7 +48,18 @@ namespace NadekoBot.Modules.Games
|
||||
HangmanGame throwaway;
|
||||
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
||||
};
|
||||
hm.Start();
|
||||
try
|
||||
{
|
||||
hm.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { }
|
||||
HangmanGame throwaway;
|
||||
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
||||
throwaway.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord);
|
||||
}
|
||||
|
@ -46,9 +46,12 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
|
||||
#if !GLOBAL_NADEKO
|
||||
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
|
||||
#endif
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var conf = uow.BotConfig.GetOrCreate();
|
||||
@ -91,7 +94,8 @@ namespace NadekoBot.Modules.Games
|
||||
lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
|
||||
|
||||
var sent = await channel.SendFileAsync(
|
||||
GetRandomCurrencyImagePath(),
|
||||
File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate),
|
||||
"RandomFlower.jpg",
|
||||
$"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
|
||||
.ConfigureAwait(false);
|
||||
plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { sent }, (id, old) => { old.Add(sent); return old; });
|
||||
@ -101,16 +105,19 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#if !GLOBAL_NADEKO
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Pick()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages || !usersRecentlyPicked.Add(Context.User.Id))
|
||||
if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages)
|
||||
return;
|
||||
|
||||
#if GLOBAL_NADEKO
|
||||
if (!usersRecentlyPicked.Add(Context.User.Id))
|
||||
return;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
|
||||
@ -122,14 +129,16 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, "Picked flower(s).", msgs.Count, false).ConfigureAwait(false);
|
||||
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {Gambling.Gambling.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
|
||||
var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{Gambling.Gambling.CurrencySign}!").ConfigureAwait(false);
|
||||
msg.DeleteAfter(10);
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if GLOBAL_NADEKO
|
||||
await Task.Delay(60000);
|
||||
usersRecentlyPicked.TryRemove(Context.User.Id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +146,7 @@ namespace NadekoBot.Modules.Games
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Plant()
|
||||
{
|
||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, "Planted a flower.", 1, false).ConfigureAwait(false);
|
||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {Gambling.Gambling.CurrencyName}", 1, false).ConfigureAwait(false);
|
||||
if (!removed)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false);
|
||||
@ -155,11 +164,11 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = await Context.Channel.SendFileAsync(file, msgToSend).ConfigureAwait(false);
|
||||
msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), "plant.jpg", msgToSend).ConfigureAwait(false);
|
||||
}
|
||||
plantedFlowers.AddOrUpdate(Context.Channel.Id, new List<IUserMessage>() { msg }, (id, old) => { old.Add(msg); return old; });
|
||||
}
|
||||
#endif
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
|
@ -7,6 +7,7 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -17,7 +18,7 @@ namespace NadekoBot.Modules.Games
|
||||
[Group]
|
||||
public class PollCommands : ModuleBase
|
||||
{
|
||||
public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>();
|
||||
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
@ -31,6 +32,18 @@ namespace NadekoBot.Modules.Games
|
||||
public Task PublicPoll([Remainder] string arg = null)
|
||||
=> InternalStartPoll(arg, isPublic: true);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task PollStats()
|
||||
{
|
||||
Games.Poll poll;
|
||||
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
||||
return;
|
||||
|
||||
await Context.Channel.EmbedAsync(poll.GetStats("Current Poll Results"));
|
||||
}
|
||||
|
||||
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
@ -44,7 +57,7 @@ namespace NadekoBot.Modules.Games
|
||||
return;
|
||||
|
||||
var poll = new Poll(Context.Message, data[0], data.Skip(1), isPublic: isPublic);
|
||||
if (ActivePolls.TryAdd(channel.Guild, poll))
|
||||
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
|
||||
{
|
||||
await poll.StartPoll().ConfigureAwait(false);
|
||||
}
|
||||
@ -60,7 +73,7 @@ namespace NadekoBot.Modules.Games
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
Poll poll;
|
||||
ActivePolls.TryRemove(channel.Guild, out poll);
|
||||
ActivePolls.TryRemove(channel.Guild.Id, out poll);
|
||||
await poll.StopPoll().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@ -69,20 +82,55 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
private readonly IUserMessage originalMessage;
|
||||
private readonly IGuild guild;
|
||||
private readonly string[] answers;
|
||||
private string[] Answers { get; }
|
||||
private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
|
||||
private readonly string question;
|
||||
private DateTime started;
|
||||
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
|
||||
private readonly bool isPublic;
|
||||
public bool IsPublic { get; }
|
||||
|
||||
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
||||
{
|
||||
this.originalMessage = umsg;
|
||||
this.guild = ((ITextChannel)umsg.Channel).Guild;
|
||||
this.question = question;
|
||||
this.answers = enumerable as string[] ?? enumerable.ToArray();
|
||||
this.isPublic = isPublic;
|
||||
this.Answers = enumerable as string[] ?? enumerable.ToArray();
|
||||
this.IsPublic = isPublic;
|
||||
}
|
||||
|
||||
public EmbedBuilder GetStats(string title)
|
||||
{
|
||||
var results = participants.GroupBy(kvp => kvp.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||
.OrderByDescending(kvp => kvp.Value)
|
||||
.ToArray();
|
||||
|
||||
var eb = new EmbedBuilder().WithTitle(title);
|
||||
|
||||
var sb = new StringBuilder()
|
||||
.AppendLine(Format.Bold(question))
|
||||
.AppendLine();
|
||||
|
||||
var totalVotesCast = 0;
|
||||
if (results.Length == 0)
|
||||
{
|
||||
sb.AppendLine("No votes cast.");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < results.Length; i++)
|
||||
{
|
||||
var result = results[i];
|
||||
sb.AppendLine($"`{i + 1}.` {Format.Bold(Answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes.");
|
||||
totalVotesCast += result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eb.WithDescription(sb.ToString())
|
||||
.WithFooter(efb => efb.WithText(totalVotesCast + " total votes cast."));
|
||||
|
||||
return eb;
|
||||
}
|
||||
|
||||
public async Task StartPoll()
|
||||
@ -91,8 +139,8 @@ namespace NadekoBot.Modules.Games
|
||||
NadekoBot.Client.MessageReceived += Vote;
|
||||
var msgToSend = $"📃**{originalMessage.Author.Username}** 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");
|
||||
if (!isPublic)
|
||||
msgToSend = Answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||
if (!IsPublic)
|
||||
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
||||
else
|
||||
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
|
||||
@ -102,30 +150,7 @@ namespace NadekoBot.Modules.Games
|
||||
public async Task StopPoll()
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= Vote;
|
||||
try
|
||||
{
|
||||
var results = participants.GroupBy(kvp => kvp.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||
.OrderByDescending(kvp => kvp.Value);
|
||||
|
||||
var totalVotesCast = results.Sum(kvp => kvp.Value);
|
||||
if (totalVotesCast == 0)
|
||||
{
|
||||
await originalMessage.Channel.SendMessageAsync("📄 **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 originalMessage.Channel.SendConfirmAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error in poll game {ex}");
|
||||
}
|
||||
await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void Vote(SocketMessage imsg)
|
||||
@ -141,11 +166,11 @@ namespace NadekoBot.Modules.Games
|
||||
int vote;
|
||||
if (!int.TryParse(imsg.Content, out vote))
|
||||
return;
|
||||
if (vote < 1 || vote > answers.Length)
|
||||
if (vote < 1 || vote > Answers.Length)
|
||||
return;
|
||||
|
||||
IMessageChannel ch;
|
||||
if (isPublic)
|
||||
if (IsPublic)
|
||||
{
|
||||
//if public, channel must be the same the poll started in
|
||||
if (originalMessage.Channel.Id != imsg.Channel.Id)
|
||||
@ -167,7 +192,7 @@ namespace NadekoBot.Modules.Games
|
||||
//user can vote only once
|
||||
if (participants.TryAdd(msg.Author.Id, vote))
|
||||
{
|
||||
if (!isPublic)
|
||||
if (!IsPublic)
|
||||
{
|
||||
await ch.SendConfirmAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
|
||||
}
|
||||
|
@ -122,17 +122,23 @@ namespace NadekoBot.Modules.Help
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public Task Hgit()
|
||||
public async Task Hgit()
|
||||
{
|
||||
var helpstr = new StringBuilder();
|
||||
helpstr.AppendLine("You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: <https://www.paypal.me/Kwoth>\n");
|
||||
helpstr.AppendLine("##Table Of Contents");
|
||||
helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.Name.ToLowerInvariant() != "help").OrderBy(m => m.Name).Prepend(NadekoBot.CommandService.Modules.FirstOrDefault(m=>m.Name.ToLowerInvariant()=="help")).Select(m => $"- [{m.Name}](#{m.Name.ToLowerInvariant()})")));
|
||||
helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.GetTopLevelModule().Name.ToLowerInvariant() != "help")
|
||||
.Select(m => m.GetTopLevelModule().Name)
|
||||
.Distinct()
|
||||
.OrderBy(m => m)
|
||||
.Prepend("Help")
|
||||
.Select(m => $"- [{m}](#{m.ToLowerInvariant()})")));
|
||||
helpstr.AppendLine();
|
||||
string lastModule = null;
|
||||
foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com => com.Module.Name).GroupBy(c => c.Aliases.First()).Select(g => g.First()))
|
||||
foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com => com.Module.GetTopLevelModule().Name).GroupBy(c => c.Aliases.First()).Select(g => g.First()))
|
||||
{
|
||||
if (com.Module.Name != lastModule)
|
||||
var module = com.Module.GetTopLevelModule();
|
||||
if (module.Name != lastModule)
|
||||
{
|
||||
if (lastModule != null)
|
||||
{
|
||||
@ -140,16 +146,16 @@ namespace NadekoBot.Modules.Help
|
||||
helpstr.AppendLine("###### [Back to TOC](#table-of-contents)");
|
||||
}
|
||||
helpstr.AppendLine();
|
||||
helpstr.AppendLine("### " + com.Module.Name + " ");
|
||||
helpstr.AppendLine("### " + module.Name + " ");
|
||||
helpstr.AppendLine("Command and aliases | Description | Usage");
|
||||
helpstr.AppendLine("----------------|--------------|-------");
|
||||
lastModule = com.Module.Name;
|
||||
lastModule = module.Name;
|
||||
}
|
||||
helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} | {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.GetPrefix())}");
|
||||
}
|
||||
helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser().Username , "@BotName");
|
||||
File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
|
||||
return Task.CompletedTask;
|
||||
await Context.Channel.SendConfirmAsync("Commandlist Regenerated").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -77,7 +77,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
public string PrettyVolume => $"🔉 {(int)(Volume * 100)}%";
|
||||
|
||||
public event Action<Song> SongRemoved = delegate { };
|
||||
public event Action<Song, int> SongRemoved = delegate { };
|
||||
|
||||
public MusicPlayer(IVoiceChannel startingVoiceChannel, float? defaultVolume)
|
||||
{
|
||||
@ -137,7 +137,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
var index = playlist.IndexOf(CurrentSong);
|
||||
if (index != -1)
|
||||
RemoveSongAt(index);
|
||||
RemoveSongAt(index, true);
|
||||
|
||||
OnStarted(this, CurrentSong);
|
||||
await CurrentSong.Play(audioClient, cancelToken);
|
||||
@ -273,16 +273,16 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
});
|
||||
}
|
||||
|
||||
public void RemoveSongAt(int index)
|
||||
public void RemoveSongAt(int index, bool silent = false)
|
||||
{
|
||||
actionQueue.Enqueue(() =>
|
||||
{
|
||||
if (index < 0 || index >= playlist.Count)
|
||||
return;
|
||||
var song = playlist.ElementAtOrDefault(index);
|
||||
if (playlist.Remove(song))
|
||||
if (playlist.Remove(song) && !silent)
|
||||
{
|
||||
SongRemoved(song);
|
||||
SongRemoved(song, index);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -62,7 +62,15 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
else if (TotalTime == TimeSpan.MaxValue)
|
||||
return "∞";
|
||||
else
|
||||
return TotalTime.ToString(@"mm\:ss");
|
||||
{
|
||||
var time = TotalTime.ToString(@"mm\:ss");
|
||||
var hrs = (int)TotalTime.TotalHours;
|
||||
|
||||
if (hrs > 0)
|
||||
return hrs + ":" + time;
|
||||
else
|
||||
return time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,16 +99,16 @@ namespace NadekoBot.Modules.Music
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Destroy()
|
||||
public Task Destroy()
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("This command is temporarily disabled.").ConfigureAwait(false);
|
||||
|
||||
/*MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask;
|
||||
if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
if(MusicPlayers.TryRemove(channel.Guild.Id, out musicPlayer))
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return Task.CompletedTask;
|
||||
if (((IGuildUser)Context.User).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
if (MusicPlayers.TryRemove(Context.Guild.Id, out musicPlayer))
|
||||
musicPlayer.Destroy();
|
||||
return Task.CompletedTask;*/
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -183,36 +183,41 @@ namespace NadekoBot.Modules.Music
|
||||
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
||||
|
||||
const int itemsPerPage = 10;
|
||||
int startAt = itemsPerPage * (page - 1);
|
||||
var number = 0 + startAt;
|
||||
|
||||
var total = musicPlayer.TotalPlaytime;
|
||||
var maxPlaytime = musicPlayer.MaxPlaytimeSeconds;
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor(eab => eab.WithName($"Player Queue - Page {page}")
|
||||
.WithMusicIcon())
|
||||
.WithDescription(string.Join("\n", musicPlayer.Playlist
|
||||
.Skip(startAt)
|
||||
.Take(10)
|
||||
.Select(v => $"`{++number}.` {v.PrettyFullName}")))
|
||||
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
||||
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s | " +
|
||||
(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit")))
|
||||
.WithOkColor();
|
||||
var lastPage = musicPlayer.Playlist.Count / itemsPerPage;
|
||||
Func<int, EmbedBuilder> printAction = (curPage) =>
|
||||
{
|
||||
int startAt = itemsPerPage * (curPage - 1);
|
||||
var number = 0 + startAt;
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor(eab => eab.WithName($"Player Queue")
|
||||
.WithMusicIcon())
|
||||
.WithDescription(string.Join("\n", musicPlayer.Playlist
|
||||
.Skip(startAt)
|
||||
.Take(itemsPerPage)
|
||||
.Select(v => $"`{++number}.` {v.PrettyFullName}")))
|
||||
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
||||
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s | " +
|
||||
(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit")))
|
||||
.WithOkColor();
|
||||
|
||||
if (musicPlayer.RepeatSong)
|
||||
{
|
||||
embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}");
|
||||
}
|
||||
else if (musicPlayer.RepeatPlaylist)
|
||||
{
|
||||
embed.WithTitle("🔁 Repeating Playlist");
|
||||
}
|
||||
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
|
||||
{
|
||||
embed.WithTitle("🎵 Song queue is full!");
|
||||
}
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
if (musicPlayer.RepeatSong)
|
||||
{
|
||||
embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}");
|
||||
}
|
||||
else if (musicPlayer.RepeatPlaylist)
|
||||
{
|
||||
embed.WithTitle("🔁 Repeating Playlist");
|
||||
}
|
||||
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
|
||||
{
|
||||
embed.WithTitle("🎵 Song queue is full!");
|
||||
}
|
||||
return embed;
|
||||
};
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -300,7 +305,7 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota
|
||||
return;
|
||||
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("💢 You need to be in a **voice channel** on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining it.").ConfigureAwait(false);
|
||||
await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
|
||||
@ -458,31 +463,16 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[Priority(0)]
|
||||
public async Task Remove(int num)
|
||||
public Task Remove(int num)
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||
return;
|
||||
|
||||
musicPlayer.SongRemoved += async (song) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor(eab => eab.WithName("Removed song #" + num).WithMusicIcon())
|
||||
.WithDescription(song.PrettyName)
|
||||
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
||||
.WithErrorColor();
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
return Task.CompletedTask;
|
||||
|
||||
musicPlayer.RemoveSongAt(num - 1);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -490,8 +480,6 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota
|
||||
[Priority(1)]
|
||||
public async Task Remove(string all)
|
||||
{
|
||||
|
||||
|
||||
if (all.Trim().ToUpperInvariant() != "ALL")
|
||||
return;
|
||||
MusicPlayer musicPlayer;
|
||||
@ -857,13 +845,34 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota
|
||||
{
|
||||
try
|
||||
{
|
||||
IUserMessage msg;
|
||||
if (paused)
|
||||
await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
||||
msg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
||||
else
|
||||
await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
||||
msg = await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
||||
|
||||
if (msg != null)
|
||||
msg.DeleteAfter(10);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
|
||||
|
||||
mp.SongRemoved += async (song, index) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor(eab => eab.WithName("Removed song #" + (index + 1)).WithMusicIcon())
|
||||
.WithDescription(song.PrettyName)
|
||||
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
||||
.WithErrorColor();
|
||||
|
||||
await textCh.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
return mp;
|
||||
});
|
||||
Song resolvedSong;
|
||||
|
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
var link = await provider.ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
{
|
||||
if (noError)
|
||||
if (!noError)
|
||||
await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
@ -23,13 +23,18 @@ namespace NadekoBot.Modules.Permissions
|
||||
[Group]
|
||||
public class BlacklistCommands : ModuleBase
|
||||
{
|
||||
public static ConcurrentHashSet<BlacklistItem> BlacklistedItems { get; set; } = new ConcurrentHashSet<BlacklistItem>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
|
||||
static BlacklistCommands()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
BlacklistedItems = new ConcurrentHashSet<BlacklistItem>(uow.BotConfig.GetOrCreate().Blacklist);
|
||||
var blacklist = uow.BotConfig.GetOrCreate().Blacklist;
|
||||
BlacklistedUsers = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.User).Select(c => c.ItemId));
|
||||
BlacklistedGuilds = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Server).Select(c => c.ItemId));
|
||||
BlacklistedChannels = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Channel).Select(c => c.ItemId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,12 +71,34 @@ namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
var item = new BlacklistItem { ItemId = id, Type = type };
|
||||
uow.BotConfig.GetOrCreate().Blacklist.Add(item);
|
||||
BlacklistedItems.Add(item);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.Add(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.BotConfig.GetOrCreate().Blacklist.RemoveWhere(bi => bi.ItemId == id && bi.Type == type);
|
||||
BlacklistedItems.RemoveWhere(bi => bi.ItemId == id && bi.Type == type);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.TryRemove(id);
|
||||
}
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
@ -73,6 +73,9 @@ namespace NadekoBot.Modules.Permissions
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task PermRole([Remainder] IRole role = null)
|
||||
{
|
||||
if (role != null && role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
@ -379,6 +382,9 @@ namespace NadekoBot.Modules.Permissions
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RoleCmd(CommandInfo command, PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var newPerm = new Permission
|
||||
@ -405,6 +411,9 @@ namespace NadekoBot.Modules.Permissions
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task RoleMdl(ModuleInfo module, PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var newPerm = new Permission
|
||||
@ -515,6 +524,9 @@ namespace NadekoBot.Modules.Permissions
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AllRoleMdls(PermissionAction action, [Remainder] IRole role)
|
||||
{
|
||||
if (role == role.Guild.EveryoneRole)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var newPerm = new Permission
|
||||
|
@ -23,8 +23,8 @@ namespace NadekoBot.Modules.Searches.Commands.Models
|
||||
public class Main
|
||||
{
|
||||
public double temp { get; set; }
|
||||
public int pressure { get; set; }
|
||||
public int humidity { get; set; }
|
||||
public float pressure { get; set; }
|
||||
public float humidity { get; set; }
|
||||
public double temp_min { get; set; }
|
||||
public double temp_max { get; set; }
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB
|
||||
{
|
||||
var res = await http.GetStringAsync(String.Format(queryUrl,name.Trim().Replace(' ','+'))).ConfigureAwait(false);
|
||||
var movie = JsonConvert.DeserializeObject<OmdbMovie>(res);
|
||||
|
||||
if (movie?.Title == null)
|
||||
return null;
|
||||
movie.Poster = await NadekoBot.Google.ShortenUrl(movie.Poster);
|
||||
return movie;
|
||||
}
|
||||
|
@ -109,61 +109,75 @@ namespace NadekoBot.Modules.Searches
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task I([Remainder] string query = null)
|
||||
public async Task Image([Remainder] string terms = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
terms = terms?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(terms))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(query)}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&fields=items%2Flink&key={NadekoBot.Credentials.GoogleApiKey}";
|
||||
var obj = JObject.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||
await Context.Channel.SendMessageAsync(obj["items"][0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Something went wrong.");
|
||||
_log.Error(exception);
|
||||
}
|
||||
}
|
||||
|
||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||
|
||||
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
|
||||
|
||||
var elems = document.QuerySelectorAll("a.image-list-link");
|
||||
|
||||
if (!elems.Any())
|
||||
return;
|
||||
|
||||
var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement);
|
||||
|
||||
if (img?.Source == null)
|
||||
return;
|
||||
|
||||
var source = img.Source.Replace("b.", ".");
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
||||
.WithUrl(fullQueryLink)
|
||||
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
||||
.WithDescription(source)
|
||||
.WithImageUrl(source)
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Ir([Remainder] string query = null)
|
||||
public async Task RandomImage([Remainder] string terms = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
terms = terms?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(terms))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var rng = new NadekoRandom();
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(query)}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&start={ rng.Next(1, 50) }&fields=items%2Flink&key={NadekoBot.Credentials.GoogleApiKey}";
|
||||
var obj = JObject.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||
var items = obj["items"] as JArray;
|
||||
await Context.Channel.SendMessageAsync(items[0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Something went wrong.");
|
||||
_log.Error(exception);
|
||||
}
|
||||
}
|
||||
|
||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||
|
||||
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
|
||||
|
||||
var elems = document.QuerySelectorAll("a.image-list-link").ToList();
|
||||
|
||||
if (!elems.Any())
|
||||
return;
|
||||
|
||||
var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement);
|
||||
|
||||
if (img?.Source == null)
|
||||
return;
|
||||
|
||||
var source = img.Source.Replace("b.", ".");
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
||||
.WithUrl(fullQueryLink)
|
||||
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
||||
.WithDescription(source)
|
||||
.WithImageUrl(source)
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -568,14 +582,10 @@ namespace NadekoBot.Modules.Searches
|
||||
public async Task Color([Remainder] string color = null)
|
||||
{
|
||||
color = color?.Trim().Replace("#", "");
|
||||
if (string.IsNullOrWhiteSpace((string)color))
|
||||
if (string.IsNullOrWhiteSpace(color))
|
||||
return;
|
||||
var img = new ImageSharp.Image(50, 50);
|
||||
|
||||
var red = Convert.ToInt32(color.Substring(0, 2), 16);
|
||||
var green = Convert.ToInt32(color.Substring(2, 2), 16);
|
||||
var blue = Convert.ToInt32(color.Substring(4, 2), 16);
|
||||
|
||||
img.BackgroundColor(new ImageSharp.Color(color));
|
||||
|
||||
await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png");
|
||||
|
@ -9,9 +9,9 @@ using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public partial class Administration
|
||||
public partial class Utility
|
||||
{
|
||||
[Group]
|
||||
public class CrossServerTextChannel : ModuleBase
|
@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue(guild.Roles.Count().ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
||||
.WithImageUrl(guild.IconUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
if (guild.Emojis.Count() > 0)
|
||||
@ -92,8 +92,7 @@ namespace NadekoBot.Modules.Utility
|
||||
embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Game**").WithValue($"{(user.Game?.Name == null ? "-" : user.Game.Value.Name)}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||
.WithThumbnailUrl(user.AvatarUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
@ -103,7 +102,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task Activity(IUserMessage imsg, int page = 1)
|
||||
public async Task Activity(int page = 1)
|
||||
{
|
||||
const int activityPerPage = 15;
|
||||
page -= 1;
|
||||
@ -119,7 +118,7 @@ namespace NadekoBot.Modules.Utility
|
||||
str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total");
|
||||
}
|
||||
|
||||
await imsg.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}")
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}")
|
||||
.WithOkColor()
|
||||
.WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total."))
|
||||
.WithDescription(str.ToString()));
|
||||
|
238
src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs
Normal file
238
src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs
Normal file
@ -0,0 +1,238 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public partial class Utility
|
||||
{
|
||||
[Group]
|
||||
public class RepeatCommands : ModuleBase
|
||||
{
|
||||
//guildid/RepeatRunners
|
||||
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> repeaters { get; }
|
||||
|
||||
public class RepeatRunner
|
||||
{
|
||||
private Logger _log { get; }
|
||||
|
||||
private CancellationTokenSource source { get; set; }
|
||||
private CancellationToken token { get; set; }
|
||||
public Repeater Repeater { get; }
|
||||
public ITextChannel Channel { get; }
|
||||
|
||||
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.Repeater = repeater;
|
||||
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult();
|
||||
if (Channel == null)
|
||||
return;
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
IUserMessage oldMsg = null;
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var toSend = "🔄 " + Repeater.Message;
|
||||
await Task.Delay(Repeater.Interval, token).ConfigureAwait(false);
|
||||
|
||||
//var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault();
|
||||
// if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel
|
||||
// continue;
|
||||
|
||||
if (oldMsg != null)
|
||||
try { await oldMsg.DeleteAsync(); } catch { }
|
||||
try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
source.Cancel();
|
||||
var t = Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
source.Cancel();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}";
|
||||
}
|
||||
}
|
||||
|
||||
static RepeatCommands()
|
||||
{
|
||||
var _log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
|
||||
.ToDictionary(gc => gc.GuildId,
|
||||
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr))
|
||||
.Where(gr => gr.Channel != null))));
|
||||
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task RepeatInvoke(int index)
|
||||
{
|
||||
index -= 1;
|
||||
ConcurrentQueue<RepeatRunner> rep;
|
||||
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var repList = rep.ToList();
|
||||
|
||||
if (index >= repList.Count)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var repeater = repList[index].Repeater;
|
||||
|
||||
await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public async Task RepeatRemove(int index)
|
||||
{
|
||||
if (index < 1)
|
||||
return;
|
||||
index -= 1;
|
||||
|
||||
ConcurrentQueue<RepeatRunner> rep;
|
||||
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||
return;
|
||||
|
||||
var repeaterList = rep.ToList();
|
||||
|
||||
if (index >= repeaterList.Count)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var repeater = repeaterList[index];
|
||||
repeater.Stop();
|
||||
repeaterList.RemoveAt(index);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters));
|
||||
|
||||
guildConfig.GuildRepeaters.RemoveWhere(r => r.Id == repeater.Repeater.Id);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
|
||||
await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[Priority(1)]
|
||||
public async Task Repeat(int minutes, [Remainder] string message)
|
||||
{
|
||||
if (minutes < 1 || minutes > 10080)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return;
|
||||
|
||||
var toAdd = new GuildRepeater()
|
||||
{
|
||||
ChannelId = Context.Channel.Id,
|
||||
GuildId = Context.Guild.Id,
|
||||
Interval = TimeSpan.FromMinutes(minutes),
|
||||
Message = message
|
||||
};
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters));
|
||||
|
||||
if (gc.GuildRepeaters.Count >= 5)
|
||||
return;
|
||||
gc.GuildRepeaters.Add(toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel);
|
||||
|
||||
repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] { rep }), (key, old) =>
|
||||
{
|
||||
old.Enqueue(rep);
|
||||
return old;
|
||||
});
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task RepeatList()
|
||||
{
|
||||
ConcurrentQueue<RepeatRunner> repRunners;
|
||||
if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners))
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var replist = repRunners.ToList();
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < replist.Count; i++)
|
||||
{
|
||||
var rep = replist[i];
|
||||
|
||||
sb.AppendLine($"`{i + 1}.` {rep.ToString()}");
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("List Of Repeaters")
|
||||
.WithDescription(sb.ToString()))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
|
@ -10,12 +10,84 @@ using System.Text.RegularExpressions;
|
||||
using System.Reflection;
|
||||
using NadekoBot.Services.Impl;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using ImageSharp;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
[NadekoModule("Utility", ".")]
|
||||
public partial class Utility : DiscordModule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, Timer> rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task RotateRoleColor(int timeout, IRole role, params string[] hexes)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
if ((timeout < 60 && timeout != 0) || timeout > 3600)
|
||||
return;
|
||||
|
||||
Timer t;
|
||||
if (timeout == 0 || hexes.Length == 0)
|
||||
{
|
||||
if (rotatingRoleColors.TryRemove(role.Id, out t))
|
||||
{
|
||||
t.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
await channel.SendConfirmAsync($"Stopped rotating colors for the **{role.Name}** role").ConfigureAwait(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var hexColors = hexes.Select(hex =>
|
||||
{
|
||||
try { return (ImageSharp.Color?)new ImageSharp.Color(hex.Replace("#", "")); } catch { return null; }
|
||||
})
|
||||
.Where(c => c != null)
|
||||
.Select(c => c.Value)
|
||||
.ToArray();
|
||||
|
||||
if (!hexColors.Any())
|
||||
{
|
||||
await channel.SendMessageAsync("No colors are in the correct format. Use `#00ff00` for example.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var images = hexColors.Select(color =>
|
||||
{
|
||||
var img = new ImageSharp.Image(50, 50);
|
||||
img.BackgroundColor(color);
|
||||
return img;
|
||||
}).Merge().ToStream();
|
||||
|
||||
var i = 0;
|
||||
t = new Timer(async (_) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var color = hexColors[i];
|
||||
await role.ModifyAsync(r => r.Color = new Discord.Color(color.R, color.G, color.B)).ConfigureAwait(false);
|
||||
++i;
|
||||
if (i >= hexColors.Length)
|
||||
i = 0;
|
||||
}
|
||||
catch { }
|
||||
}, null, 0, timeout * 1000);
|
||||
|
||||
rotatingRoleColors.AddOrUpdate(role.Id, t, (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return t;
|
||||
});
|
||||
|
||||
await channel.SendFileAsync(images, "magicalgirl.jpg", $"Rotating **{role.Name}** role's color.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task TogetherTube()
|
||||
{
|
||||
@ -170,15 +242,27 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChannelTopic()
|
||||
public async Task ChannelTopic([Remainder]ITextChannel channel = null)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
if (channel == null)
|
||||
channel = (ITextChannel)Context.Channel;
|
||||
|
||||
var topic = channel.Topic;
|
||||
if (string.IsNullOrWhiteSpace(topic))
|
||||
await channel.SendErrorAsync("No topic set.");
|
||||
await Context.Channel.SendErrorAsync("No topic set.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendConfirmAsync("Channel topic", topic);
|
||||
await Context.Channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireBotPermission(ChannelPermission.CreateInstantInvite)]
|
||||
[RequireUserPermission(ChannelPermission.CreateInstantInvite)]
|
||||
public async Task CreateInvite()
|
||||
{
|
||||
var invite = await ((ITextChannel)Context.Channel).CreateInviteAsync(0, null, isUnique: true);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -199,7 +283,7 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(stats.OwnerIds).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuilds().Count} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
|
||||
#if !GLOBAL_NADEKO
|
||||
.WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued."))
|
||||
#endif
|
||||
@ -230,7 +314,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (page < 0)
|
||||
return;
|
||||
|
||||
var guilds = NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15);
|
||||
var guilds = await Task.Run(() => NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
|
||||
|
||||
if (!guilds.Any())
|
||||
{
|
||||
@ -244,5 +328,22 @@ namespace NadekoBot.Modules.Utility
|
||||
.WithIsInline(false))))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task SaveChat(int cnt)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var msgs = new List<IMessage>(cnt);
|
||||
await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false);
|
||||
|
||||
var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt";
|
||||
var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}")
|
||||
.Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) });
|
||||
await Context.User.SendFileAsync(
|
||||
await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -91,7 +91,9 @@ namespace NadekoBot
|
||||
//connect
|
||||
await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false);
|
||||
await Client.ConnectAsync().ConfigureAwait(false);
|
||||
//await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
#if !GLOBAL_NADEKO
|
||||
await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
_log.Info("Connected");
|
||||
|
||||
|
330
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
330
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -437,6 +437,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to antilist antilst.
|
||||
/// </summary>
|
||||
public static string antilist_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("antilist_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows currently enabled protection features..
|
||||
/// </summary>
|
||||
public static string antilist_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("antilist_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}antilist`.
|
||||
/// </summary>
|
||||
public static string antilist_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("antilist_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to antiraid.
|
||||
/// </summary>
|
||||
@ -491,6 +518,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to antispamignore.
|
||||
/// </summary>
|
||||
public static string antispamignore_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("antispamignore_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Toggles whether antispam ignores current channel. Antispam must be enabled..
|
||||
/// </summary>
|
||||
public static string antispamignore_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("antispamignore_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}antispamignore`.
|
||||
/// </summary>
|
||||
public static string antispamignore_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("antispamignore_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to asar.
|
||||
/// </summary>
|
||||
@ -1841,6 +1895,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to createinvite crinv.
|
||||
/// </summary>
|
||||
public static string createinvite_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Creates a new invite which has infinite max uses and never expires..
|
||||
/// </summary>
|
||||
public static string createinvite_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}crinv`.
|
||||
/// </summary>
|
||||
public static string createinvite_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to createrole cr.
|
||||
/// </summary>
|
||||
@ -3245,33 +3326,6 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to img i.
|
||||
/// </summary>
|
||||
public static string i_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("i_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Pulls the first image found using a search parameter. Use {0}ir for different results..
|
||||
/// </summary>
|
||||
public static string i_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("i_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}i cute kitten`.
|
||||
/// </summary>
|
||||
public static string i_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("i_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to iam.
|
||||
/// </summary>
|
||||
@ -3326,6 +3380,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to image img.
|
||||
/// </summary>
|
||||
public static string image_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("image_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Pulls the first image found using a search parameter. Use {0}rimg for different results..
|
||||
/// </summary>
|
||||
public static string image_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("image_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}img cute kitten`.
|
||||
/// </summary>
|
||||
public static string image_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("image_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to imdb omdb.
|
||||
/// </summary>
|
||||
@ -3380,33 +3461,6 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ir.
|
||||
/// </summary>
|
||||
public static string ir_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("ir_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Pulls a random image using a search parameter..
|
||||
/// </summary>
|
||||
public static string ir_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("ir_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}ir cute kitten`.
|
||||
/// </summary>
|
||||
public static string ir_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("ir_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to jcsc.
|
||||
/// </summary>
|
||||
@ -5162,6 +5216,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to pollstats.
|
||||
/// </summary>
|
||||
public static string pollstats_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows the poll results without stopping the poll on this server..
|
||||
/// </summary>
|
||||
public static string pollstats_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}pollstats`.
|
||||
/// </summary>
|
||||
public static string pollstats_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to prune clr.
|
||||
/// </summary>
|
||||
@ -5405,6 +5486,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to randomimage rimg.
|
||||
/// </summary>
|
||||
public static string randomimage_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("randomimage_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Pulls a random image using a search parameter..
|
||||
/// </summary>
|
||||
public static string randomimage_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("randomimage_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}rimg cute kitten`.
|
||||
/// </summary>
|
||||
public static string randomimage_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("randomimage_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to remind.
|
||||
/// </summary>
|
||||
@ -5658,7 +5766,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Repeat a message every X minutes. If no parameters are specified, repeat is disabled..
|
||||
/// Looks up a localized string similar to Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total..
|
||||
/// </summary>
|
||||
public static string repeat_desc {
|
||||
get {
|
||||
@ -5685,7 +5793,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Immediately shows the repeat message and restarts the timer..
|
||||
/// Looks up a localized string similar to Immediately shows the repeat message on a certain index and restarts its timer..
|
||||
/// </summary>
|
||||
public static string repeatinvoke_desc {
|
||||
get {
|
||||
@ -5694,7 +5802,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}repinv`.
|
||||
/// Looks up a localized string similar to `{0}repinv 1`.
|
||||
/// </summary>
|
||||
public static string repeatinvoke_usage {
|
||||
get {
|
||||
@ -5702,6 +5810,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to repeatlist replst.
|
||||
/// </summary>
|
||||
public static string repeatlist_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatlist_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows currently repeating messages and their indexes..
|
||||
/// </summary>
|
||||
public static string repeatlist_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatlist_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}repeatlist`.
|
||||
/// </summary>
|
||||
public static string repeatlist_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatlist_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to rpeatplaylst rpl.
|
||||
/// </summary>
|
||||
@ -5729,6 +5864,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to repeatremove reprm.
|
||||
/// </summary>
|
||||
public static string repeatremove_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatremove_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes..
|
||||
/// </summary>
|
||||
public static string repeatremove_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatremove_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}reprm 2`.
|
||||
/// </summary>
|
||||
public static string repeatremove_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("repeatremove_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to reptcursong rcs.
|
||||
/// </summary>
|
||||
@ -6053,6 +6215,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to rotaterolecolor rrc.
|
||||
/// </summary>
|
||||
public static string rotaterolecolor_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("rotaterolecolor_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable..
|
||||
/// </summary>
|
||||
public static string rotaterolecolor_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("rotaterolecolor_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole`.
|
||||
/// </summary>
|
||||
public static string rotaterolecolor_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("rotaterolecolor_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to rps.
|
||||
/// </summary>
|
||||
@ -6566,6 +6755,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to setstatus.
|
||||
/// </summary>
|
||||
public static string setstatus_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("setstatus_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sets the bot's status. (Online/Idle/Dnd/Invisible).
|
||||
/// </summary>
|
||||
public static string setstatus_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("setstatus_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}setstatus Idle`.
|
||||
/// </summary>
|
||||
public static string setstatus_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("setstatus_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to setstream.
|
||||
/// </summary>
|
||||
|
@ -265,16 +265,16 @@
|
||||
<value>repeatinvoke repinv</value>
|
||||
</data>
|
||||
<data name="repeatinvoke_desc" xml:space="preserve">
|
||||
<value>Immediately shows the repeat message and restarts the timer.</value>
|
||||
<value>Immediately shows the repeat message on a certain index and restarts its timer.</value>
|
||||
</data>
|
||||
<data name="repeatinvoke_usage" xml:space="preserve">
|
||||
<value>`{0}repinv`</value>
|
||||
<value>`{0}repinv 1`</value>
|
||||
</data>
|
||||
<data name="repeat_cmd" xml:space="preserve">
|
||||
<value>repeat</value>
|
||||
</data>
|
||||
<data name="repeat_desc" xml:space="preserve">
|
||||
<value>Repeat a message every X minutes. If no parameters are specified, repeat is disabled.</value>
|
||||
<value>Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total.</value>
|
||||
</data>
|
||||
<data name="repeat_usage" xml:space="preserve">
|
||||
<value>`{0}repeat 5 Hello there`</value>
|
||||
@ -1926,23 +1926,23 @@
|
||||
<data name="randomdog_usage" xml:space="preserve">
|
||||
<value>`{0}woof`</value>
|
||||
</data>
|
||||
<data name="i_cmd" xml:space="preserve">
|
||||
<value>img i</value>
|
||||
<data name="image_cmd" xml:space="preserve">
|
||||
<value>image img</value>
|
||||
</data>
|
||||
<data name="i_desc" xml:space="preserve">
|
||||
<value>Pulls the first image found using a search parameter. Use {0}ir for different results.</value>
|
||||
<data name="image_desc" xml:space="preserve">
|
||||
<value>Pulls the first image found using a search parameter. Use {0}rimg for different results.</value>
|
||||
</data>
|
||||
<data name="i_usage" xml:space="preserve">
|
||||
<value>`{0}i cute kitten`</value>
|
||||
<data name="image_usage" xml:space="preserve">
|
||||
<value>`{0}img cute kitten`</value>
|
||||
</data>
|
||||
<data name="ir_cmd" xml:space="preserve">
|
||||
<value>ir</value>
|
||||
<data name="randomimage_cmd" xml:space="preserve">
|
||||
<value>randomimage rimg</value>
|
||||
</data>
|
||||
<data name="ir_desc" xml:space="preserve">
|
||||
<data name="randomimage_desc" xml:space="preserve">
|
||||
<value>Pulls a random image using a search parameter.</value>
|
||||
</data>
|
||||
<data name="ir_usage" xml:space="preserve">
|
||||
<value>`{0}ir cute kitten`</value>
|
||||
<data name="randomimage_usage" xml:space="preserve">
|
||||
<value>`{0}rimg cute kitten`</value>
|
||||
</data>
|
||||
<data name="lmgtfy_cmd" xml:space="preserve">
|
||||
<value>lmgtfy</value>
|
||||
@ -2853,4 +2853,76 @@
|
||||
<data name="autohentai_usage" xml:space="preserve">
|
||||
<value>`{0}autohentai 30 yuri|tail|long_hair` or `{0}autohentai`</value>
|
||||
</data>
|
||||
<data name="setstatus_cmd" xml:space="preserve">
|
||||
<value>setstatus</value>
|
||||
</data>
|
||||
<data name="setstatus_desc" xml:space="preserve">
|
||||
<value>Sets the bot's status. (Online/Idle/Dnd/Invisible)</value>
|
||||
</data>
|
||||
<data name="setstatus_usage" xml:space="preserve">
|
||||
<value>`{0}setstatus Idle`</value>
|
||||
</data>
|
||||
<data name="rotaterolecolor_cmd" xml:space="preserve">
|
||||
<value>rotaterolecolor rrc</value>
|
||||
</data>
|
||||
<data name="rotaterolecolor_desc" xml:space="preserve">
|
||||
<value>Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable.</value>
|
||||
</data>
|
||||
<data name="rotaterolecolor_usage" xml:space="preserve">
|
||||
<value>`{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole`</value>
|
||||
</data>
|
||||
<data name="createinvite_cmd" xml:space="preserve">
|
||||
<value>createinvite crinv</value>
|
||||
</data>
|
||||
<data name="createinvite_desc" xml:space="preserve">
|
||||
<value>Creates a new invite which has infinite max uses and never expires.</value>
|
||||
</data>
|
||||
<data name="createinvite_usage" xml:space="preserve">
|
||||
<value>`{0}crinv`</value>
|
||||
</data>
|
||||
<data name="pollstats_cmd" xml:space="preserve">
|
||||
<value>pollstats</value>
|
||||
</data>
|
||||
<data name="pollstats_desc" xml:space="preserve">
|
||||
<value>Shows the poll results without stopping the poll on this server.</value>
|
||||
</data>
|
||||
<data name="pollstats_usage" xml:space="preserve">
|
||||
<value>`{0}pollstats`</value>
|
||||
</data>
|
||||
<data name="repeatlist_cmd" xml:space="preserve">
|
||||
<value>repeatlist replst</value>
|
||||
</data>
|
||||
<data name="repeatlist_desc" xml:space="preserve">
|
||||
<value>Shows currently repeating messages and their indexes.</value>
|
||||
</data>
|
||||
<data name="repeatlist_usage" xml:space="preserve">
|
||||
<value>`{0}repeatlist`</value>
|
||||
</data>
|
||||
<data name="repeatremove_cmd" xml:space="preserve">
|
||||
<value>repeatremove reprm</value>
|
||||
</data>
|
||||
<data name="repeatremove_desc" xml:space="preserve">
|
||||
<value>Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes.</value>
|
||||
</data>
|
||||
<data name="repeatremove_usage" xml:space="preserve">
|
||||
<value>`{0}reprm 2`</value>
|
||||
</data>
|
||||
<data name="antilist_cmd" xml:space="preserve">
|
||||
<value>antilist antilst</value>
|
||||
</data>
|
||||
<data name="antilist_desc" xml:space="preserve">
|
||||
<value>Shows currently enabled protection features.</value>
|
||||
</data>
|
||||
<data name="antilist_usage" xml:space="preserve">
|
||||
<value>`{0}antilist`</value>
|
||||
</data>
|
||||
<data name="antispamignore_cmd" xml:space="preserve">
|
||||
<value>antispamignore</value>
|
||||
</data>
|
||||
<data name="antispamignore_desc" xml:space="preserve">
|
||||
<value>Toggles whether antispam ignores current channel. Antispam must be enabled.</value>
|
||||
</data>
|
||||
<data name="antispamignore_usage" xml:space="preserve">
|
||||
<value>`{0}antispamignore`</value>
|
||||
</data>
|
||||
</root>
|
@ -29,10 +29,16 @@ namespace Services.CleverBotApi
|
||||
|
||||
public static ChatterBot Create(ChatterBotType type, object arg)
|
||||
{
|
||||
#if GLOBAL_NADEKO
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot";
|
||||
#else
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=3210";
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ChatterBotType.CLEVERBOT:
|
||||
return new Cleverbot("http://www.cleverbot.com/", "http://www.cleverbot.com/webservicemin?uc=321", 26);
|
||||
return new Cleverbot("http://www.cleverbot.com/", url, 26);
|
||||
case ChatterBotType.JABBERWACKY:
|
||||
return new Cleverbot("http://jabberwacky.com", "http://jabberwacky.com/webservicemin", 20);
|
||||
case ChatterBotType.PANDORABOTS:
|
||||
|
@ -46,7 +46,7 @@ namespace Services.CleverBotApi
|
||||
private readonly int endIndex;
|
||||
private readonly string url;
|
||||
private readonly IDictionary<string, string> vars;
|
||||
private readonly CookieCollection cookies;
|
||||
private readonly CookieCollection cookies;
|
||||
|
||||
public CleverbotSession(string baseUrl, string url, int endIndex)
|
||||
{
|
||||
@ -60,7 +60,7 @@ namespace Services.CleverBotApi
|
||||
//vars["fno"] = "0";
|
||||
//vars["sub"] = "Say";
|
||||
//vars["cleanslate"] = "false";
|
||||
cookies = Utils.GetCookies(baseUrl);
|
||||
cookies = Utils.GetCookies(baseUrl);
|
||||
}
|
||||
|
||||
public async Task<ChatterBotThought> Think(ChatterBotThought thought)
|
||||
|
@ -17,6 +17,8 @@ using static NadekoBot.Modules.Administration.Administration;
|
||||
using NadekoBot.Modules.CustomReactions;
|
||||
using NadekoBot.Modules.Games;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using NadekoBot.DataStructures;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
@ -28,6 +30,8 @@ namespace NadekoBot.Services
|
||||
}
|
||||
public class CommandHandler
|
||||
{
|
||||
public const int GlobalCommandsCooldown = 1500;
|
||||
|
||||
private ShardedDiscordClient _client;
|
||||
private CommandService _commandService;
|
||||
private Logger _log;
|
||||
@ -39,11 +43,19 @@ namespace NadekoBot.Services
|
||||
//userid/msg count
|
||||
public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
|
||||
|
||||
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||
private Timer clearUsersOnShortCooldown { get; }
|
||||
|
||||
public CommandHandler(ShardedDiscordClient client, CommandService commandService)
|
||||
{
|
||||
_client = client;
|
||||
_commandService = commandService;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
clearUsersOnShortCooldown = new Timer((_) =>
|
||||
{
|
||||
UsersOnShortCooldown.Clear();
|
||||
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
||||
}
|
||||
public async Task StartHandling()
|
||||
{
|
||||
@ -62,158 +74,202 @@ namespace NadekoBot.Services
|
||||
_client.MessageReceived += MessageReceivedHandler;
|
||||
}
|
||||
|
||||
private async void MessageReceivedHandler(SocketMessage msg)
|
||||
private async Task<bool> TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild)
|
||||
{
|
||||
if (guild == null)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
|
||||
var usrMsg = msg as SocketUserMessage;
|
||||
if (usrMsg == null)
|
||||
return;
|
||||
|
||||
if (!usrMsg.IsAuthor())
|
||||
UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
||||
|
||||
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots
|
||||
return;
|
||||
|
||||
var guild = (msg.Channel as SocketTextChannel)?.Guild;
|
||||
|
||||
if (guild != null && guild.OwnerId != msg.Author.Id)
|
||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg).ConfigureAwait(false);
|
||||
if (cleverbotExecuted)
|
||||
{
|
||||
//todo split checks into their own modules
|
||||
if (Permissions.FilterCommands.InviteFilteringChannels.Contains(msg.Channel.Id) ||
|
||||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id))
|
||||
{
|
||||
if (usrMsg.Content.IsDiscordInvite())
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter invites in channel with id " + msg.Channel.Id, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var filteredWords = Permissions.FilterCommands.FilteredWordsForChannel(msg.Channel.Id, guild.Id).Concat(Permissions.FilterCommands.FilteredWordsForServer(guild.Id));
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredWords.Any(w => wordsInMessage.Contains(w)))
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + msg.Channel.Id, ex);
|
||||
}
|
||||
}
|
||||
_log.Info($@"CleverBot Executed
|
||||
Server: {guild.Name} [{guild.Id}]
|
||||
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||
Message: {usrMsg.Content}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
return false;
|
||||
}
|
||||
|
||||
BlacklistItem blacklistedItem;
|
||||
if ((blacklistedItem = Permissions.BlacklistCommands.BlacklistedItems.FirstOrDefault(bi =>
|
||||
(bi.Type == BlacklistItem.BlacklistType.Server && bi.ItemId == guild?.Id) ||
|
||||
(bi.Type == BlacklistItem.BlacklistType.Channel && bi.ItemId == msg.Channel.Id) ||
|
||||
(bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == msg.Author.Id))) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !GLOBAL_NADEKO
|
||||
try
|
||||
{
|
||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg);
|
||||
private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) =>
|
||||
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||
|
||||
if (cleverbotExecuted)
|
||||
return;
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
|
||||
#endif
|
||||
try
|
||||
{
|
||||
// maybe this message is a custom reaction
|
||||
var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
|
||||
private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw)
|
||||
{
|
||||
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
||||
_log.Info("Command Executed after {4}s\n\t" +
|
||||
"User: {0}\n\t" +
|
||||
"Server: {1}\n\t" +
|
||||
"Channel: {2}\n\t" +
|
||||
"Message: {3}",
|
||||
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
|
||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||
usrMsg.Content, // {3}
|
||||
sw.Elapsed.TotalSeconds);
|
||||
}
|
||||
|
||||
//if it was, don't execute the command
|
||||
if (crExecuted)
|
||||
return;
|
||||
}
|
||||
catch { }
|
||||
|
||||
string messageContent = usrMsg.Content;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best);
|
||||
var command = exec.CommandInfo;
|
||||
var permCache = exec.PermissionCache;
|
||||
var result = exec.Result;
|
||||
sw.Stop();
|
||||
var channel = (msg.Channel as ITextChannel);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
await CommandExecuted(usrMsg, command);
|
||||
_log.Info("Command Executed after {4}s\n\t" +
|
||||
"User: {0}\n\t" +
|
||||
"Server: {1}\n\t" +
|
||||
"Channel: {2}\n\t" +
|
||||
"Message: {3}",
|
||||
msg.Author + " [" + msg.Author.Id + "]", // {0}
|
||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||
usrMsg.Content, // {3}
|
||||
sw.Elapsed.TotalSeconds // {4}
|
||||
);
|
||||
}
|
||||
else if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
|
||||
{
|
||||
_log.Warn("Command Errored after {5}s\n\t" +
|
||||
private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw)
|
||||
{
|
||||
_log.Warn("Command Errored after {5}s\n\t" +
|
||||
"User: {0}\n\t" +
|
||||
"Server: {1}\n\t" +
|
||||
"Channel: {2}\n\t" +
|
||||
"Message: {3}\n\t" +
|
||||
"Error: {4}",
|
||||
msg.Author + " [" + msg.Author.Id + "]", // {0}
|
||||
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
|
||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||
usrMsg.Content,// {3}
|
||||
result.ErrorReason, // {4}
|
||||
exec.Result.ErrorReason, // {4}
|
||||
sw.Elapsed.TotalSeconds // {5}
|
||||
);
|
||||
if (guild != null && command != null && result.Error == CommandError.Exception)
|
||||
}
|
||||
|
||||
private async Task<bool> InviteFiltered(IGuild guild, SocketUserMessage usrMsg)
|
||||
{
|
||||
if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
|
||||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
|
||||
usrMsg.Content.IsDiscordInvite())
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> WordFiltered(IGuild guild, SocketUserMessage usrMsg)
|
||||
{
|
||||
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id);
|
||||
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id);
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
{
|
||||
foreach (var word in wordsInMessage)
|
||||
{
|
||||
if (filteredChannelWords.Contains(word) ||
|
||||
filteredServerWords.Contains(word))
|
||||
{
|
||||
if (permCache != null && permCache.Verbose)
|
||||
try { await msg.Channel.SendMessageAsync("⚠️ " + result.ErrorReason).ConfigureAwait(false); } catch { }
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void MessageReceivedHandler(SocketMessage msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized
|
||||
return;
|
||||
|
||||
var usrMsg = msg as SocketUserMessage;
|
||||
if (usrMsg == null) //has to be an user message, not system/other messages.
|
||||
return;
|
||||
|
||||
// track how many messagges each user is sending
|
||||
UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
||||
|
||||
// Bot will ignore commands which are ran more often than what specified by
|
||||
// GlobalCommandsCooldown constant (miliseconds)
|
||||
if (!UsersOnShortCooldown.Add(usrMsg.Author.Id))
|
||||
return;
|
||||
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
var guild = channel?.Guild;
|
||||
|
||||
if (guild != null && guild.OwnerId != msg.Author.Id)
|
||||
{
|
||||
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
|
||||
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBlacklisted(guild, usrMsg))
|
||||
return;
|
||||
|
||||
var cleverBotRan = await TryRunCleverbot(usrMsg, guild).ConfigureAwait(false);
|
||||
if (cleverBotRan)
|
||||
return;
|
||||
|
||||
// maybe this message is a custom reaction
|
||||
var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
|
||||
if (crExecuted) //if it was, don't execute the command
|
||||
return;
|
||||
|
||||
string messageContent = usrMsg.Content;
|
||||
|
||||
// execute the command and measure the time it took
|
||||
var sw = Stopwatch.StartNew();
|
||||
var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best);
|
||||
sw.Stop();
|
||||
|
||||
if (exec.Result.IsSuccess)
|
||||
{
|
||||
await LogSuccessfulExecution(usrMsg, exec, channel, sw).ConfigureAwait(false);
|
||||
}
|
||||
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
||||
{
|
||||
LogErroredExecution(usrMsg, exec, channel, sw);
|
||||
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
|
||||
{
|
||||
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
|
||||
try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (msg.Channel is IPrivateChannel)
|
||||
{
|
||||
//rofl, gotta do this to prevent this message from occuring on polls
|
||||
// rofl, gotta do this to prevent dm help message being sent to
|
||||
// users who are voting on private polls (sending a number in a DM)
|
||||
int vote;
|
||||
if (int.TryParse(msg.Content, out vote)) return;
|
||||
|
||||
|
||||
await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
|
||||
|
||||
await DMForwardCommands.HandleDMForwarding(msg, ownerChannels);
|
||||
await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex, "Error in CommandHandler");
|
||||
_log.Warn("Error in CommandHandler");
|
||||
_log.Warn(ex);
|
||||
if (ex.InnerException != null)
|
||||
_log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler");
|
||||
{
|
||||
_log.Warn("Inner Exception of the error in CommandHandler");
|
||||
_log.Warn(ex.InnerException);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling);
|
||||
|
||||
@ -308,19 +364,5 @@ namespace NadekoBot.Services
|
||||
|
||||
return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
|
||||
}
|
||||
|
||||
public struct ExecuteCommandResult
|
||||
{
|
||||
public readonly CommandInfo CommandInfo;
|
||||
public readonly PermissionCache PermissionCache;
|
||||
public readonly IResult Result;
|
||||
|
||||
public ExecuteCommandResult(CommandInfo commandInfo, PermissionCache cache, IResult result)
|
||||
{
|
||||
this.CommandInfo = commandInfo;
|
||||
this.PermissionCache = cache;
|
||||
this.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ namespace NadekoBot.Services.Database
|
||||
IReminderRepository Reminders { get; }
|
||||
ISelfAssignedRolesRepository SelfAssignedRoles { get; }
|
||||
IBotConfigRepository BotConfig { get; }
|
||||
IRepeaterRepository Repeaters { get; }
|
||||
IUnitConverterRepository ConverterUnits { get; }
|
||||
ICustomReactionRepository CustomReactions { get; }
|
||||
ICurrencyRepository Currency { get; }
|
||||
|
53
src/NadekoBot/Services/Database/Models/AntiProtection.cs
Normal file
53
src/NadekoBot/Services/Database/Models/AntiProtection.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using Discord;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
{
|
||||
public class AntiRaidSetting : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
public GuildConfig GuildConfig { get; set; }
|
||||
|
||||
public int UserThreshold { get; set; }
|
||||
public int Seconds { get; set; }
|
||||
public PunishmentAction Action { get; set; }
|
||||
}
|
||||
|
||||
public class AntiSpamSetting : DbEntity
|
||||
{
|
||||
public int GuildConfigId { get; set; }
|
||||
public GuildConfig GuildConfig { get; set; }
|
||||
|
||||
public PunishmentAction Action { get; set; }
|
||||
public int MessageThreshold { get; set; } = 3;
|
||||
public HashSet<AntiSpamIgnore> IgnoredChannels { get; set; } = new HashSet<AntiSpamIgnore>();
|
||||
}
|
||||
|
||||
|
||||
public enum PunishmentAction
|
||||
{
|
||||
Mute,
|
||||
Kick,
|
||||
Ban,
|
||||
}
|
||||
|
||||
public class AntiSpamIgnore : DbEntity
|
||||
{
|
||||
public ulong ChannelId { get; set; }
|
||||
|
||||
public override int GetHashCode() => ChannelId.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var inst = obj as AntiSpamIgnore;
|
||||
|
||||
if (inst == null)
|
||||
return false;
|
||||
|
||||
return inst.ChannelId == ChannelId;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using static NadekoBot.Modules.Administration.Administration;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
{
|
||||
@ -58,6 +59,12 @@ namespace NadekoBot.Services.Database.Models
|
||||
|
||||
public string MuteRoleName { get; set; }
|
||||
public bool CleverbotEnabled { get; set; }
|
||||
public HashSet<GuildRepeater> GuildRepeaters { get; set; } = new HashSet<GuildRepeater>();
|
||||
|
||||
public AntiRaidSetting AntiRaidSetting { get; set; }
|
||||
public AntiSpamSetting AntiSpamSetting { get; set; }
|
||||
|
||||
//public List<ProtectionIgnoredChannel> ProtectionIgnoredChannels { get; set; } = new List<ProtectionIgnoredChannel>();
|
||||
}
|
||||
|
||||
public class FilterChannelId : DbEntity
|
||||
|
@ -2,11 +2,16 @@
|
||||
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
{
|
||||
public class Repeater :DbEntity
|
||||
public class Repeater : DbEntity
|
||||
{
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public string Message { get; set; }
|
||||
public TimeSpan Interval { get; set; }
|
||||
}
|
||||
|
||||
public class GuildRepeater : Repeater
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ namespace NadekoBot.Services.Database
|
||||
public DbSet<Reminder> Reminders { get; set; }
|
||||
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
|
||||
public DbSet<BotConfig> BotConfig { get; set; }
|
||||
public DbSet<Repeater> Repeaters { get; set; }
|
||||
public DbSet<Currency> Currency { get; set; }
|
||||
public DbSet<ConvertUnit> ConversionUnits { get; set; }
|
||||
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
|
||||
@ -44,6 +43,7 @@ namespace NadekoBot.Services.Database
|
||||
this.Database.Migrate();
|
||||
EnsureSeedData();
|
||||
}
|
||||
|
||||
////Uncomment this to db initialisation with dotnet ef migration add [module]
|
||||
//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
//{
|
||||
@ -142,6 +142,17 @@ namespace NadekoBot.Services.Database
|
||||
.HasIndex(c => c.GuildId)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<AntiSpamSetting>()
|
||||
.HasOne(x => x.GuildConfig)
|
||||
.WithOne(x => x.AntiSpamSetting);
|
||||
|
||||
modelBuilder.Entity<AntiRaidSetting>()
|
||||
.HasOne(x => x.GuildConfig)
|
||||
.WithOne(x => x.AntiRaidSetting);
|
||||
|
||||
//modelBuilder.Entity<ProtectionIgnoredChannel>()
|
||||
// .HasAlternateKey(c => new { c.ChannelId, c.ProtectionType });
|
||||
|
||||
#endregion
|
||||
|
||||
#region BotConfig
|
||||
@ -172,16 +183,6 @@ namespace NadekoBot.Services.Database
|
||||
|
||||
#endregion
|
||||
|
||||
#region Repeater
|
||||
|
||||
var repeaterEntity = modelBuilder.Entity<Repeater>();
|
||||
|
||||
repeaterEntity
|
||||
.HasIndex(r => r.ChannelId)
|
||||
.IsUnique();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Currency
|
||||
var currencyEntity = modelBuilder.Entity<Currency>();
|
||||
|
||||
@ -231,6 +232,11 @@ namespace NadekoBot.Services.Database
|
||||
.IsUnique();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Services.Database.Repositories
|
||||
{
|
||||
public interface IRepeaterRepository : IRepository<Repeater>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -26,6 +26,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
.Include(gc => gc.FilterWordsChannelIds)
|
||||
.Include(gc => gc.FilteredWords)
|
||||
.Include(gc => gc.CommandCooldowns)
|
||||
.Include(gc => gc.GuildRepeaters)
|
||||
.Include(gc => gc.AntiRaidSetting)
|
||||
.Include(gc => gc.AntiSpamSetting)
|
||||
.ThenInclude(x => x.IgnoredChannels)
|
||||
.ToList();
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,12 +0,0 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
{
|
||||
public class RepeaterRepository : Repository<Repeater>, IRepeaterRepository
|
||||
{
|
||||
public RepeaterRepository(DbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -30,9 +30,6 @@ namespace NadekoBot.Services.Database
|
||||
private IBotConfigRepository _botConfig;
|
||||
public IBotConfigRepository BotConfig => _botConfig ?? (_botConfig = new BotConfigRepository(_context));
|
||||
|
||||
private IRepeaterRepository _repeaters;
|
||||
public IRepeaterRepository Repeaters => _repeaters ?? (_repeaters = new RepeaterRepository(_context));
|
||||
|
||||
private ICurrencyRepository _currency;
|
||||
public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context));
|
||||
|
||||
|
78
src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs
Normal file
78
src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services.Discord
|
||||
{
|
||||
public class ReactionEventWrapper : IDisposable
|
||||
{
|
||||
public IUserMessage Message { get; }
|
||||
public event Action<SocketReaction> OnReactionAdded = delegate { };
|
||||
public event Action<SocketReaction> OnReactionRemoved = delegate { };
|
||||
public event Action OnReactionsCleared = delegate { };
|
||||
|
||||
public ReactionEventWrapper(IUserMessage msg)
|
||||
{
|
||||
if (msg == null)
|
||||
throw new ArgumentNullException(nameof(msg));
|
||||
Message = msg;
|
||||
|
||||
NadekoBot.Client.ReactionAdded += Discord_ReactionAdded;
|
||||
NadekoBot.Client.ReactionRemoved += Discord_ReactionRemoved;
|
||||
NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared;
|
||||
}
|
||||
|
||||
private void Discord_ReactionsCleared(ulong messageId, Optional<SocketUserMessage> reaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (messageId == Message.Id)
|
||||
OnReactionsCleared?.Invoke();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void Discord_ReactionRemoved(ulong messageId, Optional<SocketUserMessage> arg2, SocketReaction reaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (messageId == Message.Id)
|
||||
OnReactionRemoved?.Invoke(reaction);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void Discord_ReactionAdded(ulong messageId, Optional<SocketUserMessage> message, SocketReaction reaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (messageId == Message.Id)
|
||||
OnReactionAdded?.Invoke(reaction);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void UnsubAll()
|
||||
{
|
||||
NadekoBot.Client.ReactionAdded -= Discord_ReactionAdded;
|
||||
NadekoBot.Client.ReactionRemoved -= Discord_ReactionRemoved;
|
||||
NadekoBot.Client.ReactionsCleared -= Discord_ReactionsCleared;
|
||||
OnReactionAdded = null;
|
||||
OnReactionRemoved = null;
|
||||
OnReactionsCleared = null;
|
||||
}
|
||||
|
||||
private bool disposing = false;
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposing)
|
||||
return;
|
||||
disposing = true;
|
||||
UnsubAll();
|
||||
}
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@ namespace NadekoBot.Services.Impl
|
||||
return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId);
|
||||
}
|
||||
|
||||
private readonly Regex YtVideoIdRegex = new Regex("(?:youtu\\.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|\\&v=)(?<id>[^#\\&\\?]*)", RegexOptions.Compiled);
|
||||
private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled);
|
||||
|
||||
public async Task<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1)
|
||||
{
|
||||
@ -149,7 +149,7 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
//todo AsyncEnumerable
|
||||
public async Task<IReadOnlyDictionary<string,TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds)
|
||||
{
|
||||
var videoIdsList = videoIds as List<string> ?? videoIds.ToList();
|
||||
|
@ -14,18 +14,21 @@ namespace NadekoBot.Services.Impl
|
||||
private ShardedDiscordClient client;
|
||||
private DateTime started;
|
||||
|
||||
public const string BotVersion = "1.1.0-beta";
|
||||
public const string BotVersion = "1.1.0";
|
||||
|
||||
public string Author => "Kwoth#2560";
|
||||
public string Library => "Discord.Net";
|
||||
public int MessageCounter { get; private set; } = 0;
|
||||
public int CommandsRan { get; private set; } = 0;
|
||||
public string Heap => Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString();
|
||||
public double MessagesPerSecond => MessageCounter / (double)GetUptime().TotalSeconds;
|
||||
public int TextChannels => client.GetGuilds().SelectMany(g => g.Channels.Where(c => c is ITextChannel)).Count();
|
||||
public int VoiceChannels => client.GetGuilds().SelectMany(g => g.Channels.Where(c => c is IVoiceChannel)).Count();
|
||||
public string Heap =>
|
||||
Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString();
|
||||
public double MessagesPerSecond => MessageCounter / GetUptime().TotalSeconds;
|
||||
private int _textChannels = 0;
|
||||
public int TextChannels => _textChannels;
|
||||
private int _voiceChannels = 0;
|
||||
public int VoiceChannels => _voiceChannels;
|
||||
public string OwnerIds => string.Join(", ", NadekoBot.Credentials.OwnerIds);
|
||||
|
||||
|
||||
Timer carbonitexTimer { get; }
|
||||
|
||||
public StatsService(ShardedDiscordClient client, CommandHandler cmdHandler)
|
||||
@ -39,17 +42,56 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
this.client.Disconnected += _ => Reset();
|
||||
|
||||
this.client.Connected += () =>
|
||||
{
|
||||
var guilds = this.client.GetGuilds();
|
||||
_textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count());
|
||||
_voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
|
||||
};
|
||||
|
||||
this.client.ChannelCreated += (c) =>
|
||||
{
|
||||
if (c is ITextChannel)
|
||||
++_textChannels;
|
||||
else if (c is IVoiceChannel)
|
||||
++_voiceChannels;
|
||||
};
|
||||
|
||||
this.client.ChannelDestroyed += (c) =>
|
||||
{
|
||||
if (c is ITextChannel)
|
||||
--_textChannels;
|
||||
else if (c is IVoiceChannel)
|
||||
--_voiceChannels;
|
||||
};
|
||||
|
||||
this.client.JoinedGuild += (g) =>
|
||||
{
|
||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
||||
var vc = g.Channels.Count - tc;
|
||||
_textChannels += tc;
|
||||
_voiceChannels += vc;
|
||||
};
|
||||
|
||||
this.client.LeftGuild += (g) =>
|
||||
{
|
||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
||||
var vc = g.Channels.Count - tc;
|
||||
_textChannels -= tc;
|
||||
_voiceChannels -= vc;
|
||||
};
|
||||
|
||||
this.carbonitexTimer = new Timer(async (state) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "servercount", this.client.GetGuilds().Count.ToString() },
|
||||
{ "servercount", this.client.GetGuildsCount().ToString() },
|
||||
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
||||
{
|
||||
content.Headers.Clear();
|
||||
@ -71,7 +113,7 @@ Bot Version: [{BotVersion}]
|
||||
Bot ID: {curUser.Id}
|
||||
Owner ID(s): {OwnerIds}
|
||||
Uptime: {GetUptimeString()}
|
||||
Servers: {client.GetGuilds().Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||
Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||
Commands Ran this session: {CommandsRan}
|
||||
Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]");
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace NadekoBot
|
||||
public event Action<SocketMessage> MessageReceived = delegate { };
|
||||
public event Action<SocketGuildUser> UserLeft = delegate { };
|
||||
public event Action<SocketUser, SocketUser> UserUpdated = delegate { };
|
||||
public event Action<SocketGuildUser, SocketGuildUser> GuildUserUpdated = delegate { };
|
||||
public event Action<Optional<SocketMessage>, SocketMessage> MessageUpdated = delegate { };
|
||||
public event Action<ulong, Optional<SocketMessage>> MessageDeleted = delegate { };
|
||||
public event Action<SocketUser, SocketGuild> UserBanned = delegate { };
|
||||
@ -27,11 +28,21 @@ namespace NadekoBot
|
||||
public event Action<SocketChannel> ChannelCreated = delegate { };
|
||||
public event Action<SocketChannel> ChannelDestroyed = delegate { };
|
||||
public event Action<SocketChannel, SocketChannel> ChannelUpdated = delegate { };
|
||||
public event Action<ulong, Optional<SocketUserMessage>, SocketReaction> ReactionAdded = delegate { };
|
||||
public event Action<ulong, Optional<SocketUserMessage>, SocketReaction> ReactionRemoved = delegate { };
|
||||
public event Action<ulong, Optional<SocketUserMessage>> ReactionsCleared = delegate { };
|
||||
|
||||
public event Action<SocketGuild> JoinedGuild = delegate { };
|
||||
public event Action<SocketGuild> LeftGuild = delegate { };
|
||||
|
||||
public event Action<Exception> Disconnected = delegate { };
|
||||
public event Action Connected = delegate { };
|
||||
|
||||
private uint _connectedCount = 0;
|
||||
private uint _downloadedCount = 0;
|
||||
|
||||
private int _guildCount = 0;
|
||||
|
||||
private IReadOnlyList<DiscordSocketClient> Clients { get; }
|
||||
|
||||
public ShardedDiscordClient(DiscordSocketConfig discordSocketConfig)
|
||||
@ -54,6 +65,7 @@ namespace NadekoBot
|
||||
};
|
||||
client.UserLeft += arg1 => { UserLeft(arg1); return Task.CompletedTask; };
|
||||
client.UserUpdated += (arg1, gu2) => { UserUpdated(arg1, gu2); return Task.CompletedTask; };
|
||||
client.GuildMemberUpdated += (arg1, arg2) => { GuildUserUpdated(arg1, arg2); return Task.CompletedTask; };
|
||||
client.MessageUpdated += (arg1, m2) => { MessageUpdated(arg1, m2); return Task.CompletedTask; };
|
||||
client.MessageDeleted += (arg1, arg2) => { MessageDeleted(arg1, arg2); return Task.CompletedTask; };
|
||||
client.UserBanned += (arg1, arg2) => { UserBanned(arg1, arg2); return Task.CompletedTask; };
|
||||
@ -63,30 +75,69 @@ namespace NadekoBot
|
||||
client.ChannelCreated += arg => { ChannelCreated(arg); return Task.CompletedTask; };
|
||||
client.ChannelDestroyed += arg => { ChannelDestroyed(arg); return Task.CompletedTask; };
|
||||
client.ChannelUpdated += (arg1, arg2) => { ChannelUpdated(arg1, arg2); return Task.CompletedTask; };
|
||||
client.JoinedGuild += (arg1) => { JoinedGuild(arg1); ++_guildCount; return Task.CompletedTask; };
|
||||
client.LeftGuild += (arg1) => { LeftGuild(arg1); --_guildCount; return Task.CompletedTask; };
|
||||
client.ReactionAdded += (arg1, arg2, arg3) => { ReactionAdded(arg1, arg2, arg3); return Task.CompletedTask; };
|
||||
client.ReactionRemoved += (arg1, arg2, arg3) => { ReactionRemoved(arg1, arg2, arg3); return Task.CompletedTask; };
|
||||
client.ReactionsCleared += (arg1, arg2) => { ReactionsCleared(arg1, arg2); return Task.CompletedTask; };
|
||||
|
||||
_log.Info($"Shard #{i} initialized.");
|
||||
#if GLOBAL_NADEKO
|
||||
client.Log += Client_Log;
|
||||
#endif
|
||||
var j = i;
|
||||
client.Disconnected += (ex) =>
|
||||
{
|
||||
_log.Error("Shard #{0} disconnected", j);
|
||||
_log.Error(ex, ex?.Message ?? "No error");
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
Clients = clientList.AsReadOnly();
|
||||
}
|
||||
|
||||
private Task Client_Log(LogMessage arg)
|
||||
{
|
||||
_log.Warn(arg.Message);
|
||||
_log.Error(arg.Exception);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public DiscordSocketClient MainClient =>
|
||||
Clients[0];
|
||||
|
||||
public SocketSelfUser CurrentUser() =>
|
||||
Clients[0].CurrentUser;
|
||||
|
||||
public IReadOnlyCollection<SocketGuild> GetGuilds() =>
|
||||
Clients.SelectMany(c => c.Guilds).ToList();
|
||||
public IEnumerable<SocketGuild> GetGuilds() =>
|
||||
Clients.SelectMany(c => c.Guilds);
|
||||
|
||||
public SocketGuild GetGuild(ulong id) =>
|
||||
Clients.Select(c => c.GetGuild(id)).FirstOrDefault(g => g != null);
|
||||
public int GetGuildsCount() =>
|
||||
_guildCount;
|
||||
|
||||
public SocketGuild GetGuild(ulong id)
|
||||
{
|
||||
foreach (var c in Clients)
|
||||
{
|
||||
var g = c.GetGuild(id);
|
||||
if (g != null)
|
||||
return g;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task<IDMChannel> GetDMChannelAsync(ulong channelId) =>
|
||||
Clients[0].GetDMChannelAsync(channelId);
|
||||
|
||||
internal Task LoginAsync(TokenType tokenType, string token) =>
|
||||
Task.WhenAll(Clients.Select(async c => { await c.LoginAsync(tokenType, token).ConfigureAwait(false); _log.Info($"Shard #{c.ShardId} logged in."); }));
|
||||
internal async Task LoginAsync(TokenType tokenType, string token)
|
||||
{
|
||||
foreach (var c in Clients)
|
||||
{
|
||||
await c.LoginAsync(tokenType, token).ConfigureAwait(false);
|
||||
_log.Info($"Shard #{c.ShardId} logged in.");
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task ConnectAsync()
|
||||
{
|
||||
@ -99,6 +150,7 @@ namespace NadekoBot
|
||||
await c.ConnectAsync().ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
_log.Info($"Shard #{c.ShardId} connected after {sw.Elapsed.TotalSeconds:F2}s ({++_connectedCount}/{Clients.Count})");
|
||||
_guildCount += c.Guilds.Count;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -111,6 +163,7 @@ namespace NadekoBot
|
||||
}
|
||||
}
|
||||
}
|
||||
Connected();
|
||||
}
|
||||
|
||||
internal Task DownloadAllUsersAsync() =>
|
||||
@ -126,5 +179,37 @@ namespace NadekoBot
|
||||
|
||||
|
||||
public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.NotStreaming)));
|
||||
|
||||
public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status))));
|
||||
|
||||
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
||||
{
|
||||
switch (sus)
|
||||
{
|
||||
case SettableUserStatus.Online:
|
||||
return UserStatus.Online;
|
||||
case SettableUserStatus.Invisible:
|
||||
return UserStatus.Invisible;
|
||||
case SettableUserStatus.Idle:
|
||||
return UserStatus.AFK;
|
||||
case SettableUserStatus.Dnd:
|
||||
return UserStatus.DoNotDisturb;
|
||||
}
|
||||
|
||||
return UserStatus.Online;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SettableUserStatus
|
||||
{
|
||||
Online = 1,
|
||||
On = 1,
|
||||
Invisible = 2,
|
||||
Invis = 2,
|
||||
Idle = 3,
|
||||
Afk = 3,
|
||||
Dnd = 4,
|
||||
DoNotDisturb = 4,
|
||||
Busy = 4,
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using ImageSharp;
|
||||
using NadekoBot.Services.Discord;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@ -16,6 +18,73 @@ namespace NadekoBot.Extensions
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
private const string arrow_left = "⬅";
|
||||
private const string arrow_right = "➡";
|
||||
|
||||
/// <summary>
|
||||
/// danny kamisama
|
||||
/// </summary>
|
||||
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null)
|
||||
{
|
||||
lastPage += 1;
|
||||
var embed = pageFunc(currentPage).AddPaginatedFooter(currentPage, lastPage);
|
||||
|
||||
var msg = await channel.EmbedAsync(embed) as IUserMessage;
|
||||
|
||||
if (currentPage >= lastPage && lastPage == 1)
|
||||
return;
|
||||
|
||||
await msg.AddReactionAsync(arrow_left).ConfigureAwait(false);
|
||||
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
|
||||
Action<SocketReaction> changePage = async r =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.Emoji.Name == arrow_left)
|
||||
{
|
||||
if (currentPage == 1)
|
||||
return;
|
||||
await msg.ModifyAsync(x => x.Embed = pageFunc(--currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false);
|
||||
}
|
||||
else if (r.Emoji.Name == arrow_right)
|
||||
{
|
||||
if (lastPage == null || lastPage > currentPage)
|
||||
await msg.ModifyAsync(x => x.Embed = pageFunc(++currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Console.WriteLine(ex); }
|
||||
};
|
||||
|
||||
using (msg.OnReaction(changePage, changePage))
|
||||
{
|
||||
await Task.Delay(30000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await msg.RemoveAllReactionsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage)
|
||||
{
|
||||
if (lastPage != null)
|
||||
return embed.WithFooter(efb => efb.WithText($"page {curPage} / {lastPage}"));
|
||||
else
|
||||
return embed.WithFooter(efb => efb.WithText($"page {curPage}"));
|
||||
}
|
||||
|
||||
public static ReactionEventWrapper OnReaction(this IUserMessage msg, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
|
||||
{
|
||||
if (reactionRemoved == null)
|
||||
reactionRemoved = delegate { };
|
||||
|
||||
var wrap = new ReactionEventWrapper(msg);
|
||||
wrap.OnReactionAdded += reactionAdded;
|
||||
wrap.OnReactionRemoved += reactionRemoved;
|
||||
return wrap;
|
||||
}
|
||||
|
||||
public static void AddFakeHeaders(this HttpClient http)
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
@ -44,7 +113,8 @@ namespace NadekoBot.Extensions
|
||||
|
||||
public static string GetPrefix(this ModuleInfo module) => NadekoBot.ModulePrefixes[module.GetTopLevelModule().Name];
|
||||
|
||||
public static ModuleInfo GetTopLevelModule(this ModuleInfo module) {
|
||||
public static ModuleInfo GetTopLevelModule(this ModuleInfo module)
|
||||
{
|
||||
while (module.Parent != null)
|
||||
{
|
||||
module = module.Parent;
|
||||
@ -93,7 +163,7 @@ namespace NadekoBot.Extensions
|
||||
|
||||
public static bool IsInteger(this decimal number) => number == Math.Truncate(number);
|
||||
|
||||
public static string SanitizeMentions(this string str) =>
|
||||
public static string SanitizeMentions(this string str) =>
|
||||
str.Replace("@everyone", "@everyοne").Replace("@here", "@һere");
|
||||
|
||||
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
@ -105,7 +175,7 @@ namespace NadekoBot.Extensions
|
||||
=> await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text));
|
||||
|
||||
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, string title, string text, string url = null)
|
||||
=> await(await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)
|
||||
=> await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)
|
||||
.WithTitle(title).WithUrl(url));
|
||||
|
||||
public static async Task<IUserMessage> SendErrorAsync(this IUser user, string title, string error, string url = null)
|
||||
@ -126,7 +196,7 @@ namespace NadekoBot.Extensions
|
||||
|
||||
public static IEnumerable<IUser> Members(this IRole role) =>
|
||||
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
||||
|
||||
|
||||
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
|
||||
=> ch.SendMessageAsync(msg, embed: embed);
|
||||
|
||||
@ -153,7 +223,7 @@ namespace NadekoBot.Extensions
|
||||
```");
|
||||
}
|
||||
|
||||
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3) =>
|
||||
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3) =>
|
||||
ch.SendTableAsync("", items, howToPrint, columns);
|
||||
|
||||
/// <summary>
|
||||
@ -286,7 +356,7 @@ namespace NadekoBot.Extensions
|
||||
|
||||
}
|
||||
|
||||
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
|
||||
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
|
||||
JsonConvert.SerializeObject(any, formatting);
|
||||
|
||||
public static int KiB(this int value) => value * 1024;
|
||||
@ -317,7 +387,7 @@ namespace NadekoBot.Extensions
|
||||
|
||||
var canvasPixels = canvas.Lock();
|
||||
int offsetX = 0;
|
||||
foreach (var img in imgList.Select(img=>img.Lock()))
|
||||
foreach (var img in imgList.Select(img => img.Lock()))
|
||||
{
|
||||
for (int i = 0; i < img.Width; i++)
|
||||
{
|
||||
@ -326,7 +396,7 @@ namespace NadekoBot.Extensions
|
||||
canvasPixels[i + offsetX, j] = img[i, j];
|
||||
}
|
||||
}
|
||||
offsetX += img.Width;
|
||||
offsetX += img.Width;
|
||||
}
|
||||
|
||||
return canvas;
|
||||
@ -345,4 +415,4 @@ namespace NadekoBot.Extensions
|
||||
public static bool IsDiscordInvite(this string str)
|
||||
=> filterRegex.IsMatch(str);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user