Compare commits

..

14 Commits
3.0.3 ... 3.0.5

Author SHA1 Message Date
Kwoth
2d92424dd4 Version upped to 3.0.5 2021-09-20 19:45:13 +02:00
Kwoth
ffba03adbe Added guides on the different ways to run the bot on linux - contributed by Bark Ranger 2021-09-18 06:19:53 +02:00
Kwoth
76ebb87fb5 updated docs formatting and windows from source update guide 2021-09-17 19:02:18 +02:00
Kwoth
4a50c30c56 Fixed .logserver - should no longer throw an exception if you had no logsettings previously 2021-09-17 17:19:11 +02:00
Kwoth
e70a91ae60 Fixed images not automatically reloading on startup if the keys don't exist 2021-09-17 17:10:38 +02:00
Kwoth
3470762b30 woops, missed an extra bracket 2021-09-17 01:08:20 +02:00
Kwoth
2cbb4ecd3d Version upped to 3.0.4 2021-09-16 23:10:19 +02:00
Kwoth
619bee811d Fixed most of the commands which used wrong error color for confirm messages 2021-09-16 23:09:17 +02:00
Kwoth
a09be96200 Added DmHelpTextKeywords to data/bot.yml
- Bot now sends dm help text ONLY if the message contains one of the keywords specified
  - If no keywords are specified, bot will reply to every DM (like before)
- Fixed several commands which used error color for success confirmation messages
2021-09-16 22:52:04 +02:00
Kwoth
81254ed5f6 Added %server.boosters% and %server.boost_level% placeholders 2021-09-16 19:22:05 +02:00
Kwoth
d82e3bd444 Merge branch 'v3' of https://gitlab.com/kwoth/nadekobot into v3 2021-09-16 19:09:51 +02:00
Kwoth
9011646b02 Update responses.pt-BR.json (POEditor.com) 2021-09-16 17:09:46 +00:00
Kwoth
2a1f45819d .waifugift pagination fixed - maximum number of pages properly scales with the number of items 2021-09-16 19:09:19 +02:00
Kwoth
d2d0cb9e03 - Possible fix for .repeat bug
- Slight adjustment for repeater logic
  - Timer should no longer increase on some repeaters
  - Repeaters should no longer have periods when they're missing from the list
2021-09-16 07:19:08 +02:00
40 changed files with 1350 additions and 1081 deletions

View File

@@ -4,7 +4,27 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
## Unreleased
## [3.0.5] - 20.09.2021
### Fixed
- Fixed images not automatically reloading on startup if the keys don't exist
- Fixed `.logserver` - it should no longer throw an exception if you had no logsettings previously
## [3.0.4] - 16.09.2021
### Added
- Fully translated to Brazilian Portuguese 🎉
- Added `%server.boosters%` and `%server.boost_level%` placeholders
- Added `DmHelpTextKeywords` to `data/bot.yml`
- Bot now sends dm help text ONLY if the message contains one of the keywords specified
- If no keywords are specified, bot will reply to every DM (like before)
### Fixed
- Possible fix for `.repeat` bug
- Slight adjustment for repeater logic
- Timer should no longer increase on some repeaters
- Repeaters should no longer have periods when they're missing from the list
- Fixed several commands which used error color for success confirmation messages
## [3.0.3] - 15.09.2021

View File

@@ -1,3 +1,35 @@
# Setting up NadekoBot with Docker
Soon:tm:
# DO NOT USE YET - WORK IN PROGRESS
Upgrade from 2.x to v3 does not work because the file is mount readonly
### Docker Compose
```yml
version: "3.7"
services:
nadeko:
image: registry.gitlab.com/veovis/nadekobot:v3-docker
depends_on:
- redis
environment:
TZ: Europe/Paris
#NadekoBot_RedisOptions: redis,name=nadeko
#NadekoBot_ShardRunCommand: dotnet
#NadekoBot_ShardRunArguments: /app/NadekoBot.dll {0} {1}
volumes:
- /srv/nadeko/conf/creds.yml:/app/creds.yml:ro
- /srv/nadeko/data:/app/data
redis:
image: redis:4-alpine
sysctls:
- net.core.somaxconn=511
command: redis-server --maxmemory 32M --maxmemory-policy volatile-lru
volumes:
- /srv/nadeko/redis-data:/data
```
### Updating
- `cd /srv/nadeko`
- `docker-compose pull`
- `docker-compose up -d`

View File

@@ -16,12 +16,12 @@ Open Terminal (if you're on an installation with a window manager) and navigate
4. Exit the installer in order to set up your `creds.yml`
5. Copy the creds.yml template `cp nadekobot/output/creds_example.yml nadekobot/output/creds.yml`
6. Open `nadekobot/output/creds.yml` with your favorite text editor. We will use nano here
- `nano nadekobot/output/creds.yml`
- `nano nadekobot/output/creds.yml`
7. [Enter your bot's token](../../creds-guide)
- After you're done, you can close nano (and save the file) by inputting, in order
- `CTRL` + `X`
- `Y`
- `Enter`
- After you're done, you can close nano (and save the file) by inputting, in order
- `CTRL` + `X`
- `Y`
- `Enter`
8. Run the bot (type `3` and press enter)
##### Update Instructions
@@ -37,51 +37,51 @@ Open Terminal (if you're on an installation with a window manager) and navigate
##### Installation Instructions
1. Download the latest release from <https://gitlab.com/Kwoth/nadekobot/-/releases>
- Look for the file called "X.XX.X-linux-x64-build.tar" (where X.XX.X is a series of numbers) and download it
- Look for the file called "X.XX.X-linux-x64-build.tar" (where X.XX.X is a series of numbers) and download it
2. Untar it
- ⚠ Make sure that you change X.XX.X to the same series of numbers as in step 1!
- `tar xf X.XX.X-linux-x64-build.tar`
- ⚠ Make sure that you change X.XX.X to the same series of numbers as in step 1!
- `tar xf X.XX.X-linux-x64-build.tar`
3. Rename the `nadekobot-linux-x64` to `nadekobot`
- `mv nadekobot-linux-x64 nadekobot`
- `mv nadekobot-linux-x64 nadekobot`
4. Move into nadekobot directory and make NadekoBot executable
- `cd nadekobot && chmod +x NadekoBot`
- `cd nadekobot && chmod +x NadekoBot`
5. Copy the creds.yml template
- `cp creds_example.yml creds.yml`
- `cp creds_example.yml creds.yml`
6. Open `creds.yml` with your favorite text editor. We will use nano here
- `nano nadekobot/output/creds.yml`
- `nano nadekobot/output/creds.yml`
8. [Enter your bot's token](#creds-guide)
- After you're done, you can close nano (and save the file) by inputting, in order
- `CTRL` + `X`
- `Y`
- `Enter`
- After you're done, you can close nano (and save the file) by inputting, in order
- `CTRL` + `X`
- `Y`
- `Enter`
9. Run the bot
- `./NadekoBot`
- `./NadekoBot`
##### Update Instructions
1. Stop the bot
2. Download the latest release from <https://gitlab.com/Kwoth/nadekobot/-/releases>
- Look for the file called "X.XX.X-linux-x64-build.tar" (where X.XX.X is a series of numbers) and download it
- Look for the file called "x.x.x-linux-x64-build.tar" (where `X.X.X` is a version, for example 3.0.4) and download it
3. Untar it
- ⚠ Make sure that you change X.XX.X to the same series of numbers as in step 2!
- `tar xf 2.99.8-linux-x64-build.tar`
- ⚠ Make sure that you change `X.X.X` to the same series of numbers as in step 2!
- `tar xf x.x.x-linux-x64-build.tar`
4. Rename the old nadekobot directory to nadekobot-old (remove your old backup first if you have one, or back it up under a different name)
- `rm -rf nadekobot-old 2>/dev/null`
- `mv nadekobot nadekobot-old`
- `rm -rf nadekobot-old 2>/dev/null`
- `mv nadekobot nadekobot-old`
5. Rename the new nadekobot directory to nadekobot
- `mv nadekobot-linux-x64 nadekobot`
- `mv nadekobot-linux-x64 nadekobot`
6. Remove old strings and aliases to avoid overwriting the updated versions of those files
- ⚠ If you've modified said files, back them up instead
- `rm nadekobot-old/data/aliases.yml`
- `rm -r nadekobot-old/data/strings`
- ⚠ If you've modified said files, back them up instead
- `rm nadekobot-old/data/aliases.yml`
- `rm -r nadekobot-old/data/strings`
7. Copy old data
- `cp -RT nadekobot-old/data/ nadekobot/data/`
- `cp -RT nadekobot-old/data/ nadekobot/data`
8. Copy creds.yml
- `cp nadekobot-old/creds.yml nadekobot/`
- `cp nadekobot-old/creds.yml nadekobot/`
9. Move into nadekobot directory and make the NadekoBot executable
- `cd nadekobot && chmod +x NadekoBot`
- `cd nadekobot && chmod +x NadekoBot`
10. Run the bot
- `./NadekoBot`
- `./NadekoBot`
🎉 Enjoy
@@ -95,7 +95,135 @@ mv nadekobot nadekobot-old && \
mv nadekobot-linux-x64 nadekobot && \
rm nadekobot-old/data/aliases.yml && \
rm -r nadekobot-old/data/strings && \
cp -RT nadekobot-old/data/ nadekobot/data/ && \
cp -RT nadekobot-old/data/ nadekobot/data && \
cp nadekobot-old/creds.yml nadekobot/ && \
cd nadekobot && chmod +x NadekoBot
```
## Running Nadeko
While there are two run modes built into the installer, these options only run Nadeko within the current session. Below are 3 methods of running Nadeko as a background process.
### Tmux (Preferred Method)
Using `tmux` is the simplest method, and is therefore recommended for most users.
1. Start a tmux session:
- `tmux`
2. Navigate to the project's root directory
- Project root directory location example: `/home/user/nadekobot/`
3. Enter the `output` directory:
- `cd output`
4. Run the bot using:
- `dotnet NadekoBot.dll`
5. Detatch the tmux session:
- Press `Ctrl` + `B`
- Then press `D`
Nadeko should now be running in the background of your system. To re-open the tmux session to either update, restart, or whatever, execute `tmux a`.
### Systemd
Compared to using tmux, this method requires a little bit more work to set up, but has the benefit of allowing Nadeko to automatically start back up after a system reboot or the execution of the `.die` command.
1. Navigate to the project's root directory
- Project root directory location example: `/home/user/nadekobot/`
2. Use the following command to create a service that will be used to start Nadeko:
```bash
echo "[Unit]
Description=NadekoBot service
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=$PWD/output
# If you want Nadeko to be compiled prior to every startup, uncomment the lines
# below. Note that it's not neccessary unless you are personally modifying the
# source code.
#ExecStartPre=/usr/bin/dotnet build ../src/NadekoBot/NadekoBot.csproj -c Release -o output/
ExecStart=/usr/bin/dotnet NadekoBot.dll
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=NadekoBot
Restart=always
[Install]
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/nadeko.service
```
3. Make the new service available:
- `sudo systemctl daemon-reload`
4. Start Nadeko:
- `sudo systemctl start nadeko.service && sudo systemctl enable nadeko.service`
### Systemd + Script
This method is similar to the one above, but requires one extra step, with the added benefit of better error logging and control over what happens before and after the startup of Nadeko.
1. Locate the project and move to its parent directory
- Project location example: `/home/user/nadekobot/`
- Parent directory example: `/home/user/`
2. Use the following command to create a service that will be used to execute `NadekoRun.sh`:
```bash
echo "[Unit]
Description=NadekoBot service
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=$PWD
ExecStart=/bin/bash NadekoRun.sh
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=NadekoBot
[Install]
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/nadeko.service
```
3. Make the new service available:
- `sudo systemctl daemon-reload`
4. Use the following command to create a script that will be used to start Nadeko:
```bash
echo "#\!/bin/bash
echo \"\"
echo \"Running NadekoBot in the background with auto restart\"
youtube-dl -U
# If you want Nadeko to be compiled prior to every startup, uncomment the lines
# below. Note that it's not neccessary unless you are personally modifying the
# source code.
#echo \"Compiling NadekoBot...\"
#cd \"$PWD\"/nadekobot
#dotnet build src/NadekoBot/NadekoBot.csproj -c Release -o output/
echo \"Starting NadekoBot...\"
while true; do
{
cd \"$PWD\"/nadekobot/output
dotnet NadekoBot.dll
## If a non-zero exit code is produced, exit this script.
} || {
error_code=\"\$?\"
echo \"An error occurred when trying to start NadekBot\"
echo \"EXIT CODE: \$?\"
exit \"\$error_code\"
}
youtube-dl -U
echo \"Restarting NadekoBot...\"
done
echo \"Stopping NadekoBot...\"" > NadekoRun.sh
```
5. Start Nadeko:
- `sudo systemctl start nadeko.service && sudo systemctl enable nadeko.service`

View File

@@ -80,6 +80,7 @@ You can still install them manually:
Open PowerShell (press windows button on your keyboard and type powershell, it should show up; alternatively, right click the start menu and select Windows PowerShell), and navigate to the location where you want to install the bot (for example `cd ~/Desktop/`)
1. `git clone https://gitlab.com/kwoth/nadekobot -b v3 --depth 1`
2. `cd nadekobot`
3. `dotnet publish -c Release -o output/ src/NadekoBot/`
4. `cd output && cp creds_example.yml creds.yml`
5. Open `creds.yml` with your favorite text editor (Please don't use Notepad or WordPad. You can use Notepad++, VSCode, Atom, Sublime, or something similar)
@@ -91,16 +92,30 @@ Open PowerShell (press windows button on your keyboard and type powershell, it s
Open PowerShell as described above and run the following commands:
1. Navigate to your bot's folder, for example `cd ~/Desktop/nadekobot/src/NadekoBot`
2. Pull the latest updates (this will fail if you have custom code changes).
- If you don't have custom code changes, just run `git pull`
- If you do have custom code changes, You have 3 options
- Undo all changes with `git checkout -- * && git pull`
- Stash changes and try to re-apply them `git stash && git pull && git stash apply`
- Commit your changes and resolve merge conflicts `git add . && git commit -m "My commit message" && git pull`
3. Re-run the bot `dotnet run -c Release`
1. Stop the bot
- ⚠️ Make sure you don't have your database, credentials or any other nadekobot folder open in some application, this might prevent some of the steps from executing succesfully
2. Navigate to your bot's folder, example:
- `cd ~/Desktop/nadekobot`
3. Pull the new version
- `git pull`
- ⚠️ If this fails, you may want to stash or remove your code changes if you don't know how to resolve merge conflicts
4. **Backup** old output in case your data is overwritten
- `cp -r -fo output/ output-old`
5. Build the bot again
- `dotnet publish -c Release -o output/ src/NadekoBot/`
6. Remove old strings and aliases to avoid overwriting the updated versions of those files
- ⚠ If you've modified said files, back them up instead
- `rm output-old/data/aliases.yml`
- `rm -r output-old/data/strings`
7. Copy old data
- `cp -Recurse .\output-old\data\ .\output\ -Force`
8. Copy creds.yml
- `cp output-old/creds.yml output/`
9. Run the bot
- `cd output`
- `dotnet NadekoBot.dll`
⚠ You're expected to understand that your database will be in `bin/Release/<framework>/data/`, and if `<framework>` gets changed in the future, you will have to move your database manually.
🎉 Enjoy
#### Music prerequisites
In order to use music commands, you need ffmpeg and youtube-dl installed.

View File

@@ -102,7 +102,6 @@ namespace NadekoBot
.AddSingleton(Client) // discord socket client
.AddSingleton(_commandService)
.AddSingleton(this)
.AddSingleton<IDataCache, RedisCache>()
.AddSingleton<ISeria, JsonSeria>()
.AddSingleton<IPubSub, RedisPubSub>()
.AddSingleton<IConfigSeria, YamlSeria>()
@@ -132,10 +131,18 @@ namespace NadekoBot
}
else
{
svcs.AddSingleton<ICoordinator, RemoteGrpcCoordinator>()
.AddSingleton<IReadyExecutor>(x => (IReadyExecutor)x.GetRequiredService<ICoordinator>());
svcs.AddSingleton<RemoteGrpcCoordinator>()
.AddSingleton<ICoordinator>(x => x.GetRequiredService<RemoteGrpcCoordinator>())
.AddSingleton<IReadyExecutor>(x => x.GetRequiredService<RemoteGrpcCoordinator>());
}
svcs.AddSingleton<RedisLocalDataCache>()
.AddSingleton<ILocalDataCache>(x => x.GetRequiredService<RedisLocalDataCache>())
.AddSingleton<RedisImagesCache>()
.AddSingleton<IImageCache>(x => x.GetRequiredService<RedisImagesCache>())
.AddSingleton<IReadyExecutor>(x => x.GetRequiredService<RedisImagesCache>())
.AddSingleton<IDataCache, RedisCache>();
svcs.Scan(scan => scan
.FromAssemblyOf<IReadyExecutor>()
.AddClasses(classes => classes.AssignableToAny(

View File

@@ -12,7 +12,7 @@ namespace NadekoBot.Common.Configs
public sealed partial class BotConfig : ICloneable<BotConfig>
{
[Comment(@"DO NOT CHANGE")]
public int Version { get; set; }
public int Version { get; set; } = 2;
[Comment(@"Most commands, when executed, have a small colored line
next to the response. The color depends whether the command
@@ -48,6 +48,11 @@ they will receive this message. Leave empty for no response. The string which wi
Supports embeds. How it looks: https://puu.sh/B0BLV.png")]
[YamlMember(ScalarStyle = ScalarStyle.Literal)]
public string DmHelpText { get; set; }
[Comment(@"Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response.
Case insensitive.
Leave empty to reply with DmHelpText to every DM.")]
public List<string> DmHelpTextKeywords { get; set; }
[Comment(@"This is the response for the .h command")]
[YamlMember(ScalarStyle = ScalarStyle.Literal)]
@@ -89,7 +94,6 @@ See RotatingStatuses submodule in Administration.")]
public BotConfig()
{
Version = 1;
var color = new ColorConfig();
Color = color;
DefaultLocale = new CultureInfo("en-US");
@@ -127,6 +131,14 @@ See RotatingStatuses submodule in Administration.")]
Prefix = ".";
RotateStatuses = false;
GroupGreets = false;
DmHelpTextKeywords = new List<string>()
{
"help",
"commands",
"cmds",
"module",
"can you do"
};
}
}

View File

@@ -89,6 +89,8 @@ namespace NadekoBot.Common.Replacements
_reps.TryAdd("%server.id%", () => g is null ? "DM" : g.Id.ToString());
_reps.TryAdd("%server.name%", () => g is null ? "DM" : g.Name);
_reps.TryAdd("%server.members%", () => g != null && g is SocketGuild sg ? sg.MemberCount.ToString() : "?");
_reps.TryAdd("%server.boosters%", () => g.PremiumSubscriptionCount.ToString());
_reps.TryAdd("%server.boost_level%", () => ((int)g.PremiumTier).ToString());
_reps.TryAdd("%server.time%", () =>
{
TimeZoneInfo to = TimeZoneInfo.Local;

View File

@@ -120,6 +120,15 @@ namespace NadekoBot.Db
.Include(x => x.IgnoredChannels)
.Where(x => x.GuildId == guildId)
.FirstOrDefault();
if (logSetting is null)
{
ctx.LogSettings.Add(logSetting = new ()
{
GuildId = guildId
});
ctx.SaveChanges();
}
return logSetting;
}

View File

@@ -90,7 +90,7 @@ namespace NadekoBot.Modules.Administration
return;
await _service.TimedMute(user, ctx.User, time.Time, reason: reason).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.user_muted_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
await ReplyConfirmLocalizedAsync(strs.user_muted_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
}
catch (Exception ex)
{
@@ -150,7 +150,7 @@ namespace NadekoBot.Modules.Administration
return;
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason: reason).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.user_chat_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
await ReplyConfirmLocalizedAsync(strs.user_chat_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
}
catch (Exception ex)
{
@@ -209,7 +209,7 @@ namespace NadekoBot.Modules.Administration
return;
await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason: reason).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.user_voice_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
await ReplyConfirmLocalizedAsync(strs.user_voice_mute_time(Format.Bold(user.ToString()), (int)time.Time.TotalMinutes));
}
catch
{

View File

@@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Administration
if (msg is null)
return;
await ReplyErrorLocalizedAsync(strs.reprm(msg));
await ReplyConfirmLocalizedAsync(strs.reprm(msg));
}
}
}

View File

@@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration
return;
}
await ReplyErrorLocalizedAsync(strs.protection_not_running("Anti-Alt"));
await ReplyConfirmLocalizedAsync(strs.protection_not_running("Anti-Alt"));
}
[NadekoCommand, Aliases]
@@ -69,11 +69,11 @@ namespace NadekoBot.Modules.Administration
{
if (_service.TryStopAntiRaid(ctx.Guild.Id))
{
return ReplyErrorLocalizedAsync(strs.prot_disable("Anti-Raid"));
return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Raid"));
}
else
{
return ReplyErrorLocalizedAsync(strs.protection_not_running("Anti-Raid"));
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Raid"));
}
}
@@ -145,11 +145,11 @@ namespace NadekoBot.Modules.Administration
{
if (_service.TryStopAntiSpam(ctx.Guild.Id))
{
return ReplyErrorLocalizedAsync(strs.prot_disable("Anti-Spam"));
return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Spam"));
}
else
{
return ReplyErrorLocalizedAsync(strs.protection_not_running("Anti-Spam"));
return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Spam"));
}
}

View File

@@ -189,7 +189,7 @@ namespace NadekoBot.Modules.Administration
index--;
var rr = rrs[index];
_service.Remove(ctx.Guild.Id, index);
await ReplyErrorLocalizedAsync(strs.reaction_role_removed(index + 1));
await ReplyConfirmLocalizedAsync(strs.reaction_role_removed(index + 1));
}
[NadekoCommand, Aliases]

View File

@@ -24,11 +24,11 @@ namespace NadekoBot.Modules.Administration
if (newVal)
{
await ReplyErrorLocalizedAsync(strs.adsarm_enable(Prefix));
await ReplyConfirmLocalizedAsync(strs.adsarm_enable(Prefix));
}
else
{
await ReplyErrorLocalizedAsync(strs.adsarm_disable(Prefix));
await ReplyConfirmLocalizedAsync(strs.adsarm_disable(Prefix));
}
}

View File

@@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Administration
};
_service.AddNewAutoCommand(cmd);
await ReplyErrorLocalizedAsync(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval));
await ReplyConfirmLocalizedAsync(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval));
}
[NadekoCommand, Aliases]
@@ -226,7 +226,7 @@ namespace NadekoBot.Modules.Administration
if (enabled)
await ReplyConfirmLocalizedAsync(strs.fwdm_start).ConfigureAwait(false);
else
await ReplyConfirmLocalizedAsync(strs.fwdm_stop).ConfigureAwait(false);
await ReplyPendingLocalizedAsync(strs.fwdm_stop).ConfigureAwait(false);
}
[NadekoCommand, Aliases]
@@ -238,7 +238,7 @@ namespace NadekoBot.Modules.Administration
if (enabled)
await ReplyConfirmLocalizedAsync(strs.fwall_start).ConfigureAwait(false);
else
await ReplyConfirmLocalizedAsync(strs.fwall_stop).ConfigureAwait(false);
await ReplyPendingLocalizedAsync(strs.fwall_stop).ConfigureAwait(false);
}
@@ -376,7 +376,7 @@ namespace NadekoBot.Modules.Administration
var curUser = await ctx.Guild.GetCurrentUserAsync().ConfigureAwait(false);
await curUser.ModifyAsync(u => u.Nickname = newNick).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.bot_nick(Format.Bold(newNick) ?? "-"));
await ReplyConfirmLocalizedAsync(strs.bot_nick(Format.Bold(newNick) ?? "-"));
}
[NadekoCommand, Aliases]
@@ -395,7 +395,7 @@ namespace NadekoBot.Modules.Administration
await gu.ModifyAsync(u => u.Nickname = newNick).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"));
await ReplyConfirmLocalizedAsync(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"));
}
[NadekoCommand, Aliases]
@@ -496,7 +496,7 @@ namespace NadekoBot.Modules.Administration
public async Task ImagesReload()
{
await _service.ReloadImagesAsync();
await ReplyErrorLocalizedAsync(strs.images_loading);
await ReplyConfirmLocalizedAsync(strs.images_loading);
}
[NadekoCommand, Aliases]

View File

@@ -294,7 +294,7 @@ namespace NadekoBot.Modules.CustomReactions
.WithDescription("This will delete all custom reactions on this server.")).ConfigureAwait(false))
{
var count = _service.DeleteAllCustomReactions(ctx.Guild.Id);
await ReplyErrorLocalizedAsync(strs.cleared(count));
await ReplyConfirmLocalizedAsync(strs.cleared(count));
}
}

View File

@@ -217,7 +217,7 @@ namespace NadekoBot.Modules.Gambling
[Priority(0)]
public async Task Cash(ulong userId)
{
await ReplyErrorLocalizedAsync(strs.has(Format.Code(userId.ToString()), $"{GetCurrency(userId)} {CurrencySign}"));
await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), $"{GetCurrency(userId)} {CurrencySign}"));
}
[NadekoCommand, Aliases]
@@ -269,7 +269,7 @@ namespace NadekoBot.Modules.Gambling
$"Awarded by bot owner. ({ctx.User.Username}/{ctx.User.Id}) {(msg ?? "")}",
amount,
gamble: (ctx.Client.CurrentUser.Id != usrId)).ConfigureAwait(false);
await ReplyErrorLocalizedAsync(strs.awarded(n(amount) + CurrencySign, $"<@{usrId}>"));
await ReplyConfirmLocalizedAsync(strs.awarded(n(amount) + CurrencySign, $"<@{usrId}>"));
}
[NadekoCommand, Aliases]
@@ -340,7 +340,7 @@ namespace NadekoBot.Modules.Gambling
if (await _cs.RemoveAsync(usrId, $"Taken by bot owner.({ctx.User.Username}/{ctx.User.Id})", amount,
gamble: (ctx.Client.CurrentUser.Id != usrId)).ConfigureAwait(false))
await ReplyErrorLocalizedAsync(strs.take(amount + CurrencySign, $"<@{usrId}>"));
await ReplyConfirmLocalizedAsync(strs.take(amount + CurrencySign, $"<@{usrId}>"));
else
await ReplyErrorLocalizedAsync(strs.take_fail(amount + CurrencySign, Format.Code(usrId.ToString()), CurrencySign));
}

View File

@@ -145,11 +145,11 @@ namespace NadekoBot.Modules.Gambling
if (result == DivorceResult.SucessWithPenalty)
{
await ReplyErrorLocalizedAsync(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()), amount + CurrencySign));
await ReplyConfirmLocalizedAsync(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()), amount + CurrencySign));
}
else if (result == DivorceResult.Success)
{
await ReplyErrorLocalizedAsync(strs.waifu_divorced_notlike(amount + CurrencySign));
await ReplyConfirmLocalizedAsync(strs.waifu_divorced_notlike(amount + CurrencySign));
}
else if (result == DivorceResult.NotYourWife)
{
@@ -306,7 +306,7 @@ namespace NadekoBot.Modules.Gambling
[Priority(1)]
public async Task WaifuGift(int page = 1)
{
if (--page < 0 || page > 3)
if (--page < 0 || page > (_config.Waifu.Items.Count - 1) / 9)
return;
var waifuItems = _service.GetWaifuItems();

View File

@@ -434,7 +434,7 @@ namespace NadekoBot.Modules.Help
[NadekoCommand, Aliases]
public async Task Donate()
{
await ReplyErrorLocalizedAsync(strs.donate(PatreonUrl, PaypalUrl));
await ReplyConfirmLocalizedAsync(strs.donate(PatreonUrl, PaypalUrl));
}
}

View File

@@ -44,6 +44,11 @@ namespace NadekoBot.Modules.Help.Services
{
if (string.IsNullOrWhiteSpace(settings.DmHelpText) || settings.DmHelpText == "-")
return Task.CompletedTask;
// only send dm help text if it contains one of the keywords, if they're specified
// if they're not, then reply to every DM
if (settings.DmHelpTextKeywords.Any() && !settings.DmHelpTextKeywords.Any(k => msg.Content.Contains(k)))
return Task.CompletedTask;
var rep = new ReplacementBuilder()
.WithOverride("%prefix%", () => _bss.Data.Prefix)

View File

@@ -125,7 +125,7 @@ namespace NadekoBot.Modules.Music
queuedMessage?.DeleteAfter(10, _logService);
if (mp.IsStopped)
{
var msg = await ReplyErrorLocalizedAsync(strs.queue_stopped(Format.Code(Prefix + "play")));
var msg = await ReplyPendingLocalizedAsync(strs.queue_stopped(Format.Code(Prefix + "play")));
msg.DeleteAfter(10, _logService);
}
}
@@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Music
return;
await _service.SetVolumeAsync(ctx.Guild.Id, vol);
await ReplyErrorLocalizedAsync(strs.volume_set(vol));
await ReplyConfirmLocalizedAsync(strs.volume_set(vol));
}
[NadekoCommand, Aliases]

View File

@@ -189,7 +189,7 @@ namespace NadekoBot.Modules.NSFW
return t;
});
await ReplyErrorLocalizedAsync(strs.started(interval));
await ReplyConfirmLocalizedAsync(strs.started(interval));
}
[NadekoCommand, Aliases]
@@ -229,7 +229,7 @@ namespace NadekoBot.Modules.NSFW
return t;
});
await ReplyErrorLocalizedAsync(strs.started(interval));
await ReplyConfirmLocalizedAsync(strs.started(interval));
}
#endif
@@ -363,9 +363,9 @@ namespace NadekoBot.Modules.NSFW
var added = _service.ToggleBlacklistedTag(ctx.Guild.Id, tag);
if (added)
await ReplyErrorLocalizedAsync(strs.blacklisted_tag_add(tag));
await ReplyPendingLocalizedAsync(strs.blacklisted_tag_add(tag));
else
await ReplyErrorLocalizedAsync(strs.blacklisted_tag_remove(tag));
await ReplyPendingLocalizedAsync(strs.blacklisted_tag_remove(tag));
}
}

View File

@@ -217,7 +217,7 @@ namespace NadekoBot.Modules.Permissions
{
}
}
await ReplyErrorLocalizedAsync(strs.perm_out_of_range).ConfigureAwait(false);
await ReplyConfirmLocalizedAsync(strs.perm_out_of_range).ConfigureAwait(false);
}
[NadekoCommand, Aliases]

View File

@@ -66,7 +66,7 @@ namespace NadekoBot.Modules.Searches
}
}
await ReplyErrorLocalizedAsync(strs.feed_not_valid).ConfigureAwait(false);
await ReplyConfirmLocalizedAsync(strs.feed_not_valid).ConfigureAwait(false);
}
[NadekoCommand, Aliases]

View File

@@ -191,7 +191,7 @@ namespace NadekoBot.Modules.Searches
return;
}
await ReplyErrorLocalizedAsync(strs.stream_message_set_all(count));
await ReplyConfirmLocalizedAsync(strs.stream_message_set_all(count));
}
[NadekoCommand, Aliases]

View File

@@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Searches
_searches.UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
await ReplyErrorLocalizedAsync(strs.atl_set(from, to));
await ReplyConfirmLocalizedAsync(strs.atl_set(from, to));
}
[NadekoCommand, Aliases]

View File

@@ -37,7 +37,7 @@ namespace NadekoBot.Modules.Utility
public async Task AliasesClear()
{
var count = _service.ClearAliases(ctx.Guild.Id);
await ReplyErrorLocalizedAsync(strs.aliases_cleared(count));
await ReplyConfirmLocalizedAsync(strs.aliases_cleared(count));
}
[NadekoCommand, Aliases]

View File

@@ -148,7 +148,7 @@ namespace NadekoBot.Modules.Utility
}
else
{
await ReplyErrorLocalizedAsync(strs.reminder_deleted(index + 1));
await ReplyConfirmLocalizedAsync(strs.reminder_deleted(index + 1));
}
}

View File

@@ -183,7 +183,9 @@ namespace NadekoBot.Modules.Utility
private string GetRepeaterInfoString(RunningRepeater runner)
{
var intervalString = Format.Bold(runner.Repeater.Interval.ToPrettyStringHM());
var executesIn = runner.NextTime - DateTime.UtcNow;
var executesIn = runner.NextTime < DateTime.UtcNow
? TimeSpan.Zero
: runner.NextTime - DateTime.UtcNow;
var executesInString = Format.Bold(executesIn.ToPrettyStringHM());
var message = Format.Sanitize(runner.Repeater.Message.TrimTo(50));

View File

@@ -76,7 +76,9 @@ where ((guildid >> 22) % {_creds.TotalShards}) == {_client.ShardId};")
// because repeaters might've been modified meanwhile
if (timeout > TimeSpan.Zero)
{
await Task.Delay(timeout);
await Task.Delay(timeout > TimeSpan.FromMinutes(1)
? TimeSpan.FromMinutes(1)
: timeout);
continue;
}
@@ -84,16 +86,17 @@ where ((guildid >> 22) % {_creds.TotalShards}) == {_client.ShardId};")
var now = DateTime.UtcNow + TimeSpan.FromSeconds(3);
var toExecute = new List<RunningRepeater>();
while (true)
lock (_repeaterQueue)
{
lock (_repeaterQueue)
var current = _repeaterQueue.First;
while (true)
{
var current = _repeaterQueue.First;
if (current is null || current.Value.NextTime > now)
break;
toExecute.Add(current.Value);
_repeaterQueue.RemoveFirst();
current = current.Next;
}
}
@@ -121,14 +124,24 @@ where ((guildid >> 22) % {_creds.TotalShards}) == {_client.ShardId};")
{
if (rep.ErrorCount >= 10)
{
RemoveFromQueue(rep.Repeater.Id);
await RemoveRepeaterInternal(rep.Repeater);
return;
}
rep.UpdateNextTime();
AddToQueue(rep);
UpdatePosition(rep);
}
private void UpdatePosition(RunningRepeater rep)
{
lock (_queueLocker)
{
rep.UpdateNextTime();
_repeaterQueue.Remove(rep);
AddToQueue(rep);
}
}
public async Task<bool> TriggerExternal(ulong guildId, int index)
{
using var uow = _db.GetDbContext();

View File

@@ -92,5 +92,15 @@ namespace NadekoBot.Modules.Utility.Services
var initialIntervalMultiplier = 1 - (triggerCount - Math.Truncate(triggerCount));
return DateTime.UtcNow + (Repeater.Interval * initialIntervalMultiplier);
}
public override bool Equals(object? obj)
{
return obj is RunningRepeater rr && rr.Repeater.Id == this.Repeater.Id;
}
public override int GetHashCode()
{
return this.Repeater.Id;
}
}
}

View File

@@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Xp
_service.XpReset(ctx.Guild.Id, userId);
await ReplyErrorLocalizedAsync(strs.reset_user(userId));
await ReplyConfirmLocalizedAsync(strs.reset_user(userId));
}
[NadekoCommand, Aliases]

View File

@@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Xp.Services
private void Migrate()
{
if (_data.Version <= 1)
if (_data.Version < 2)
{
ModifyConfig(c =>
{

View File

@@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Xp
public async Task XpRoleReward(int level)
{
_service.ResetRoleReward(ctx.Guild.Id, level);
await ReplyErrorLocalizedAsync(strs.xp_role_reward_cleared(level));
await ReplyConfirmLocalizedAsync(strs.xp_role_reward_cleared(level));
}
[NadekoCommand, Aliases]

View File

@@ -11,11 +11,12 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using NadekoBot.Common.ModuleBehaviors;
using Serilog;
namespace NadekoBot.Services
{
public sealed class RedisImagesCache : IImageCache
public sealed class RedisImagesCache : IImageCache, IReadyExecutor
{
private readonly ConnectionMultiplexer _con;
private readonly IBotCredentials _creds;
@@ -73,6 +74,14 @@ namespace NadekoBot.Services
Currency,
}
public async Task OnReadyAsync()
{
if (await AllKeysExist())
return;
await Reload();
}
public RedisImagesCache(ConnectionMultiplexer con, IBotCredentials creds)
{
_con = con;

View File

@@ -5,7 +5,6 @@ using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
namespace NadekoBot.Services
@@ -20,12 +19,13 @@ namespace NadekoBot.Services
private readonly string _redisKey;
private readonly EndPoint _redisEndpoint;
public RedisCache(ConnectionMultiplexer redis, IBotCredentials creds, DiscordSocketClient client)
public RedisCache(ConnectionMultiplexer redis, IBotCredentials creds,
IImageCache imageCache, ILocalDataCache dataCache)
{
Redis = redis;
_redisEndpoint = Redis.GetEndPoints().First();
LocalImages = new RedisImagesCache(Redis, creds);
LocalData = new RedisLocalDataCache(Redis, creds, client.ShardId);
LocalImages = imageCache;
LocalData = dataCache;
_redisKey = creds.RedisKey();
}

View File

@@ -7,6 +7,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Discord;
using Discord.WebSocket;
using Serilog;
namespace NadekoBot.Services
@@ -25,56 +27,33 @@ namespace NadekoBot.Services
public IReadOnlyDictionary<string, SearchPokemon> Pokemons
{
get
{
return Get<Dictionary<string, SearchPokemon>>("pokemon_list");
}
private set
{
Set("pokemon_list", value);
}
get => Get<Dictionary<string, SearchPokemon>>("pokemon_list");
private set => Set("pokemon_list", value);
}
public IReadOnlyDictionary<string, SearchPokemonAbility> PokemonAbilities
{
get
{
return Get<Dictionary<string, SearchPokemonAbility>>("pokemon_abilities");
}
private set
{
Set("pokemon_abilities", value);
}
get => Get<Dictionary<string, SearchPokemonAbility>>("pokemon_abilities");
private set => Set("pokemon_abilities", value);
}
public TriviaQuestion[] TriviaQuestions
{
get
{
return Get<TriviaQuestion[]>("trivia_questions");
}
private set
{
Set("trivia_questions", value);
}
get => Get<TriviaQuestion[]>("trivia_questions");
private set => Set("trivia_questions", value);
}
public IReadOnlyDictionary<int, string> PokemonMap
{
get
{
return Get<Dictionary<int, string>>("pokemon_map");
}
private set
{
Set("pokemon_map", value);
}
get => Get<Dictionary<int, string>>("pokemon_map");
private set => Set("pokemon_map", value);
}
public RedisLocalDataCache(ConnectionMultiplexer con, IBotCredentials creds, int shardId)
public RedisLocalDataCache(ConnectionMultiplexer con, IBotCredentials creds, DiscordSocketClient client)
{
_con = con;
_creds = creds;
var shardId = client.ShardId;
if (shardId == 0)
{

View File

@@ -19,7 +19,7 @@ namespace NadekoBot.Services
private readonly IBotCredentials _creds;
private readonly DateTime _started;
public const string BotVersion = "3.0.3";
public const string BotVersion = "3.0.5";
public string Author => "Kwoth#2452";
public string Library => "Discord.Net";

View File

@@ -28,19 +28,15 @@ namespace NadekoBot.Services
AddParsedProp("locale", bs => bs.DefaultLocale, ConfigParsers.Culture, ConfigPrinters.Culture);
AddParsedProp("prefix", bs => bs.Prefix, ConfigParsers.String, ConfigPrinters.ToString);
UpdateColors();
Migrate();
}
private void UpdateColors()
private void Migrate()
{
var ok = _data.Color.Ok;
var error = _data.Color.Error;
var pend = _data.Color.Pending;
}
protected override void OnStateUpdate()
{
UpdateColors();
if (_data.Version < 2)
{
ModifyConfig(c => c.Version = 2);
}
}
}
}

View File

@@ -1,5 +1,5 @@
# DO NOT CHANGE
version: 1
version: 2
# Most commands, when executed, have a small colored line
# next to the response. The color depends whether the command
# is completed, errored or in progress (pending)
@@ -28,6 +28,15 @@ forwardToAllOwners: false
# Supports embeds. How it looks: https://puu.sh/B0BLV.png
dmHelpText: |-
{"description": "Type `%prefix%h` for help."}
# Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response.
# Case insensitive.
# Leave empty to reply with DmHelpText to every DM.
dmHelpTextKeywords:
- help
- commands
- cmds
- module
- can you do
# This is the response for the .h command
helpText: |-
{

File diff suppressed because it is too large Load Diff