@ -1 +1 @@
|
|||||||
Subproject commit 80384323790471d254c7db5c237a49dc62624378
|
Subproject commit 0fd1e70a22612ff9fa697dace96f22780080b01f
|
@ -18,56 +18,6 @@ You can support the project on patreon: <https://patreon.com/nadekobot> or paypa
|
|||||||
### Administration
|
### Administration
|
||||||
Command and aliases | Description | Usage
|
Command and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`.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`
|
|
||||||
`.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`
|
|
||||||
`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore`
|
|
||||||
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
|
||||||
`.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`
|
|
||||||
`.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`
|
|
||||||
`.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
|
|
||||||
`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms`
|
`.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`
|
`.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`
|
`.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest`
|
||||||
@ -91,6 +41,57 @@ Command and aliases | Description | Usage
|
|||||||
`.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`
|
`.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`
|
`.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`
|
`.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount`
|
||||||
|
`.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
|
||||||
|
`.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`
|
||||||
|
`.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%, %time%,%shardid%,%shardcount%, %shardguilds% **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`
|
||||||
|
`.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`
|
||||||
|
`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore`
|
||||||
|
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
||||||
|
`.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`
|
||||||
|
`.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`
|
||||||
|
`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner only.** | `.reloadimages`
|
||||||
|
`.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.** | `.v+t`
|
||||||
|
`.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`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
@ -125,24 +126,6 @@ Command and aliases | Description | Usage
|
|||||||
### Gambling
|
### Gambling
|
||||||
Command and aliases | Description | Usage
|
Command and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama`
|
|
||||||
`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot`
|
|
||||||
`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity`
|
|
||||||
`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus`
|
|
||||||
`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo`
|
|
||||||
`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner only.** | `$slotstats`
|
|
||||||
`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner only.** | `$slottest 1000`
|
|
||||||
`$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5`
|
|
||||||
`$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`
|
|
||||||
`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction`
|
|
||||||
`$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`
|
`$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`
|
`$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
|
||||||
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
||||||
@ -150,36 +133,54 @@ Command and aliases | Description | Usage
|
|||||||
`$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"`
|
`$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`
|
`$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`
|
`$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`
|
||||||
|
`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction`
|
||||||
|
`$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.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t`
|
||||||
|
`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner only.** | `$slotstats`
|
||||||
|
`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner only.** | `$slottest 1000`
|
||||||
|
`$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5`
|
||||||
|
`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama`
|
||||||
|
`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot`
|
||||||
|
`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity`
|
||||||
|
`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus`
|
||||||
|
`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
### Games
|
### Games
|
||||||
Command and aliases | Description | Usage
|
Command and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`>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`
|
|
||||||
`>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`
|
`>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`
|
`>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`
|
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
|
||||||
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
||||||
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
||||||
|
`>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 an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) | `>plant` or `>plant 5`
|
||||||
|
`>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`
|
||||||
|
`>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`
|
||||||
|
`>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`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
@ -227,6 +228,7 @@ Command and aliases | Description | Usage
|
|||||||
`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
|
`!!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`
|
`!!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`
|
||||||
|
`!!setmusicchannel` `!!smch` | Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. **Requires ManageMessages server permission.** | `!!smch`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
@ -236,12 +238,12 @@ 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`
|
`~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. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai`
|
`~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. **Requires ManageMessages channel permission.** | `~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`
|
`~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`
|
`~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`
|
`~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`
|
`~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`
|
`~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`
|
||||||
|
`~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`
|
||||||
|
`~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`
|
||||||
`~cp` | We all know where this will lead you to. | `~cp`
|
`~cp` | We all know where this will lead you to. | `~cp`
|
||||||
`~boobs` | Real adult content. | `~boobs`
|
`~boobs` | Real adult content. | `~boobs`
|
||||||
`~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass`
|
`~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass`
|
||||||
@ -251,18 +253,6 @@ Command and aliases | Description | Usage
|
|||||||
### Permissions
|
### Permissions
|
||||||
Command and aliases | Description | Usage
|
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`
|
|
||||||
`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2`
|
|
||||||
`;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`
|
`;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`
|
`;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`
|
`;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`
|
||||||
@ -280,6 +270,18 @@ Command and aliases | Description | Usage
|
|||||||
`;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole`
|
`;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`
|
`;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]`
|
`;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`
|
||||||
|
`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2`
|
||||||
|
`;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)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
@ -297,32 +299,6 @@ Command and aliases | Description | Usage
|
|||||||
### Searches
|
### Searches
|
||||||
Command and aliases | Description | Usage
|
Command and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`~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`
|
|
||||||
`~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`
|
`~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`
|
`~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`
|
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
|
||||||
@ -353,34 +329,40 @@ Command and aliases | Description | Usage
|
|||||||
`~lolban` | Shows top banned champions ordered by ban rate. | `~lolban`
|
`~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`
|
`~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"`
|
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
||||||
|
`~mal` | Shows basic info from myanimelist profile. | `~mal straysocks`
|
||||||
|
`~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`
|
||||||
|
`~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`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
### Utility
|
### Utility
|
||||||
Command and aliases | Description | Usage
|
Command and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
|
`.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. **Requires ManageRoles server permission.** **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole`
|
||||||
`.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`
|
|
||||||
`.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. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
|
|
||||||
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
|
|
||||||
`.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`
|
|
||||||
`.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`
|
|
||||||
`.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`
|
`.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`
|
`.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`
|
`.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`
|
||||||
@ -396,3 +378,24 @@ Command and aliases | Description | Usage
|
|||||||
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3`
|
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3`
|
||||||
`.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`
|
||||||
`.activity` | Checks for spammers. **Bot Owner only.** | `.activity`
|
`.activity` | Checks for spammers. **Bot Owner only.** | `.activity`
|
||||||
|
`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1`
|
||||||
|
`.calcops` | Shows all available operations in .calc command | `.calcops`
|
||||||
|
`.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`
|
||||||
|
`.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`
|
||||||
|
`.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. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
|
||||||
|
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
|
||||||
|
`.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`
|
||||||
|
82
src/NadekoBot/DataStructures/DisposableImutableList.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class DisposableReadOnlyListExtensions
|
||||||
|
{
|
||||||
|
public static IDisposableReadOnlyList<T> AsDisposable<T>(this IReadOnlyList<T> arr) where T : IDisposable
|
||||||
|
=> new DisposableReadOnlyList<T>(arr);
|
||||||
|
|
||||||
|
public static IDisposableReadOnlyList<KeyValuePair<TKey, TValue>> AsDisposable<TKey, TValue>(this IReadOnlyList<KeyValuePair<TKey, TValue>> arr) where TValue : IDisposable
|
||||||
|
=> new DisposableReadOnlyList<TKey, TValue>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDisposableReadOnlyList<T> : IReadOnlyList<T>, IDisposable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisposableReadOnlyList<T> : IDisposableReadOnlyList<T>
|
||||||
|
where T : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<T> _arr;
|
||||||
|
|
||||||
|
public int Count => _arr.Count;
|
||||||
|
|
||||||
|
public T this[int index] => _arr[index];
|
||||||
|
|
||||||
|
public DisposableReadOnlyList(IReadOnlyList<T> arr)
|
||||||
|
{
|
||||||
|
this._arr = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
=> _arr.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
=> _arr.GetEnumerator();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var item in _arr)
|
||||||
|
{
|
||||||
|
item.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisposableReadOnlyList<T, U> : IDisposableReadOnlyList<KeyValuePair<T, U>>
|
||||||
|
where U : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<KeyValuePair<T, U>> _arr;
|
||||||
|
|
||||||
|
public int Count => _arr.Count;
|
||||||
|
|
||||||
|
KeyValuePair<T, U> IReadOnlyList<KeyValuePair<T, U>>.this[int index] => _arr[index];
|
||||||
|
|
||||||
|
public DisposableReadOnlyList(IReadOnlyList<KeyValuePair<T, U>> arr)
|
||||||
|
{
|
||||||
|
this._arr = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() =>
|
||||||
|
_arr.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() =>
|
||||||
|
_arr.GetEnumerator();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var item in _arr)
|
||||||
|
{
|
||||||
|
item.Value.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd)
|
private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -52,6 +54,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
_log.Warn(ex, "Delmsgoncmd errored...");
|
_log.Warn(ex, "Delmsgoncmd errored...");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -105,18 +105,19 @@ namespace NadekoBot.Modules.Administration
|
|||||||
antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||||
}
|
}
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += async (imsg) =>
|
NadekoBot.Client.MessageReceived += (imsg) =>
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var msg = imsg as IUserMessage;
|
var msg = imsg as IUserMessage;
|
||||||
if (msg == null || msg.Author.IsBot)
|
if (msg == null || msg.Author.IsBot)
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var channel = msg.Channel as ITextChannel;
|
var channel = msg.Channel as ITextChannel;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
AntiSpamStats spamSettings;
|
AntiSpamStats spamSettings;
|
||||||
if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
||||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
||||||
@ -126,7 +127,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
||||||
(id, old) => { old.ApplyNextMessage(msg.Content); return old; });
|
(id, old) =>
|
||||||
|
{
|
||||||
|
old.ApplyNextMessage(msg.Content); return old;
|
||||||
|
});
|
||||||
|
|
||||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||||
{
|
{
|
||||||
@ -138,20 +142,24 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
NadekoBot.Client.UserJoined += async (usr) =>
|
NadekoBot.Client.UserJoined += (usr) =>
|
||||||
|
{
|
||||||
|
if (usr.IsBot)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
AntiRaidStats settings;
|
||||||
|
if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
if (!settings.RaidUsers.Add(usr))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (usr.IsBot)
|
|
||||||
return;
|
|
||||||
AntiRaidStats settings;
|
|
||||||
if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
|
||||||
return;
|
|
||||||
if (!settings.RaidUsers.Add(usr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
++settings.UsersCount;
|
++settings.UsersCount;
|
||||||
|
|
||||||
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
||||||
@ -168,11 +176,14 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
||||||
{
|
{
|
||||||
|
_log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild");
|
||||||
foreach (var gu in gus)
|
foreach (var gu in gus)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (action)
|
||||||
|
@ -3,6 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -168,6 +169,14 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task ReloadImages()
|
||||||
|
{
|
||||||
|
var time = await NadekoBot.Images.Reload().ConfigureAwait(false);
|
||||||
|
await Context.Channel.SendConfirmAsync($"Images loaded after {time.TotalSeconds:F3}s!").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
||||||
{
|
{
|
||||||
switch (sus)
|
switch (sus)
|
||||||
@ -184,6 +193,14 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
return UserStatus.Online;
|
return UserStatus.Online;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SettableUserStatus
|
||||||
|
{
|
||||||
|
Online,
|
||||||
|
Invisible,
|
||||||
|
Idle,
|
||||||
|
Dnd
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,11 @@ using NadekoBot.Services;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
@ -22,6 +24,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||||
|
|
||||||
private static ConcurrentHashSet<ulong> voicePlusTextCache { get; }
|
private static ConcurrentHashSet<ulong> voicePlusTextCache { get; }
|
||||||
|
|
||||||
|
private static ConcurrentDictionary<ulong, SemaphoreSlim> guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||||
static VoicePlusTextCommands()
|
static VoicePlusTextCommands()
|
||||||
{
|
{
|
||||||
var _log = LogManager.GetCurrentClassLogger();
|
var _log = LogManager.GetCurrentClassLogger();
|
||||||
@ -36,22 +40,26 @@ namespace NadekoBot.Modules.Administration
|
|||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after)
|
private static Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after)
|
||||||
{
|
{
|
||||||
var user = (iuser as SocketGuildUser);
|
var user = (iuser as SocketGuildUser);
|
||||||
var guild = user?.Guild;
|
var guild = user?.Guild;
|
||||||
|
|
||||||
if (guild == null)
|
if (guild == null)
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var botUserPerms = guild.CurrentUser.GuildPermissions;
|
var botUserPerms = guild.CurrentUser.GuildPermissions;
|
||||||
|
|
||||||
if (before.VoiceChannel == after.VoiceChannel) return;
|
if (before.VoiceChannel == after.VoiceChannel)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
if (!voicePlusTextCache.Contains(guild.Id))
|
if (!voicePlusTextCache.Contains(guild.Id))
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
|
if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
|
||||||
{
|
{
|
||||||
@ -71,43 +79,80 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var semaphore = guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var beforeVch = before.VoiceChannel;
|
var beforeVch = before.VoiceChannel;
|
||||||
if (beforeVch != null)
|
if (beforeVch != null)
|
||||||
{
|
{
|
||||||
var textChannel = guild.TextChannels.Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
|
var beforeRoleName = GetRoleName(beforeVch);
|
||||||
if (textChannel != null)
|
var beforeRole = guild.Roles.FirstOrDefault(x => x.Name == beforeRoleName);
|
||||||
await textChannel.AddPermissionOverwriteAsync(user,
|
if (beforeRole != null)
|
||||||
new OverwritePermissions(readMessages: PermValue.Deny,
|
try
|
||||||
sendMessages: PermValue.Deny)).ConfigureAwait(false);
|
{
|
||||||
|
_log.Info("Removing role " + beforeRoleName + " from user " + user.Username);
|
||||||
|
await user.RemoveRolesAsync(beforeRole).ConfigureAwait(false);
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var afterVch = after.VoiceChannel;
|
var afterVch = after.VoiceChannel;
|
||||||
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
||||||
{
|
{
|
||||||
|
var roleName = GetRoleName(afterVch);
|
||||||
|
IRole roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName);
|
||||||
|
if (roleToAdd == null)
|
||||||
|
roleToAdd = await guild.CreateRoleAsync(roleName).ConfigureAwait(false);
|
||||||
|
|
||||||
ITextChannel textChannel = guild.TextChannels
|
ITextChannel textChannel = guild.TextChannels
|
||||||
.Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
|
.Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
if (textChannel == null)
|
if (textChannel == null)
|
||||||
{
|
{
|
||||||
textChannel = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
||||||
await textChannel.AddPermissionOverwriteAsync(guild.EveryoneRole,
|
|
||||||
new OverwritePermissions(readMessages: PermValue.Deny,
|
try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch { }
|
||||||
sendMessages: PermValue.Deny)).ConfigureAwait(false);
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
|
||||||
|
readMessages: PermValue.Allow,
|
||||||
|
sendMessages: PermValue.Allow))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
await created.AddPermissionOverwriteAsync(guild.EveryoneRole, new OverwritePermissions(
|
||||||
|
readMessages: PermValue.Deny,
|
||||||
|
sendMessages: PermValue.Deny))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await textChannel.AddPermissionOverwriteAsync(user,
|
_log.Warn("Adding role " + roleToAdd.Name + " to user " + user.Username);
|
||||||
new OverwritePermissions(readMessages: PermValue.Allow,
|
await user.AddRolesAsync(roleToAdd).ConfigureAwait(false);
|
||||||
sendMessages: PermValue.Allow)).ConfigureAwait(false);
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
_log.Warn(ex);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetChannelName(string voiceName) =>
|
private static string GetChannelName(string voiceName) =>
|
||||||
channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||||
|
|
||||||
|
private static string GetRoleName(IVoiceChannel ch) =>
|
||||||
|
"nvoice-" + ch.Id;
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
@ -127,7 +172,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("⚠️ You are enabling this feature and **I do not have ADMINISTRATOR permissions**. " +
|
await Context.Channel.SendErrorAsync("⚠️ You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. " +
|
||||||
"`This may cause some issues, and you will have to clean up text channels yourself afterwards.`");
|
"`This may cause some issues, and you will have to clean up text channels yourself afterwards.`");
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@ -147,6 +192,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
||||||
{
|
{
|
||||||
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var role in guild.Roles.Where(c => c.Name.StartsWith("nvoice-")))
|
||||||
|
{
|
||||||
|
try { await role.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -163,7 +215,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||||
|
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
//[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task CleanVPlusT()
|
public async Task CleanVPlusT()
|
||||||
{
|
{
|
||||||
var guild = Context.Guild;
|
var guild = Context.Guild;
|
||||||
@ -174,15 +228,27 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var allTxtChannels = (await guild.GetTextChannelsAsync()).Where(c => c.Name.EndsWith("-voice"));
|
var textChannels = await guild.GetTextChannelsAsync().ConfigureAwait(false);
|
||||||
var validTxtChannelNames = (await guild.GetVoiceChannelsAsync()).Select(c => GetChannelName(c.Name).ToLowerInvariant());
|
var voiceChannels = await guild.GetVoiceChannelsAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var invalidTxtChannels = allTxtChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
var boundTextChannels = textChannels.Where(c => c.Name.EndsWith("-voice"));
|
||||||
|
var validTxtChannelNames = new HashSet<string>(voiceChannels.Select(c => GetChannelName(c.Name).ToLowerInvariant()));
|
||||||
|
var invalidTxtChannels = boundTextChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
||||||
|
|
||||||
foreach (var c in invalidTxtChannels)
|
foreach (var c in invalidTxtChannels)
|
||||||
{
|
{
|
||||||
try { await c.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await c.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
await Task.Delay(500);
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var boundRoles = guild.Roles.Where(r => r.Name.StartsWith("nvoice-"));
|
||||||
|
var validRoleNames = new HashSet<string>(voiceChannels.Select(c => GetRoleName(c).ToLowerInvariant()));
|
||||||
|
var invalidRoles = boundRoles.Where(r => !validRoleNames.Contains(r.Name));
|
||||||
|
|
||||||
|
foreach (var r in invalidRoles)
|
||||||
|
{
|
||||||
|
try { await r.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("Cleaned v+t.").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("Cleaned v+t.").ConfigureAwait(false);
|
||||||
|
@ -78,6 +78,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
_secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
_secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var game = NadekoBot.Client.Game?.Name;
|
||||||
await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName)
|
await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
@ -94,10 +95,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
await Task.Delay(num * 1000);
|
await Task.Delay(num * 1000);
|
||||||
NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
||||||
|
|
||||||
|
var cnt = _sneakyGameAwardedUsers.Count;
|
||||||
_sneakyGameAwardedUsers.Clear();
|
_sneakyGameAwardedUsers.Clear();
|
||||||
_secretCode = String.Empty;
|
_secretCode = String.Empty;
|
||||||
|
|
||||||
await NadekoBot.Client.SetGameAsync($"SneakyGame event ended.")
|
await NadekoBot.Client.SetGameAsync($"SneakyGame event ended. {cnt} users received a reward.")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,16 +33,12 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var num1 = gen / 10;
|
var num1 = gen / 10;
|
||||||
var num2 = gen % 10;
|
var num2 = gen % 10;
|
||||||
var imageStream = await Task.Run(() =>
|
var imageStream = await Task.Run(() =>
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
|
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}).ConfigureAwait(false);
|
||||||
catch { return new MemoryStream(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -82,7 +78,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
await InternallDndRoll(arg, false).ConfigureAwait(false);
|
await InternallDndRoll(arg, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternalRoll( int num, bool ordered)
|
private async Task InternalRoll(int num, bool ordered)
|
||||||
{
|
{
|
||||||
if (num < 1 || num > 30)
|
if (num < 1 || num > 30)
|
||||||
{
|
{
|
||||||
@ -209,22 +205,26 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private Image GetDice(int num)
|
private Image GetDice(int num)
|
||||||
{
|
{
|
||||||
const string pathToImage = "data/images/dice";
|
if (num < 0 || num > 10)
|
||||||
if (num != 10)
|
throw new ArgumentOutOfRangeException(nameof(num));
|
||||||
{
|
|
||||||
using (var stream = File.OpenRead(Path.Combine(pathToImage, $"{num}.png")))
|
|
||||||
return new Image(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var one = File.OpenRead(Path.Combine(pathToImage, "1.png")))
|
if (num == 10)
|
||||||
using (var zero = File.OpenRead(Path.Combine(pathToImage, "0.png")))
|
|
||||||
{
|
{
|
||||||
Image imgOne = new Image(one);
|
var images = NadekoBot.Images.Dice;
|
||||||
Image imgZero = new Image(zero);
|
using (var imgOneStream = images[1].Value.ToStream())
|
||||||
|
using (var imgZeroStream = images[0].Value.ToStream())
|
||||||
|
{
|
||||||
|
Image imgOne = new Image(imgOneStream);
|
||||||
|
Image imgZero = new Image(imgZeroStream);
|
||||||
|
|
||||||
return new[] { imgOne, imgZero }.Merge();
|
return new[] { imgOne, imgZero }.Merge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
using (var die = NadekoBot.Images.Dice[num].Value.ToStream())
|
||||||
|
{
|
||||||
|
return new Image(die);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Image = ImageSharp.Image;
|
using Image = ImageSharp.Image;
|
||||||
@ -16,9 +17,15 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[Group]
|
[Group]
|
||||||
public class FlipCoinCommands : ModuleBase
|
public class FlipCoinCommands : ModuleBase
|
||||||
{
|
{
|
||||||
|
private readonly IImagesService _images;
|
||||||
|
|
||||||
private static NadekoRandom rng { get; } = new NadekoRandom();
|
private static NadekoRandom rng { get; } = new NadekoRandom();
|
||||||
private const string headsPath = "data/images/coins/heads.png";
|
|
||||||
private const string tailsPath = "data/images/coins/tails.png";
|
public FlipCoinCommands()
|
||||||
|
{
|
||||||
|
//todo DI in the future, can't atm
|
||||||
|
this._images = NadekoBot.Images;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Flip(int count = 1)
|
public async Task Flip(int count = 1)
|
||||||
@ -26,25 +33,39 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
if (count == 1)
|
if (count == 1)
|
||||||
{
|
{
|
||||||
if (rng.Next(0, 2) == 1)
|
if (rng.Next(0, 2) == 1)
|
||||||
await Context.Channel.SendFileAsync(File.Open(headsPath, FileMode.OpenOrCreate), "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
{
|
||||||
|
using (var heads = _images.Heads.ToStream())
|
||||||
|
{
|
||||||
|
await Context.Channel.SendFileAsync(heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
await Context.Channel.SendFileAsync(File.Open(tailsPath, FileMode.OpenOrCreate), "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
{
|
||||||
|
using (var tails = _images.Tails.ToStream())
|
||||||
|
{
|
||||||
|
await Context.Channel.SendFileAsync(tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (count > 10 || count < 1)
|
if (count > 10 || count < 1)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`");
|
await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var imgs = new Image[count];
|
var imgs = new Image[count];
|
||||||
|
using (var heads = _images.Heads.ToStream())
|
||||||
|
using(var tails = _images.Tails.ToStream())
|
||||||
|
{
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
imgs[i] = rng.Next(0, 10) < 5 ?
|
imgs[i] = rng.Next(0, 10) < 5 ?
|
||||||
new Image(File.OpenRead(headsPath)) :
|
new Image(heads) :
|
||||||
new Image(File.OpenRead(tailsPath));
|
new Image(tails);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Betflip(int amount, string guess)
|
public async Task Betflip(int amount, string guess)
|
||||||
@ -68,17 +89,18 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
//heads = true
|
//heads = true
|
||||||
//tails = false
|
//tails = false
|
||||||
|
|
||||||
|
//todo this seems stinky, no time to look at it right now
|
||||||
var isHeads = guessStr == "HEADS" || guessStr == "H";
|
var isHeads = guessStr == "HEADS" || guessStr == "H";
|
||||||
bool result = false;
|
bool result = false;
|
||||||
string imgPathToSend;
|
IEnumerable<byte> imageToSend;
|
||||||
if (rng.Next(0, 2) == 1)
|
if (rng.Next(0, 2) == 1)
|
||||||
{
|
{
|
||||||
imgPathToSend = headsPath;
|
imageToSend = _images.Heads;
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
imgPathToSend = tailsPath;
|
imageToSend = _images.Tails;
|
||||||
}
|
}
|
||||||
|
|
||||||
string str;
|
string str;
|
||||||
@ -92,8 +114,10 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
str = $"{Context.User.Mention}`Better luck next time.`";
|
str = $"{Context.User.Mention}`Better luck next time.`";
|
||||||
}
|
}
|
||||||
|
using (var toSend = imageToSend.ToStream())
|
||||||
await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), new FileInfo(imgPathToSend).Name, str).ConfigureAwait(false);
|
{
|
||||||
|
await Context.Channel.SendFileAsync(toSend, "result.png", str).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,52 +21,19 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private static int totalBet = 0;
|
private static int totalBet = 0;
|
||||||
private static int totalPaidOut = 0;
|
private static int totalPaidOut = 0;
|
||||||
|
|
||||||
private const string backgroundPath = "data/slots/background.png";
|
|
||||||
|
|
||||||
private static readonly byte[] backgroundBuffer;
|
|
||||||
private static readonly byte[][] numbersBuffer = new byte[10][];
|
|
||||||
private static readonly byte[][] emojiBuffer;
|
|
||||||
|
|
||||||
const int alphaCutOut = byte.MaxValue / 3;
|
const int alphaCutOut = byte.MaxValue / 3;
|
||||||
|
|
||||||
static Slots()
|
|
||||||
{
|
|
||||||
backgroundBuffer = File.ReadAllBytes(backgroundPath);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
numbersBuffer[i] = File.ReadAllBytes("data/slots/" + i + ".png");
|
|
||||||
}
|
|
||||||
int throwaway;
|
|
||||||
var emojiFiles = Directory.GetFiles("data/slots/emojis/", "*.png")
|
|
||||||
.Where(f => int.TryParse(Path.GetFileNameWithoutExtension(f), out throwaway))
|
|
||||||
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
emojiBuffer = new byte[emojiFiles.Length][];
|
|
||||||
for (int i = 0; i < emojiFiles.Length; i++)
|
|
||||||
{
|
|
||||||
emojiBuffer[i] = File.ReadAllBytes(emojiFiles[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static MemoryStream InternalGetStream(string path)
|
|
||||||
{
|
|
||||||
var ms = new MemoryStream();
|
|
||||||
using (var fs = File.Open(path, FileMode.Open))
|
|
||||||
{
|
|
||||||
fs.CopyTo(ms);
|
|
||||||
fs.Flush();
|
|
||||||
}
|
|
||||||
ms.Position = 0;
|
|
||||||
return ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
//here is a payout chart
|
//here is a payout chart
|
||||||
//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg
|
//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg
|
||||||
//thanks to judge for helping me with this
|
//thanks to judge for helping me with this
|
||||||
|
|
||||||
|
private readonly IImagesService _images;
|
||||||
|
|
||||||
|
public Slots()
|
||||||
|
{
|
||||||
|
this._images = NadekoBot.Images;
|
||||||
|
}
|
||||||
|
|
||||||
public class SlotMachine
|
public class SlotMachine
|
||||||
{
|
{
|
||||||
public const int MaxValue = 5;
|
public const int MaxValue = 5;
|
||||||
@ -154,7 +121,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
const int bet = 1;
|
const int bet = 1;
|
||||||
int payout = 0;
|
int payout = 0;
|
||||||
foreach (var key in dict.Keys.OrderByDescending(x=>x))
|
foreach (var key in dict.Keys.OrderByDescending(x => x))
|
||||||
{
|
{
|
||||||
sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%");
|
sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%");
|
||||||
payout += key * dict[key];
|
payout += key * dict[key];
|
||||||
@ -164,6 +131,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
static HashSet<ulong> runningUsers = new HashSet<ulong>();
|
static HashSet<ulong> runningUsers = new HashSet<ulong>();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Slot(int amount = 0)
|
public async Task Slot(int amount = 0)
|
||||||
{
|
{
|
||||||
@ -189,7 +157,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Interlocked.Add(ref totalBet, amount);
|
Interlocked.Add(ref totalBet, amount);
|
||||||
using (var bgFileStream = new MemoryStream(backgroundBuffer))
|
using (var bgFileStream = NadekoBot.Images.SlotBackground.ToStream())
|
||||||
{
|
{
|
||||||
var bgImage = new ImageSharp.Image(bgFileStream);
|
var bgImage = new ImageSharp.Image(bgFileStream);
|
||||||
|
|
||||||
@ -199,7 +167,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
using (var file = new MemoryStream(emojiBuffer[numbers[i]]))
|
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
||||||
{
|
{
|
||||||
var randomImage = new ImageSharp.Image(file);
|
var randomImage = new ImageSharp.Image(file);
|
||||||
using (var toAdd = randomImage.Lock())
|
using (var toAdd = randomImage.Lock())
|
||||||
@ -226,7 +194,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
var digit = printWon % 10;
|
var digit = printWon % 10;
|
||||||
using (var fs = new MemoryStream(numbersBuffer[digit]))
|
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
|
||||||
{
|
{
|
||||||
var img = new ImageSharp.Image(fs);
|
var img = new ImageSharp.Image(fs);
|
||||||
using (var pixels = img.Lock())
|
using (var pixels = img.Lock())
|
||||||
@ -251,7 +219,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
var digit = printAmount % 10;
|
var digit = printAmount % 10;
|
||||||
using (var fs = new MemoryStream(numbersBuffer[digit]))
|
using (var fs = _images.SlotNumbers[digit].ToStream())
|
||||||
{
|
{
|
||||||
var img = new ImageSharp.Image(fs);
|
var img = new ImageSharp.Image(fs);
|
||||||
using (var pixels = img.Lock())
|
using (var pixels = img.Lock())
|
||||||
|
@ -10,6 +10,7 @@ using NLog;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -51,24 +52,27 @@ namespace NadekoBot.Modules.Games
|
|||||||
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task PotentialFlowerGeneration(SocketMessage imsg)
|
private static Task PotentialFlowerGeneration(SocketMessage imsg)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var msg = imsg as SocketUserMessage;
|
var msg = imsg as SocketUserMessage;
|
||||||
if (msg == null || msg.IsAuthor() || msg.Author.IsBot)
|
if (msg == null || msg.IsAuthor() || msg.Author.IsBot)
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var channel = imsg.Channel as ITextChannel;
|
var channel = imsg.Channel as ITextChannel;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
if (!generationChannels.Contains(channel.Id))
|
if (!generationChannels.Contains(channel.Id))
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
|
var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
//todo i'm stupid :rofl: wtg kwoth. real async programming :100: :ok_hand: :100: :100: :thumbsup:
|
||||||
if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
|
if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -93,20 +97,28 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!";
|
firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!";
|
||||||
}
|
}
|
||||||
var file = GetRandomCurrencyImagePath();
|
var file = GetRandomCurrencyImage();
|
||||||
|
using (var fileStream = file.Value.ToStream())
|
||||||
|
{
|
||||||
var sent = await channel.SendFileAsync(
|
var sent = await channel.SendFileAsync(
|
||||||
File.Open(file, FileMode.OpenOrCreate),
|
fileStream,
|
||||||
new FileInfo(file).Name,
|
file.Key,
|
||||||
$"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
|
$"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
msgs[0] = sent;
|
msgs[0] = sent;
|
||||||
|
}
|
||||||
|
|
||||||
plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
|
plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -159,18 +171,15 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = GetRandomCurrencyImagePath();
|
var imgData = GetRandomCurrencyImage();
|
||||||
IUserMessage msg;
|
|
||||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
||||||
|
|
||||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
|
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
|
||||||
if (file == null)
|
|
||||||
|
IUserMessage msg;
|
||||||
|
using (var toSend = imgData.Value.ToStream())
|
||||||
{
|
{
|
||||||
msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
msg = await Context.Channel.SendFileAsync(toSend, imgData.Key, msgToSend).ConfigureAwait(false);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), new FileInfo(file).Name, msgToSend).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var msgs = new IUserMessage[amount];
|
var msgs = new IUserMessage[amount];
|
||||||
@ -220,10 +229,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetRandomCurrencyImagePath()
|
private static KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
|
||||||
{
|
{
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
return Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
|
var images = NadekoBot.Images.Currency;
|
||||||
|
|
||||||
|
return images[rng.Next(0, images.Length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetRandomNumber()
|
int GetRandomNumber()
|
||||||
|
@ -140,24 +140,6 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
public async Task Danbooru([Remainder] string tag = null)
|
|
||||||
{
|
|
||||||
tag = tag?.Trim() ?? "";
|
|
||||||
|
|
||||||
var url = await GetDanbooruImageLink(tag).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (url == null)
|
|
||||||
await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false);
|
|
||||||
else
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithDescription(Context.User.Mention + " " + tag)
|
|
||||||
.WithImageUrl(url)
|
|
||||||
.WithFooter(efb => efb.WithText("Danbooru")))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Yandere([Remainder] string tag = null)
|
public Task Yandere([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere);
|
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere);
|
||||||
@ -166,10 +148,6 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
public Task Konachan([Remainder] string tag = null)
|
public Task Konachan([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan);
|
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
public Task Gelbooru([Remainder] string tag = null)
|
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru);
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Rule34([Remainder] string tag = null)
|
public Task Rule34([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34);
|
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34);
|
||||||
@ -191,6 +169,49 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
public async Task Danbooru([Remainder] string tag = null)
|
||||||
|
{
|
||||||
|
tag = tag?.Trim() ?? "";
|
||||||
|
|
||||||
|
var url = await GetDanbooruImageLink(tag).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (url == null)
|
||||||
|
await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithDescription(Context.User.Mention + " " + tag)
|
||||||
|
.WithImageUrl(url)
|
||||||
|
.WithFooter(efb => efb.WithText("Danbooru")))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task<string> GetDanbooruImageLink(string tag) => Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag).ConfigureAwait(false);
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
doc.Load(data);
|
||||||
|
var nodes = doc.GetElementsByTagName("file-url");
|
||||||
|
|
||||||
|
var node = nodes[new NadekoRandom().Next(0, nodes.Count)];
|
||||||
|
return "https://danbooru.donmai.us" + node.InnerText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
public Task Gelbooru([Remainder] string tag = null)
|
||||||
|
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Cp()
|
public async Task Cp()
|
||||||
{
|
{
|
||||||
@ -233,27 +254,6 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !GLOBAL_NADEKO
|
#if !GLOBAL_NADEKO
|
||||||
public static Task<string> GetDanbooruImageLink(string tag) => Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
http.AddFakeHeaders();
|
|
||||||
var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag).ConfigureAwait(false);
|
|
||||||
var doc = new XmlDocument();
|
|
||||||
doc.Load(data);
|
|
||||||
var nodes = doc.GetElementsByTagName("file-url");
|
|
||||||
|
|
||||||
var node = nodes[new NadekoRandom().Next(0, nodes.Count)];
|
|
||||||
return "https://danbooru.donmai.us" + node.InnerText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
public static Task<string> GetE621ImageLink(string tag) => Task.Run(async () =>
|
public static Task<string> GetE621ImageLink(string tag) => Task.Run(async () =>
|
||||||
|
@ -33,6 +33,7 @@ namespace NadekoBot
|
|||||||
|
|
||||||
public static GoogleApiService Google { get; private set; }
|
public static GoogleApiService Google { get; private set; }
|
||||||
public static StatsService Stats { get; private set; }
|
public static StatsService Stats { get; private set; }
|
||||||
|
public static IImagesService Images { get; private set; }
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, string> ModulePrefixes { get; private set; }
|
public static ConcurrentDictionary<string, string> ModulePrefixes { get; private set; }
|
||||||
public static bool Ready { get; private set; }
|
public static bool Ready { get; private set; }
|
||||||
@ -67,8 +68,12 @@ namespace NadekoBot
|
|||||||
MessageCacheSize = 10,
|
MessageCacheSize = 10,
|
||||||
LogLevel = LogSeverity.Warning,
|
LogLevel = LogSeverity.Warning,
|
||||||
TotalShards = Credentials.TotalShards,
|
TotalShards = Credentials.TotalShards,
|
||||||
ConnectionTimeout = int.MaxValue
|
ConnectionTimeout = int.MaxValue,
|
||||||
|
#if !GLOBAL_NADEKO
|
||||||
|
//AlwaysDownloadUsers = true,
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
#if GLOBAL_NADEKO
|
#if GLOBAL_NADEKO
|
||||||
Client.Log += Client_Log;
|
Client.Log += Client_Log;
|
||||||
#endif
|
#endif
|
||||||
@ -81,6 +86,7 @@ namespace NadekoBot
|
|||||||
Google = new GoogleApiService();
|
Google = new GoogleApiService();
|
||||||
CommandHandler = new CommandHandler(Client, CommandService);
|
CommandHandler = new CommandHandler(Client, CommandService);
|
||||||
Stats = new StatsService(Client, CommandHandler);
|
Stats = new StatsService(Client, CommandHandler);
|
||||||
|
Images = await ImagesService.Create().ConfigureAwait(false);
|
||||||
|
|
||||||
////setup DI
|
////setup DI
|
||||||
//var depMap = new DependencyMap();
|
//var depMap = new DependencyMap();
|
||||||
@ -112,7 +118,7 @@ namespace NadekoBot
|
|||||||
|
|
||||||
await CommandHandler.StartHandling().ConfigureAwait(false);
|
await CommandHandler.StartHandling().ConfigureAwait(false);
|
||||||
|
|
||||||
await CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly).ConfigureAwait(false);
|
var _ = await Task.Run(() => CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly)).ConfigureAwait(false);
|
||||||
#if !GLOBAL_NADEKO
|
#if !GLOBAL_NADEKO
|
||||||
await CommandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
await CommandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
||||||
#endif
|
#endif
|
||||||
|
27
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -5621,6 +5621,33 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to reloadimages.
|
||||||
|
/// </summary>
|
||||||
|
public static string reloadimages_cmd {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("reloadimages_cmd", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Reloads images bot is using. Safe to use even when bot is being used heavily..
|
||||||
|
/// </summary>
|
||||||
|
public static string reloadimages_desc {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("reloadimages_desc", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to `{0}reloadimages`.
|
||||||
|
/// </summary>
|
||||||
|
public static string reloadimages_usage {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("reloadimages_usage", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to remind.
|
/// Looks up a localized string similar to remind.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3042,4 +3042,13 @@
|
|||||||
<data name="setmusicchannel_usage" xml:space="preserve">
|
<data name="setmusicchannel_usage" xml:space="preserve">
|
||||||
<value>`{0}smch`</value>
|
<value>`{0}smch`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="reloadimages_cmd" xml:space="preserve">
|
||||||
|
<value>reloadimages</value>
|
||||||
|
</data>
|
||||||
|
<data name="reloadimages_desc" xml:space="preserve">
|
||||||
|
<value>Reloads images bot is using. Safe to use even when bot is being used heavily.</value>
|
||||||
|
</data>
|
||||||
|
<data name="reloadimages_usage" xml:space="preserve">
|
||||||
|
<value>`{0}reloadimages`</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -105,9 +105,8 @@ namespace NadekoBot.Services
|
|||||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||||
|
|
||||||
const float oneThousandth = 1.0f / 1000;
|
const float oneThousandth = 1.0f / 1000;
|
||||||
private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks)
|
private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks)
|
||||||
{
|
{
|
||||||
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
|
||||||
_log.Info("Command Executed after {4}s\n\t" +
|
_log.Info("Command Executed after {4}s\n\t" +
|
||||||
"User: {0}\n\t" +
|
"User: {0}\n\t" +
|
||||||
"Server: {1}\n\t" +
|
"Server: {1}\n\t" +
|
||||||
@ -118,6 +117,7 @@ namespace NadekoBot.Services
|
|||||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||||
usrMsg.Content, // {3}
|
usrMsg.Content, // {3}
|
||||||
ticks * oneThousandth);
|
ticks * oneThousandth);
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks)
|
private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks)
|
||||||
@ -184,7 +184,9 @@ namespace NadekoBot.Services
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task MessageReceivedHandler(SocketMessage msg)
|
private Task MessageReceivedHandler(SocketMessage msg)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -235,6 +237,7 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
if (exec.Result.IsSuccess)
|
if (exec.Result.IsSuccess)
|
||||||
{
|
{
|
||||||
|
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
||||||
await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false);
|
await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
||||||
@ -271,6 +274,8 @@ namespace NadekoBot.Services
|
|||||||
_log.Warn(ex.InnerException);
|
_log.Warn(ex.InnerException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||||
|
26
src/NadekoBot/Services/IImagesService.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services
|
||||||
|
{
|
||||||
|
public interface IImagesService
|
||||||
|
{
|
||||||
|
ImmutableArray<byte> Heads { get; }
|
||||||
|
ImmutableArray<byte> Tails { get; }
|
||||||
|
|
||||||
|
ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; }
|
||||||
|
ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; }
|
||||||
|
|
||||||
|
ImmutableArray<byte> SlotBackground { get; }
|
||||||
|
ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; }
|
||||||
|
ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; }
|
||||||
|
|
||||||
|
Task<TimeSpan> Reload();
|
||||||
|
}
|
||||||
|
}
|
99
src/NadekoBot/Services/Impl/ImagesService.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Impl
|
||||||
|
{
|
||||||
|
public class ImagesService : IImagesService
|
||||||
|
{
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
private const string basePath = "data/images/";
|
||||||
|
|
||||||
|
private const string headsPath = basePath + "coins/heads.png";
|
||||||
|
private const string tailsPath = basePath + "coins/tails.png";
|
||||||
|
|
||||||
|
private const string currencyImagesPath = basePath + "currency";
|
||||||
|
private const string diceImagesPath = basePath + "dice";
|
||||||
|
|
||||||
|
private const string slotBackgroundPath = basePath + "slots/background.png";
|
||||||
|
private const string slotNumbersPath = basePath + "slots/numbers/";
|
||||||
|
private const string slotEmojisPath = basePath + "slots/emojis/";
|
||||||
|
|
||||||
|
|
||||||
|
public ImmutableArray<byte> Heads { get; private set; }
|
||||||
|
public ImmutableArray<byte> Tails { get; private set; }
|
||||||
|
|
||||||
|
//todo C#7
|
||||||
|
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; private set; }
|
||||||
|
|
||||||
|
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; private set; }
|
||||||
|
|
||||||
|
public ImmutableArray<byte> SlotBackground { get; private set; }
|
||||||
|
public ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; private set; }
|
||||||
|
public ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; private set; }
|
||||||
|
|
||||||
|
private ImagesService()
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<IImagesService> Create()
|
||||||
|
{
|
||||||
|
var srvc = new ImagesService();
|
||||||
|
await srvc.Reload().ConfigureAwait(false);
|
||||||
|
return srvc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TimeSpan> Reload() => Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_log.Info("Loading images...");
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
Heads = File.ReadAllBytes(headsPath).ToImmutableArray();
|
||||||
|
Tails = File.ReadAllBytes(tailsPath).ToImmutableArray();
|
||||||
|
|
||||||
|
Currency = Directory.GetFiles(currencyImagesPath)
|
||||||
|
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(
|
||||||
|
Path.GetFileName(x),
|
||||||
|
File.ReadAllBytes(x).ToImmutableArray()))
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
Dice = Directory.GetFiles(diceImagesPath)
|
||||||
|
.OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x)))
|
||||||
|
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(x,
|
||||||
|
File.ReadAllBytes(x).ToImmutableArray()))
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
SlotBackground = File.ReadAllBytes(slotBackgroundPath).ToImmutableArray();
|
||||||
|
|
||||||
|
SlotNumbers = Directory.GetFiles(slotNumbersPath)
|
||||||
|
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
||||||
|
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
SlotEmojis = Directory.GetFiles(slotEmojisPath)
|
||||||
|
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
_log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!");
|
||||||
|
return sw.Elapsed;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
private DiscordShardedClient client;
|
private DiscordShardedClient client;
|
||||||
private DateTime started;
|
private DateTime started;
|
||||||
|
|
||||||
public const string BotVersion = "1.1.5a";
|
public const string BotVersion = "1.1.6";
|
||||||
|
|
||||||
public string Author => "Kwoth#2560";
|
public string Author => "Kwoth#2560";
|
||||||
public string Library => "Discord.Net";
|
public string Library => "Discord.Net";
|
||||||
|
@ -1,199 +0,0 @@
|
|||||||
using Discord;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NLog;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace NadekoBot
|
|
||||||
{
|
|
||||||
public class ShardedDiscordClient
|
|
||||||
{
|
|
||||||
private DiscordSocketConfig discordSocketConfig;
|
|
||||||
private Logger _log { get; }
|
|
||||||
|
|
||||||
public event Action<SocketGuildUser> UserJoined = delegate { };
|
|
||||||
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 { };
|
|
||||||
public event Action<SocketUser, SocketGuild> UserUnbanned = delegate { };
|
|
||||||
public event Action<Optional<SocketGuild>, SocketUser, SocketPresence, SocketPresence> UserPresenceUpdated = delegate { };
|
|
||||||
public event Action<SocketUser, SocketVoiceState, SocketVoiceState> UserVoiceStateUpdated = delegate { };
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
this.discordSocketConfig = discordSocketConfig;
|
|
||||||
|
|
||||||
var clientList = new List<DiscordSocketClient>();
|
|
||||||
for (int i = 0; i < discordSocketConfig.TotalShards; i++)
|
|
||||||
{
|
|
||||||
discordSocketConfig.ShardId = i;
|
|
||||||
var client = new DiscordSocketClient(discordSocketConfig);
|
|
||||||
clientList.Add(client);
|
|
||||||
client.UserJoined += arg1 => { UserJoined(arg1); return Task.CompletedTask; };
|
|
||||||
client.MessageReceived += arg1 =>
|
|
||||||
{
|
|
||||||
if (arg1.Author == null || arg1.Author.IsBot)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
MessageReceived(arg1);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
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; };
|
|
||||||
client.UserUnbanned += (arg1, arg2) => { UserUnbanned(arg1, arg2); return Task.CompletedTask; };
|
|
||||||
client.UserPresenceUpdated += (arg1, arg2, arg3, arg4) => { UserPresenceUpdated(arg1, arg2, arg3, arg4); return Task.CompletedTask; };
|
|
||||||
client.UserVoiceStateUpdated += (arg1, arg2, arg3) => { UserVoiceStateUpdated(arg1, arg2, arg3); return Task.CompletedTask; };
|
|
||||||
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 IEnumerable<SocketGuild> GetGuilds() =>
|
|
||||||
Clients.SelectMany(c => c.Guilds);
|
|
||||||
|
|
||||||
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 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()
|
|
||||||
{
|
|
||||||
|
|
||||||
foreach (var c in Clients)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sw = Stopwatch.StartNew();
|
|
||||||
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
|
|
||||||
{
|
|
||||||
_log.Error($"Shard #{c.ShardId} FAILED CONNECTING.");
|
|
||||||
try { await c.ConnectAsync().ConfigureAwait(false); }
|
|
||||||
catch (Exception ex2)
|
|
||||||
{
|
|
||||||
_log.Error($"Shard #{c.ShardId} FAILED CONNECTING TWICE.");
|
|
||||||
_log.Error(ex2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Connected();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Task DownloadAllUsersAsync() =>
|
|
||||||
Task.WhenAll(Clients.Select(async c =>
|
|
||||||
{
|
|
||||||
var sw = Stopwatch.StartNew();
|
|
||||||
await c.DownloadAllUsersAsync().ConfigureAwait(false);
|
|
||||||
sw.Stop();
|
|
||||||
_log.Info($"Shard #{c.ShardId} downloaded {c.Guilds.Sum(g => g.Users.Count)} users after {sw.Elapsed.TotalSeconds:F2}s ({++_downloadedCount}/{Clients.Count}).");
|
|
||||||
}));
|
|
||||||
|
|
||||||
public Task SetGame(string game) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(game)));
|
|
||||||
|
|
||||||
|
|
||||||
public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.Twitch)));
|
|
||||||
|
|
||||||
//public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SettableUserStatus
|
|
||||||
{
|
|
||||||
Online = 1,
|
|
||||||
On = 1,
|
|
||||||
Invisible = 2,
|
|
||||||
Invis = 2,
|
|
||||||
Idle = 3,
|
|
||||||
Afk = 3,
|
|
||||||
Dnd = 4,
|
|
||||||
DoNotDisturb = 4,
|
|
||||||
Busy = 4,
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,9 @@ namespace NadekoBot.Extensions
|
|||||||
private const string arrow_left = "⬅";
|
private const string arrow_left = "⬅";
|
||||||
private const string arrow_right = "➡";
|
private const string arrow_right = "➡";
|
||||||
|
|
||||||
|
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
||||||
|
=> new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// danny kamisama
|
/// danny kamisama
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Before Width: | Height: | Size: 225 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
BIN
src/NadekoBot/data/images/currency/img2.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 551 B After Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 553 B |
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 539 B |
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 471 B |
Before Width: | Height: | Size: 542 B After Width: | Height: | Size: 542 B |
Before Width: | Height: | Size: 562 B After Width: | Height: | Size: 562 B |
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 417 B |
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 597 B |
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |