commit
4dbdce7f5d
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
#Manually added files
|
#Manually added files
|
||||||
|
|
||||||
|
patreon_rewards.json
|
||||||
command_errors*.txt
|
command_errors*.txt
|
||||||
|
|
||||||
src/NadekoBot/Command Errors*.txt
|
src/NadekoBot/Command Errors*.txt
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26430.6
|
VisualStudioVersion = 15.0.26430.12
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
||||||
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
||||||
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
||||||
[![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png)](http://nadekobot.xyz)
|
[![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png)](https://nadekobot.me)
|
||||||
[![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
[![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
||||||
[![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
[![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ Commands and aliases | Description | Usage
|
|||||||
`.creatxtchanl` `.ctch` | Creates a new text channel with a given name. **Requires ManageChannels server permission.** | `.ctch TextChannelName`
|
`.creatxtchanl` `.ctch` | Creates a new text channel with a given name. **Requires ManageChannels server permission.** | `.ctch TextChannelName`
|
||||||
`.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic`
|
`.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic`
|
||||||
`.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName`
|
`.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName`
|
||||||
`.prune` `.clear` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
|
|
||||||
`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. **Requires MentionEveryone server permission.** | `.menro RoleName`
|
`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. **Requires MentionEveryone server permission.** | `.menro RoleName`
|
||||||
`.donators` | List of the lovely people who donated to keep this project alive. | `.donators`
|
`.donators` | List of the 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`
|
||||||
@ -65,6 +64,7 @@ Commands and aliases | Description | Usage
|
|||||||
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban`
|
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **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`
|
`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore`
|
||||||
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
||||||
|
`.prune` `.clear` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
|
||||||
`.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`
|
`.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`
|
||||||
`.slowmodewl` | Ignores a role or a user from the slowmode feature. **Requires ManageMessages server permission.** | `.slowmodewl SomeRole` or `.slowmodewl AdminDude`
|
`.slowmodewl` | Ignores a role or a user from the slowmode feature. **Requires ManageMessages server permission.** | `.slowmodewl SomeRole` or `.slowmodewl AdminDude`
|
||||||
`.adsarm` | Toggles the automatic deletion of confirmations for `.iam` and `.iamn` commands. **Requires ManageMessages server permission.** | `.adsarm`
|
`.adsarm` | Toggles the automatic deletion of confirmations for `.iam` and `.iamn` commands. **Requires ManageMessages server permission.** | `.adsarm`
|
||||||
@ -81,7 +81,6 @@ Commands and aliases | Description | Usage
|
|||||||
`.scclr` | Removes all startup commands. **Bot owner only** | `.scclr`
|
`.scclr` | Removes all startup commands. **Bot owner only** | `.scclr`
|
||||||
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs`
|
`.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 file **Bot owner only** | `.fwtoall`
|
`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall`
|
||||||
`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2`
|
|
||||||
`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot owner only** | `.leave 123123123331`
|
`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot owner only** | `.leave 123123123331`
|
||||||
`.die` | Shuts the bot down. **Bot owner only** | `.die`
|
`.die` | Shuts the bot down. **Bot owner only** | `.die`
|
||||||
`.setname` `.newnm` | Gives the bot a new name. **Bot owner only** | `.newnm BotName`
|
`.setname` `.newnm` | Gives the bot a new name. **Bot owner only** | `.newnm BotName`
|
||||||
@ -105,6 +104,7 @@ Commands and aliases | Description | Usage
|
|||||||
`.timezone` | Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) | `.timezone` or `.timezone GMT Standard Time`
|
`.timezone` | Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) | `.timezone` or `.timezone GMT Standard Time`
|
||||||
`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person`
|
`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person`
|
||||||
`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy`
|
`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy`
|
||||||
|
`.warnlogall` | See a list of all warnings on the server. 15 users per page. **Requires BanMembers server permission.** | `.warnlogall` or `.warnlogall 2`
|
||||||
`.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude`
|
`.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude`
|
||||||
`.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3`
|
`.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3`
|
||||||
`.warnpunishlist` `.warnpl` | Lists punishments for warnings. | `.warnpunishlist`
|
`.warnpunishlist` `.warnpl` | Lists punishments for warnings. | `.warnpunishlist`
|
||||||
@ -199,11 +199,11 @@ Commands and aliases | Description | Usage
|
|||||||
`.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`
|
`.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`
|
`.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`
|
`.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`
|
||||||
|
`.hangmanstop` | Stops the active hangman game on this channel if it exists. | `.hangmanstop`
|
||||||
`.pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `.pick`
|
`.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`
|
`.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`
|
`.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`
|
`.poll` `.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`
|
||||||
`.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`
|
`.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`
|
`.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`
|
`.typestart` | Starts a typing contest. | `.typestart`
|
||||||
@ -233,35 +233,36 @@ Commands and aliases | Description | Usage
|
|||||||
### Music
|
### Music
|
||||||
Commands and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
|
`.play` `.start` | If no arguments are specified, acts as `.next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `.q` command | `.play` or `.play 5` or `.play Dream Of Venice`
|
||||||
|
`.queue` `.q` `.yq` | Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. | `.q Dream Of Venice`
|
||||||
|
`.queuesearch` `.qs` `.yqs` | Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**. | `.qs Dream Of Venice`
|
||||||
|
`.listqueue` `.lq` | Lists 10 currently queued songs per page. Default page is 1. | `.lq` or `.lq 2`
|
||||||
`.next` `.n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if .rcs or .rpl is enabled. | `.n` or `.n 5`
|
`.next` `.n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if .rcs or .rpl is enabled. | `.n` or `.n 5`
|
||||||
`.stop` `.s` | Stops the music and clears the playlist. Stays in the channel. | `.s`
|
`.stop` `.s` | Stops the music and clears the playlist. Stays in the channel. | `.s`
|
||||||
`.destroy` `.d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `.d`
|
`.destroy` `.d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `.d`
|
||||||
`.pause` `.p` | Pauses or Unpauses the song. | `.p`
|
`.pause` `.p` | Pauses or Unpauses the song. | `.p`
|
||||||
`.fairplay` `.fp` | Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `.fp`
|
|
||||||
`.queue` `.q` `.yq` | Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. | `.q Dream Of Venice`
|
|
||||||
`.queuesearch` `.qs` `.yqs` | Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**. | `.qs Dream Of Venice`
|
|
||||||
`.soundcloudqueue` `.sq` | Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. | `.sq Dream Of Venice`
|
|
||||||
`.listqueue` `.lq` | Lists 15 currently queued songs per page. Default page is 1. | `.lq` or `.lq 2`
|
|
||||||
`.nowplaying` `.np` | Shows the song that the bot is currently playing. | `.np`
|
|
||||||
`.volume` `.vol` | Sets the music playback volume (0-100%) | `.vol 50`
|
`.volume` `.vol` | Sets the music playback volume (0-100%) | `.vol 50`
|
||||||
`.defvol` `.dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `.dv 80`
|
`.defvol` `.dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `.dv 80`
|
||||||
`.playlistshuffle` `.plsh` | Shuffles the current playlist. | `.plsh`
|
`.songremove` `.srm` | Remove a song by its # in the queue, or 'all' to remove all songs from the queue. | `.srm 5`
|
||||||
`.playlist` `.pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `.pl playlist link or name`
|
`.playlists` `.pls` | Lists all playlists. Paginated, 20 per page. Default page is 0. | `.pls 1`
|
||||||
|
`.deleteplaylist` `.delpls` | Deletes a saved playlist. Works only if you made it or if you are the bot owner. | `.delpls animu-5`
|
||||||
|
`.save` | Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. | `.save classical1`
|
||||||
|
`.load` | Loads a saved playlist using its ID. Use `.pls` to list all saved playlists and `.save` to save new ones. | `.load 5`
|
||||||
|
`.fairplay` `.fp` | Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `.fp`
|
||||||
|
`.soundcloudqueue` `.sq` | Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. | `.sq Dream Of Venice`
|
||||||
`.soundcloudpl` `.scpl` | Queue a Soundcloud playlist using a link. | `.scpl soundcloudseturl`
|
`.soundcloudpl` `.scpl` | Queue a Soundcloud playlist using a link. | `.scpl soundcloudseturl`
|
||||||
`.localplaylst` `.lopl` | Queues all songs from a directory. **Bot owner only** | `.lopl C:/music/classical`
|
`.nowplaying` `.np` | Shows the song that the bot is currently playing. | `.np`
|
||||||
|
`.shuffle` `.sh` `.plsh` | Shuffles the current playlist. | `.plsh`
|
||||||
|
`.playlist` `.pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `.pl playlist link or name`
|
||||||
`.radio` `.ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `.ra radio link here`
|
`.radio` `.ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `.ra radio link here`
|
||||||
`.local` `.lo` | Queues a local file by specifying a full path. **Bot owner only** | `.lo C:/music/mysong.mp3`
|
`.local` `.lo` | Queues a local file by specifying a full path. **Bot owner only** | `.lo C:/music/mysong.mp3`
|
||||||
`.songremove` `.srm` | Remove a song by its # in the queue, or 'all' to remove all songs from the queue. | `.srm 5`
|
`.localplaylst` `.lopl` | Queues all songs from a directory. **Bot owner only** | `.lopl C:/music/classical`
|
||||||
|
`.move` `.mv` | Moves the bot to your voice channel. (works only if music is already playing) | `.mv`
|
||||||
`.movesong` `.ms` | Moves a song from one position to another. | `.ms 5>3`
|
`.movesong` `.ms` | Moves a song from one position to another. | `.ms 5>3`
|
||||||
`.setmaxqueue` `.smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `.smq 50` or `.smq`
|
`.setmaxqueue` `.smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `.smq 50` or `.smq`
|
||||||
`.setmaxplaytime` `.smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `.smp 0` or `.smp 270`
|
`.setmaxplaytime` `.smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `.smp 0` or `.smp 270`
|
||||||
`.reptcursong` `.rcs` | Toggles repeat of current song. | `.rcs`
|
`.reptcursong` `.rcs` | Toggles repeat of current song. | `.rcs`
|
||||||
`.rpeatplaylst` `.rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `.rpl`
|
`.rpeatplaylst` `.rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `.rpl`
|
||||||
`.save` | Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. | `.save classical1`
|
|
||||||
`.load` | Loads a saved playlist using its ID. Use `.pls` to list all saved playlists and `.save` to save new ones. | `.load 5`
|
|
||||||
`.playlists` `.pls` | Lists all playlists. Paginated, 20 per page. Default page is 0. | `.pls 1`
|
|
||||||
`.deleteplaylist` `.delpls` | Deletes a saved playlist. Works 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`
|
|
||||||
`.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`
|
`.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`
|
||||||
|
|
||||||
@ -411,7 +412,6 @@ Commands and aliases | Description | Usage
|
|||||||
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
||||||
`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv`
|
`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv`
|
||||||
`.shardstats` | Stats for shards. Paginated with 25 shards per page. | `.shardstats` or `.shardstats 2`
|
`.shardstats` | Stats for shards. Paginated with 25 shards per page. | `.shardstats` or `.shardstats 2`
|
||||||
`.shardid` | Shows which shard is a certain guild on, by guildid. | `.shardid 117523346618318850`
|
|
||||||
`.stats` | Shows some basic stats for Nadeko. | `.stats`
|
`.stats` | Shows some basic stats for Nadeko. | `.stats`
|
||||||
`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis`
|
`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis`
|
||||||
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3`
|
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3`
|
||||||
@ -421,10 +421,7 @@ Commands and aliases | Description | Usage
|
|||||||
`.calcops` | Shows all available operations in the `.calc` command | `.calcops`
|
`.calcops` | Shows all available operations in the `.calc` command | `.calcops`
|
||||||
`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows`
|
`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows`
|
||||||
`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3`
|
`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3`
|
||||||
`.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`
|
`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no server is supplied, it defaults to current one. | `.sinfo Some Server`
|
||||||
`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere`
|
|
||||||
`.lcsc` | Leaves a 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`
|
`.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`
|
`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser`
|
||||||
`.activity` | Checks for spammers. **Bot owner only** | `.activity`
|
`.activity` | Checks for spammers. **Bot owner only** | `.activity`
|
||||||
|
@ -36,14 +36,4 @@ For example:
|
|||||||
Now if you try to trigger `/o/`, it won't print anything.
|
Now if you try to trigger `/o/`, it won't print anything.
|
||||||
|
|
||||||
###Placeholders!
|
###Placeholders!
|
||||||
There are currently three different placeholders which we will look at, with more placeholders potentially coming in the future.
|
To learn about placeholders, go [here](Placeholders.md)
|
||||||
|
|
||||||
| Placeholder | Description | Example Usage | Usage |
|
|
||||||
|:-----------:|-------------|---------------|-------|
|
|
||||||
|`%mention%`|The `%mention%` placeholder is triggered when you type `@BotName` - It's important to note that if you've given the bot a custom nickname, this trigger won't work!|```.acr "Hello %mention%" I, %mention%, also say hello!```|Input: "Hello @BotName" Output: "I, @BotName, also say hello!"|
|
|
||||||
|`%user%`|The `%user%` placeholder mentions the person who said the command|`.acr "Who am I?" You are %user%!`|Input: "Who am I?" Output: "You are @Username!"|
|
|
||||||
|`%rng%`|The `%rng%` placeholder generates a random number between 0 and 10. You can also specify a custom range (%rng1-100%) even with negative numbers: `%rng-9--1%` (from -9 to -1) . |`.acr "Random number" %rng%`|Input: "Random number" Output: "2"|
|
|
||||||
|`%rnduser%`|The `%rnduser%` placeholder mentions a random user from the server. |`.acr "Random user" %rnduser%`|Input: "Random number" Output: @SomeUser|
|
|
||||||
|`%target%`|The `%target%` placeholder is used to make Nadeko Mention another person or phrase, it is only supported as part of the response|`.acr "Say this: " %target%`|Input: "Say this: I, @BotName, am a parrot!". Output: "I, @BotName, am a parrot!".|
|
|
||||||
|
|
||||||
Thanks to Nekai for being creative. <3
|
|
||||||
|
@ -17,8 +17,12 @@ If you do not see `credentials.json` you will need to rename `credentials_exampl
|
|||||||
"MashapeKey": "4UrKpcWXc2mshS8RKi00000y8Kf5p1Q8kI6jsn32bmd8oVWiY7",
|
"MashapeKey": "4UrKpcWXc2mshS8RKi00000y8Kf5p1Q8kI6jsn32bmd8oVWiY7",
|
||||||
"OsuApiKey": "4c8c8fdff8e1234581725db27fd140a7d93320d6",
|
"OsuApiKey": "4c8c8fdff8e1234581725db27fd140a7d93320d6",
|
||||||
"PatreonAccessToken": "",
|
"PatreonAccessToken": "",
|
||||||
|
"PatreonCampaignId": "334038",
|
||||||
"Db": null,
|
"Db": null,
|
||||||
"TotalShards": 1
|
"TotalShards": 1,
|
||||||
|
"ShardRunCommand": "",
|
||||||
|
"ShardRunArguments": "",
|
||||||
|
"ShardRunPort": null
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
-----
|
-----
|
||||||
@ -152,10 +156,11 @@ It should look like:
|
|||||||
- You can get this key [here.](https://osu.ppy.sh/p/api)
|
- You can get this key [here.](https://osu.ppy.sh/p/api)
|
||||||
- **PatreonAccessToken**
|
- **PatreonAccessToken**
|
||||||
- For Patreon creators only.
|
- For Patreon creators only.
|
||||||
|
- **PatreonCampaignId**
|
||||||
|
- For Patreon creators only. Id of your campaign.
|
||||||
- **TotalShards**
|
- **TotalShards**
|
||||||
- Required if the bot will be connected to more than 1500 servers.
|
- Required if the bot will be connected to more than 1500 servers.
|
||||||
- Most likely unnecessary to change until your bot is added to more than 1500 servers.
|
- Most likely unnecessary to change until your bot is added to more than 1500 servers.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## DB files
|
## DB files
|
||||||
@ -163,6 +168,7 @@ It should look like:
|
|||||||
Nadeko saves all the settings and infomations in `NadekoBot.db` file here:
|
Nadeko saves all the settings and infomations in `NadekoBot.db` file here:
|
||||||
`NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data/NadekoBot.db` (macOS and Linux)
|
`NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data/NadekoBot.db` (macOS and Linux)
|
||||||
`NadekoBot\system\data` (Windows)
|
`NadekoBot\system\data` (Windows)
|
||||||
|
|
||||||
in order to open the database file you will need [DB Browser for SQLite](http://sqlitebrowser.org/).
|
in order to open the database file you will need [DB Browser for SQLite](http://sqlitebrowser.org/).
|
||||||
|
|
||||||
*NOTE: You don't have to worry if you don't have `NadekoBot.db` file, it gets auto created once you run the bot successfully.*
|
*NOTE: You don't have to worry if you don't have `NadekoBot.db` file, it gets auto created once you run the bot successfully.*
|
||||||
@ -181,6 +187,23 @@ in order to open the database file you will need [DB Browser for SQLite](http://
|
|||||||
|
|
||||||
and that will save all the changes.
|
and that will save all the changes.
|
||||||
|
|
||||||
|
## Sharding your bot
|
||||||
|
|
||||||
|
- **ShardRunCommand**
|
||||||
|
- Command with which to run shards 1+
|
||||||
|
- Required if you're sharding your bot on windows using .exe, or in a custom way.
|
||||||
|
- This internally defaults to `dotnet`
|
||||||
|
- For example, if you want to shard your NadekoBot which you installed using windows installer, you would want to set it to something like this: `C:\Program Files\NadekoBot\system\NadekoBot.exe`
|
||||||
|
- **ShardRunArguments**
|
||||||
|
- Arguments to the shard run command
|
||||||
|
- Required if you're sharding your bot on windows using .exe, or in a custom way.
|
||||||
|
- This internally defaults to `run -c Release -- {0} {1} {2}` which will be enough to run linux and other 'from source' setups
|
||||||
|
- {0} will be replaced by the `shard ID` of the shard being ran, {1} by the shard 0's process id, and {2} by the port shard communication is happening on
|
||||||
|
- If shard0 (main window) is closed, all other shards will close too
|
||||||
|
- For example, if you want to shard your NadekoBot which you installed using windows installer, you would want to set it to `{0} {1} {2}`
|
||||||
|
- **ShardRunPort**
|
||||||
|
- Bot uses a random UDP port in [5000, 6000) range for communication between shards
|
||||||
|
|
||||||
|
|
||||||
![nadekodb](https://cdn.discordapp.com/attachments/251504306010849280/254067055240806400/nadekodb.gif)
|
![nadekodb](https://cdn.discordapp.com/attachments/251504306010849280/254067055240806400/nadekodb.gif)
|
||||||
|
|
||||||
|
25
docs/Placeholders.md
Normal file
25
docs/Placeholders.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Placeholders are used in Quotes, Custom Reactions, Greet/bye messages, playing statuses, and a few other places.
|
||||||
|
|
||||||
|
They can be used to make the message more user friendly, generate random numbers or pictures, etc...
|
||||||
|
|
||||||
|
Some features have their own specific placeholders which are noted in that feature's command help. Some placeholders are not available in certain features because they don't make sense there.
|
||||||
|
|
||||||
|
### Here is a list of the usual placeholders:
|
||||||
|
- `%mention%` - Mention the bot
|
||||||
|
- `%shardid%` - Shard id
|
||||||
|
- `%server%` - Server name
|
||||||
|
- `%sid%` - Server Id
|
||||||
|
- `%channel%` - Channel mention
|
||||||
|
- `%chname%` - Channel mention
|
||||||
|
- `%cid%` - Channel Id
|
||||||
|
- `%user%` - User mention
|
||||||
|
- `%id%` or `%uid%` - User Id
|
||||||
|
- `%userfull%` - Username#discriminator
|
||||||
|
- `%userdiscrim%` - discriminator (for example 1234)
|
||||||
|
- `%rngX-Y%` - Replace X and Y with the range (for example `%rng5-10%` - random between 5 and 10)
|
||||||
|
- `%time%` - Bot time
|
||||||
|
- `%server_time%` - Time on this server, set with `.timezone` command
|
||||||
|
|
||||||
|
**If you're using placeholders in embeds, don't use %user% and in titles, footers and field names. They will not show properly.**
|
||||||
|
|
||||||
|
![img](http://i.imgur.com/lNNNfs1.png)
|
@ -8,7 +8,7 @@ Follow the respective guide for your operating system found here [Docker Engine
|
|||||||
For this guide we will be using the folder /nadeko as our config root folder.
|
For this guide we will be using the folder /nadeko as our config root folder.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker create --name=nadeko -v /nadeko/:/root/nadeko uirel/nadeko:1.4
|
docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data uirel/nadeko:1.4
|
||||||
```
|
```
|
||||||
-If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder.
|
-If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder.
|
||||||
|
|
||||||
@ -37,7 +37,9 @@ The following commands are required for the default options
|
|||||||
|
|
||||||
`docker stop nadeko; docker rm nadeko`
|
`docker stop nadeko; docker rm nadeko`
|
||||||
|
|
||||||
`docker create --name=nadeko -v /nadeko/:/root/nadeko uirel/nadeko:1.4`
|
```
|
||||||
|
docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data uirel/nadeko:1.4
|
||||||
|
```
|
||||||
|
|
||||||
`docker start nadeko`
|
`docker start nadeko`
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#### Prerequisites
|
#### Prerequisites
|
||||||
- [Notepad++][Notepad++] (or some other decent text editor)
|
- [Notepad++][Notepad++] (or some other decent text editor)
|
||||||
- Windows 8 or later
|
- Windows 8 or later
|
||||||
- [.NET Core SDK (Command line / other)][.NET Core SDK]
|
|
||||||
- [Create Discord Bot application](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#creating-discord-bot-application) and [Invite the bot to your server](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#inviting-your-bot-to-your-server).
|
- [Create Discord Bot application](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#creating-discord-bot-application) and [Invite the bot to your server](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#inviting-your-bot-to-your-server).
|
||||||
|
|
||||||
#### Guide
|
#### Guide
|
||||||
|
@ -28,6 +28,7 @@ If you want to contribute, be sure to PR on the **[1.4][1.4]** branch.
|
|||||||
- [Permissions System](Permissions System.md)
|
- [Permissions System](Permissions System.md)
|
||||||
- [JSON Explanations](JSON Explanations.md)
|
- [JSON Explanations](JSON Explanations.md)
|
||||||
- [Custom Reactions](Custom Reactions.md)
|
- [Custom Reactions](Custom Reactions.md)
|
||||||
|
- [Placeholders](Placeholders.md)
|
||||||
- [Frequently Asked Questions](Frequently Asked Questions.md)
|
- [Frequently Asked Questions](Frequently Asked Questions.md)
|
||||||
- [Contribution Guide](Contribution Guide.md)
|
- [Contribution Guide](Contribution Guide.md)
|
||||||
- [Donate](Donate.md)
|
- [Donate](Donate.md)
|
||||||
|
@ -14,9 +14,10 @@ pages:
|
|||||||
- Readme: Readme.md
|
- Readme: Readme.md
|
||||||
- Commands List: Commands List.md
|
- Commands List: Commands List.md
|
||||||
- Features Explained:
|
- Features Explained:
|
||||||
- Permissions System: Permissions System.md
|
|
||||||
- JSON Explanations: JSON Explanations.md
|
- JSON Explanations: JSON Explanations.md
|
||||||
|
- Permissions System: Permissions System.md
|
||||||
- Custom Reactions: Custom Reactions.md
|
- Custom Reactions: Custom Reactions.md
|
||||||
|
- Placeholders: Placeholders.md
|
||||||
- Frequently Asked Questions: Frequently Asked Questions.md
|
- Frequently Asked Questions: Frequently Asked Questions.md
|
||||||
- Contribution Guide: Contribution Guide.md
|
- Contribution Guide: Contribution Guide.md
|
||||||
- ❤ Donate ❤: Donate.md
|
- ❤ Donate ❤: Donate.md
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NadekoBot.DataStructures
|
namespace NadekoBot.DataStructures
|
||||||
{
|
{
|
||||||
@ -31,18 +33,30 @@ namespace NadekoBot.DataStructures
|
|||||||
|
|
||||||
public EmbedBuilder ToEmbed()
|
public EmbedBuilder ToEmbed()
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder();
|
||||||
.WithTitle(Title)
|
|
||||||
.WithDescription(Description)
|
if (!string.IsNullOrWhiteSpace(Title))
|
||||||
.WithColor(new Discord.Color(Color));
|
embed.WithTitle(Title);
|
||||||
|
if (!string.IsNullOrWhiteSpace(Description))
|
||||||
|
embed.WithDescription(Description);
|
||||||
|
embed.WithColor(new Discord.Color(Color));
|
||||||
if (Footer != null)
|
if (Footer != null)
|
||||||
embed.WithFooter(efb => efb.WithIconUrl(Footer.IconUrl).WithText(Footer.Text));
|
embed.WithFooter(efb =>
|
||||||
embed.WithThumbnailUrl(Thumbnail)
|
{
|
||||||
.WithImageUrl(Image);
|
efb.WithText(Footer.Text);
|
||||||
|
if (Uri.IsWellFormedUriString(Footer.IconUrl, UriKind.Absolute))
|
||||||
|
efb.WithIconUrl(Footer.IconUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Thumbnail != null && Uri.IsWellFormedUriString(Thumbnail, UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(Thumbnail);
|
||||||
|
if(Image != null && Uri.IsWellFormedUriString(Image, UriKind.Absolute))
|
||||||
|
embed.WithImageUrl(Image);
|
||||||
|
|
||||||
if (Fields != null)
|
if (Fields != null)
|
||||||
foreach (var f in Fields)
|
foreach (var f in Fields)
|
||||||
{
|
{
|
||||||
|
if(!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value))
|
||||||
embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline));
|
embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +73,12 @@ namespace NadekoBot.DataStructures
|
|||||||
{
|
{
|
||||||
var crembed = JsonConvert.DeserializeObject<CREmbed>(input);
|
var crembed = JsonConvert.DeserializeObject<CREmbed>(input);
|
||||||
|
|
||||||
|
if(crembed.Fields != null && crembed.Fields.Length > 0)
|
||||||
|
foreach (var f in crembed.Fields)
|
||||||
|
{
|
||||||
|
f.Name = f.Name.TrimTo(256);
|
||||||
|
f.Value = f.Value.TrimTo(1024);
|
||||||
|
}
|
||||||
if (!crembed.IsValid)
|
if (!crembed.IsValid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -13,6 +13,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
|||||||
/// Try to execute some logic within some module's service.
|
/// Try to execute some logic within some module's service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Whether it should block other command executions after it.</returns>
|
/// <returns>Whether it should block other command executions after it.</returns>
|
||||||
Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg);
|
Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
|||||||
{
|
{
|
||||||
public interface ILateBlocker
|
public interface ILateBlocker
|
||||||
{
|
{
|
||||||
Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild,
|
Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild,
|
||||||
IMessageChannel channel, IUser user, string moduleName, string commandName);
|
IMessageChannel channel, IUser user, string moduleName, string commandName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILateExecutor
|
public interface ILateExecutor
|
||||||
{
|
{
|
||||||
Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg);
|
Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
src/NadekoBot/DataStructures/PoopyRingBuffer.cs
Normal file
116
src/NadekoBot/DataStructures/PoopyRingBuffer.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class PoopyRingBuffer : IDisposable
|
||||||
|
{
|
||||||
|
// readpos == writepos means empty
|
||||||
|
// writepos == readpos - 1 means full
|
||||||
|
|
||||||
|
private byte[] buffer;
|
||||||
|
public int Capacity { get; }
|
||||||
|
|
||||||
|
private int _readPos = 0;
|
||||||
|
private int ReadPos
|
||||||
|
{
|
||||||
|
get => _readPos;
|
||||||
|
set => _readPos = value;
|
||||||
|
}
|
||||||
|
private int _writePos = 0;
|
||||||
|
private int WritePos
|
||||||
|
{
|
||||||
|
get => _writePos;
|
||||||
|
set => _writePos = value;
|
||||||
|
}
|
||||||
|
public int Length => ReadPos <= WritePos
|
||||||
|
? WritePos - ReadPos
|
||||||
|
: Capacity - (ReadPos - WritePos);
|
||||||
|
|
||||||
|
public int RemainingCapacity
|
||||||
|
{
|
||||||
|
get => Capacity - Length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
|
public PoopyRingBuffer(int capacity = 81920 * 100)
|
||||||
|
{
|
||||||
|
this.Capacity = capacity + 1;
|
||||||
|
this.buffer = new byte[this.Capacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Read(byte[] b, int offset, int toRead)
|
||||||
|
{
|
||||||
|
if (WritePos == ReadPos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (toRead > Length)
|
||||||
|
toRead = Length;
|
||||||
|
|
||||||
|
if (WritePos > ReadPos)
|
||||||
|
{
|
||||||
|
Array.Copy(buffer, ReadPos, b, offset, toRead);
|
||||||
|
ReadPos += toRead;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var toEnd = Capacity - ReadPos;
|
||||||
|
var firstRead = toRead > toEnd ?
|
||||||
|
toEnd :
|
||||||
|
toRead;
|
||||||
|
Array.Copy(buffer, ReadPos, b, offset, firstRead);
|
||||||
|
ReadPos += firstRead;
|
||||||
|
var secondRead = toRead - firstRead;
|
||||||
|
if (secondRead > 0)
|
||||||
|
{
|
||||||
|
Array.Copy(buffer, 0, b, offset + firstRead, secondRead);
|
||||||
|
ReadPos = secondRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Write(byte[] b, int offset, int toWrite)
|
||||||
|
{
|
||||||
|
while (toWrite > RemainingCapacity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (toWrite == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (WritePos < ReadPos)
|
||||||
|
{
|
||||||
|
Array.Copy(b, offset, buffer, WritePos, toWrite);
|
||||||
|
WritePos += toWrite;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var toEnd = Capacity - WritePos;
|
||||||
|
var firstWrite = toWrite > toEnd ?
|
||||||
|
toEnd :
|
||||||
|
toWrite;
|
||||||
|
Array.Copy(b, offset, buffer, WritePos, firstWrite);
|
||||||
|
var secondWrite = toWrite - firstWrite;
|
||||||
|
if (secondWrite > 0)
|
||||||
|
{
|
||||||
|
Array.Copy(b, offset + firstWrite, buffer, 0, secondWrite);
|
||||||
|
WritePos = secondWrite;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WritePos += firstWrite;
|
||||||
|
if (WritePos == Capacity)
|
||||||
|
WritePos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
src/NadekoBot/DataStructures/Replacements/ReplacementBuilder.cs
Normal file
148
src/NadekoBot/DataStructures/Replacements/ReplacementBuilder.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
|
using NadekoBot.Services.Music;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures.Replacements
|
||||||
|
{
|
||||||
|
public class ReplacementBuilder
|
||||||
|
{
|
||||||
|
private static readonly Regex rngRegex = new Regex("%rng(?:(?<from>(?:-)?\\d+)-(?<to>(?:-)?\\d+))?%", RegexOptions.Compiled);
|
||||||
|
private ConcurrentDictionary<string, Func<string>> _reps = new ConcurrentDictionary<string, Func<string>>();
|
||||||
|
private ConcurrentDictionary<Regex, Func<Match, string>> _regex = new ConcurrentDictionary<Regex, Func<Match, string>>();
|
||||||
|
|
||||||
|
public ReplacementBuilder()
|
||||||
|
{
|
||||||
|
WithRngRegex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithDefault(IUser usr, IMessageChannel ch, IGuild g, DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
return this.WithUser(usr)
|
||||||
|
.WithChannel(ch)
|
||||||
|
.WithServer(client, g)
|
||||||
|
.WithClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithDefault(ICommandContext ctx) =>
|
||||||
|
WithDefault(ctx.User, ctx.Channel, ctx.Guild, (DiscordSocketClient)ctx.Client);
|
||||||
|
|
||||||
|
public ReplacementBuilder WithClient(DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
_reps.TryAdd("%mention%", () => $"<@{client.CurrentUser.Id}>");
|
||||||
|
_reps.TryAdd("%shardid%", () => client.ShardId.ToString());
|
||||||
|
_reps.TryAdd("%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithServer(DiscordSocketClient client, IGuild g)
|
||||||
|
{
|
||||||
|
|
||||||
|
_reps.TryAdd("%sid%", () => g == null ? "DM" : g.Id.ToString());
|
||||||
|
_reps.TryAdd("%server%", () => g == null ? "DM" : g.Name);
|
||||||
|
_reps.TryAdd("%server_time%", () =>
|
||||||
|
{
|
||||||
|
TimeZoneInfo to = TimeZoneInfo.Local;
|
||||||
|
if (g != null)
|
||||||
|
{
|
||||||
|
if (GuildTimezoneService.AllServices.TryGetValue(client.CurrentUser.Id, out var tz))
|
||||||
|
to = tz.GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TimeZoneInfo.ConvertTime(DateTime.UtcNow,
|
||||||
|
TimeZoneInfo.Utc,
|
||||||
|
to).ToString("HH:mm ") + to.StandardName.GetInitials();
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithChannel(IMessageChannel ch)
|
||||||
|
{
|
||||||
|
_reps.TryAdd("%channel%", () => (ch as ITextChannel)?.Mention ?? "#" + ch.Name);
|
||||||
|
_reps.TryAdd("%chname%", () => ch.Name);
|
||||||
|
_reps.TryAdd("%cid%", () => ch?.Id.ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithUser(IUser user)
|
||||||
|
{
|
||||||
|
_reps.TryAdd("%user%", () => user.Mention);
|
||||||
|
_reps.TryAdd("%userfull%", () => user.ToString());
|
||||||
|
_reps.TryAdd("%username%", () => user.Username);
|
||||||
|
_reps.TryAdd("%userdiscrim%", () => user.Discriminator);
|
||||||
|
_reps.TryAdd("%id%", () => user.Id.ToString());
|
||||||
|
_reps.TryAdd("%uid%", () => user.Id.ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithStats(DiscordSocketClient c)
|
||||||
|
{
|
||||||
|
_reps.TryAdd("%servers%", () => c.Guilds.Count.ToString());
|
||||||
|
_reps.TryAdd("%users%", () => c.Guilds.Sum(s => s.Users.Count).ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithMusic(MusicService ms)
|
||||||
|
{
|
||||||
|
_reps.TryAdd("%playing%", () =>
|
||||||
|
{
|
||||||
|
var cnt = ms.MusicPlayers.Count(kvp => kvp.Value.Current.Current != null);
|
||||||
|
if (cnt != 1) return cnt.ToString();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mp = ms.MusicPlayers.FirstOrDefault();
|
||||||
|
var title = mp.Value?.Current.Current?.Title;
|
||||||
|
return title ?? "No songs";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_reps.TryAdd("%queued%", () => ms.MusicPlayers.Sum(kvp => kvp.Value.QueueArray().Songs.Length).ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithRngRegex()
|
||||||
|
{
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
_regex.TryAdd(rngRegex, (match) =>
|
||||||
|
{
|
||||||
|
int from = 0;
|
||||||
|
int.TryParse(match.Groups["from"].ToString(), out from);
|
||||||
|
|
||||||
|
int to = 0;
|
||||||
|
int.TryParse(match.Groups["to"].ToString(), out to);
|
||||||
|
|
||||||
|
if (from == 0 && to == 0)
|
||||||
|
{
|
||||||
|
return rng.Next(0, 11).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from >= to)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return rng.Next(from, to + 1).ToString();
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementBuilder WithOverride(string key, Func<string> output)
|
||||||
|
{
|
||||||
|
_reps.AddOrUpdate(key, output, delegate { return output; });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Replacer Build()
|
||||||
|
{
|
||||||
|
return new Replacer(_reps.Select(x => (x.Key, x.Value)).ToArray(), _regex.Select(x => (x.Key, x.Value)).ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/NadekoBot/DataStructures/Replacements/Replacer.cs
Normal file
54
src/NadekoBot/DataStructures/Replacements/Replacer.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures.Replacements
|
||||||
|
{
|
||||||
|
public class Replacer
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<(string Key, Func<string> Text)> _replacements;
|
||||||
|
private readonly IEnumerable<(Regex Regex, Func<Match, string> Replacement)> _regex;
|
||||||
|
|
||||||
|
public Replacer(IEnumerable<(string, Func<string>)> replacements, IEnumerable<(Regex, Func<Match, string>)> regex)
|
||||||
|
{
|
||||||
|
_replacements = replacements;
|
||||||
|
_regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Replace(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return input;
|
||||||
|
|
||||||
|
foreach (var item in _replacements)
|
||||||
|
{
|
||||||
|
if (input.Contains(item.Key))
|
||||||
|
input = input.Replace(item.Key, item.Text());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in _regex)
|
||||||
|
{
|
||||||
|
input = item.Regex.Replace(input, (m) => item.Replacement(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Replace(CREmbed embedData)
|
||||||
|
{
|
||||||
|
embedData.PlainText = Replace(embedData.PlainText);
|
||||||
|
embedData.Description = Replace(embedData.Description);
|
||||||
|
embedData.Title = Replace(embedData.Title);
|
||||||
|
|
||||||
|
if (embedData.Fields != null)
|
||||||
|
foreach (var f in embedData.Fields)
|
||||||
|
{
|
||||||
|
f.Name = Replace(f.Name);
|
||||||
|
f.Value = Replace(f.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (embedData.Footer != null)
|
||||||
|
embedData.Footer.Text = Replace(embedData.Footer.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
216
src/NadekoBot/DataStructures/SearchImageCacher.cs
Normal file
216
src/NadekoBot/DataStructures/SearchImageCacher.cs
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class SearchImageCacher
|
||||||
|
{
|
||||||
|
private readonly NadekoRandom _rng;
|
||||||
|
private readonly ConcurrentDictionary<DapiSearchType, SemaphoreSlim> _locks = new ConcurrentDictionary<DapiSearchType, SemaphoreSlim>();
|
||||||
|
|
||||||
|
private readonly SortedSet<ImageCacherObject> _cache;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public SearchImageCacher()
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_rng = new NadekoRandom();
|
||||||
|
_cache = new SortedSet<ImageCacherObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ImageCacherObject> GetImage(string tag, bool forceExplicit, DapiSearchType type)
|
||||||
|
{
|
||||||
|
tag = tag?.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (type == DapiSearchType.E621)
|
||||||
|
tag = tag?.Replace("yuri", "female/female");
|
||||||
|
|
||||||
|
var _lock = GetLock(type);
|
||||||
|
await _lock.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ImageCacherObject[] imgs;
|
||||||
|
if (!string.IsNullOrWhiteSpace(tag))
|
||||||
|
{
|
||||||
|
imgs = _cache.Where(x => x.Tags.IsSupersetOf(tag.Split('+')) && x.SearchType == type && (!forceExplicit || x.Rating == "e")).ToArray();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tag = null;
|
||||||
|
imgs = _cache.Where(x => x.SearchType == type).ToArray();
|
||||||
|
}
|
||||||
|
ImageCacherObject img;
|
||||||
|
if (imgs.Length == 0)
|
||||||
|
img = null;
|
||||||
|
else
|
||||||
|
img = imgs[_rng.Next(imgs.Length)];
|
||||||
|
|
||||||
|
if (img != null)
|
||||||
|
{
|
||||||
|
_cache.Remove(img);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var images = await DownloadImages(tag, forceExplicit, type).ConfigureAwait(false);
|
||||||
|
if (images.Length == 0)
|
||||||
|
return null;
|
||||||
|
var toReturn = images[_rng.Next(images.Length)];
|
||||||
|
foreach (var dledImg in images)
|
||||||
|
{
|
||||||
|
if(dledImg != toReturn)
|
||||||
|
_cache.Add(dledImg);
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SemaphoreSlim GetLock(DapiSearchType type)
|
||||||
|
{
|
||||||
|
return _locks.GetOrAdd(type, _ => new SemaphoreSlim(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ImageCacherObject[]> DownloadImages(string tag, bool isExplicit, DapiSearchType type)
|
||||||
|
{
|
||||||
|
_log.Info($"Loading extra images from {type}");
|
||||||
|
tag = tag?.Replace(" ", "_").ToLowerInvariant();
|
||||||
|
if (isExplicit)
|
||||||
|
tag = "rating%3Aexplicit+" + tag;
|
||||||
|
var website = "";
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case DapiSearchType.Safebooru:
|
||||||
|
website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.E621:
|
||||||
|
website = $"https://e621.net/post/index.json?limit=1000&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.Danbooru:
|
||||||
|
website = $"http://danbooru.donmai.us/posts.json?limit=200&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.Gelbooru:
|
||||||
|
website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.Rule34:
|
||||||
|
website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.Konachan:
|
||||||
|
website = $"https://konachan.com/post.json?s=post&q=index&limit=1000&tags={tag}";
|
||||||
|
break;
|
||||||
|
case DapiSearchType.Yandere:
|
||||||
|
website = $"https://yande.re/post.json?limit=1000&tags={tag}";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
|
||||||
|
if (type == DapiSearchType.Konachan || type == DapiSearchType.Yandere ||
|
||||||
|
type == DapiSearchType.E621 || type == DapiSearchType.Danbooru)
|
||||||
|
{
|
||||||
|
var data = await http.GetStringAsync(website).ConfigureAwait(false);
|
||||||
|
return JsonConvert.DeserializeObject<DapiImageObject[]>(data)
|
||||||
|
.Where(x => x.File_Url != null)
|
||||||
|
.Select(x => new ImageCacherObject(x, type))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await LoadXmlAsync(website, type)).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ImageCacherObject[]> LoadXmlAsync(string website, DapiSearchType type)
|
||||||
|
{
|
||||||
|
var list = new List<ImageCacherObject>(1000);
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
using (var reader = XmlReader.Create(await http.GetStreamAsync(website), new XmlReaderSettings()
|
||||||
|
{
|
||||||
|
Async = true,
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
while (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element &&
|
||||||
|
reader.Name == "post")
|
||||||
|
{
|
||||||
|
list.Add(new ImageCacherObject(new DapiImageObject()
|
||||||
|
{
|
||||||
|
File_Url = reader["file_url"],
|
||||||
|
Tags = reader["tags"],
|
||||||
|
Rating = reader["rating"] ?? "e"
|
||||||
|
|
||||||
|
}, type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageCacherObject : IComparable<ImageCacherObject>
|
||||||
|
{
|
||||||
|
public DapiSearchType SearchType { get; }
|
||||||
|
public string FileUrl { get; }
|
||||||
|
public HashSet<string> Tags { get; }
|
||||||
|
public string Rating { get; }
|
||||||
|
|
||||||
|
public ImageCacherObject(DapiImageObject obj, DapiSearchType type)
|
||||||
|
{
|
||||||
|
if (type == DapiSearchType.Danbooru)
|
||||||
|
this.FileUrl = "https://danbooru.donmai.us" + obj.File_Url;
|
||||||
|
else
|
||||||
|
this.FileUrl = obj.File_Url.StartsWith("http") ? obj.File_Url : "https:" + obj.File_Url;
|
||||||
|
this.SearchType = type;
|
||||||
|
this.Rating = obj.Rating;
|
||||||
|
this.Tags = new HashSet<string>((obj.Tags ?? obj.Tag_String).Split(' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return FileUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ImageCacherObject other)
|
||||||
|
{
|
||||||
|
return FileUrl.CompareTo(other.FileUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DapiImageObject
|
||||||
|
{
|
||||||
|
public string File_Url { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
|
public string Tag_String { get; set; }
|
||||||
|
public string Rating { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DapiSearchType
|
||||||
|
{
|
||||||
|
Safebooru,
|
||||||
|
E621,
|
||||||
|
Gelbooru,
|
||||||
|
Konachan,
|
||||||
|
Rule34,
|
||||||
|
Yandere,
|
||||||
|
Danbooru
|
||||||
|
}
|
||||||
|
}
|
22
src/NadekoBot/DataStructures/Shard0Precondition.cs
Normal file
22
src/NadekoBot/DataStructures/Shard0Precondition.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class Shard0Precondition : PreconditionAttribute
|
||||||
|
{
|
||||||
|
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
|
||||||
|
{
|
||||||
|
var c = (DiscordSocketClient)context.Client;
|
||||||
|
if (c.ShardId == 0)
|
||||||
|
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||||
|
else
|
||||||
|
return Task.FromResult(PreconditionResult.FromError("Must be ran from shard #0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs
Normal file
17
src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Discord;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures.ShardCom
|
||||||
|
{
|
||||||
|
public class ShardComMessage
|
||||||
|
{
|
||||||
|
public int ShardId { get; set; }
|
||||||
|
public ConnectionState ConnectionState { get; set; }
|
||||||
|
public int Guilds { get; set; }
|
||||||
|
public DateTime Time { get; set; }
|
||||||
|
}
|
||||||
|
}
|
29
src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs
Normal file
29
src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures.ShardCom
|
||||||
|
{
|
||||||
|
public class ShardComClient
|
||||||
|
{
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
public ShardComClient(int port)
|
||||||
|
{
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Send(ShardComMessage data)
|
||||||
|
{
|
||||||
|
var msg = JsonConvert.SerializeObject(data);
|
||||||
|
using (var client = new UdpClient())
|
||||||
|
{
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(msg);
|
||||||
|
await client.SendAsync(bytes, bytes.Length, IPAddress.Loopback.ToString(), port).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs
Normal file
40
src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures.ShardCom
|
||||||
|
{
|
||||||
|
public class ShardComServer : IDisposable
|
||||||
|
{
|
||||||
|
private readonly UdpClient _client;
|
||||||
|
|
||||||
|
public ShardComServer(int port)
|
||||||
|
{
|
||||||
|
_client = new UdpClient(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var ip = new IPEndPoint(IPAddress.Any, 0);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var recv = await _client.ReceiveAsync();
|
||||||
|
var data = Encoding.UTF8.GetString(recv.Buffer);
|
||||||
|
var _ = OnDataReceived(JsonConvert.DeserializeObject<ShardComMessage>(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_client.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Func<ShardComMessage, Task> OnDataReceived = delegate { return Task.CompletedTask; };
|
||||||
|
}
|
||||||
|
}
|
23
src/NadekoBot/DataStructures/SyncPrecondition.cs
Normal file
23
src/NadekoBot/DataStructures/SyncPrecondition.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
//public class SyncPrecondition : PreconditionAttribute
|
||||||
|
//{
|
||||||
|
// public override Task<PreconditionResult> CheckPermissions(ICommandContext context,
|
||||||
|
// CommandInfo command,
|
||||||
|
// IServiceProvider services)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//public enum SyncType
|
||||||
|
//{
|
||||||
|
// Guild
|
||||||
|
//}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.CustomReactions;
|
using NadekoBot.Services.CustomReactions;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
_cmdHandler = cmdHandler;
|
_cmdHandler = cmdHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.ToUpperInvariant();
|
input = input.ToUpperInvariant();
|
||||||
var prefix = _cmdHandler.GetPrefix(context.Guild);
|
var prefix = _cmdHandler.GetPrefix(context.Guild);
|
||||||
@ -44,7 +45,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
_crs = crs;
|
_crs = crs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.ToUpperInvariant();
|
input = input.ToUpperInvariant();
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd = await base.Read(context, input);
|
var cmd = await base.Read(context, input, _);
|
||||||
if (cmd.IsSuccess)
|
if (cmd.IsSuccess)
|
||||||
{
|
{
|
||||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
||||||
|
@ -14,7 +14,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
_gts = gts;
|
_gts = gts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
if (!DateTime.TryParse(input, out var dt))
|
if (!DateTime.TryParse(input, out var dt))
|
||||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input string is in an incorrect format."));
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input string is in an incorrect format."));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -7,13 +8,13 @@ namespace NadekoBot.TypeReaders
|
|||||||
{
|
{
|
||||||
public class GuildTypeReader : TypeReader
|
public class GuildTypeReader : TypeReader
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public GuildTypeReader(DiscordShardedClient client)
|
public GuildTypeReader(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.Trim().ToLowerInvariant();
|
input = input.Trim().ToLowerInvariant();
|
||||||
var guilds = _client.Guilds;
|
var guilds = _client.Guilds;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
_cmds = cmds;
|
_cmds = cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.ToUpperInvariant();
|
input = input.ToUpperInvariant();
|
||||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
|
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
|
||||||
@ -34,7 +35,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
_cmds = cmds;
|
_cmds = cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.ToLowerInvariant();
|
input = input.ToLowerInvariant();
|
||||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToLowerInvariant() == input)?.Key;
|
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToLowerInvariant() == input)?.Key;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Modules.Permissions;
|
using NadekoBot.Modules.Permissions;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NadekoBot.TypeReaders
|
namespace NadekoBot.TypeReaders
|
||||||
{
|
{
|
||||||
@ -9,7 +10,7 @@ namespace NadekoBot.TypeReaders
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PermissionActionTypeReader : TypeReader
|
public class PermissionActionTypeReader : TypeReader
|
||||||
{
|
{
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider _)
|
||||||
{
|
{
|
||||||
input = input.ToUpperInvariant();
|
input = input.ToUpperInvariant();
|
||||||
switch (input)
|
switch (input)
|
||||||
|
@ -126,16 +126,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
var guser = (IGuildUser)Context.User;
|
var guser = (IGuildUser)Context.User;
|
||||||
|
|
||||||
var userRoles = user.GetRoles();
|
var userRoles = user.GetRoles().Except(new[] { guser.Guild.EveryoneRole });
|
||||||
if (guser.Id != Context.Guild.OwnerId &&
|
if (user.Id == Context.Guild.OwnerId || (Context.User.Id != Context.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||||
(user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.RemoveRolesAsync(userRoles).ConfigureAwait(false);
|
await user.RemoveRolesAsync(userRoles).ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("rar_err").ConfigureAwait(false);
|
await ReplyErrorLocalized("rar_err").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -27,17 +27,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task RotatePlaying()
|
public async Task RotatePlaying()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
bool enabled;
|
||||||
{
|
|
||||||
using (var uow = _db.UnitOfWork)
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
|
|
||||||
_service.RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses;
|
enabled = config.RotatingStatuses = !config.RotatingStatuses;
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
}
|
if (enabled)
|
||||||
if (_service.RotatingStatuses)
|
|
||||||
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
||||||
@ -52,7 +50,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
var toAdd = new PlayingStatus { Status = status };
|
var toAdd = new PlayingStatus { Status = status };
|
||||||
config.RotatingStatusMessages.Add(toAdd);
|
config.RotatingStatusMessages.Add(toAdd);
|
||||||
_service.RotatingStatusMessages.Add(toAdd);
|
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,13 +60,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ListPlaying()
|
public async Task ListPlaying()
|
||||||
{
|
{
|
||||||
if (!_service.RotatingStatusMessages.Any())
|
if (!_service.BotConfig.RotatingStatusMessages.Any())
|
||||||
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var i = 1;
|
var i = 1;
|
||||||
await ReplyConfirmLocalized("ropl_list",
|
await ReplyConfirmLocalized("ropl_list",
|
||||||
string.Join("\n\t", _service.RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
string.Join("\n\t", _service.BotConfig.RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +87,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
msg = config.RotatingStatusMessages[index].Status;
|
msg = config.RotatingStatusMessages[index].Status;
|
||||||
config.RotatingStatusMessages.RemoveAt(index);
|
config.RotatingStatusMessages.RemoveAt(index);
|
||||||
_service.RotatingStatusMessages.RemoveAt(index);
|
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
||||||
|
@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page, (curPage) =>
|
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) =>
|
||||||
{
|
{
|
||||||
return new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.WithTitle(GetText("self_assign_list", roleCnt))
|
.WithTitle(GetText("self_assign_list", roleCnt))
|
||||||
|
@ -13,6 +13,9 @@ using NadekoBot.Services;
|
|||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Services.Administration;
|
using NadekoBot.Services.Administration;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.Services.Music;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
@ -25,16 +28,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
private static readonly object _locker = new object();
|
private static readonly object _locker = new object();
|
||||||
private readonly SelfService _service;
|
private readonly SelfService _service;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IImagesService _images;
|
private readonly IImagesService _images;
|
||||||
|
private readonly MusicService _music;
|
||||||
|
|
||||||
public SelfCommands(DbService db, SelfService service, DiscordShardedClient client,
|
public SelfCommands(DbService db, SelfService service, DiscordSocketClient client,
|
||||||
IImagesService images)
|
MusicService music, IImagesService images)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_service = service;
|
_service = service;
|
||||||
_client = client;
|
_client = client;
|
||||||
_images = images;
|
_images = images;
|
||||||
|
_music = music;
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -204,28 +209,28 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
//todo 2 shard commands
|
||||||
[OwnerOnly]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ConnectShard(int shardid)
|
//[Shard0Precondition]
|
||||||
{
|
//[OwnerOnly]
|
||||||
var shard = _client.GetShard(shardid);
|
//public async Task RestartShard(int shardid)
|
||||||
|
//{
|
||||||
if (shard == null)
|
// if (shardid == 0 || shardid > b)
|
||||||
{
|
// {
|
||||||
await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false);
|
// await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
// await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||||
await shard.StartAsync().ConfigureAwait(false);
|
// await shard.StartAsync().ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
// await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
_log.Warn(ex);
|
// _log.Warn(ex);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
@ -266,6 +271,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
await Task.Delay(2000).ConfigureAwait(false);
|
await Task.Delay(2000).ConfigureAwait(false);
|
||||||
|
try { await _music.DestroyAllPlayers().ConfigureAwait(false); } catch { }
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,8 +423,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ReloadImages()
|
public async Task ReloadImages()
|
||||||
{
|
{
|
||||||
var time = _images.Reload();
|
var sw = Stopwatch.StartNew();
|
||||||
await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
_images.Reload();
|
||||||
|
sw.Stop();
|
||||||
|
await ReplyConfirmLocalized("images_loaded", sw.Elapsed.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
||||||
|
@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
var timezonesPerPage = 20;
|
var timezonesPerPage = 20;
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page,
|
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page,
|
||||||
(curPage) => new EmbedBuilder()
|
(curPage) => new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText("timezones_available"))
|
.WithTitle(GetText("timezones_available"))
|
||||||
|
@ -28,6 +28,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
_muteService = muteService;
|
_muteService = muteService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo move to service
|
||||||
private async Task<PunishmentAction?> InternalWarn(IGuild guild, ulong userId, string modName, string reason)
|
private async Task<PunishmentAction?> InternalWarn(IGuild guild, ulong userId, string modName, string reason)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(reason))
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
@ -109,7 +110,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await (await user.CreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor()
|
await (await user.GetOrCreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor()
|
||||||
.WithDescription(GetText("warned_on", Context.Guild.ToString()))
|
.WithDescription(GetText("warned_on", Context.Guild.ToString()))
|
||||||
.AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString()))
|
.AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString()))
|
||||||
.AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-")))
|
.AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-")))
|
||||||
@ -131,24 +132,27 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[Priority(1)]
|
||||||
public Task Warnlog(int page, IGuildUser user)
|
public Task Warnlog(int page, IGuildUser user)
|
||||||
=> Warnlog(page, user.Id);
|
=> Warnlog(page, user.Id);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[Priority(0)]
|
||||||
public Task Warnlog(IGuildUser user)
|
public Task Warnlog(IGuildUser user)
|
||||||
=> Warnlog(user.Id);
|
=> Context.User.Id == user.Id || ((IGuildUser)Context.User).GuildPermissions.BanMembers ? Warnlog(user.Id) : Task.CompletedTask;
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[Priority(3)]
|
||||||
public Task Warnlog(int page, ulong userId)
|
public Task Warnlog(int page, ulong userId)
|
||||||
=> InternalWarnlog(userId, page - 1);
|
=> InternalWarnlog(userId, page - 1);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[Priority(2)]
|
||||||
public Task Warnlog(ulong userId)
|
public Task Warnlog(ulong userId)
|
||||||
=> InternalWarnlog(userId, 0);
|
=> InternalWarnlog(userId, 0);
|
||||||
|
|
||||||
@ -191,6 +195,39 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await Context.Channel.EmbedAsync(embed);
|
await Context.Channel.EmbedAsync(embed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task WarnlogAll(int page = 1)
|
||||||
|
{
|
||||||
|
if (--page < 0)
|
||||||
|
return;
|
||||||
|
IGrouping<ulong, Warning>[] warnings;
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
warnings = uow.Warnings.GetForGuild(Context.Guild.Id).GroupBy(x => x.UserId).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, async (curPage) =>
|
||||||
|
{
|
||||||
|
var ws = await Task.WhenAll(warnings.Skip(curPage * 15)
|
||||||
|
.Take(15)
|
||||||
|
.ToArray()
|
||||||
|
.Select(async x =>
|
||||||
|
{
|
||||||
|
var all = x.Count();
|
||||||
|
var forgiven = x.Count(y => y.Forgiven);
|
||||||
|
var total = all - forgiven;
|
||||||
|
return ((await Context.Guild.GetUserAsync(x.Key))?.ToString() ?? x.Key.ToString()) + $" | {total} ({all} - {forgiven})";
|
||||||
|
}));
|
||||||
|
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.WithTitle(GetText("warnings_list"))
|
||||||
|
.WithDescription(string.Join("\n", ws));
|
||||||
|
|
||||||
|
}, warnings.Length / 15);
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
@ -17,10 +17,10 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly CustomReactionsService _crs;
|
private readonly CustomReactionsService _crs;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public CustomReactions(IBotCredentials creds, DbService db, CustomReactionsService crs,
|
public CustomReactions(IBotCredentials creds, DbService db, CustomReactionsService crs,
|
||||||
DiscordShardedClient client)
|
DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
_db = db;
|
_db = db;
|
||||||
@ -79,7 +79,7 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
.WithTitle(GetText("new_cust_react"))
|
.WithTitle(GetText("new_cust_react"))
|
||||||
.WithDescription($"#{cr.Id}")
|
.WithDescription($"#{cr.Id}")
|
||||||
.AddField(efb => efb.WithName(GetText("trigger")).WithValue(key))
|
.AddField(efb => efb.WithName(GetText("trigger")).WithValue(key))
|
||||||
.AddField(efb => efb.WithName(GetText("response")).WithValue(message))
|
.AddField(efb => efb.WithName(GetText("response")).WithValue(message.Length > 1024 ? GetText("redacted_too_long") : message))
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
|
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
|
||||||
|
|
||||||
public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordShardedClient client)
|
public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
_cs = cs;
|
_cs = cs;
|
||||||
@ -82,14 +82,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private readonly ITextChannel _raceChannel;
|
private readonly ITextChannel _raceChannel;
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly ILocalization _localization;
|
private readonly ILocalization _localization;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public bool Started { get; private set; }
|
public bool Started { get; private set; }
|
||||||
|
|
||||||
public AnimalRace(ulong serverId, ITextChannel channel, string prefix, BotConfig bc,
|
public AnimalRace(ulong serverId, ITextChannel channel, string prefix, BotConfig bc,
|
||||||
CurrencyService cs, DiscordShardedClient client, ILocalization localization,
|
CurrencyService cs, DiscordSocketClient client, ILocalization localization,
|
||||||
NadekoStrings strings)
|
NadekoStrings strings)
|
||||||
{
|
{
|
||||||
_prefix = prefix;
|
_prefix = prefix;
|
||||||
|
@ -34,11 +34,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
private string _secretCode = string.Empty;
|
private string _secretCode = string.Empty;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
|
|
||||||
public CurrencyEvents(DiscordShardedClient client, BotConfig bc, CurrencyService cs)
|
public CurrencyEvents(DiscordSocketClient client, BotConfig bc, CurrencyService cs)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
@ -151,19 +151,21 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
|
private readonly SocketSelfUser _botUser;
|
||||||
|
|
||||||
private IUserMessage StartingMessage { get; set; }
|
private IUserMessage StartingMessage { get; set; }
|
||||||
|
|
||||||
private CancellationTokenSource Source { get; }
|
private CancellationTokenSource Source { get; }
|
||||||
private CancellationToken CancelToken { get; }
|
private CancellationToken CancelToken { get; }
|
||||||
|
|
||||||
public FlowerReactionEvent(DiscordShardedClient client, CurrencyService cs)
|
public FlowerReactionEvent(DiscordSocketClient client, CurrencyService cs)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
_cs = cs;
|
_cs = cs;
|
||||||
|
_botUser = client.CurrentUser;
|
||||||
Source = new CancellationTokenSource();
|
Source = new CancellationTokenSource();
|
||||||
CancelToken = Source.Token;
|
CancelToken = Source.Token;
|
||||||
}
|
}
|
||||||
@ -208,6 +210,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (r.UserId == _botUser.Id)
|
||||||
|
return;
|
||||||
|
|
||||||
if (r.Emote.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
if (r.Emote.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
||||||
{
|
{
|
||||||
await _cs.AddAsync(r.User.Value, "Flower Reaction Event", amount, false)
|
await _cs.AddAsync(r.User.Value, "Flower Reaction Event", amount, false)
|
||||||
|
@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public enum Role
|
public enum Role
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
List
|
List
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordShardedClient client)
|
public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
@ -154,7 +154,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await (await Context.User.CreateDMChannelAsync())
|
await (await Context.User.GetOrCreateDMChannelAsync())
|
||||||
.EmbedAsync(new EmbedBuilder().WithOkColor()
|
.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(GetText("shop_purchase", Context.Guild.Name))
|
.WithTitle(GetText("shop_purchase", Context.Guild.Name))
|
||||||
.AddField(efb => efb.WithName(GetText("item")).WithValue(item.Text).WithIsInline(false))
|
.AddField(efb => efb.WithName(GetText("item")).WithValue(item.Text).WithIsInline(false))
|
||||||
|
@ -20,12 +20,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class Acropobia : NadekoSubmodule
|
public class Acropobia : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
||||||
|
|
||||||
public Acropobia(DiscordShardedClient client)
|
public Acropobia(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
@ -86,10 +86,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
//text, votes
|
//text, votes
|
||||||
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public AcrophobiaGame(DiscordShardedClient client, NadekoStrings strings, ITextChannel channel, int time)
|
public AcrophobiaGame(DiscordSocketClient client, NadekoStrings strings, ITextChannel channel, int time)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
public class HangmanGame: IDisposable
|
public class HangmanGame: IDisposable
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public IMessageChannel GameChannel { get; }
|
public IMessageChannel GameChannel { get; }
|
||||||
public HashSet<char> Guesses { get; } = new HashSet<char>();
|
public HashSet<char> Guesses { get; } = new HashSet<char>();
|
||||||
@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
|
|
||||||
public event Action<HangmanGame> OnEnded;
|
public event Action<HangmanGame> OnEnded;
|
||||||
|
|
||||||
public HangmanGame(DiscordShardedClient client, IMessageChannel channel, string type)
|
public HangmanGame(DiscordSocketClient client, IMessageChannel channel, string type)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
@ -109,8 +109,10 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
var embed = new EmbedBuilder().WithTitle("Hangman Game")
|
var embed = new EmbedBuilder().WithTitle("Hangman Game")
|
||||||
.WithDescription(toSend)
|
.WithDescription(toSend)
|
||||||
.AddField(efb => efb.WithName("It was").WithValue(Term.Word))
|
.AddField(efb => efb.WithName("It was").WithValue(Term.Word))
|
||||||
.WithImageUrl(Term.ImageUrl)
|
|
||||||
.WithFooter(efb => efb.WithText(string.Join(" ", Guesses)));
|
.WithFooter(efb => efb.WithText(string.Join(" ", Guesses)));
|
||||||
|
if(Uri.IsWellFormedUriString(Term.ImageUrl, UriKind.Absolute))
|
||||||
|
embed.WithImageUrl(Term.ImageUrl);
|
||||||
|
|
||||||
if (Errors >= MaxErrors)
|
if (Errors >= MaxErrors)
|
||||||
await GameChannel.EmbedAsync(embed.WithErrorColor()).ConfigureAwait(false);
|
await GameChannel.EmbedAsync(embed.WithErrorColor()).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
|
@ -15,9 +15,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class HangmanCommands : NadekoSubmodule
|
public class HangmanCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public HangmanCommands(DiscordShardedClient client)
|
public HangmanCommands(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
@ -25,12 +25,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Hangmanlist()
|
public async Task Hangmanlist()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + string.Join(", ", HangmanTermPool.data.Keys));
|
await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + string.Join(", ", HangmanTermPool.data.Keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Hangman([Remainder]string type = "All")
|
public async Task Hangman([Remainder]string type = "All")
|
||||||
{
|
{
|
||||||
var hm = new HangmanGame(_client, Context.Channel, type);
|
var hm = new HangmanGame(_client, Context.Channel, type);
|
||||||
@ -59,6 +61,17 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(GetText("hangman_game_started"), hm.ScrambledWord + "\n" + hm.GetHangman());
|
await Context.Channel.SendConfirmAsync(GetText("hangman_game_started"), hm.ScrambledWord + "\n" + hm.GetHangman());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task HangmanStop()
|
||||||
|
{
|
||||||
|
if (HangmanGames.TryRemove(Context.Channel.Id, out HangmanGame throwaway))
|
||||||
|
{
|
||||||
|
throwaway.Dispose();
|
||||||
|
await ReplyConfirmLocalized("hangman_stopped").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,13 @@ namespace NadekoBot.Modules.Games.Models
|
|||||||
public bool IsActive { get; private set; }
|
public bool IsActive { get; private set; }
|
||||||
private readonly Stopwatch sw;
|
private readonly Stopwatch sw;
|
||||||
private readonly List<ulong> finishedUserIds;
|
private readonly List<ulong> finishedUserIds;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly GamesService _games;
|
private readonly GamesService _games;
|
||||||
private readonly string _prefix;
|
private readonly string _prefix;
|
||||||
|
|
||||||
private Logger _log { get; }
|
private Logger _log { get; }
|
||||||
|
|
||||||
public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel, string prefix) //kek@prefix
|
public TypingGame(GamesService games, DiscordSocketClient client, ITextChannel channel, string prefix) //kek@prefix
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_games = games;
|
_games = games;
|
||||||
|
@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = _db.UnitOfWork)
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var guildConfig = uow.GuildConfigs.For(channel.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
|
var guildConfig = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
|
||||||
|
|
||||||
var toAdd = new GCChannelId() { ChannelId = channel.Id };
|
var toAdd = new GCChannelId() { ChannelId = channel.Id };
|
||||||
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
||||||
|
@ -13,10 +13,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class PollCommands : NadekoSubmodule
|
public class PollCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly PollService _polls;
|
private readonly PollService _polls;
|
||||||
|
|
||||||
public PollCommands(DiscordShardedClient client, PollService polls)
|
public PollCommands(DiscordSocketClient client, PollService polls)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_polls = polls;
|
_polls = polls;
|
||||||
@ -26,13 +26,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task Poll([Remainder] string arg = null)
|
public Task Poll([Remainder] string arg = null)
|
||||||
=> InternalStartPoll(arg, false);
|
=> InternalStartPoll(arg);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
public Task PublicPoll([Remainder] string arg = null)
|
|
||||||
=> InternalStartPoll(arg, true);
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
@ -45,9 +39,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results")));
|
await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
private async Task InternalStartPoll(string arg)
|
||||||
{
|
{
|
||||||
if(await _polls.StartPoll((ITextChannel)Context.Channel, Context.Message, arg, isPublic) == false)
|
if(await _polls.StartPoll((ITextChannel)Context.Channel, Context.Message, arg) == false)
|
||||||
await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false);
|
await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
||||||
private readonly GamesService _games;
|
private readonly GamesService _games;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public SpeedTypingCommands(DiscordShardedClient client, GamesService games)
|
public SpeedTypingCommands(DiscordSocketClient client, GamesService games)
|
||||||
{
|
{
|
||||||
_games = games;
|
_games = games;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
||||||
|
|
||||||
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public TicTacToeCommands(DiscordShardedClient client)
|
public TicTacToeCommands(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
@ -87,9 +87,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
private IUserMessage _previousMessage;
|
private IUserMessage _previousMessage;
|
||||||
private Timer _timeoutTimer;
|
private Timer _timeoutTimer;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public TicTacToe(NadekoStrings strings, DiscordShardedClient client, ITextChannel channel, IGuildUser firstUser)
|
public TicTacToe(NadekoStrings strings, DiscordSocketClient client, ITextChannel channel, IGuildUser firstUser)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_strings = strings;
|
_strings = strings;
|
||||||
|
@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
|
|
||||||
public int WinRequirement { get; }
|
public int WinRequirement { get; }
|
||||||
|
|
||||||
public TriviaGame(NadekoStrings strings, DiscordShardedClient client, BotConfig bc,
|
public TriviaGame(NadekoStrings strings, DiscordSocketClient client, BotConfig bc,
|
||||||
CurrencyService cs, IGuild guild, ITextChannel channel,
|
CurrencyService cs, IGuild guild, ITextChannel channel,
|
||||||
bool showHints, int winReq, bool isPokemon)
|
bool showHints, int winReq, bool isPokemon)
|
||||||
{
|
{
|
||||||
@ -89,8 +89,9 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
questionEmbed = new EmbedBuilder().WithOkColor()
|
questionEmbed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(GetText("trivia_game"))
|
.WithTitle(GetText("trivia_game"))
|
||||||
.AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category))
|
.AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category))
|
||||||
.AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question))
|
.AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question));
|
||||||
.WithImageUrl(CurrentQuestion.ImageUrl);
|
if (Uri.IsWellFormedUriString(CurrentQuestion.ImageUrl, UriKind.Absolute))
|
||||||
|
questionEmbed.WithImageUrl(CurrentQuestion.ImageUrl);
|
||||||
|
|
||||||
questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -145,11 +146,13 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Channel.EmbedAsync(new EmbedBuilder().WithErrorColor()
|
var embed = new EmbedBuilder().WithErrorColor()
|
||||||
.WithTitle(GetText("trivia_game"))
|
.WithTitle(GetText("trivia_game"))
|
||||||
.WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer)))
|
.WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer)));
|
||||||
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
if (Uri.IsWellFormedUriString(CurrentQuestion.AnswerImageUrl, UriKind.Absolute))
|
||||||
.ConfigureAwait(false);
|
embed.WithImageUrl(CurrentQuestion.AnswerImageUrl);
|
||||||
|
|
||||||
|
await Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -215,13 +218,14 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
var embedS = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(GetText("trivia_game"))
|
.WithTitle(GetText("trivia_game"))
|
||||||
.WithDescription(GetText("trivia_win",
|
.WithDescription(GetText("trivia_win",
|
||||||
guildUser.Mention,
|
guildUser.Mention,
|
||||||
Format.Bold(CurrentQuestion.Answer)))
|
Format.Bold(CurrentQuestion.Answer)));
|
||||||
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
if (Uri.IsWellFormedUriString(CurrentQuestion.AnswerImageUrl, UriKind.Absolute))
|
||||||
.ConfigureAwait(false);
|
embedS.WithImageUrl(CurrentQuestion.AnswerImageUrl);
|
||||||
|
await Channel.EmbedAsync(embedS).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -232,12 +236,12 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
await _cs.AddAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
await _cs.AddAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithTitle(GetText("trivia_game"))
|
.WithTitle(GetText("trivia_game"))
|
||||||
.WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer)))
|
.WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer)));
|
||||||
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
if (Uri.IsWellFormedUriString(CurrentQuestion.AnswerImageUrl, UriKind.Absolute))
|
||||||
.ConfigureAwait(false);
|
embed.WithImageUrl(CurrentQuestion.AnswerImageUrl);
|
||||||
|
await Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
});
|
});
|
||||||
|
@ -18,12 +18,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
public class TriviaCommands : NadekoSubmodule
|
public class TriviaCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||||
|
|
||||||
public TriviaCommands(DiscordShardedClient client, BotConfig bc, CurrencyService cs)
|
public TriviaCommands(DiscordSocketClient client, BotConfig bc, CurrencyService cs)
|
||||||
{
|
{
|
||||||
_cs = cs;
|
_cs = cs;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Help
|
|||||||
|
|
||||||
if (com == null)
|
if (com == null)
|
||||||
{
|
{
|
||||||
IMessageChannel ch = channel is ITextChannel ? await ((IGuildUser)Context.User).CreateDMChannelAsync() : channel;
|
IMessageChannel ch = channel is ITextChannel ? await ((IGuildUser)Context.User).GetOrCreateDMChannelAsync() : channel;
|
||||||
await ch.SendMessageAsync(HelpString).ConfigureAwait(false);
|
await ch.SendMessageAsync(HelpString).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@ using System.Xml;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NadekoBot.Services.Searches;
|
using NadekoBot.Services.Searches;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.NSFW
|
namespace NadekoBot.Modules.NSFW
|
||||||
{
|
{
|
||||||
@ -28,29 +29,12 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||||
{
|
{
|
||||||
tag = tag?.Trim() ?? "";
|
|
||||||
|
|
||||||
tag = "rating%3Aexplicit+" + tag;
|
|
||||||
|
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
var provider = Task.FromResult("");
|
var arr = Enum.GetValues(typeof(DapiSearchType));
|
||||||
switch (rng.Next(0, 4))
|
var type = (DapiSearchType)arr.GetValue(new NadekoRandom().Next(2, arr.Length));
|
||||||
{
|
var img = await _service.DapiSearch(tag, type, Context.Guild?.Id, true).ConfigureAwait(false);
|
||||||
case 0:
|
|
||||||
provider = GetDanbooruImageLink(tag);
|
if (img == null)
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
provider = GetGelbooruImageLink(tag);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
provider = GetKonachanImageLink(tag);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
provider = GetYandereImageLink(tag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var link = await provider.ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrWhiteSpace(link))
|
|
||||||
{
|
{
|
||||||
if (!noError)
|
if (!noError)
|
||||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||||
@ -58,8 +42,8 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
|
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithImageUrl(link)
|
.WithImageUrl(img.FileUrl)
|
||||||
.WithDescription($"[{GetText("tag")}: {tag}]({link})"))
|
.WithDescription($"[{GetText("tag")}: {tag}]({img})"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,110 +96,58 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
interval,
|
interval,
|
||||||
string.Join(", ", tagsArr)).ConfigureAwait(false);
|
string.Join(", ", tagsArr)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task HentaiBomb([Remainder] string tag = null)
|
public async Task HentaiBomb([Remainder] string tag = null)
|
||||||
{
|
{
|
||||||
if (!_hentaiBombBlacklist.Add(Context.User.Id))
|
if (!_hentaiBombBlacklist.Add(Context.Guild?.Id ?? Context.User.Id))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tag = tag?.Trim() ?? "";
|
var images = await Task.WhenAll(_service.DapiSearch(tag, DapiSearchType.Gelbooru, Context.Guild?.Id, true),
|
||||||
tag = "rating%3Aexplicit+" + tag;
|
_service.DapiSearch(tag, DapiSearchType.Danbooru, Context.Guild?.Id, true),
|
||||||
|
_service.DapiSearch(tag, DapiSearchType.Konachan, Context.Guild?.Id, true),
|
||||||
|
_service.DapiSearch(tag, DapiSearchType.Yandere, Context.Guild?.Id, true)).ConfigureAwait(false);
|
||||||
|
|
||||||
var links = await Task.WhenAll(GetGelbooruImageLink(tag),
|
var linksEnum = images?.Where(l => l != null).ToArray();
|
||||||
GetDanbooruImageLink(tag),
|
if (images == null || !linksEnum.Any())
|
||||||
GetKonachanImageLink(tag),
|
|
||||||
GetYandereImageLink(tag)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var linksEnum = links?.Where(l => l != null).ToArray();
|
|
||||||
if (links == null || !linksEnum.Any())
|
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(string.Join("\n\n", linksEnum)).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(string.Join("\n\n", linksEnum.Select(x => x.FileUrl))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
_hentaiBombBlacklist.TryRemove(Context.Guild?.Id ?? Context.User.Id);
|
||||||
_hentaiBombBlacklist.TryRemove(Context.User.Id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Yandere([Remainder] string tag = null)
|
public Task Yandere([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, DapiSearchType.Yandere);
|
=> InternalDapiCommand(tag, DapiSearchType.Yandere, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Konachan([Remainder] string tag = null)
|
public Task Konachan([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, DapiSearchType.Konachan);
|
=> InternalDapiCommand(tag, DapiSearchType.Konachan, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task E621([Remainder] string tag = null)
|
public Task E621([Remainder] string tag = null)
|
||||||
{
|
=> InternalDapiCommand(tag, DapiSearchType.E621, false);
|
||||||
tag = tag?.Trim() ?? "";
|
|
||||||
|
|
||||||
var url = await GetE621ImageLink(tag).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (url == null)
|
|
||||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
|
||||||
else
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithDescription(Context.User.Mention + " " + tag)
|
|
||||||
.WithImageUrl(url)
|
|
||||||
.WithFooter(efb => efb.WithText("e621")))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Rule34([Remainder] string tag = null)
|
public Task Rule34([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, DapiSearchType.Rule34);
|
=> InternalDapiCommand(tag, DapiSearchType.Rule34, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Danbooru([Remainder] string tag = null)
|
public Task Danbooru([Remainder] string tag = null)
|
||||||
{
|
=> InternalDapiCommand(tag, DapiSearchType.Danbooru, false);
|
||||||
tag = tag?.Trim() ?? "";
|
|
||||||
|
|
||||||
var url = await GetDanbooruImageLink(tag).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (url == null)
|
|
||||||
await ReplyErrorLocalized("not_found").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]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Gelbooru([Remainder] string tag = null)
|
public Task Gelbooru([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, DapiSearchType.Gelbooru);
|
=> InternalDapiCommand(tag, DapiSearchType.Gelbooru, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Boobs()
|
public async Task Boobs()
|
||||||
@ -253,52 +185,16 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<string> GetE621ImageLink(string tag) => Task.Run(async () =>
|
public async Task InternalDapiCommand(string tag, DapiSearchType type, bool forceExplicit)
|
||||||
{
|
{
|
||||||
try
|
var imgObj = await _service.DapiSearch(tag, type, Context.Guild?.Id, forceExplicit).ConfigureAwait(false);
|
||||||
{
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
http.AddFakeHeaders();
|
|
||||||
var data = await http.GetStreamAsync("http://e621.net/post/index.xml?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)];
|
if (imgObj == null)
|
||||||
return node.InnerText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public Task<string> GetRule34ImageLink(string tag) =>
|
|
||||||
_service.DapiSearch(tag, DapiSearchType.Rule34);
|
|
||||||
|
|
||||||
public Task<string> GetYandereImageLink(string tag) =>
|
|
||||||
_service.DapiSearch(tag, DapiSearchType.Yandere);
|
|
||||||
|
|
||||||
public Task<string> GetKonachanImageLink(string tag) =>
|
|
||||||
_service.DapiSearch(tag, DapiSearchType.Konachan);
|
|
||||||
|
|
||||||
public Task<string> GetGelbooruImageLink(string tag) =>
|
|
||||||
_service.DapiSearch(tag, DapiSearchType.Gelbooru);
|
|
||||||
|
|
||||||
public async Task InternalDapiCommand(string tag, DapiSearchType type)
|
|
||||||
{
|
|
||||||
tag = tag?.Trim() ?? "";
|
|
||||||
|
|
||||||
var url = await _service.DapiSearch(tag, type).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (url == null)
|
|
||||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription($"{Context.User} [{tag}]({url}) ")
|
.WithDescription($"{Context.User} [{tag ?? "url"}]({imgObj}) ")
|
||||||
.WithImageUrl(url)
|
.WithImageUrl(imgObj.FileUrl)
|
||||||
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace NadekoBot.Modules
|
|||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void BeforeExecute()
|
protected override void BeforeExecute(CommandInfo cmd)
|
||||||
{
|
{
|
||||||
_cultureInfo = _localization.GetCultureInfo(Context.Guild?.Id);
|
_cultureInfo = _localization.GetCultureInfo(Context.Guild?.Id);
|
||||||
}
|
}
|
||||||
@ -87,12 +87,11 @@ namespace NadekoBot.Modules
|
|||||||
return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text);
|
return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo maybe make this generic and use
|
// TypeConverter typeConverter = TypeDescriptor.GetConverter(propType); ?
|
||||||
// TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
|
|
||||||
public async Task<string> GetUserInputAsync(ulong userId, ulong channelId)
|
public async Task<string> GetUserInputAsync(ulong userId, ulong channelId)
|
||||||
{
|
{
|
||||||
var userInputTask = new TaskCompletionSource<string>();
|
var userInputTask = new TaskCompletionSource<string>();
|
||||||
var dsc = (DiscordShardedClient)Context.Client;
|
var dsc = (DiscordSocketClient)Context.Client;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dsc.MessageReceived += MessageReceived;
|
dsc.MessageReceived += MessageReceived;
|
||||||
|
@ -195,7 +195,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
var fws = fwHash.ToArray();
|
var fws = fwHash.ToArray();
|
||||||
|
|
||||||
await channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client,
|
await channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client,
|
||||||
page,
|
page,
|
||||||
(curPage) =>
|
(curPage) =>
|
||||||
new EmbedBuilder()
|
new EmbedBuilder()
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -29,26 +31,30 @@ namespace NadekoBot.Modules.Searches
|
|||||||
"If you consider playing teemo, do it. If you consider teemo, you deserve him.",
|
"If you consider playing teemo, do it. If you consider teemo, you deserve him.",
|
||||||
"Doesn't matter what you ban really. Enemy will ban your main and you will lose." };
|
"Doesn't matter what you ban really. Enemy will ban your main and you will lose." };
|
||||||
|
|
||||||
|
private static readonly Lazy<Dictionary<int, string>> champData = new Lazy<Dictionary<int, string>>(() =>
|
||||||
|
((IDictionary<string, JToken>)JObject.Parse(File.ReadAllText("data/lolchamps.json")))
|
||||||
|
.ToDictionary(x => (int)x.Value["id"], x => x.Value["name"].ToString()), true);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Lolban()
|
public async Task Lolban()
|
||||||
{
|
{
|
||||||
const int showCount = 8;
|
//const int showCount = 8;
|
||||||
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var data = JObject.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/champs/mostBanned?" +
|
var data = JArray.Parse(await http.GetStringAsync($"http://api.champion.gg/v2/champions?champData=general&limit=200&api_key={_creds.LoLApiKey}"));
|
||||||
$"api_key={_creds.LoLApiKey}&page=1&" +
|
|
||||||
$"limit={showCount}")
|
var champs = data.OrderByDescending(x => (double)x["banRate"]).Distinct(x => x["championId"]).Take(6);
|
||||||
.ConfigureAwait(false))["data"] as JArray;
|
|
||||||
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
//_log.Info(string.Join("\n", champs.Select(x => x["championId"] + " | " + x["banRate"] + " | " + x["normalized"]["banRate"])));
|
||||||
var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline(GetText("x_most_banned_champs",dataList.Count)));
|
var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline(GetText("x_most_banned_champs", champs.Count())));
|
||||||
foreach (var champ in dataList)
|
foreach (var champ in champs)
|
||||||
{
|
{
|
||||||
var champ1 = champ;
|
var lChamp = champ;
|
||||||
eb.AddField(efb => efb.WithName(champ1["name"].ToString()).WithValue(champ1["general"]["banRate"] + "%").WithIsInline(true));
|
if (!champData.Value.TryGetValue((int)champ["championId"], out var champName))
|
||||||
|
champName = "UNKNOWN";
|
||||||
|
eb.AddField(efb => efb.WithName(champName).WithValue(((double)lChamp["banRate"] * 100).ToString("F2") + "%").WithIsInline(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(eb, Format.Italics(trashTalk[new NadekoRandom().Next(0, trashTalk.Length)])).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(eb, Format.Italics(trashTalk[new NadekoRandom().Next(0, trashTalk.Length)])).ConfigureAwait(false);
|
||||||
@ -173,7 +179,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
// .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
// .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
||||||
// if (general == null)
|
// if (general == null)
|
||||||
// {
|
// {
|
||||||
// //Console.WriteLine("General is null.");
|
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// //get build data for this role
|
// //get build data for this role
|
||||||
@ -309,7 +314,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
// }
|
// }
|
||||||
// catch (Exception ex)
|
// catch (Exception ex)
|
||||||
// {
|
// {
|
||||||
// //Console.WriteLine(ex);
|
|
||||||
// await channel.SendMessageAsync("💢 Failed retreiving data for that champion.").ConfigureAwait(false);
|
// await channel.SendMessageAsync("💢 Failed retreiving data for that champion.").ConfigureAwait(false);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
@ -62,8 +62,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.AddField(fb => fb.WithName(GetText("quick_wins")).WithValue(qp.OverallStats.wins.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_wins")).WithValue(qp.OverallStats.wins.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("compet_wins")).WithValue(compet.OverallStats.wins.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_wins")).WithValue(compet.OverallStats.wins.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("compet_loses")).WithValue(compet.OverallStats.losses.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_loses")).WithValue(compet.OverallStats.losses.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("compet_played")).WithValue(compet.OverallStats.games.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_played")).WithValue(compet.OverallStats.games.ToString() ?? "-").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(compet.OverallStats.comprank.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(compet.OverallStats.comprank?.ToString() ?? "-").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("compet_playtime")).WithValue(compet.GameStats.timePlayed + "hrs").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_playtime")).WithValue(compet.GameStats.timePlayed + "hrs").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue(qp.GameStats.timePlayed.ToString("F1") + "hrs").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue(qp.GameStats.timePlayed.ToString("F1") + "hrs").WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
|
@ -21,6 +21,7 @@ using NadekoBot.Attributes;
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using ImageSharp;
|
using ImageSharp;
|
||||||
using NadekoBot.Services.Searches;
|
using NadekoBot.Services.Searches;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
@ -666,7 +667,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
str += new NadekoRandom().Next();
|
str += new NadekoRandom().Next();
|
||||||
foreach (var usr in allUsrsArray)
|
foreach (var usr in allUsrsArray)
|
||||||
{
|
{
|
||||||
await (await usr.CreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false);
|
await (await usr.GetOrCreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,14 +792,14 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
tag = tag?.Trim() ?? "";
|
tag = tag?.Trim() ?? "";
|
||||||
|
|
||||||
var url = await _searches.DapiSearch(tag, type).ConfigureAwait(false);
|
var imgObj = await _searches.DapiSearch(tag, type, Context.Guild?.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
if (url == null)
|
if (imgObj == null)
|
||||||
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
||||||
else
|
else
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription($"{umsg.Author.Mention} [{tag}]({url})")
|
.WithDescription($"{umsg.Author.Mention} [{tag ?? "url"}]({imgObj.FileUrl})")
|
||||||
.WithImageUrl(url)
|
.WithImageUrl(imgObj.FileUrl)
|
||||||
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
private readonly CommandMapService _service;
|
private readonly CommandMapService _service;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public CommandMapCommands(CommandMapService service, DbService db, DiscordShardedClient client)
|
public CommandMapCommands(CommandMapService service, DbService db, DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_service = service;
|
_service = service;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using NadekoBot.Attributes;
|
|
||||||
using NadekoBot.Extensions;
|
|
||||||
using NadekoBot.Services;
|
|
||||||
using NadekoBot.Services.Utility;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
|
||||||
{
|
|
||||||
public partial class Utility
|
|
||||||
{
|
|
||||||
[Group]
|
|
||||||
public class CrossServerTextChannel : NadekoSubmodule
|
|
||||||
{
|
|
||||||
private readonly CrossServerTextService _service;
|
|
||||||
|
|
||||||
public CrossServerTextChannel(CrossServerTextService service)
|
|
||||||
{
|
|
||||||
_service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[OwnerOnly]
|
|
||||||
public async Task Scsc()
|
|
||||||
{
|
|
||||||
var token = new NadekoRandom().Next();
|
|
||||||
var set = new ConcurrentHashSet<ITextChannel>();
|
|
||||||
if (_service.Subscribers.TryAdd(token, set))
|
|
||||||
{
|
|
||||||
set.Add((ITextChannel) Context.Channel);
|
|
||||||
await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString())
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
|
||||||
public async Task Jcsc(int token)
|
|
||||||
{
|
|
||||||
ConcurrentHashSet<ITextChannel> set;
|
|
||||||
if (!_service.Subscribers.TryGetValue(token, out set))
|
|
||||||
return;
|
|
||||||
set.Add((ITextChannel) Context.Channel);
|
|
||||||
await ReplyConfirmLocalized("csc_join").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
|
||||||
public async Task Lcsc()
|
|
||||||
{
|
|
||||||
foreach (var subscriber in _service.Subscribers)
|
|
||||||
{
|
|
||||||
subscriber.Value.TryRemove((ITextChannel) Context.Channel);
|
|
||||||
}
|
|
||||||
await ReplyConfirmLocalized("csc_leave").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,10 +16,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class InfoCommands : NadekoSubmodule
|
public class InfoCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IStatsService _stats;
|
private readonly IStatsService _stats;
|
||||||
|
|
||||||
public InfoCommands(DiscordShardedClient client, IStatsService stats, CommandHandler ch)
|
public InfoCommands(DiscordSocketClient client, IStatsService stats, CommandHandler ch)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_stats = stats;
|
_stats = stats;
|
||||||
@ -59,8 +59,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.AddField(fb => fb.WithName(GetText("region")).WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("region")).WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("roles")).WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("roles")).WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true))
|
||||||
.WithImageUrl(guild.IconUrl)
|
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
|
if (Uri.IsWellFormedUriString(guild.IconUrl, UriKind.Absolute))
|
||||||
|
embed.WithImageUrl(guild.IconUrl);
|
||||||
if (guild.Emotes.Any())
|
if (guild.Emotes.Any())
|
||||||
{
|
{
|
||||||
embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emotes.Count})").WithValue(string.Join(" ", guild.Emotes.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emotes.Count})").WithValue(string.Join(" ", guild.Emotes.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||||
|
@ -32,18 +32,23 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
|
[RequireContext(ContextType.DM)]
|
||||||
public async Task PatreonRewardsReload()
|
public async Task PatreonRewardsReload()
|
||||||
{
|
{
|
||||||
await _patreon.LoadPledges().ConfigureAwait(false);
|
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
|
||||||
|
return;
|
||||||
|
await _patreon.RefreshPledges(true).ConfigureAwait(false);
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.DM)]
|
||||||
public async Task ClaimPatreonRewards()
|
public async Task ClaimPatreonRewards()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
|
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (DateTime.UtcNow.Day < 5)
|
if (DateTime.UtcNow.Day < 5)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false);
|
await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false);
|
||||||
|
@ -9,6 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.DataStructures.Replacements;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
@ -66,22 +67,18 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (quote == null)
|
if (quote == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CREmbed crembed;
|
var rep = new ReplacementBuilder()
|
||||||
if (CREmbed.TryParse(quote.Text, out crembed))
|
.WithDefault(Context)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
if (CREmbed.TryParse(quote.Text, out var crembed))
|
||||||
{
|
{
|
||||||
try
|
rep.Replace(crembed);
|
||||||
{
|
await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText?.SanitizeMentions() ?? "")
|
||||||
await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "")
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn("Sending CREmbed failed");
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Context.Channel.SendMessageAsync($"`#{quote.Id}` 📣 " + quote.Text.SanitizeMentions());
|
await Context.Channel.SendMessageAsync($"`#{quote.Id}` 📣 " + rep.Replace(quote.Text)?.SanitizeMentions());
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -118,29 +115,28 @@ namespace NadekoBot.Modules.Utility
|
|||||||
using (var uow = _db.UnitOfWork)
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var qfromid = uow.Quotes.Get(id);
|
var qfromid = uow.Quotes.Get(id);
|
||||||
CREmbed crembed;
|
|
||||||
|
var rep = new ReplacementBuilder()
|
||||||
|
.WithDefault(Context)
|
||||||
|
.Build();
|
||||||
|
|
||||||
if (qfromid == null)
|
if (qfromid == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync(GetText("quotes_notfound"));
|
await Context.Channel.SendErrorAsync(GetText("quotes_notfound"));
|
||||||
}
|
}
|
||||||
else if (CREmbed.TryParse(qfromid.Text, out crembed))
|
else if (CREmbed.TryParse(qfromid.Text, out var crembed))
|
||||||
{
|
{
|
||||||
try
|
rep.Replace(crembed);
|
||||||
{
|
|
||||||
await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "")
|
await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText?.SanitizeMentions() ?? "")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else
|
||||||
{
|
{
|
||||||
_log.Warn("Sending CREmbed failed");
|
await Context.Channel.SendMessageAsync($"`#{qfromid.Id}` 🗯️ " + qfromid.Keyword.ToLowerInvariant().SanitizeMentions() + ": " +
|
||||||
_log.Warn(ex);
|
rep.Replace(qfromid.Text)?.SanitizeMentions());
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else { await Context.Channel.SendMessageAsync($"`#{qfromid.Id}` 🗯️ " + qfromid.Keyword.ToLowerInvariant().SanitizeMentions() + ": " +
|
|
||||||
qfromid.Text.SanitizeMentions()); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NadekoBot.Services.Utility;
|
using NadekoBot.Services.Utility;
|
||||||
using System;
|
using System;
|
||||||
@ -19,11 +20,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
private readonly RemindService _service;
|
private readonly RemindService _service;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
private readonly GuildTimezoneService _tz;
|
||||||
|
|
||||||
public RemindCommands(RemindService service, DbService db)
|
public RemindCommands(RemindService service, DbService db, GuildTimezoneService tz)
|
||||||
{
|
{
|
||||||
_service = service;
|
_service = service;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
_tz = tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MeOrHere
|
public enum MeOrHere
|
||||||
@ -33,7 +36,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[Priority(1)]
|
[Priority(0)]
|
||||||
public async Task Remind(MeOrHere meorhere, string timeStr, [Remainder] string message)
|
public async Task Remind(MeOrHere meorhere, string timeStr, [Remainder] string message)
|
||||||
{
|
{
|
||||||
ulong target;
|
ulong target;
|
||||||
@ -44,7 +47,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[Priority(0)]
|
[Priority(1)]
|
||||||
public async Task Remind(ITextChannel channel, string timeStr, [Remainder] string message)
|
public async Task Remind(ITextChannel channel, string timeStr, [Remainder] string message)
|
||||||
{
|
{
|
||||||
var perms = ((IGuildUser)Context.User).GetPermissions((ITextChannel)channel);
|
var perms = ((IGuildUser)Context.User).GetPermissions((ITextChannel)channel);
|
||||||
@ -119,6 +122,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gTime = TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(Context.Guild.Id));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(
|
await Context.Channel.SendConfirmAsync(
|
||||||
@ -126,7 +130,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
Format.Bold(!isPrivate ? $"<#{targetId}>" : Context.User.Username),
|
Format.Bold(!isPrivate ? $"<#{targetId}>" : Context.User.Username),
|
||||||
Format.Bold(message.SanitizeMentions()),
|
Format.Bold(message.SanitizeMentions()),
|
||||||
Format.Bold(output),
|
Format.Bold(output),
|
||||||
time, time)).ConfigureAwait(false);
|
gTime, gTime)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -22,10 +22,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public class RepeatCommands : NadekoSubmodule
|
public class RepeatCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly MessageRepeaterService _service;
|
private readonly MessageRepeaterService _service;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public RepeatCommands(MessageRepeaterService service, DiscordShardedClient client, DbService db)
|
public RepeatCommands(MessageRepeaterService service, DiscordSocketClient client, DbService db)
|
||||||
{
|
{
|
||||||
_service = service;
|
_service = service;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -6,7 +6,6 @@ using NadekoBot.Services.Utility;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
public partial class Utility
|
public partial class Utility
|
||||||
|
@ -18,100 +18,26 @@ using Discord.WebSocket;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Color = Discord.Color;
|
using Color = Discord.Color;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
public partial class Utility : NadekoTopLevelModule
|
public partial class Utility : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IStatsService _stats;
|
private readonly IStatsService _stats;
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
|
private readonly NadekoBot _bot;
|
||||||
|
|
||||||
public Utility(DiscordShardedClient client, IStatsService stats, IBotCredentials creds)
|
public Utility(NadekoBot bot, DiscordSocketClient client, IStatsService stats, IBotCredentials creds)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_stats = stats;
|
_stats = stats;
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
|
_bot = bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
//[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
//[RequireContext(ContextType.Guild)]
|
|
||||||
//public async Task Midorina([Remainder] string arg)
|
|
||||||
//{
|
|
||||||
// var channel = (ITextChannel)Context.Channel;
|
|
||||||
|
|
||||||
// var roleNames = arg?.Split(';');
|
|
||||||
|
|
||||||
// if (roleNames == null || roleNames.Length == 0)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// var j = 0;
|
|
||||||
// var roles = roleNames.Select(x => Context.Guild.Roles.FirstOrDefault(r => String.Compare(r.Name, x, StringComparison.OrdinalIgnoreCase) == 0))
|
|
||||||
// .Where(x => x != null)
|
|
||||||
// .Take(10)
|
|
||||||
// .ToArray();
|
|
||||||
|
|
||||||
// var rnd = new NadekoRandom();
|
|
||||||
// var reactions = new[] { "🎬", "🐧", "🌍", "🌺", "🚀", "☀", "🌲", "🍒", "🐾", "🏀" }
|
|
||||||
// .OrderBy(x => rnd.Next())
|
|
||||||
// .ToArray();
|
|
||||||
|
|
||||||
// var roleStrings = roles
|
|
||||||
// .Select(x => $"{reactions[j++]} -> {x.Name}");
|
|
||||||
|
|
||||||
// var msg = await Context.Channel.SendConfirmAsync("Pick a Role",
|
|
||||||
// string.Join("\n", roleStrings)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// for (int i = 0; i < roles.Length; i++)
|
|
||||||
// {
|
|
||||||
// try { await msg.AddReactionAsync(reactions[i]).ConfigureAwait(false); }
|
|
||||||
// catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
// await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// msg.OnReaction((r) => Task.Run(async () =>
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var usr = r.User.GetValueOrDefault() as IGuildUser;
|
|
||||||
|
|
||||||
// if (usr == null)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// var index = Array.IndexOf<string>(reactions, r.Emoji.Name);
|
|
||||||
// if (index == -1)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// await usr.RemoveRolesAsync(roles[index]);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// _log.Warn(ex);
|
|
||||||
// }
|
|
||||||
// }), (r) => Task.Run(async () =>
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var usr = r.User.GetValueOrDefault() as IGuildUser;
|
|
||||||
|
|
||||||
// if (usr == null)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// var index = Array.IndexOf<string>(reactions, r.Emoji.Name);
|
|
||||||
// if (index == -1)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// await usr.RemoveRolesAsync(roles[index]);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// _log.Warn(ex);
|
|
||||||
// }
|
|
||||||
// }));
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
@ -354,23 +280,30 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[Shard0Precondition]
|
||||||
public async Task ShardStats(int page = 1)
|
public async Task ShardStats(int page = 1)
|
||||||
{
|
{
|
||||||
if (--page < 0)
|
if (--page < 0)
|
||||||
return;
|
return;
|
||||||
|
var statuses = _bot.ShardCoord.Statuses.ToArray()
|
||||||
|
.Where(x => x != null);
|
||||||
|
|
||||||
var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState)
|
var status = string.Join(", ", statuses
|
||||||
|
.GroupBy(x => x.ConnectionState)
|
||||||
.Select(x => $"{x.Count()} {x.Key}")
|
.Select(x => $"{x.Count()} {x.Key}")
|
||||||
.ToArray());
|
.ToArray());
|
||||||
|
|
||||||
var allShardStrings = _client.Shards
|
var allShardStrings = statuses
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
GetText("shard_stats_txt", x.ShardId.ToString(),
|
{
|
||||||
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString())))
|
var timeDiff = DateTime.UtcNow - x.Time;
|
||||||
|
if (timeDiff > TimeSpan.FromSeconds(20))
|
||||||
|
return $"Shard #{Format.Bold(x.ShardId.ToString())} **UNRESPONSIVE** for {timeDiff.ToString(@"hh\:mm\:ss")}";
|
||||||
|
return GetText("shard_stats_txt", x.ShardId.ToString(),
|
||||||
|
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()), timeDiff.ToString(@"hh\:mm\:ss"));
|
||||||
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
|
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -387,21 +320,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}, allShardStrings.Length / 25);
|
}, allShardStrings.Length / 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
public async Task ShardId(IGuild guild)
|
|
||||||
{
|
|
||||||
var shardId = _client.GetShardIdFor(guild);
|
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Stats()
|
public async Task Stats()
|
||||||
{
|
{
|
||||||
var shardId = Context.Guild != null
|
|
||||||
? _client.GetShardIdFor(Context.Guild)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(
|
await Context.Channel.EmbedAsync(
|
||||||
new EmbedBuilder().WithOkColor()
|
new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
||||||
@ -409,7 +330,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
||||||
.AddField(efb => efb.WithName(GetText("author")).WithValue(_stats.Author).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("author")).WithValue(_stats.Author).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {_client.Shards.Count}").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{_bot.ShardId} / {_creds.TotalShards}").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(_stats.CommandsRan.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(_stats.CommandsRan.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true))
|
||||||
@ -417,13 +338,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
||||||
GetText("presence_txt",
|
GetText("presence_txt",
|
||||||
_client.Guilds.Count, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true))
|
_stats.GuildCount, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true)));
|
||||||
#if !GLOBAL_NADEKO
|
|
||||||
//.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
|
||||||
// _music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
|
||||||
// _music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -4,8 +4,6 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Impl;
|
using NadekoBot.Services.Impl;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
|
||||||
using NLog.Targets;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -27,6 +25,7 @@ using NadekoBot.Services.Utility;
|
|||||||
using NadekoBot.Services.Help;
|
using NadekoBot.Services.Help;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NadekoBot.Services.Pokemon;
|
using NadekoBot.Services.Pokemon;
|
||||||
|
using NadekoBot.DataStructures.ShardCom;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
|
||||||
@ -45,72 +44,113 @@ namespace NadekoBot
|
|||||||
public static Color OkColor { get; private set; }
|
public static Color OkColor { get; private set; }
|
||||||
public static Color ErrorColor { get; private set; }
|
public static Color ErrorColor { get; private set; }
|
||||||
|
|
||||||
public ImmutableArray<GuildConfig> AllGuildConfigs { get; }
|
public ImmutableArray<GuildConfig> AllGuildConfigs { get; private set; }
|
||||||
public BotConfig BotConfig { get; }
|
public BotConfig BotConfig { get; }
|
||||||
public DbService Db { get; }
|
public DbService Db { get; }
|
||||||
public CommandService CommandService { get; }
|
public CommandService CommandService { get; }
|
||||||
public CommandHandler CommandHandler { get; private set; }
|
public CommandHandler CommandHandler { get; private set; }
|
||||||
public Localization Localization { get; }
|
public Localization Localization { get; private set; }
|
||||||
public NadekoStrings Strings { get; }
|
public NadekoStrings Strings { get; private set; }
|
||||||
public StatsService Stats { get; }
|
public StatsService Stats { get; private set; }
|
||||||
public ImagesService Images { get; }
|
public ImagesService Images { get; }
|
||||||
public CurrencyService Currency { get; }
|
public CurrencyService Currency { get; }
|
||||||
public GoogleApiService GoogleApi { get; }
|
public GoogleApiService GoogleApi { get; }
|
||||||
|
|
||||||
public DiscordShardedClient Client { get; }
|
public DiscordSocketClient Client { get; }
|
||||||
public bool Ready { get; private set; }
|
public bool Ready { get; private set; }
|
||||||
|
|
||||||
public INServiceProvider Services { get; private set; }
|
public INServiceProvider Services { get; private set; }
|
||||||
public BotCredentials Credentials { get; }
|
public BotCredentials Credentials { get; }
|
||||||
|
|
||||||
public NadekoBot()
|
public int ShardId { get; }
|
||||||
|
public ShardsCoordinator ShardCoord { get; private set; }
|
||||||
|
|
||||||
|
private readonly ShardComClient _comClient;
|
||||||
|
|
||||||
|
public NadekoBot(int shardId, int parentProcessId, int? port = null)
|
||||||
{
|
{
|
||||||
SetupLogger();
|
if (shardId < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(shardId));
|
||||||
|
|
||||||
|
ShardId = shardId;
|
||||||
|
|
||||||
|
LogSetup.SetupLogger();
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
TerribleElevatedPermissionCheck();
|
TerribleElevatedPermissionCheck();
|
||||||
|
|
||||||
Credentials = new BotCredentials();
|
Credentials = new BotCredentials();
|
||||||
|
|
||||||
|
port = port ?? Credentials.ShardRunPort;
|
||||||
|
_comClient = new ShardComClient(port.Value);
|
||||||
|
|
||||||
Db = new DbService(Credentials);
|
Db = new DbService(Credentials);
|
||||||
|
|
||||||
using (var uow = Db.UnitOfWork)
|
using (var uow = Db.UnitOfWork)
|
||||||
{
|
{
|
||||||
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray();
|
|
||||||
BotConfig = uow.BotConfig.GetOrCreate();
|
BotConfig = uow.BotConfig.GetOrCreate();
|
||||||
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
||||||
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
Client = new DiscordShardedClient(new DiscordSocketConfig
|
Client = new DiscordSocketClient(new DiscordSocketConfig
|
||||||
{
|
{
|
||||||
MessageCacheSize = 10,
|
MessageCacheSize = 10,
|
||||||
LogLevel = LogSeverity.Warning,
|
LogLevel = LogSeverity.Warning,
|
||||||
TotalShards = Credentials.TotalShards,
|
|
||||||
ConnectionTimeout = int.MaxValue,
|
ConnectionTimeout = int.MaxValue,
|
||||||
|
TotalShards = Credentials.TotalShards,
|
||||||
|
ShardId = shardId,
|
||||||
AlwaysDownloadUsers = false,
|
AlwaysDownloadUsers = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
CommandService = new CommandService(new CommandServiceConfig()
|
CommandService = new CommandService(new CommandServiceConfig()
|
||||||
{
|
{
|
||||||
CaseSensitiveCommands = false,
|
CaseSensitiveCommands = false,
|
||||||
DefaultRunMode = RunMode.Async,
|
DefaultRunMode = RunMode.Sync,
|
||||||
});
|
});
|
||||||
|
|
||||||
//foundation services
|
|
||||||
Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
|
|
||||||
Strings = new NadekoStrings(Localization);
|
|
||||||
CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this);
|
|
||||||
Stats = new StatsService(Client, CommandHandler, Credentials);
|
|
||||||
Images = new ImagesService();
|
Images = new ImagesService();
|
||||||
Currency = new CurrencyService(BotConfig, Db);
|
Currency = new CurrencyService(BotConfig, Db);
|
||||||
GoogleApi = new GoogleApiService(Credentials);
|
GoogleApi = new GoogleApiService(Credentials);
|
||||||
|
|
||||||
|
SetupShard(shardId, parentProcessId, port.Value);
|
||||||
|
|
||||||
#if GLOBAL_NADEKO
|
#if GLOBAL_NADEKO
|
||||||
Client.Log += Client_Log;
|
Client.Log += Client_Log;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartSendingData()
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await _comClient.Send(new ShardComMessage()
|
||||||
|
{
|
||||||
|
ConnectionState = Client.ConnectionState,
|
||||||
|
Guilds = Client.ConnectionState == ConnectionState.Connected ? Client.Guilds.Count : 0,
|
||||||
|
ShardId = Client.ShardId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
});
|
||||||
|
await Task.Delay(5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void AddServices()
|
private void AddServices()
|
||||||
{
|
{
|
||||||
|
var startingGuildIdList = Client.Guilds.Select(x => (long)x.Id).ToList();
|
||||||
|
|
||||||
|
//this unit of work will be used for initialization of all modules too, to prevent multiple queries from running
|
||||||
|
using (var uow = Db.UnitOfWork)
|
||||||
|
{
|
||||||
|
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray();
|
||||||
|
|
||||||
|
Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
|
||||||
|
Strings = new NadekoStrings(Localization);
|
||||||
|
CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this);
|
||||||
|
Stats = new StatsService(Client, CommandHandler, Credentials, ShardCoord);
|
||||||
|
|
||||||
var soundcloudApiService = new SoundCloudApiService(Credentials);
|
var soundcloudApiService = new SoundCloudApiService(Credentials);
|
||||||
|
|
||||||
#region help
|
#region help
|
||||||
@ -120,18 +160,17 @@ namespace NadekoBot
|
|||||||
//module services
|
//module services
|
||||||
//todo 90 - autodiscover, DI, and add instead of manual like this
|
//todo 90 - autodiscover, DI, and add instead of manual like this
|
||||||
#region utility
|
#region utility
|
||||||
var crossServerTextService = new CrossServerTextService(AllGuildConfigs, Client);
|
var remindService = new RemindService(Client, BotConfig, Db, startingGuildIdList, uow);
|
||||||
var remindService = new RemindService(Client, BotConfig, Db);
|
|
||||||
var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs);
|
var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs);
|
||||||
var converterService = new ConverterService(Db);
|
var converterService = new ConverterService(Client, Db);
|
||||||
var commandMapService = new CommandMapService(AllGuildConfigs);
|
var commandMapService = new CommandMapService(AllGuildConfigs);
|
||||||
var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency);
|
var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency, Client);
|
||||||
var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService);
|
var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService);
|
||||||
var pruneService = new PruneService();
|
var pruneService = new PruneService();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region permissions
|
#region permissions
|
||||||
var permissionsService = new PermissionService(Db, BotConfig, CommandHandler);
|
var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler, Strings);
|
||||||
var blacklistService = new BlacklistService(BotConfig);
|
var blacklistService = new BlacklistService(BotConfig);
|
||||||
var cmdcdsService = new CmdCdService(AllGuildConfigs);
|
var cmdcdsService = new CmdCdService(AllGuildConfigs);
|
||||||
var filterService = new FilterService(Client, AllGuildConfigs);
|
var filterService = new FilterService(Client, AllGuildConfigs);
|
||||||
@ -144,13 +183,13 @@ namespace NadekoBot
|
|||||||
var animeSearchService = new AnimeSearchService();
|
var animeSearchService = new AnimeSearchService();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var clashService = new ClashOfClansService(Client, Db, Localization, Strings);
|
var clashService = new ClashOfClansService(Client, Db, Localization, Strings, uow, startingGuildIdList);
|
||||||
var musicService = new MusicService(GoogleApi, Strings, Localization, Db, soundcloudApiService, Credentials, AllGuildConfigs);
|
var musicService = new MusicService(Client, GoogleApi, Strings, Localization, Db, soundcloudApiService, Credentials, AllGuildConfigs);
|
||||||
var crService = new CustomReactionsService(permissionsService, Db, Client, CommandHandler, BotConfig);
|
var crService = new CustomReactionsService(permissionsService, Db, Strings, Client, CommandHandler, BotConfig, uow);
|
||||||
|
|
||||||
#region Games
|
#region Games
|
||||||
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler);
|
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler);
|
||||||
var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler);
|
var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler, Strings);
|
||||||
var pollService = new PollService(Client, Strings);
|
var pollService = new PollService(Client, Strings);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -163,18 +202,17 @@ namespace NadekoBot
|
|||||||
var muteService = new MuteService(Client, AllGuildConfigs, Db);
|
var muteService = new MuteService(Client, AllGuildConfigs, Db);
|
||||||
var ratelimitService = new SlowmodeService(Client, AllGuildConfigs);
|
var ratelimitService = new SlowmodeService(Client, AllGuildConfigs);
|
||||||
var protectionService = new ProtectionService(Client, AllGuildConfigs, muteService);
|
var protectionService = new ProtectionService(Client, AllGuildConfigs, muteService);
|
||||||
var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService);
|
var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService, Db);
|
||||||
var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs);
|
var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs);
|
||||||
var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs);
|
var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs);
|
||||||
var logCommandService = new LogCommandService(Client, Strings, AllGuildConfigs, Db, muteService, protectionService);
|
var guildTimezoneService = new GuildTimezoneService(Client, AllGuildConfigs, Db);
|
||||||
var guildTimezoneService = new GuildTimezoneService(AllGuildConfigs, Db);
|
var logCommandService = new LogCommandService(Client, Strings, AllGuildConfigs, Db, muteService, protectionService, guildTimezoneService);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region pokemon
|
#region pokemon
|
||||||
var pokemonService = new PokemonService();
|
var pokemonService = new PokemonService();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
//initialize Services
|
//initialize Services
|
||||||
Services = new NServiceProvider.ServiceProviderBuilder()
|
Services = new NServiceProvider.ServiceProviderBuilder()
|
||||||
.Add<ILocalization>(Localization)
|
.Add<ILocalization>(Localization)
|
||||||
@ -185,13 +223,12 @@ namespace NadekoBot
|
|||||||
.Add<IBotCredentials>(Credentials)
|
.Add<IBotCredentials>(Credentials)
|
||||||
.Add<CommandService>(CommandService)
|
.Add<CommandService>(CommandService)
|
||||||
.Add<NadekoStrings>(Strings)
|
.Add<NadekoStrings>(Strings)
|
||||||
.Add<DiscordShardedClient>(Client)
|
.Add<DiscordSocketClient>(Client)
|
||||||
.Add<BotConfig>(BotConfig)
|
.Add<BotConfig>(BotConfig)
|
||||||
.Add<CurrencyService>(Currency)
|
.Add<CurrencyService>(Currency)
|
||||||
.Add<CommandHandler>(CommandHandler)
|
.Add<CommandHandler>(CommandHandler)
|
||||||
.Add<DbService>(Db)
|
.Add<DbService>(Db)
|
||||||
//modules
|
//modules
|
||||||
.Add(crossServerTextService)
|
|
||||||
.Add(commandMapService)
|
.Add(commandMapService)
|
||||||
.Add(remindService)
|
.Add(remindService)
|
||||||
.Add(repeaterService)
|
.Add(repeaterService)
|
||||||
@ -228,6 +265,7 @@ namespace NadekoBot
|
|||||||
.Add(filterService)
|
.Add(filterService)
|
||||||
.Add(globalPermsService)
|
.Add(globalPermsService)
|
||||||
.Add<PokemonService>(pokemonService)
|
.Add<PokemonService>(pokemonService)
|
||||||
|
.Add<NadekoBot>(this)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
CommandHandler.AddServices(Services);
|
CommandHandler.AddServices(Services);
|
||||||
@ -240,36 +278,76 @@ namespace NadekoBot
|
|||||||
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
||||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
||||||
CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService));
|
CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoginAsync(string token)
|
private async Task LoginAsync(string token)
|
||||||
{
|
{
|
||||||
_log.Info("Logging in...");
|
var clientReady = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
Task SetClientReady()
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
clientReady.TrySetResult(true);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var chan in (await Client.GetDMChannelsAsync()))
|
||||||
|
{
|
||||||
|
await chan.CloseAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
//connect
|
//connect
|
||||||
|
_log.Info("Shard {0} logging in ...", ShardId);
|
||||||
await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false);
|
await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false);
|
||||||
await Client.StartAsync().ConfigureAwait(false);
|
await Client.StartAsync().ConfigureAwait(false);
|
||||||
|
Client.Ready += SetClientReady;
|
||||||
_log.Info("Waiting for all shards to connect...");
|
await clientReady.Task.ConfigureAwait(false);
|
||||||
while (!Client.Shards.All(x => x.ConnectionState == ConnectionState.Connected))
|
Client.Ready -= SetClientReady;
|
||||||
{
|
Client.JoinedGuild += Client_JoinedGuild;
|
||||||
_log.Info("Connecting... {0}/{1}", Client.Shards.Count(x => x.ConnectionState == ConnectionState.Connected), Client.Shards.Count);
|
Client.LeftGuild += Client_LeftGuild;
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
_log.Info("Shard {0} logged in.", ShardId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task Client_LeftGuild(SocketGuild arg)
|
||||||
|
{
|
||||||
|
_log.Info("Left server: {0} [{1}]", arg?.Name, arg?.Id);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Client_JoinedGuild(SocketGuild arg)
|
||||||
|
{
|
||||||
|
_log.Info("Joined server: {0} [{1}]", arg?.Name, arg?.Id);
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RunAsync(params string[] args)
|
public async Task RunAsync(params string[] args)
|
||||||
{
|
{
|
||||||
|
if(ShardId == 0)
|
||||||
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
await LoginAsync(Credentials.Token).ConfigureAwait(false);
|
await LoginAsync(Credentials.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
_log.Info("Loading services...");
|
_log.Info($"Shard {ShardId} loading services...");
|
||||||
AddServices();
|
AddServices();
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Info($"Connected in {sw.Elapsed.TotalSeconds:F2} s");
|
_log.Info($"Shard {ShardId} connected in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
|
|
||||||
var stats = Services.GetService<IStatsService>();
|
var stats = Services.GetService<IStatsService>();
|
||||||
stats.Initialize();
|
stats.Initialize();
|
||||||
@ -282,7 +360,11 @@ namespace NadekoBot
|
|||||||
var _ = await CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly);
|
var _ = await CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
|
||||||
//Console.WriteLine(string.Join(", ", CommandService.Commands
|
bool isPublicNadeko = false;
|
||||||
|
#if GLOBAL_NADEKO
|
||||||
|
isPublicNadeko = true;
|
||||||
|
#endif
|
||||||
|
//_log.Info(string.Join(", ", CommandService.Commands
|
||||||
// .Distinct(x => x.Name + x.Module.Name)
|
// .Distinct(x => x.Name + x.Module.Name)
|
||||||
// .SelectMany(x => x.Aliases)
|
// .SelectMany(x => x.Aliases)
|
||||||
// .GroupBy(x => x)
|
// .GroupBy(x => x)
|
||||||
@ -290,15 +372,17 @@ namespace NadekoBot
|
|||||||
// .Select(x => x.Key + $"({x.Count()})")));
|
// .Select(x => x.Key + $"({x.Count()})")));
|
||||||
|
|
||||||
//unload modules which are not available on the public bot
|
//unload modules which are not available on the public bot
|
||||||
#if GLOBAL_NADEKO
|
|
||||||
|
if(isPublicNadeko)
|
||||||
CommandService
|
CommandService
|
||||||
.Modules
|
.Modules
|
||||||
.ToArray()
|
.ToArray()
|
||||||
.Where(x => x.Preconditions.Any(y => y.GetType() == typeof(NoPublicBot)))
|
.Where(x => x.Preconditions.Any(y => y.GetType() == typeof(NoPublicBot)))
|
||||||
.ForEach(x => CommandService.RemoveModuleAsync(x));
|
.ForEach(x => CommandService.RemoveModuleAsync(x));
|
||||||
#endif
|
|
||||||
Ready = true;
|
Ready = true;
|
||||||
_log.Info(await stats.Print().ConfigureAwait(false));
|
_log.Info($"Shard {ShardId} ready.");
|
||||||
|
//_log.Info(await stats.Print().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Client_Log(LogMessage arg)
|
private Task Client_Log(LogMessage arg)
|
||||||
@ -313,8 +397,14 @@ namespace NadekoBot
|
|||||||
public async Task RunAndBlockAsync(params string[] args)
|
public async Task RunAndBlockAsync(params string[] args)
|
||||||
{
|
{
|
||||||
await RunAsync(args).ConfigureAwait(false);
|
await RunAsync(args).ConfigureAwait(false);
|
||||||
|
StartSendingData();
|
||||||
|
if (ShardCoord != null)
|
||||||
|
await ShardCoord.RunAndBlockAsync();
|
||||||
|
else
|
||||||
|
{
|
||||||
await Task.Delay(-1).ConfigureAwait(false);
|
await Task.Delay(-1).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void TerribleElevatedPermissionCheck()
|
private void TerribleElevatedPermissionCheck()
|
||||||
{
|
{
|
||||||
@ -331,18 +421,29 @@ namespace NadekoBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupLogger()
|
private void SetupShard(int shardId, int parentProcessId, int port)
|
||||||
{
|
{
|
||||||
var logConfig = new LoggingConfiguration();
|
if (shardId != 0)
|
||||||
var consoleTarget = new ColoredConsoleTarget()
|
|
||||||
{
|
{
|
||||||
Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}"
|
new Thread(new ThreadStart(() =>
|
||||||
};
|
{
|
||||||
logConfig.AddTarget("Console", consoleTarget);
|
try
|
||||||
|
{
|
||||||
logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget));
|
var p = Process.GetProcessById(parentProcessId);
|
||||||
|
if (p == null)
|
||||||
LogManager.Configuration = logConfig;
|
return;
|
||||||
|
p.WaitForExit();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Environment.Exit(10);
|
||||||
|
}
|
||||||
|
})).Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ShardCoord = new ShardsCoordinator(port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
||||||
<PackageReference Include="Discord.Net" Version="1.0.0-rc3-00746" />
|
<PackageReference Include="Discord.Net" Version="1.0.1-build-00785" />
|
||||||
<PackageReference Include="libvideo" Version="1.0.1" />
|
<PackageReference Include="libvideo" Version="1.0.1" />
|
||||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
||||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
||||||
@ -74,6 +74,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||||
<PackageReference Include="NLog" Version="5.0.0-beta03" />
|
<PackageReference Include="NLog" Version="5.0.0-beta03" />
|
||||||
|
<PackageReference Include="NYoutubeDL" Version="0.4.4" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.4.0-preview1-25305-02" />
|
<PackageReference Include="System.ValueTuple" Version="4.4.0-preview1-25305-02" />
|
||||||
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -90,5 +91,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Modules\Music\Classes\" />
|
<Folder Include="Modules\Music\Classes\" />
|
||||||
|
<Folder Include="Utility\Services\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -2,7 +2,17 @@
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args) =>
|
public static void Main(string[] args)
|
||||||
new NadekoBot().RunAndBlockAsync(args).GetAwaiter().GetResult();
|
{
|
||||||
|
if (args.Length == 3 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId))
|
||||||
|
{
|
||||||
|
int? port = null;
|
||||||
|
if (int.TryParse(args[2], out var outPort))
|
||||||
|
port = outPort;
|
||||||
|
new NadekoBot(shardId, parentProcessId, outPort).RunAndBlockAsync(args).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new NadekoBot(0, 0).RunAndBlockAsync(args).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
src/NadekoBot/Properties/launchSettings.json
Normal file
7
src/NadekoBot/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"NadekoBot": {
|
||||||
|
"commandName": "Project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -814,7 +814,7 @@
|
|||||||
<value>serverinfo sinfo</value>
|
<value>serverinfo sinfo</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="serverinfo_desc" xml:space="preserve">
|
<data name="serverinfo_desc" xml:space="preserve">
|
||||||
<value>Shows info about the server the bot is on. If no channel is supplied, it defaults to current one.</value>
|
<value>Shows info about the server the bot is on. If no server is supplied, it defaults to current one.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="serverinfo_usage" xml:space="preserve">
|
<data name="serverinfo_usage" xml:space="preserve">
|
||||||
<value>`{0}sinfo Some Server`</value>
|
<value>`{0}sinfo Some Server`</value>
|
||||||
@ -1198,7 +1198,7 @@
|
|||||||
<value>`{0}drawnew` or `{0}drawnew 5`</value>
|
<value>`{0}drawnew` or `{0}drawnew 5`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="shuffleplaylist_cmd" xml:space="preserve">
|
<data name="shuffleplaylist_cmd" xml:space="preserve">
|
||||||
<value>playlistshuffle plsh</value>
|
<value>shuffle sh plsh</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="shuffleplaylist_desc" xml:space="preserve">
|
<data name="shuffleplaylist_desc" xml:space="preserve">
|
||||||
<value>Shuffles the current playlist.</value>
|
<value>Shuffles the current playlist.</value>
|
||||||
@ -1377,15 +1377,6 @@
|
|||||||
<data name="typeadd_usage" xml:space="preserve">
|
<data name="typeadd_usage" xml:space="preserve">
|
||||||
<value>`{0}typeadd wordswords`</value>
|
<value>`{0}typeadd wordswords`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="poll_cmd" xml:space="preserve">
|
|
||||||
<value>poll</value>
|
|
||||||
</data>
|
|
||||||
<data name="poll_desc" xml:space="preserve">
|
|
||||||
<value>Creates a poll which requires users to send the number of the voting option to the bot.</value>
|
|
||||||
</data>
|
|
||||||
<data name="poll_usage" xml:space="preserve">
|
|
||||||
<value>`{0}poll Question?;Answer1;Answ 2;A_3`</value>
|
|
||||||
</data>
|
|
||||||
<data name="pollend_cmd" xml:space="preserve">
|
<data name="pollend_cmd" xml:space="preserve">
|
||||||
<value>pollend</value>
|
<value>pollend</value>
|
||||||
</data>
|
</data>
|
||||||
@ -1476,6 +1467,15 @@
|
|||||||
<data name="next_usage" xml:space="preserve">
|
<data name="next_usage" xml:space="preserve">
|
||||||
<value>`{0}n` or `{0}n 5`</value>
|
<value>`{0}n` or `{0}n 5`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="play_cmd" xml:space="preserve">
|
||||||
|
<value>play start</value>
|
||||||
|
</data>
|
||||||
|
<data name="play_desc" xml:space="preserve">
|
||||||
|
<value>If no arguments are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command</value>
|
||||||
|
</data>
|
||||||
|
<data name="play_usage" xml:space="preserve">
|
||||||
|
<value>`{0}play` or `{0}play 5` or `{0}play Dream Of Venice`</value>
|
||||||
|
</data>
|
||||||
<data name="stop_cmd" xml:space="preserve">
|
<data name="stop_cmd" xml:space="preserve">
|
||||||
<value>stop s</value>
|
<value>stop s</value>
|
||||||
</data>
|
</data>
|
||||||
@ -1534,7 +1534,7 @@
|
|||||||
<value>listqueue lq</value>
|
<value>listqueue lq</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="listqueue_desc" xml:space="preserve">
|
<data name="listqueue_desc" xml:space="preserve">
|
||||||
<value>Lists 15 currently queued songs per page. Default page is 1.</value>
|
<value>Lists 10 currently queued songs per page. Default page is 1.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="listqueue_usage" xml:space="preserve">
|
<data name="listqueue_usage" xml:space="preserve">
|
||||||
<value>`{0}lq` or `{0}lq 2`</value>
|
<value>`{0}lq` or `{0}lq 2`</value>
|
||||||
@ -2583,13 +2583,13 @@
|
|||||||
<data name="togethertube_usage" xml:space="preserve">
|
<data name="togethertube_usage" xml:space="preserve">
|
||||||
<value>`{0}totube`</value>
|
<value>`{0}totube`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="publicpoll_cmd" xml:space="preserve">
|
<data name="poll_cmd" xml:space="preserve">
|
||||||
<value>publicpoll ppoll</value>
|
<value>poll ppoll</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="publicpoll_desc" xml:space="preserve">
|
<data name="poll_desc" xml:space="preserve">
|
||||||
<value>Creates a public poll which requires users to type a number of the voting option in the channel command is ran in.</value>
|
<value>Creates a public poll which requires users to type a number of the voting option in the channel command is ran in.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="publicpoll_usage" xml:space="preserve">
|
<data name="poll_usage" xml:space="preserve">
|
||||||
<value>`{0}ppoll Question?;Answer1;Answ 2;A_3`</value>
|
<value>`{0}ppoll Question?;Answer1;Answ 2;A_3`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="autotranslang_cmd" xml:space="preserve">
|
<data name="autotranslang_cmd" xml:space="preserve">
|
||||||
@ -2790,6 +2790,15 @@
|
|||||||
<data name="hangman_usage" xml:space="preserve">
|
<data name="hangman_usage" xml:space="preserve">
|
||||||
<value>`{0}hangman` or `{0}hangman movies`</value>
|
<value>`{0}hangman` or `{0}hangman movies`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="hangmanstop_cmd" xml:space="preserve">
|
||||||
|
<value>hangmanstop</value>
|
||||||
|
</data>
|
||||||
|
<data name="hangmanstop_desc" xml:space="preserve">
|
||||||
|
<value>Stops the active hangman game on this channel if it exists.</value>
|
||||||
|
</data>
|
||||||
|
<data name="hangmanstop_usage" xml:space="preserve">
|
||||||
|
<value>`{0}hangmanstop`</value>
|
||||||
|
</data>
|
||||||
<data name="crstatsclear_cmd" xml:space="preserve">
|
<data name="crstatsclear_cmd" xml:space="preserve">
|
||||||
<value>crstatsclear</value>
|
<value>crstatsclear</value>
|
||||||
</data>
|
</data>
|
||||||
@ -3096,14 +3105,14 @@
|
|||||||
<data name="shardstats_usage" xml:space="preserve">
|
<data name="shardstats_usage" xml:space="preserve">
|
||||||
<value>`{0}shardstats` or `{0}shardstats 2`</value>
|
<value>`{0}shardstats` or `{0}shardstats 2`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="connectshard_cmd" xml:space="preserve">
|
<data name="restartshard_cmd" xml:space="preserve">
|
||||||
<value>connectshard</value>
|
<value>restartshard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="connectshard_desc" xml:space="preserve">
|
<data name="restartshard_desc" xml:space="preserve">
|
||||||
<value>Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors.</value>
|
<value>Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="connectshard_usage" xml:space="preserve">
|
<data name="restartshard_usage" xml:space="preserve">
|
||||||
<value>`{0}connectshard 2`</value>
|
<value>`{0}restartshard 2`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="shardid_cmd" xml:space="preserve">
|
<data name="shardid_cmd" xml:space="preserve">
|
||||||
<value>shardid</value>
|
<value>shardid</value>
|
||||||
@ -3258,6 +3267,15 @@
|
|||||||
<data name="warnlog_usage" xml:space="preserve">
|
<data name="warnlog_usage" xml:space="preserve">
|
||||||
<value>`{0}warnlog @b1nzy`</value>
|
<value>`{0}warnlog @b1nzy`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="warnlogall_cmd" xml:space="preserve">
|
||||||
|
<value>warnlogall</value>
|
||||||
|
</data>
|
||||||
|
<data name="warnlogall_desc" xml:space="preserve">
|
||||||
|
<value>See a list of all warnings on the server. 15 users per page.</value>
|
||||||
|
</data>
|
||||||
|
<data name="warnlogall_usage" xml:space="preserve">
|
||||||
|
<value>`{0}warnlogall` or `{0}warnlogall 2`</value>
|
||||||
|
</data>
|
||||||
<data name="warn_cmd" xml:space="preserve">
|
<data name="warn_cmd" xml:space="preserve">
|
||||||
<value>warn</value>
|
<value>warn</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -12,12 +12,12 @@ namespace NadekoBot.Services.Administration
|
|||||||
public class AutoAssignRoleService
|
public class AutoAssignRoleService
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
//guildid/roleid
|
//guildid/roleid
|
||||||
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
||||||
|
|
||||||
public AutoAssignRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
public AutoAssignRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -16,9 +16,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public GameVoiceChannelService(DiscordShardedClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_db = db;
|
_db = db;
|
||||||
|
@ -5,15 +5,18 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Administration
|
namespace NadekoBot.Services.Administration
|
||||||
{
|
{
|
||||||
public class GuildTimezoneService
|
public class GuildTimezoneService
|
||||||
{
|
{
|
||||||
|
//hack >.>
|
||||||
|
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
|
||||||
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
|
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public GuildTimezoneService(IEnumerable<GuildConfig> gcs, DbService db)
|
public GuildTimezoneService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||||
{
|
{
|
||||||
_timezones = gcs
|
_timezones = gcs
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
@ -21,6 +24,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
TimeZoneInfo tz;
|
TimeZoneInfo tz;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (x.TimeZoneId == null)
|
||||||
|
tz = null;
|
||||||
|
else
|
||||||
tz = TimeZoneInfo.FindSystemTimeZoneById(x.TimeZoneId);
|
tz = TimeZoneInfo.FindSystemTimeZoneById(x.TimeZoneId);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -33,6 +39,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
.ToDictionary(x => x.Item1, x => x.Item2)
|
.ToDictionary(x => x.Item1, x => x.Item2)
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
|
var curUser = client.CurrentUser;
|
||||||
|
if (curUser != null)
|
||||||
|
AllServices.TryAdd(curUser.Id, this);
|
||||||
_db = db;
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,24 @@ namespace NadekoBot.Services.Administration
|
|||||||
public class LogCommandService
|
public class LogCommandService
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
private string PrettyCurrentTime => $"【{DateTime.UtcNow:HH:mm:ss}】";
|
private string PrettyCurrentTime(IGuild g)
|
||||||
private string CurrentTime => $"{DateTime.UtcNow:HH:mm:ss}";
|
{
|
||||||
|
var time = DateTime.UtcNow;
|
||||||
|
if(g != null)
|
||||||
|
time = TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(g.Id));
|
||||||
|
return $"【{time:HH:mm:ss}】";
|
||||||
|
}
|
||||||
|
private string CurrentTime(IGuild g)
|
||||||
|
{
|
||||||
|
DateTime time = DateTime.UtcNow;
|
||||||
|
if (g != null)
|
||||||
|
time = TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(g.Id));
|
||||||
|
|
||||||
|
return $"{time:HH:mm:ss}";
|
||||||
|
}
|
||||||
|
|
||||||
public ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
|
public ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
|
||||||
|
|
||||||
@ -30,9 +43,10 @@ namespace NadekoBot.Services.Administration
|
|||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly MuteService _mute;
|
private readonly MuteService _mute;
|
||||||
private readonly ProtectionService _prot;
|
private readonly ProtectionService _prot;
|
||||||
|
private readonly GuildTimezoneService _tz;
|
||||||
|
|
||||||
public LogCommandService(DiscordShardedClient client, NadekoStrings strings,
|
public LogCommandService(DiscordSocketClient client, NadekoStrings strings,
|
||||||
IEnumerable<GuildConfig> gcs, DbService db, MuteService mute, ProtectionService prot)
|
IEnumerable<GuildConfig> gcs, DbService db, MuteService mute, ProtectionService prot, GuildTimezoneService tz)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
@ -40,6 +54,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
_db = db;
|
_db = db;
|
||||||
_mute = mute;
|
_mute = mute;
|
||||||
_prot = prot;
|
_prot = prot;
|
||||||
|
_tz = tz;
|
||||||
|
|
||||||
GuildLogSettings = gcs
|
GuildLogSettings = gcs
|
||||||
.ToDictionary(g => g.GuildId, g => g.LogSetting)
|
.ToDictionary(g => g.GuildId, g => g.LogSetting)
|
||||||
@ -51,14 +66,15 @@ namespace NadekoBot.Services.Administration
|
|||||||
{
|
{
|
||||||
var keys = PresenceUpdates.Keys.ToList();
|
var keys = PresenceUpdates.Keys.ToList();
|
||||||
|
|
||||||
await Task.WhenAll(keys.Select(async key =>
|
await Task.WhenAll(keys.Select(key =>
|
||||||
{
|
{
|
||||||
if (PresenceUpdates.TryRemove(key, out List<string> messages))
|
if (PresenceUpdates.TryRemove(key, out var msgs))
|
||||||
try { await key.SendConfirmAsync(GetText(key.Guild, "presence_updates"), string.Join(Environment.NewLine, messages)); }
|
|
||||||
catch
|
|
||||||
{
|
{
|
||||||
// ignored
|
var title = GetText(key.Guild, "presence_updates");
|
||||||
|
var desc = string.Join(Environment.NewLine, msgs);
|
||||||
|
return key.SendConfirmAsync(title, desc.TrimTo(2048));
|
||||||
}
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -74,7 +90,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
_client.UserUnbanned += _client_UserUnbanned;
|
_client.UserUnbanned += _client_UserUnbanned;
|
||||||
_client.UserJoined += _client_UserJoined;
|
_client.UserJoined += _client_UserJoined;
|
||||||
_client.UserLeft += _client_UserLeft;
|
_client.UserLeft += _client_UserLeft;
|
||||||
_client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
//_client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
||||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
||||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
||||||
_client.GuildMemberUpdated += _client_GuildUserUpdated;
|
_client.GuildMemberUpdated += _client_GuildUserUpdated;
|
||||||
@ -124,17 +140,20 @@ namespace NadekoBot.Services.Administration
|
|||||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||||
.AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true))
|
.AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true))
|
.AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true))
|
||||||
.WithFooter(fb => fb.WithText(CurrentTime))
|
.WithFooter(fb => fb.WithText(CurrentTime(g)))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
}
|
}
|
||||||
else if (before.AvatarId != after.AvatarId)
|
else if (before.AvatarId != after.AvatarId)
|
||||||
{
|
{
|
||||||
embed.WithTitle("👥" + GetText(g, "avatar_changed"))
|
embed.WithTitle("👥" + GetText(g, "avatar_changed"))
|
||||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||||
.WithThumbnailUrl(before.GetAvatarUrl())
|
.WithFooter(fb => fb.WithText(CurrentTime(g)))
|
||||||
.WithImageUrl(after.GetAvatarUrl())
|
|
||||||
.WithFooter(fb => fb.WithText(CurrentTime))
|
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
|
if (Uri.IsWellFormedUriString(before.GetAvatarUrl(), UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(before.GetAvatarUrl());
|
||||||
|
if (Uri.IsWellFormedUriString(after.GetAvatarUrl(), UriKind.Absolute))
|
||||||
|
embed.WithImageUrl(after.GetAvatarUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -244,7 +263,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
|
|
||||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
||||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||||
.WithFooter(fb => fb.WithText(CurrentTime))
|
.WithFooter(fb => fb.WithText(CurrentTime(usr.Guild)))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -287,7 +306,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
|
|
||||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
||||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||||
.WithFooter(fb => fb.WithText($"{CurrentTime}"))
|
.WithFooter(fb => fb.WithText($"{CurrentTime(usr.Guild)}"))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -335,7 +354,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}"))
|
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}"))
|
||||||
.WithTitle(GetText(logChannel.Guild, "users") + " " + punishment)
|
.WithTitle(GetText(logChannel.Guild, "users") + " " + punishment)
|
||||||
.WithDescription(string.Join("\n", users.Select(u => u.ToString())))
|
.WithDescription(string.Join("\n", users.Select(u => u.ToString())))
|
||||||
.WithFooter(fb => fb.WithText($"{CurrentTime}"))
|
.WithFooter(fb => fb.WithText(CurrentTime(logChannel.Guild)))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -354,21 +373,21 @@ namespace NadekoBot.Services.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting)
|
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting))
|
||||||
|| (logSetting.UserUpdatedId == null))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ITextChannel logChannel;
|
ITextChannel logChannel;
|
||||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
|
if (logSetting.UserUpdatedId != null && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) != null)
|
||||||
return;
|
{
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime))
|
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime(before.Guild)))
|
||||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
||||||
if (before.Nickname != after.Nickname)
|
if (before.Nickname != after.Nickname)
|
||||||
{
|
{
|
||||||
embed.WithAuthor(eab => eab.WithName("👥 " + GetText(logChannel.Guild, "nick_change")))
|
embed.WithAuthor(eab => eab.WithName("👥 " + GetText(logChannel.Guild, "nick_change")))
|
||||||
|
|
||||||
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
|
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
|
||||||
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
|
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
|
||||||
|
|
||||||
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (!before.Roles.SequenceEqual(after.Roles))
|
else if (!before.Roles.SequenceEqual(after.Roles))
|
||||||
{
|
{
|
||||||
@ -384,11 +403,30 @@ namespace NadekoBot.Services.Administration
|
|||||||
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_rem")))
|
embed.WithAuthor(eab => eab.WithName("⚔ " + GetText(logChannel.Guild, "user_role_rem")))
|
||||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logChannel = null;
|
||||||
|
if (logSetting.LogUserPresenceId != null && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserPresence)) != null)
|
||||||
|
{
|
||||||
|
if (before.Status != after.Status)
|
||||||
|
{
|
||||||
|
var str = "🎭" + Format.Code(PrettyCurrentTime(after.Guild)) +
|
||||||
|
GetText(logChannel.Guild, "user_status_change",
|
||||||
|
"👤" + Format.Bold(after.Username),
|
||||||
|
Format.Bold(after.Status.ToString()));
|
||||||
|
PresenceUpdates.AddOrUpdate(logChannel,
|
||||||
|
new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||||
|
}
|
||||||
|
else if (before.Game?.Name != after.Game?.Name)
|
||||||
|
{
|
||||||
|
var str = $"👾`{PrettyCurrentTime(after.Guild)}`👤__**{after.Username}**__ is now playing **{after.Game?.Name ?? "-"}**.";
|
||||||
|
PresenceUpdates.AddOrUpdate(logChannel,
|
||||||
|
new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
@ -417,7 +455,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
|
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime));
|
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime(before.Guild)));
|
||||||
|
|
||||||
var beforeTextChannel = cbefore as ITextChannel;
|
var beforeTextChannel = cbefore as ITextChannel;
|
||||||
var afterTextChannel = cafter as ITextChannel;
|
var afterTextChannel = cafter as ITextChannel;
|
||||||
@ -477,7 +515,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("🆕 " + title)
|
.WithTitle("🆕 " + title)
|
||||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(ch.Guild)))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -515,7 +553,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("🆕 " + title)
|
.WithTitle("🆕 " + title)
|
||||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(ch.Guild)))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
});
|
});
|
||||||
@ -549,23 +587,23 @@ namespace NadekoBot.Services.Administration
|
|||||||
string str = null;
|
string str = null;
|
||||||
if (beforeVch?.Guild == afterVch?.Guild)
|
if (beforeVch?.Guild == afterVch?.Guild)
|
||||||
{
|
{
|
||||||
str = "🎙" + Format.Code(PrettyCurrentTime) + GetText(logChannel.Guild, "user_vmoved",
|
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild, "user_vmoved",
|
||||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||||
Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? ""));
|
Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? ""));
|
||||||
}
|
}
|
||||||
else if (beforeVch == null)
|
else if (beforeVch == null)
|
||||||
{
|
{
|
||||||
str = "🎙" + Format.Code(PrettyCurrentTime) + GetText(logChannel.Guild, "user_vjoined",
|
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild, "user_vjoined",
|
||||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||||
Format.Bold(afterVch.Name ?? ""));
|
Format.Bold(afterVch.Name ?? ""));
|
||||||
}
|
}
|
||||||
else if (afterVch == null)
|
else if (afterVch == null)
|
||||||
{
|
{
|
||||||
str = "🎙" + Format.Code(PrettyCurrentTime) + GetText(logChannel.Guild, "user_vleft",
|
str = "🎙" + Format.Code(PrettyCurrentTime(usr.Guild)) + GetText(logChannel.Guild, "user_vleft",
|
||||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||||
Format.Bold(beforeVch.Name ?? ""));
|
Format.Bold(beforeVch.Name ?? ""));
|
||||||
}
|
}
|
||||||
if (str != null)
|
if (!string.IsNullOrWhiteSpace(str))
|
||||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -576,48 +614,48 @@ namespace NadekoBot.Services.Administration
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after)
|
//private Task _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after)
|
||||||
{
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild;
|
|
||||||
|
|
||||||
if (guild == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
|
|
||||||
|| (logSetting.LogUserPresenceId == null)
|
|
||||||
|| before.Status == after.Status)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ITextChannel logChannel;
|
|
||||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null)
|
|
||||||
return;
|
|
||||||
string str = "";
|
|
||||||
if (before.Status != after.Status)
|
|
||||||
str = "🎭" + Format.Code(PrettyCurrentTime) +
|
|
||||||
GetText(logChannel.Guild, "user_status_change",
|
|
||||||
"👤" + Format.Bold(usr.Username),
|
|
||||||
Format.Bold(after.Status.ToString()));
|
|
||||||
|
|
||||||
//if (before.Game?.Name != after.Game?.Name)
|
|
||||||
//{
|
//{
|
||||||
// if (str != "")
|
// var _ = Task.Run(async () =>
|
||||||
// str += "\n";
|
// {
|
||||||
// str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
|
// try
|
||||||
//}
|
// {
|
||||||
|
// var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild;
|
||||||
|
|
||||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
// if (guild == null)
|
||||||
}
|
// return;
|
||||||
catch
|
|
||||||
{
|
// if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
|
||||||
// ignored
|
// || (logSetting.LogUserPresenceId == null)
|
||||||
}
|
// || before.Status == after.Status)
|
||||||
});
|
// return;
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
// ITextChannel logChannel;
|
||||||
|
// if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null)
|
||||||
|
// return;
|
||||||
|
// string str = "";
|
||||||
|
// if (before.Status != after.Status)
|
||||||
|
// str = "🎭" + Format.Code(PrettyCurrentTime(g)) +
|
||||||
|
// GetText(logChannel.Guild, "user_status_change",
|
||||||
|
// "👤" + Format.Bold(usr.Username),
|
||||||
|
// Format.Bold(after.Status.ToString()));
|
||||||
|
|
||||||
|
// //if (before.Game?.Name != after.Game?.Name)
|
||||||
|
// //{
|
||||||
|
// // if (str != "")
|
||||||
|
// // str += "\n";
|
||||||
|
// // str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
|
||||||
|
// //}
|
||||||
|
|
||||||
|
// PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// // ignored
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
//}
|
||||||
|
|
||||||
private Task _client_UserLeft(IGuildUser usr)
|
private Task _client_UserLeft(IGuildUser usr)
|
||||||
{
|
{
|
||||||
@ -632,14 +670,17 @@ namespace NadekoBot.Services.Administration
|
|||||||
ITextChannel logChannel;
|
ITextChannel logChannel;
|
||||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
|
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
|
||||||
return;
|
return;
|
||||||
|
var embed = new EmbedBuilder()
|
||||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("❌ " + GetText(logChannel.Guild, "user_left"))
|
.WithTitle("❌ " + GetText(logChannel.Guild, "user_left"))
|
||||||
.WithThumbnailUrl(usr.GetAvatarUrl())
|
|
||||||
.WithDescription(usr.ToString())
|
.WithDescription(usr.ToString())
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)));
|
||||||
|
|
||||||
|
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||||
|
|
||||||
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -663,13 +704,17 @@ namespace NadekoBot.Services.Administration
|
|||||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
|
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("✅ " + GetText(logChannel.Guild, "user_joined"))
|
.WithTitle("✅ " + GetText(logChannel.Guild, "user_joined"))
|
||||||
.WithThumbnailUrl(usr.GetAvatarUrl())
|
|
||||||
.WithDescription($"{usr}")
|
.WithDescription($"{usr}")
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(usr.Guild)));
|
||||||
|
|
||||||
|
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||||
|
|
||||||
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
});
|
});
|
||||||
@ -689,14 +734,17 @@ namespace NadekoBot.Services.Administration
|
|||||||
ITextChannel logChannel;
|
ITextChannel logChannel;
|
||||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
|
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
|
||||||
return;
|
return;
|
||||||
|
var embed = new EmbedBuilder()
|
||||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("♻️ " + GetText(logChannel.Guild, "user_unbanned"))
|
.WithTitle("♻️ " + GetText(logChannel.Guild, "user_unbanned"))
|
||||||
.WithThumbnailUrl(usr.GetAvatarUrl())
|
|
||||||
.WithDescription(usr.ToString())
|
.WithDescription(usr.ToString())
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(guild)));
|
||||||
|
|
||||||
|
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||||
|
|
||||||
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
});
|
});
|
||||||
@ -716,13 +764,19 @@ namespace NadekoBot.Services.Administration
|
|||||||
ITextChannel logChannel;
|
ITextChannel logChannel;
|
||||||
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
|
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
|
||||||
return;
|
return;
|
||||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("🚫 " + GetText(logChannel.Guild, "user_banned"))
|
.WithTitle("🚫 " + GetText(logChannel.Guild, "user_banned"))
|
||||||
.WithThumbnailUrl(usr.GetAvatarUrl())
|
|
||||||
.WithDescription(usr.ToString())
|
.WithDescription(usr.ToString())
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
|
.WithFooter(efb => efb.WithText(CurrentTime(guild)));
|
||||||
|
|
||||||
|
var avatarUrl = usr.GetAvatarUrl();
|
||||||
|
|
||||||
|
if (Uri.IsWellFormedUriString(avatarUrl, UriKind.Absolute))
|
||||||
|
embed.WithThumbnailUrl(usr.GetAvatarUrl());
|
||||||
|
|
||||||
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
});
|
});
|
||||||
@ -757,7 +811,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
.WithDescription(msg.Author.ToString())
|
.WithDescription(msg.Author.ToString())
|
||||||
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime));
|
.WithFooter(efb => efb.WithText(CurrentTime(channel.Guild)));
|
||||||
if (msg.Attachments.Any())
|
if (msg.Attachments.Any())
|
||||||
embed.AddField(efb => efb.WithName(GetText(logChannel.Guild, "attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false));
|
embed.AddField(efb => efb.WithName(GetText(logChannel.Guild, "attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false));
|
||||||
|
|
||||||
@ -809,7 +863,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(GetText(logChannel.Guild, "new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(CurrentTime));
|
.WithFooter(efb => efb.WithText(CurrentTime(channel.Guild)));
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,10 @@ namespace NadekoBot.Services.Administration
|
|||||||
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
||||||
|
|
||||||
private readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public MuteService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
public MuteService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
@ -1,102 +1,75 @@
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.DataStructures.Replacements;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NadekoBot.Services.Music;
|
using NadekoBot.Services.Music;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Administration
|
namespace NadekoBot.Services.Administration
|
||||||
{
|
{
|
||||||
//todo 99 - Could make a placeholder service, which can work for any module
|
|
||||||
//and have replacements which are dependent on the types provided in the constructor
|
|
||||||
public class PlayingRotateService
|
public class PlayingRotateService
|
||||||
{
|
{
|
||||||
public List<PlayingStatus> RotatingStatusMessages { get; }
|
|
||||||
public volatile bool RotatingStatuses;
|
|
||||||
private readonly Timer _t;
|
private readonly Timer _t;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly BotConfig _bc;
|
|
||||||
private readonly MusicService _music;
|
private readonly MusicService _music;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly Replacer _rep;
|
||||||
|
private readonly DbService _db;
|
||||||
|
public BotConfig BotConfig { get; private set; } //todo load whole botconifg, not just for this service when you have the time
|
||||||
|
|
||||||
private class TimerState
|
private class TimerState
|
||||||
{
|
{
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayingRotateService(DiscordShardedClient client, BotConfig bc, MusicService music)
|
public PlayingRotateService(DiscordSocketClient client, BotConfig bc, MusicService music, DbService db)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_bc = bc;
|
BotConfig = bc;
|
||||||
_music = music;
|
_music = music;
|
||||||
|
_db = db;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_rep = new ReplacementBuilder()
|
||||||
RotatingStatusMessages = _bc.RotatingStatusMessages;
|
.WithClient(client)
|
||||||
RotatingStatuses = _bc.RotatingStatuses;
|
.WithStats(client)
|
||||||
|
.WithMusic(music)
|
||||||
|
.Build();
|
||||||
|
|
||||||
_t = new Timer(async (objState) =>
|
_t = new Timer(async (objState) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
BotConfig = uow.BotConfig.GetOrCreate();
|
||||||
|
}
|
||||||
var state = (TimerState)objState;
|
var state = (TimerState)objState;
|
||||||
if (!RotatingStatuses)
|
if (!BotConfig.RotatingStatuses)
|
||||||
return;
|
return;
|
||||||
if (state.Index >= RotatingStatusMessages.Count)
|
if (state.Index >= BotConfig.RotatingStatusMessages.Count)
|
||||||
state.Index = 0;
|
state.Index = 0;
|
||||||
|
|
||||||
if (!RotatingStatusMessages.Any())
|
if (!BotConfig.RotatingStatusMessages.Any())
|
||||||
return;
|
return;
|
||||||
var status = RotatingStatusMessages[state.Index++].Status;
|
var status = BotConfig.RotatingStatusMessages[state.Index++].Status;
|
||||||
if (string.IsNullOrWhiteSpace(status))
|
if (string.IsNullOrWhiteSpace(status))
|
||||||
return;
|
return;
|
||||||
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client,_music)));
|
|
||||||
var shards = _client.Shards;
|
status = _rep.Replace(status);
|
||||||
for (int i = 0; i < shards.Count; i++)
|
|
||||||
{
|
try { await client.SetGameAsync(status).ConfigureAwait(false); }
|
||||||
var curShard = shards.ElementAt(i);
|
|
||||||
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard)));
|
|
||||||
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_log.Warn(ex);
|
_log.Warn(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_log.Warn("Rotating playing status errored.\n" + ex);
|
_log.Warn("Rotating playing status errored.\n" + ex);
|
||||||
}
|
}
|
||||||
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, Func<DiscordShardedClient, MusicService, string>> PlayingPlaceholders { get; } =
|
|
||||||
new Dictionary<string, Func<DiscordShardedClient, MusicService, string>> {
|
|
||||||
{ "%servers%", (c, ms) => c.Guilds.Count.ToString()},
|
|
||||||
{ "%users%", (c, ms) => c.Guilds.Sum(s => s.Users.Count).ToString()},
|
|
||||||
{ "%playing%", (c, ms) => {
|
|
||||||
var cnt = ms.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
|
||||||
if (cnt != 1) return cnt.ToString();
|
|
||||||
try {
|
|
||||||
var mp = ms.MusicPlayers.FirstOrDefault();
|
|
||||||
return mp.Value.CurrentSong.SongInfo.Title;
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return "No songs";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ "%queued%", (c, ms) => ms.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
|
|
||||||
{ "%time%", (c, ms) => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
|
|
||||||
{ "%shardcount%", (c, ms) => c.Shards.Count.ToString() },
|
|
||||||
};
|
|
||||||
|
|
||||||
public Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =
|
|
||||||
new Dictionary<string, Func<DiscordSocketClient, string>> {
|
|
||||||
{ "%shardid%", (client) => client.ShardId.ToString()},
|
|
||||||
{ "%shardguilds%", (client) => client.Guilds.Count.ToString()},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,10 @@ namespace NadekoBot.Services.Administration
|
|||||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; };
|
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; };
|
||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly MuteService _mute;
|
private readonly MuteService _mute;
|
||||||
|
|
||||||
public ProtectionService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
|
public ProtectionService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -12,7 +12,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
public class PruneService
|
public class PruneService
|
||||||
{
|
{
|
||||||
//channelids where prunes are currently occuring
|
//channelids where prunes are currently occuring
|
||||||
private ConcurrentHashSet<ulong> _pruningChannels = new ConcurrentHashSet<ulong>();
|
private ConcurrentHashSet<ulong> _pruningGuilds = new ConcurrentHashSet<ulong>();
|
||||||
private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
||||||
|
|
||||||
public async Task PruneWhere(ITextChannel channel, int amount, Func<IMessage, bool> predicate)
|
public async Task PruneWhere(ITextChannel channel, int amount, Func<IMessage, bool> predicate)
|
||||||
@ -21,14 +21,14 @@ namespace NadekoBot.Services.Administration
|
|||||||
if (amount <= 0)
|
if (amount <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(amount));
|
throw new ArgumentOutOfRangeException(nameof(amount));
|
||||||
|
|
||||||
if (!_pruningChannels.Add(channel.Id))
|
if (!_pruningGuilds.Add(channel.GuildId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IMessage[] msgs;
|
IMessage[] msgs;
|
||||||
IMessage lastMessage = null;
|
IMessage lastMessage = null;
|
||||||
msgs = (await channel.GetMessagesAsync().Flatten()).Where(predicate).Take(amount).ToArray();
|
msgs = (await channel.GetMessagesAsync(50).Flatten()).Where(predicate).Take(amount).ToArray();
|
||||||
while (amount > 0 && msgs.Any())
|
while (amount > 0 && msgs.Any())
|
||||||
{
|
{
|
||||||
lastMessage = msgs[msgs.Length - 1];
|
lastMessage = msgs[msgs.Length - 1];
|
||||||
@ -52,9 +52,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
|
|
||||||
//this isn't good, because this still work as if i want to remove only specific user's messages from the last
|
//this isn't good, because this still work as if i want to remove only specific user's messages from the last
|
||||||
//100 messages, Maybe this needs to be reduced by msgs.Length instead of 100
|
//100 messages, Maybe this needs to be reduced by msgs.Length instead of 100
|
||||||
amount -= 100;
|
amount -= 50;
|
||||||
if(amount > 0)
|
if(amount > 0)
|
||||||
msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before).Flatten()).Where(predicate).Take(amount).ToArray();
|
msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).Flatten()).Where(predicate).Take(amount).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -63,7 +63,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_pruningChannels.TryRemove(channel.Id);
|
_pruningGuilds.TryRemove(channel.GuildId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public SlowmodeService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
public SlowmodeService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -23,11 +23,11 @@ namespace NadekoBot.Services.Administration
|
|||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly ILocalization _localization;
|
private readonly ILocalization _localization;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels = new ImmutableArray<AsyncLazy<IDMChannel>>();
|
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels = new ImmutableArray<AsyncLazy<IDMChannel>>();
|
||||||
|
|
||||||
public SelfService(DiscordShardedClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db,
|
public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db,
|
||||||
BotConfig bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds)
|
BotConfig bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds)
|
||||||
{
|
{
|
||||||
_bot = bot;
|
_bot = bot;
|
||||||
@ -39,12 +39,8 @@ namespace NadekoBot.Services.Administration
|
|||||||
_client = client;
|
_client = client;
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
|
|
||||||
using (var uow = _db.UnitOfWork)
|
ForwardDMs = bc.ForwardMessages;
|
||||||
{
|
ForwardDMsToAllOwners = bc.ForwardToAllOwners;
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
|
||||||
ForwardDMs = config.ForwardMessages;
|
|
||||||
ForwardDMsToAllOwners = config.ForwardToAllOwners;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -67,12 +63,8 @@ namespace NadekoBot.Services.Administration
|
|||||||
|
|
||||||
_client.Guilds.SelectMany(g => g.Users);
|
_client.Guilds.SelectMany(g => g.Users);
|
||||||
|
|
||||||
|
if(client.ShardId == 0)
|
||||||
LoadOwnerChannels();
|
LoadOwnerChannels();
|
||||||
|
|
||||||
if (!ownerChannels.Any())
|
|
||||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
|
||||||
else
|
|
||||||
_log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels.");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,11 +73,9 @@ namespace NadekoBot.Services.Administration
|
|||||||
var hs = new HashSet<ulong>(_creds.OwnerIds);
|
var hs = new HashSet<ulong>(_creds.OwnerIds);
|
||||||
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
||||||
|
|
||||||
foreach (var s in _client.Shards)
|
if (hs.Count > 0)
|
||||||
{
|
{
|
||||||
if (hs.Count == 0)
|
foreach (var g in _client.Guilds)
|
||||||
break;
|
|
||||||
foreach (var g in s.Guilds)
|
|
||||||
{
|
{
|
||||||
if (hs.Count == 0)
|
if (hs.Count == 0)
|
||||||
break;
|
break;
|
||||||
@ -94,7 +84,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
{
|
{
|
||||||
if (hs.Remove(u.Id))
|
if (hs.Remove(u.Id))
|
||||||
{
|
{
|
||||||
channels.Add(u.Id, new AsyncLazy<IDMChannel>(async () => await u.CreateDMChannelAsync()));
|
channels.Add(u.Id, new AsyncLazy<IDMChannel>(async () => await u.GetOrCreateDMChannelAsync()));
|
||||||
if (hs.Count == 0)
|
if (hs.Count == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -105,10 +95,15 @@ namespace NadekoBot.Services.Administration
|
|||||||
ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key))
|
ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key))
|
||||||
.Select(x => x.Value)
|
.Select(x => x.Value)
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
if (!ownerChannels.Any())
|
||||||
|
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||||
|
else
|
||||||
|
_log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// forwards dms
|
// forwards dms
|
||||||
public async Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg)
|
public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
|
||||||
{
|
{
|
||||||
if (msg.Channel is IDMChannel && ForwardDMs && ownerChannels.Length > 0)
|
if (msg.Channel is IDMChannel && ForwardDMs && ownerChannels.Length > 0)
|
||||||
{
|
{
|
||||||
|
@ -14,11 +14,11 @@ namespace NadekoBot.Services.Administration
|
|||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
||||||
|
|
||||||
public VcRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
public VcRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_db = db;
|
_db = db;
|
||||||
|
@ -20,12 +20,12 @@ namespace NadekoBot.Services.Administration
|
|||||||
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
|
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public VplusTService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
|
public VplusTService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
|
||||||
DbService db)
|
DbService db)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -17,7 +18,7 @@ namespace NadekoBot.Services.ClashOfClans
|
|||||||
// shouldn't be here
|
// shouldn't be here
|
||||||
public class ClashOfClansService
|
public class ClashOfClansService
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly ILocalization _localization;
|
private readonly ILocalization _localization;
|
||||||
private readonly NadekoStrings _strings;
|
private readonly NadekoStrings _strings;
|
||||||
@ -25,18 +26,18 @@ namespace NadekoBot.Services.ClashOfClans
|
|||||||
|
|
||||||
public ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; }
|
public ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; }
|
||||||
|
|
||||||
public ClashOfClansService(DiscordShardedClient client, DbService db, ILocalization localization, NadekoStrings strings)
|
public ClashOfClansService(DiscordSocketClient client, DbService db,
|
||||||
|
ILocalization localization, NadekoStrings strings, IUnitOfWork uow,
|
||||||
|
List<long> guilds)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_db = db;
|
_db = db;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_strings = strings;
|
_strings = strings;
|
||||||
|
|
||||||
using (var uow = _db.UnitOfWork)
|
|
||||||
{
|
|
||||||
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
|
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
|
||||||
uow.ClashOfClans
|
uow.ClashOfClans
|
||||||
.GetAllWars()
|
.GetAllWars(guilds)
|
||||||
.Select(cw =>
|
.Select(cw =>
|
||||||
{
|
{
|
||||||
cw.Channel = _client.GetGuild(cw.GuildId)?
|
cw.Channel = _client.GetGuild(cw.GuildId)?
|
||||||
@ -46,7 +47,6 @@ namespace NadekoBot.Services.ClashOfClans
|
|||||||
.Where(cw => cw.Channel != null)
|
.Where(cw => cw.Channel != null)
|
||||||
.GroupBy(cw => cw.GuildId)
|
.GroupBy(cw => cw.GuildId)
|
||||||
.ToDictionary(g => g.Key, g => g.ToList()));
|
.ToDictionary(g => g.Key, g => g.ToList()));
|
||||||
}
|
|
||||||
|
|
||||||
checkWarTimer = new Timer(async _ =>
|
checkWarTimer = new Timer(async _ =>
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
public const int GlobalCommandsCooldown = 750;
|
public const int GlobalCommandsCooldown = 750;
|
||||||
|
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly CommandService _commandService;
|
private readonly CommandService _commandService;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
@ -48,7 +48,7 @@ namespace NadekoBot.Services
|
|||||||
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||||
private readonly Timer _clearUsersOnShortCooldown;
|
private readonly Timer _clearUsersOnShortCooldown;
|
||||||
|
|
||||||
public CommandHandler(DiscordShardedClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
|
public CommandHandler(DiscordSocketClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_commandService = commandService;
|
_commandService = commandService;
|
||||||
@ -355,7 +355,7 @@ namespace NadekoBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var execResult = await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
|
var execResult = (ExecuteResult)(await commands[i].ExecuteAsync(context, parseResult, serviceProvider));
|
||||||
if (execResult.Exception != null && (!(execResult.Exception is HttpException he) || he.DiscordCode != 50013))
|
if (execResult.Exception != null && (!(execResult.Exception is HttpException he) || he.DiscordCode != 50013))
|
||||||
{
|
{
|
||||||
lock (errorLogLock)
|
lock (errorLogLock)
|
||||||
|
@ -10,6 +10,7 @@ using System;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Services.Permissions;
|
using NadekoBot.Services.Permissions;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database;
|
||||||
|
|
||||||
namespace NadekoBot.Services.CustomReactions
|
namespace NadekoBot.Services.CustomReactions
|
||||||
{
|
{
|
||||||
@ -22,13 +23,14 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly PermissionService _perms;
|
private readonly PermissionService _perms;
|
||||||
private readonly CommandHandler _cmd;
|
private readonly CommandHandler _cmd;
|
||||||
private readonly BotConfig _bc;
|
private readonly BotConfig _bc;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public CustomReactionsService(PermissionService perms, DbService db,
|
public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings,
|
||||||
DiscordShardedClient client, CommandHandler cmd, BotConfig bc)
|
DiscordSocketClient client, CommandHandler cmd, BotConfig bc, IUnitOfWork uow)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_db = db;
|
_db = db;
|
||||||
@ -36,17 +38,12 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
_perms = perms;
|
_perms = perms;
|
||||||
_cmd = cmd;
|
_cmd = cmd;
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
|
_strings = strings;
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
|
||||||
using (var uow = _db.UnitOfWork)
|
|
||||||
{
|
|
||||||
var items = uow.CustomReactions.GetAll();
|
var items = uow.CustomReactions.GetAll();
|
||||||
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
|
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
|
||||||
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
||||||
}
|
}
|
||||||
sw.Stop();
|
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearStats() => ReactionStats.Clear();
|
public void ClearStats() => ReactionStats.Clear();
|
||||||
|
|
||||||
@ -98,7 +95,7 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
return greaction;
|
return greaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg)
|
public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg)
|
||||||
{
|
{
|
||||||
// maybe this message is a custom reaction
|
// maybe this message is a custom reaction
|
||||||
var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false);
|
var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false);
|
||||||
@ -114,7 +111,7 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
{
|
{
|
||||||
if (pc.Verbose)
|
if (pc.Verbose)
|
||||||
{
|
{
|
||||||
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), sg)}** is preventing this action.";
|
var returnMsg = _strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)));
|
||||||
try { await msg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
try { await msg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
||||||
_log.Info(returnMsg);
|
_log.Info(returnMsg);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using AngleSharp.Dom.Html;
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.DataStructures.Replacements;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System;
|
using System;
|
||||||
@ -15,62 +16,12 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static Dictionary<string, Func<IUserMessage, string, string>> responsePlaceholders = new Dictionary<string, Func<IUserMessage, string, string>>()
|
|
||||||
{
|
|
||||||
{"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } },
|
|
||||||
{"%rnduser%", (ctx, client) => {
|
|
||||||
//var ch = ctx.Channel as ITextChannel;
|
|
||||||
//if(ch == null)
|
|
||||||
// return "";
|
|
||||||
|
|
||||||
//var g = ch.Guild as SocketGuild;
|
|
||||||
//if(g == null)
|
|
||||||
// return "";
|
|
||||||
//try {
|
|
||||||
// var usr = g.Users.Skip(new NadekoRandom().Next(0, g.Users.Count)).FirstOrDefault();
|
|
||||||
// return usr.Mention;
|
|
||||||
//}
|
|
||||||
//catch {
|
|
||||||
return "[%rnduser% is temp. disabled]";
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var users = g.Users.ToArray();
|
|
||||||
|
|
||||||
//return users[new NadekoRandom().Next(0, users.Length-1)].Mention;
|
|
||||||
} },
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>> placeholders = new Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>>()
|
|
||||||
{
|
|
||||||
{"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } },
|
|
||||||
{"%user%", (ctx, client) => { return ctx.Author.Mention; } },
|
|
||||||
//{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } }
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly Regex rngRegex = new Regex("%rng(?:(?<from>(?:-)?\\d+)-(?<to>(?:-)?\\d+))?%", RegexOptions.Compiled);
|
|
||||||
private static readonly Regex imgRegex = new Regex("%(img|image):(?<tag>.*?)%", RegexOptions.Compiled);
|
private static readonly Regex imgRegex = new Regex("%(img|image):(?<tag>.*?)%", RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly NadekoRandom rng = new NadekoRandom();
|
private static readonly NadekoRandom rng = new NadekoRandom();
|
||||||
|
|
||||||
public static Dictionary<Regex, Func<Match, Task<string>>> regexPlaceholders = new Dictionary<Regex, Func<Match, Task<string>>>()
|
public static Dictionary<Regex, Func<Match, Task<string>>> regexPlaceholders = new Dictionary<Regex, Func<Match, Task<string>>>()
|
||||||
{
|
{
|
||||||
{ rngRegex, (match) => {
|
|
||||||
int from = 0;
|
|
||||||
int.TryParse(match.Groups["from"].ToString(), out from);
|
|
||||||
|
|
||||||
int to = 0;
|
|
||||||
int.TryParse(match.Groups["to"].ToString(), out to);
|
|
||||||
|
|
||||||
if(from == 0 && to == 0)
|
|
||||||
{
|
|
||||||
return Task.FromResult(rng.Next(0, 11).ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(from >= to)
|
|
||||||
return Task.FromResult(string.Empty);
|
|
||||||
|
|
||||||
return Task.FromResult(rng.Next(from,to+1).ToString());
|
|
||||||
} },
|
|
||||||
{ imgRegex, async (match) => {
|
{ imgRegex, async (match) => {
|
||||||
var tag = match.Groups["tag"].ToString();
|
var tag = match.Groups["tag"].ToString();
|
||||||
if(string.IsNullOrWhiteSpace(tag))
|
if(string.IsNullOrWhiteSpace(tag))
|
||||||
@ -94,31 +45,26 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
} }
|
} }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordShardedClient client)
|
private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
foreach (var ph in placeholders)
|
var rep = new ReplacementBuilder()
|
||||||
{
|
.WithUser(ctx.Author)
|
||||||
if (str.Contains(ph.Key))
|
.WithClient(client)
|
||||||
str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx, client));
|
.Build();
|
||||||
}
|
|
||||||
|
str = rep.Replace(str.ToLowerInvariant());
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger)
|
private static async Task<string> ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordSocketClient client, string resolvedTrigger)
|
||||||
{
|
{
|
||||||
foreach (var ph in placeholders)
|
var rep = new ReplacementBuilder()
|
||||||
{
|
.WithDefault(ctx.Author, ctx.Channel, (ctx.Channel as ITextChannel)?.Guild, client)
|
||||||
var lowerKey = ph.Key.ToLowerInvariant();
|
.WithOverride("%target%", () => ctx.Content.Substring(resolvedTrigger.Length).Trim())
|
||||||
if (str.Contains(lowerKey))
|
.Build();
|
||||||
str = str.Replace(lowerKey, ph.Value(ctx, client));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var ph in responsePlaceholders)
|
str = rep.Replace(str);
|
||||||
{
|
|
||||||
var lowerKey = ph.Key.ToLowerInvariant();
|
|
||||||
if (str.Contains(lowerKey))
|
|
||||||
str = str.Replace(lowerKey, ph.Value(ctx, resolvedTrigger));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var ph in regexPlaceholders)
|
foreach (var ph in regexPlaceholders)
|
||||||
{
|
{
|
||||||
@ -127,23 +73,30 @@ namespace NadekoBot.Services.CustomReactions
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client)
|
public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client)
|
||||||
=> cr.Trigger.ResolveTriggerString(ctx, client);
|
=> cr.Trigger.ResolveTriggerString(ctx, client);
|
||||||
|
|
||||||
public static Task<string > ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client)
|
public static Task<string > ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client)
|
||||||
=> cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client));
|
=> cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client));
|
||||||
|
|
||||||
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context, DiscordShardedClient client, CustomReactionsService crs)
|
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, CustomReactionsService crs)
|
||||||
{
|
{
|
||||||
var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel;
|
var channel = cr.DmResponse ? await ctx.Author.GetOrCreateDMChannelAsync() : ctx.Channel;
|
||||||
|
|
||||||
crs.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old);
|
crs.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old);
|
||||||
|
|
||||||
if (CREmbed.TryParse(cr.Response, out CREmbed crembed))
|
if (CREmbed.TryParse(cr.Response, out CREmbed crembed))
|
||||||
{
|
{
|
||||||
return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "");
|
var rep = new ReplacementBuilder()
|
||||||
|
.WithDefault(ctx.Author, ctx.Channel, (ctx.Channel as ITextChannel)?.Guild, client)
|
||||||
|
.WithOverride("%target%", () => ctx.Content.Substring(cr.Trigger.ResolveTriggerString(ctx, client).Length).Trim())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
rep.Replace(crembed);
|
||||||
|
|
||||||
|
return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText?.SanitizeMentions() ?? "");
|
||||||
}
|
}
|
||||||
return await channel.SendMessageAsync((await cr.ResponseWithContextAsync(context, client)).SanitizeMentions());
|
return await channel.SendMessageAsync((await cr.ResponseWithContextAsync(ctx, client)).SanitizeMentions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
public enum MusicType
|
public enum MusicType
|
||||||
{
|
{
|
||||||
Radio,
|
Radio,
|
||||||
Normal,
|
YouTube,
|
||||||
Local,
|
Local,
|
||||||
Soundcloud
|
Soundcloud
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ namespace NadekoBot.Services.Database
|
|||||||
{
|
{
|
||||||
var optionsBuilder = new DbContextOptionsBuilder();
|
var optionsBuilder = new DbContextOptionsBuilder();
|
||||||
optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db");
|
optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db");
|
||||||
return new NadekoContext(optionsBuilder.Options);
|
var ctx = new NadekoContext(optionsBuilder.Options);
|
||||||
|
ctx.Database.SetCommandTimeout(60);
|
||||||
|
return ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,6 @@ namespace NadekoBot.Services.Database.Repositories
|
|||||||
{
|
{
|
||||||
public interface IClashOfClansRepository : IRepository<ClashWar>
|
public interface IClashOfClansRepository : IRepository<ClashWar>
|
||||||
{
|
{
|
||||||
IEnumerable<ClashWar> GetAllWars();
|
IEnumerable<ClashWar> GetAllWars(List<long> guilds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ namespace NadekoBot.Services.Database.Repositories
|
|||||||
GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
|
GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
|
||||||
GuildConfig LogSettingsFor(ulong guildId);
|
GuildConfig LogSettingsFor(ulong guildId);
|
||||||
IEnumerable<GuildConfig> OldPermissionsForAll();
|
IEnumerable<GuildConfig> OldPermissionsForAll();
|
||||||
IEnumerable<GuildConfig> GetAllGuildConfigs();
|
IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds);
|
||||||
IEnumerable<FollowedStream> GetAllFollowedStreams();
|
IEnumerable<FollowedStream> GetAllFollowedStreams(List<long> included);
|
||||||
void SetCleverbotEnabled(ulong id, bool cleverbotEnabled);
|
void SetCleverbotEnabled(ulong id, bool cleverbotEnabled);
|
||||||
IEnumerable<GuildConfig> Permissionsv2ForAll();
|
IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include);
|
||||||
GuildConfig GcWithPermissionsv2For(ulong guildId);
|
GuildConfig GcWithPermissionsv2For(ulong guildId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Database.Repositories
|
namespace NadekoBot.Services.Database.Repositories
|
||||||
{
|
{
|
||||||
public interface IReminderRepository : IRepository<Reminder>
|
public interface IReminderRepository : IRepository<Reminder>
|
||||||
{
|
{
|
||||||
|
IEnumerable<Reminder> GetIncludedReminders(List<long> guildIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,6 @@ namespace NadekoBot.Services.Database.Repositories
|
|||||||
{
|
{
|
||||||
Warning[] For(ulong guildId, ulong userId);
|
Warning[] For(ulong guildId, ulong userId);
|
||||||
Task ForgiveAll(ulong guildId, ulong userId, string mod);
|
Task ForgiveAll(ulong guildId, ulong userId, string mod);
|
||||||
|
Warning[] GetForGuild(ulong id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ClashWar> GetAllWars()
|
public IEnumerable<ClashWar> GetAllWars(List<long> guilds)
|
||||||
{
|
{
|
||||||
var toReturn = _set.Include(cw => cw.Bases)
|
var toReturn = _set
|
||||||
|
.Where(cw => guilds.Contains((long)cw.GuildId))
|
||||||
|
.Include(cw => cw.Bases)
|
||||||
.ToList();
|
.ToList();
|
||||||
toReturn.ForEach(cw => cw.Bases = cw.Bases.Where(w => w.SequenceNumber != null).OrderBy(w => w.SequenceNumber).ToList());
|
toReturn.ForEach(cw => cw.Bases = cw.Bases.Where(w => w.SequenceNumber != null).OrderBy(w => w.SequenceNumber).ToList());
|
||||||
return toReturn;
|
return toReturn;
|
||||||
|
@ -24,8 +24,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<GuildConfig> GetAllGuildConfigs() =>
|
public IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds) =>
|
||||||
_set.Include(gc => gc.LogSetting)
|
_set
|
||||||
|
.Where(gc => availableGuilds.Contains((long)gc.GuildId))
|
||||||
|
.Include(gc => gc.LogSetting)
|
||||||
.ThenInclude(ls => ls.IgnoredChannels)
|
.ThenInclude(ls => ls.IgnoredChannels)
|
||||||
.Include(gc => gc.MutedUsers)
|
.Include(gc => gc.MutedUsers)
|
||||||
.Include(gc => gc.CommandAliases)
|
.Include(gc => gc.CommandAliases)
|
||||||
@ -42,6 +44,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
.Include(gc => gc.SlowmodeIgnoredUsers)
|
.Include(gc => gc.SlowmodeIgnoredUsers)
|
||||||
.Include(gc => gc.AntiSpamSetting)
|
.Include(gc => gc.AntiSpamSetting)
|
||||||
.ThenInclude(x => x.IgnoredChannels)
|
.ThenInclude(x => x.IgnoredChannels)
|
||||||
|
.Include(gc => gc.FollowedStreams)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -134,9 +137,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
return query.ToList();
|
return query.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<GuildConfig> Permissionsv2ForAll()
|
public IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include)
|
||||||
{
|
{
|
||||||
var query = _set
|
var query = _set
|
||||||
|
.Where(x => include.Contains((long)x.GuildId))
|
||||||
.Include(gc => gc.Permissions);
|
.Include(gc => gc.Permissions);
|
||||||
|
|
||||||
return query.ToList();
|
return query.ToList();
|
||||||
@ -167,8 +171,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<FollowedStream> GetAllFollowedStreams() =>
|
public IEnumerable<FollowedStream> GetAllFollowedStreams(List<long> included) =>
|
||||||
_set.Include(gc => gc.FollowedStreams)
|
_set
|
||||||
|
.Where(gc => included.Contains((long)gc.GuildId))
|
||||||
|
.Include(gc => gc.FollowedStreams)
|
||||||
.SelectMany(gc => gc.FollowedStreams)
|
.SelectMany(gc => gc.FollowedStreams)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Database.Repositories.Impl
|
namespace NadekoBot.Services.Database.Repositories.Impl
|
||||||
{
|
{
|
||||||
@ -8,5 +11,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
public ReminderRepository(DbContext context) : base(context)
|
public ReminderRepository(DbContext context) : base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Reminder> GetIncludedReminders(List<long> guildIds)
|
||||||
|
{
|
||||||
|
return _set.Where(x => guildIds.Contains((long)x.ServerId)).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Database.Repositories.Impl
|
namespace NadekoBot.Services.Database.Repositories.Impl
|
||||||
{
|
{
|
||||||
@ -32,5 +33,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
})
|
})
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Warning[] GetForGuild(ulong id)
|
||||||
|
{
|
||||||
|
return _set.Where(x => x.GuildId == id).ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,21 @@ namespace NadekoBot.Services
|
|||||||
public NadekoContext GetDbContext()
|
public NadekoContext GetDbContext()
|
||||||
{
|
{
|
||||||
var context = new NadekoContext(options);
|
var context = new NadekoContext(options);
|
||||||
|
context.Database.SetCommandTimeout(60);
|
||||||
context.Database.Migrate();
|
context.Database.Migrate();
|
||||||
context.EnsureSeedData();
|
context.EnsureSeedData();
|
||||||
|
|
||||||
|
//set important sqlite stuffs
|
||||||
|
var conn = context.Database.GetDbConnection();
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
context.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL");
|
||||||
|
using (var com = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
com.CommandText = "PRAGMA journal_mode=WAL; PRAGMA synchronous=OFF";
|
||||||
|
com.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ namespace NadekoBot.Services.Discord
|
|||||||
public event Action<SocketReaction> OnReactionRemoved = delegate { };
|
public event Action<SocketReaction> OnReactionRemoved = delegate { };
|
||||||
public event Action OnReactionsCleared = delegate { };
|
public event Action OnReactionsCleared = delegate { };
|
||||||
|
|
||||||
public ReactionEventWrapper(DiscordShardedClient client, IUserMessage msg)
|
public ReactionEventWrapper(DiscordSocketClient client, IUserMessage msg)
|
||||||
{
|
{
|
||||||
Message = msg ?? throw new ArgumentNullException(nameof(msg));
|
Message = msg ?? throw new ArgumentNullException(nameof(msg));
|
||||||
_client = client;
|
_client = client;
|
||||||
@ -69,7 +69,7 @@ namespace NadekoBot.Services.Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool disposing = false;
|
private bool disposing = false;
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
@ -15,19 +15,22 @@ namespace NadekoBot.Services.Games
|
|||||||
{
|
{
|
||||||
public class ChatterBotService : IEarlyBlockingExecutor
|
public class ChatterBotService : IEarlyBlockingExecutor
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly PermissionService _perms;
|
private readonly PermissionService _perms;
|
||||||
private readonly CommandHandler _cmd;
|
private readonly CommandHandler _cmd;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; }
|
public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; }
|
||||||
|
|
||||||
public ChatterBotService(DiscordShardedClient client, PermissionService perms, IEnumerable<GuildConfig> gcs, CommandHandler cmd)
|
public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable<GuildConfig> gcs,
|
||||||
|
CommandHandler cmd, NadekoStrings strings)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_perms = perms;
|
_perms = perms;
|
||||||
_cmd = cmd;
|
_cmd = cmd;
|
||||||
|
_strings = strings;
|
||||||
|
|
||||||
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
||||||
gcs.Where(gc => gc.CleverbotEnabled)
|
gcs.Where(gc => gc.CleverbotEnabled)
|
||||||
@ -83,7 +86,7 @@ namespace NadekoBot.Services.Games
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg)
|
public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage usrMsg)
|
||||||
{
|
{
|
||||||
if (!(guild is SocketGuild sg))
|
if (!(guild is SocketGuild sg))
|
||||||
return false;
|
return false;
|
||||||
@ -101,8 +104,7 @@ namespace NadekoBot.Services.Games
|
|||||||
{
|
{
|
||||||
if (pc.Verbose)
|
if (pc.Verbose)
|
||||||
{
|
{
|
||||||
//todo move this to permissions
|
var returnMsg = _strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)));
|
||||||
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), sg)}** is preventing this action.";
|
|
||||||
try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
||||||
_log.Info(returnMsg);
|
_log.Info(returnMsg);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user