Merge pull request #6 from Kwoth/dev

Updating fork dev
This commit is contained in:
miraai 2016-07-28 20:24:51 +02:00 committed by GitHub
commit 07fd374a1c
45 changed files with 1256 additions and 686 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "discord.net"] [submodule "discord.net"]
path = discord.net path = discord.net
url = git://github.com/kwoth/discord.net.git url = git://github.com/kwoth/discord.net.git
[submodule "ffmpeg-installer"]
path = ffmpeg-installer
url = https://github.com/kwoth/ffmpeg-installer

View File

@ -36,9 +36,7 @@ ________________________________________________________________________________
###### Setting up `ffmpeg` with installer: ###### Setting up `ffmpeg` with installer:
1) Google Account 1) Google Account
2) Soundcloud Account (if you want soundcloud support) 2) Soundcloud Account (if you want soundcloud support)
3) Download installer here: https://goo.gl/lQZnsH (pick the one for your system, either 32 or 64bit and then click 'download')
3) Download installer here: http://luxcaeli.de/owncloud/s/fIxSgh4Nde3Td6e/download
4) Run the installer 4) Run the installer
5) Follow these steps on how to setup API keys: 5) Follow these steps on how to setup API keys:

View File

@ -222,6 +222,8 @@ Type/ Copy and hit **Enter**.
Now time to **move bot to background** and to do that, press **CTRL+B+D** (this will ditach the nadeko session using TMUX), and you can finally close PuTTY now. Now time to **move bot to background** and to do that, press **CTRL+B+D** (this will ditach the nadeko session using TMUX), and you can finally close PuTTY now.
Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link: `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with it. Go to that link and you will be able to add your bot to your server.
**NOW YOU HAVE YOUR OWN NADEKO BOT** `Thanks to Kwoth <3` **NOW YOU HAVE YOUR OWN NADEKO BOT** `Thanks to Kwoth <3`
######SOME MORE INFO (JUST TO KNOW): ######SOME MORE INFO (JUST TO KNOW):

View File

@ -138,7 +138,7 @@ namespace NadekoBot.Extensions
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="list"></param> /// <param name="list"></param>
public static void Shuffle<T>(this IList<T> list) public static IList<T> Shuffle<T>(this IList<T> list)
{ {
// Thanks to @Joe4Evr for finding a bug in the old version of the shuffle // Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
@ -160,6 +160,7 @@ namespace NadekoBot.Extensions
list[k] = list[n]; list[k] = list[n];
list[n] = value; list[n] = value;
} }
return list;
} }
/// <summary> /// <summary>
@ -303,6 +304,15 @@ namespace NadekoBot.Extensions
public static int GiB(this int value) => value.MiB() * 1024; public static int GiB(this int value) => value.MiB() * 1024;
public static int GB(this int value) => value.MB() * 1000; public static int GB(this int value) => value.MB() * 1000;
public static ulong KiB(this ulong value) => value * 1024;
public static ulong KB(this ulong value) => value * 1000;
public static ulong MiB(this ulong value) => value.KiB() * 1024;
public static ulong MB(this ulong value) => value.KB() * 1000;
public static ulong GiB(this ulong value) => value.MiB() * 1024;
public static ulong GB(this ulong value) => value.MB() * 1000;
public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null) public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null)
{ {
if (format == null) if (format == null)
@ -362,5 +372,7 @@ namespace NadekoBot.Extensions
return sw.BaseStream; return sw.BaseStream;
} }
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
} }
} }

View File

@ -4,8 +4,10 @@ using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands; using NadekoBot.Modules.Administration.Commands;
using NadekoBot.Modules.Music; using NadekoBot.Modules.Music;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
@ -41,7 +43,23 @@ namespace NadekoBot
var commandService = NadekoBot.Client.GetService<CommandService>(); var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start(); statsStopwatch.Start();
commandService.CommandExecuted += StatsCollector_RanCommand; commandService.CommandExecuted += StatsCollector_RanCommand;
commandService.CommandFinished += CommandService_CommandFinished;
commandService.CommandErrored += (s, e) =>
{
try
{
if (e.ErrorType == CommandErrorType.Exception)
File.AppendAllText("errors.txt", $@"Command: {e.Command}
{e.Exception}
-------------------------------------
");
}
catch {
Console.WriteLine("Command errored errorring");
}
};
Task.Run(StartCollecting); Task.Run(StartCollecting);
@ -97,7 +115,7 @@ namespace NadekoBot
if (e.Channel.IsPrivate) if (e.Channel.IsPrivate)
return; return;
if (e.Channel.Type == ChannelType.Text) if (e.Channel.Type == ChannelType.Text)
VoiceChannelsCount++; TextChannelsCount--;
else if (e.Channel.Type == ChannelType.Voice) else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount--; VoiceChannelsCount--;
} }
@ -106,6 +124,7 @@ namespace NadekoBot
carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false); carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false);
carbonStatusTimer.Start(); carbonStatusTimer.Start();
} }
HttpClient carbonClient = new HttpClient(); HttpClient carbonClient = new HttpClient();
private async Task SendUpdateToCarbon() private async Task SendUpdateToCarbon()
{ {
@ -176,9 +195,11 @@ namespace NadekoBot
private async Task StartCollecting() private async Task StartCollecting()
{ {
var statsSw = new Stopwatch();
while (true) while (true)
{ {
await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false); await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
statsSw.Start();
try try
{ {
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false); var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false);
@ -195,6 +216,13 @@ namespace NadekoBot
ConnectedServers = connectedServers, ConnectedServers = connectedServers,
DateAdded = DateTime.Now DateAdded = DateTime.Now
}); });
statsSw.Stop();
var clr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"--------------\nCollecting stats finished in {statsSw.Elapsed.TotalSeconds}s\n-------------");
Console.ForegroundColor = clr;
statsSw.Reset();
} }
catch catch
{ {
@ -204,9 +232,21 @@ namespace NadekoBot
} }
} }
private static ConcurrentDictionary<ulong, DateTime> commandTracker = new ConcurrentDictionary<ulong, DateTime>();
private void CommandService_CommandFinished(object sender, CommandEventArgs e)
{
DateTime dt;
if (!commandTracker.TryGetValue(e.Message.Id, out dt))
return;
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
}
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e) private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
{ {
Console.WriteLine($">> Cmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----"); commandTracker.TryAdd(e.Message.Id, DateTime.UtcNow);
Console.WriteLine($">>COMMAND STARTED\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
#if !NADEKO_RELEASE
await Task.Run(() => await Task.Run(() =>
{ {
try try
@ -230,6 +270,7 @@ namespace NadekoBot
Console.WriteLine(ex); Console.WriteLine(ex);
} }
}).ConfigureAwait(false); }).ConfigureAwait(false);
#endif
} }
} }
} }

View File

@ -364,9 +364,7 @@ namespace NadekoBot.Classes
} }
var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse; var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse;
if (httpResponse == null) return "HTTP_RESPONSE_ERROR";
var responseStream = httpResponse.GetResponseStream(); var responseStream = httpResponse.GetResponseStream();
if (responseStream == null) return "RESPONSE_STREAM ERROR";
using (var streamReader = new StreamReader(responseStream)) using (var streamReader = new StreamReader(responseStream))
{ {
var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false); var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false);
@ -375,6 +373,7 @@ namespace NadekoBot.Classes
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Shortening of this url failed: " + url);
Console.WriteLine(ex.ToString()); Console.WriteLine(ex.ToString());
return url; return url;
} }

View File

@ -6,6 +6,8 @@ using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Classes namespace NadekoBot.Classes
{ {
@ -27,9 +29,12 @@ namespace NadekoBot.Classes
{ {
configs = JsonConvert configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>( .DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
File.ReadAllText(filePath), new JsonSerializerSettings() { File.ReadAllText(filePath), new JsonSerializerSettings()
Error = (s,e) => { {
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") { Error = (s, e) =>
{
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
{
e.ErrorContext.Handled = true; e.ErrorContext.Handled = true;
} }
} }
@ -52,14 +57,19 @@ namespace NadekoBot.Classes
public ServerSpecificConfig Of(ulong id) => public ServerSpecificConfig Of(ulong id) =>
configs.GetOrAdd(id, _ => new ServerSpecificConfig()); configs.GetOrAdd(id, _ => new ServerSpecificConfig());
private readonly object saveLock = new object(); private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1);
public void Save() public async Task Save()
{ {
lock (saveLock) await saveLock.WaitAsync();
try
{ {
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented)); File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
} }
finally
{
saveLock.Release();
}
} }
} }
@ -245,7 +255,7 @@ namespace NadekoBot.Classes
LogserverIgnoreChannels = new ObservableCollection<ulong>(); LogserverIgnoreChannels = new ObservableCollection<ulong>();
} }
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); }; public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); };
private void OnPropertyChanged([CallerMemberName] string propertyName = null) private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ {

View File

@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Administration
{ {
var conf = SpecificConfigurations.Default.Of(e.Server.Id); var conf = SpecificConfigurations.Default.Of(e.Server.Id);
conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand; conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
Classes.JSONModels.ConfigHandler.SaveConfig(); await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
if (conf.AutoDeleteMessagesOnCommand) if (conf.AutoDeleteMessagesOnCommand)
await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`"); await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`");
else else
@ -90,7 +90,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr") cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
.Description("Sets a role for a given user. | .sr @User Guest") .Description($"Sets a role for a given user. | `{Prefix}sr @User Guest`")
.Parameter("user_name", ParameterType.Required) .Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr") cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
.Description("Removes a role from a given user. | .rr @User Admin") .Description($"Removes a role from a given user. | `{Prefix}rr @User Admin`")
.Parameter("user_name", ParameterType.Required) .Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar") cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
.Description("Removes all roles from a mentioned user. | .rar @User") .Description($"Removes all roles from a mentioned user. | `{Prefix}rar @User`")
.Parameter("user_name", ParameterType.Unparsed) .Parameter("user_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => .Do(async e =>
@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr") cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr")
.Description("Creates a role with a given name.**Usage**: `.r Awesome Role`") .Description($"Creates a role with a given name. | `{Prefix}cr Awesome Role`")
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => .Do(async e =>
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.Administration
.Parameter("r", ParameterType.Optional) .Parameter("r", ParameterType.Optional)
.Parameter("g", ParameterType.Optional) .Parameter("g", ParameterType.Optional)
.Parameter("b", ParameterType.Optional) .Parameter("b", ParameterType.Optional)
.Description("Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55`") .Description($"Set a role's color to the hex or 0-255 rgb color value provided. | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
.Do(async e => .Do(async e =>
{ {
if (!e.User.ServerPermissions.ManageRoles) if (!e.User.ServerPermissions.ManageRoles)
@ -298,7 +298,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b") cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
.Parameter("user", ParameterType.Required) .Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Description("Bans a user by id or name with an optional message. | .b \"@some Guy\" Your behaviour is toxic.") .Description($"Bans a user by id or name with an optional message. | `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
.Do(async e => .Do(async e =>
{ {
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb") cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
.Parameter("user", ParameterType.Required) .Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Description("Bans and then unbans a user by id or name with an optional message. | .sb \"@some Guy\" Your behaviour is toxic.") .Description($"Bans and then unbans a user by id or name with an optional message. | `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
.Do(async e => .Do(async e =>
{ {
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
@ -369,7 +369,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k") cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k")
.Parameter("user") .Parameter("user")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Description("Kicks a mentioned user.") .Description($"Kicks a mentioned user. | `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
.Do(async e => .Do(async e =>
{ {
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
@ -400,7 +400,7 @@ namespace NadekoBot.Modules.Administration
} }
}); });
cgb.CreateCommand(Prefix + "mute") cgb.CreateCommand(Prefix + "mute")
.Description("Mutes mentioned user or users.") .Description($"Mutes mentioned user or users. | `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -426,7 +426,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "unmute") cgb.CreateCommand(Prefix + "unmute")
.Description("Unmutes mentioned user or users.") .Description($"Unmutes mentioned user or users. | `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -453,7 +453,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "deafen") cgb.CreateCommand(Prefix + "deafen")
.Alias(Prefix + "deaf") .Alias(Prefix + "deaf")
.Description("Deafens mentioned user or users") .Description($"Deafens mentioned user or users | `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -480,7 +480,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "undeafen") cgb.CreateCommand(Prefix + "undeafen")
.Alias(Prefix + "undef") .Alias(Prefix + "undef")
.Description("Undeafens mentioned user or users") .Description($"Undeafens mentioned user or users | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -507,7 +507,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "delvoichanl") cgb.CreateCommand(Prefix + "delvoichanl")
.Alias(Prefix + "dvch") .Alias(Prefix + "dvch")
.Description("Deletes a voice channel with a given name.") .Description($"Deletes a voice channel with a given name. | `{Prefix}dvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -530,7 +530,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatvoichanl") cgb.CreateCommand(Prefix + "creatvoichanl")
.Alias(Prefix + "cvch") .Alias(Prefix + "cvch")
.Description("Creates a new voice channel with a given name.") .Description($"Creates a new voice channel with a given name. | `{Prefix}cvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -550,7 +550,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "deltxtchanl") cgb.CreateCommand(Prefix + "deltxtchanl")
.Alias(Prefix + "dtch") .Alias(Prefix + "dtch")
.Description("Deletes a text channel with a given name.") .Description($"Deletes a text channel with a given name. | `{Prefix}dtch TextChannelName`")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -572,7 +572,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatxtchanl") cgb.CreateCommand(Prefix + "creatxtchanl")
.Alias(Prefix + "ctch") .Alias(Prefix + "ctch")
.Description("Creates a new text channel with a given name.") .Description($"Creates a new text channel with a given name. | `{Prefix}ctch TextChannelName`")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -604,7 +604,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "setchanlname") cgb.CreateCommand(Prefix + "setchanlname")
.Alias(Prefix + "schn") .Alias(Prefix + "schn")
.Description("Changed the name of the current channel.") .Description($"Changed the name of the current channel.| `{Prefix}schn NewName`")
.AddCheck(SimpleCheckers.ManageChannels()) .AddCheck(SimpleCheckers.ManageChannels())
.Parameter("name", ParameterType.Unparsed) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -636,7 +636,8 @@ namespace NadekoBot.Modules.Administration
Message[] msgs; Message[] msgs;
if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
{ {
msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray(); msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false));//.Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
msgs = msgs.Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
if (!msgs.Any()) if (!msgs.Any())
return; return;
await e.Channel.DeleteMessages(msgs).ConfigureAwait(false); await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
@ -684,7 +685,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "setname") cgb.CreateCommand(Prefix + "setname")
.Alias(Prefix + "newnm") .Alias(Prefix + "newnm")
.Description("Give the bot a new name. **Bot Owner Only!**") .Description($"Give the bot a new name. **Bot Owner Only!** | {Prefix}newnm BotName")
.Parameter("new_name", ParameterType.Unparsed) .Parameter("new_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -696,7 +697,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "newavatar") cgb.CreateCommand(Prefix + "newavatar")
.Alias(Prefix + "setavatar") .Alias(Prefix + "setavatar")
.Description("Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`") .Description($"Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `{Prefix}setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
.Parameter("img", ParameterType.Unparsed) .Parameter("img", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -717,7 +718,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "setgame") cgb.CreateCommand(Prefix + "setgame")
.Description("Sets the bots game. **Bot Owner Only!**") .Description($"Sets the bots game. **Bot Owner Only!** | `{Prefix}setgame Playing with kwoth`")
.Parameter("set_game", ParameterType.Unparsed) .Parameter("set_game", ParameterType.Unparsed)
.Do(e => .Do(e =>
{ {
@ -727,7 +728,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "send") cgb.CreateCommand(Prefix + "send")
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`") .Description($"Send a message to someone on a different server through the bot. **Bot Owner Only!** | `{Prefix}send serverid|u:user_id Send this to a user!` or `{Prefix}send serverid|c:channel_id Send this to a channel!`")
.Parameter("ids", ParameterType.Required) .Parameter("ids", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
@ -775,7 +776,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "mentionrole") cgb.CreateCommand(Prefix + "mentionrole")
.Alias(Prefix + "menro") .Alias(Prefix + "menro")
.Description("Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.") .Description($"Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `{Prefix}menro RoleName`")
.Parameter("roles", ParameterType.Unparsed) .Parameter("roles", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -828,7 +829,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "donadd") cgb.CreateCommand(Prefix + "donadd")
.Description("Add a donator to the database.") .Description($"Add a donator to the database. | `.donadd Donate Amount`")
.Parameter("donator") .Parameter("donator")
.Parameter("amount") .Parameter("amount")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
@ -854,7 +855,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "announce") cgb.CreateCommand(Prefix + "announce")
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | {Prefix}announce Useless spam") .Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `{Prefix}announce Useless spam`")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -868,7 +869,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "savechat") cgb.CreateCommand(Prefix + "savechat")
.Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`") .Description($"Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `{Prefix}savechat 150`")
.Parameter("cnt", ParameterType.Required) .Parameter("cnt", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>

View File

@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Administration.Commands
NadekoBot.Config.CustomReactions[name].Add(message); NadekoBot.Config.CustomReactions[name].Add(message);
else else
NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List<string>() { message }); NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List<string>() { message });
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false); await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false);
}); });
@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration.Commands
index = index - 1; index = index - 1;
NadekoBot.Config.CustomReactions[name][index] = msg; NadekoBot.Config.CustomReactions[name][index] = msg;
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false); await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false);
}); });
@ -183,7 +183,7 @@ namespace NadekoBot.Modules.Administration.Commands
NadekoBot.Config.CustomReactions.Remove(name); NadekoBot.Config.CustomReactions.Remove(name);
message = $"Deleted custom reaction: `{name}`"; message = $"Deleted custom reaction: `{name}`";
} }
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage(message).ConfigureAwait(false); await e.Channel.SendMessage(message).ConfigureAwait(false);
}); });
} }

View File

@ -7,8 +7,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers; using System.Timers;
using Timer = System.Timers.Timer;
namespace NadekoBot.Modules.Administration.Commands namespace NadekoBot.Modules.Administration.Commands
{ {
@ -36,7 +38,7 @@ namespace NadekoBot.Modules.Administration.Commands
{"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()} {"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()}
}; };
private readonly object playingPlaceholderLock = new object(); private readonly SemaphoreSlim playingPlaceholderLock = new SemaphoreSlim(1,1);
public PlayingRotate(DiscordModule module) : base(module) public PlayingRotate(DiscordModule module) : base(module)
{ {
@ -47,7 +49,9 @@ namespace NadekoBot.Modules.Administration.Commands
{ {
i++; i++;
var status = ""; var status = "";
lock (playingPlaceholderLock) //wtf am i doing, just use a queue ffs
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{ {
if (PlayingPlaceholders.Count == 0 if (PlayingPlaceholders.Count == 0
|| NadekoBot.Config.RotatingStatuses.Count == 0 || NadekoBot.Config.RotatingStatuses.Count == 0
@ -59,6 +63,7 @@ namespace NadekoBot.Modules.Administration.Commands
status = PlayingPlaceholders.Aggregate(status, status = PlayingPlaceholders.Aggregate(status,
(current, kvp) => current.Replace(kvp.Key, kvp.Value())); (current, kvp) => current.Replace(kvp.Key, kvp.Value()));
} }
finally { playingPlaceholderLock.Release(); }
if (string.IsNullOrWhiteSpace(status)) if (string.IsNullOrWhiteSpace(status))
return; return;
await Task.Run(() => { NadekoBot.Client.SetGame(status); }); await Task.Run(() => { NadekoBot.Client.SetGame(status); });
@ -71,14 +76,18 @@ namespace NadekoBot.Modules.Administration.Commands
public Func<CommandEventArgs, Task> DoFunc() => async e => public Func<CommandEventArgs, Task> DoFunc() => async e =>
{ {
lock (playingPlaceholderLock) await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{ {
if (timer.Enabled) if (timer.Enabled)
timer.Stop(); timer.Stop();
else else
timer.Start(); timer.Start();
NadekoBot.Config.IsRotatingStatus = timer.Enabled; NadekoBot.Config.IsRotatingStatus = timer.Enabled;
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
}
finally {
playingPlaceholderLock.Release();
} }
await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false); await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false);
}; };
@ -102,10 +111,15 @@ namespace NadekoBot.Modules.Administration.Commands
var arg = e.GetArg("text"); var arg = e.GetArg("text");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; return;
lock (playingPlaceholderLock) await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{ {
NadekoBot.Config.RotatingStatuses.Add(arg); NadekoBot.Config.RotatingStatuses.Add(arg);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig();
}
finally
{
playingPlaceholderLock.Release();
} }
await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false); await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false);
}); });
@ -137,14 +151,15 @@ namespace NadekoBot.Modules.Administration.Commands
var arg = e.GetArg("number"); var arg = e.GetArg("number");
int num; int num;
string str; string str;
lock (playingPlaceholderLock) await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
{ try {
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count) if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
return; return;
str = NadekoBot.Config.RotatingStatuses[num - 1]; str = NadekoBot.Config.RotatingStatuses[num - 1];
NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1); NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
} }
finally { playingPlaceholderLock.Release(); }
await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false); await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false);
}); });
} }

View File

@ -149,9 +149,10 @@ namespace NadekoBot.Modules.Administration.Commands
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError) catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{ {
} }
catch (Exception) catch (Exception ex)
{ {
await e.Channel.SendMessage($":anger:`I am unable to add that role to you. I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false); await e.Channel.SendMessage($":anger:`I am unable to add that role to you. I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
return;
} }
var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false); var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
await Task.Delay(3000).ConfigureAwait(false); await Task.Delay(3000).ConfigureAwait(false);

View File

@ -1,46 +0,0 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration.Commands
{
internal class VoiceNotificationCommand : DiscordCommand
{
//voicechannel/text channel
private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>();
public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
var arg = e.GetArg("voice_name");
if (string.IsNullOrWhiteSpace("voice_name"))
return;
var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault();
if (voiceChannel == null)
return;
if (subscribers.ContainsKey(voiceChannel))
{
await e.Channel.SendMessage("`Voice channel notifications disabled.`").ConfigureAwait(false);
return;
}
if (subscribers.TryAdd(voiceChannel, e.Channel))
{
await e.Channel.SendMessage("`Voice channel notifications enabled.`").ConfigureAwait(false);
}
};
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "voicenotif")
.Description("Enables notifications on who joined/left the voice channel. |.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed)
.Do(DoFunc());
}
public VoiceNotificationCommand(DiscordModule module) : base(module) { }
}
}

View File

@ -1,9 +1,8 @@
using Discord.Commands; using Newtonsoft.Json;
using System; using System;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; //using Manatee.Json.Serialization;
using System.Threading.Tasks;
namespace NadekoBot.Classes.ClashOfClans namespace NadekoBot.Classes.ClashOfClans
{ {
@ -11,16 +10,22 @@ namespace NadekoBot.Classes.ClashOfClans
{ {
One, Two, Three One, Two, Three
} }
public enum WarState
{
Started, Ended, Created
}
[System.Serializable]
internal class Caller internal class Caller
{ {
public string CallUser { get; } public string CallUser { get; set; }
public DateTime TimeAdded { get; private set; } public DateTime TimeAdded { get; set; }
public bool BaseDestroyed { get; internal set; } public bool BaseDestroyed { get; set; }
public int Stars { get; set; } = 3; public int Stars { get; set; } = 3;
public Caller() { }
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
{ {
@ -31,7 +36,7 @@ namespace NadekoBot.Classes.ClashOfClans
public void ResetTime() public void ResetTime()
{ {
TimeAdded = DateTime.Now; TimeAdded = DateTime.UtcNow;
} }
public void Destroy() public void Destroy()
@ -44,97 +49,84 @@ namespace NadekoBot.Classes.ClashOfClans
{ {
private static TimeSpan callExpire => new TimeSpan(2, 0, 0); private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
public string EnemyClan { get; } public string EnemyClan { get; set; }
public int Size { get; } public int Size { get; set; }
private Caller[] bases { get; } public Caller[] Bases { get; set; }
private CancellationTokenSource[] baseCancelTokens; public WarState WarState { get; set; } = WarState.Created;
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource(); //public bool Started { get; set; } = false;
public event Action<string> OnUserTimeExpired = delegate { }; public DateTime StartedAt { get; set; }
public event Action OnWarEnded = delegate { }; //public bool Ended { get; private set; } = false;
public bool Started { get; set; } = false;
public ClashWar(string enemyClan, int size, CommandEventArgs e) public ulong ServerId { get; set; }
public ulong ChannelId { get; set; }
[JsonIgnore]
public Discord.Channel Channel { get; internal set; }
/// <summary>
/// This init is purely for the deserialization
/// </summary>
public ClashWar() { }
public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId)
{ {
this.EnemyClan = enemyClan; this.EnemyClan = enemyClan;
this.Size = size; this.Size = size;
this.bases = new Caller[size]; this.Bases = new Caller[size];
this.baseCancelTokens = new CancellationTokenSource[size]; this.ServerId = serverId;
this.ChannelId = channelId;
this.Channel = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id == serverId)?.TextChannels.FirstOrDefault(c => c.Id == channelId);
} }
internal void End() internal void End()
{ {
if (endTokenSource.Token.IsCancellationRequested) return; //Ended = true;
endTokenSource.Cancel(); WarState = WarState.Ended;
OnWarEnded();
} }
internal void Call(string u, int baseNumber) internal void Call(string u, int baseNumber)
{ {
if (baseNumber < 0 || baseNumber >= bases.Length) if (baseNumber < 0 || baseNumber >= Bases.Length)
throw new ArgumentException("Invalid base number"); throw new ArgumentException("Invalid base number");
if (bases[baseNumber] != null) if (Bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed."); throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < bases.Length; i++) for (var i = 0; i < Bases.Length; i++)
{ {
if (bases[i]?.BaseDestroyed == false && bases[i]?.CallUser == u) if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one."); throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
} }
bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false); Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false);
} }
internal async Task Start() internal void Start()
{ {
if (Started) if (WarState == WarState.Started)
throw new InvalidOperationException(); throw new InvalidOperationException("War already started");
try //if (Started)
{ // throw new InvalidOperationException();
Started = true; //Started = true;
foreach (var b in bases.Where(b => b != null)) WarState = WarState.Started;
StartedAt = DateTime.UtcNow;
foreach (var b in Bases.Where(b => b != null))
{ {
b.ResetTime(); b.ResetTime();
} }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(async () => await ClearArray()).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
await Task.Delay(new TimeSpan(24, 0, 0), endTokenSource.Token).ConfigureAwait(false);
}
catch { }
finally
{
End();
}
} }
internal int Uncall(string user) internal int Uncall(string user)
{ {
user = user.Trim(); user = user.Trim();
for (var i = 0; i < bases.Length; i++) for (var i = 0; i < Bases.Length; i++)
{ {
if (bases[i]?.CallUser != user) continue; if (Bases[i]?.CallUser != user) continue;
bases[i] = null; Bases[i] = null;
return i; return i;
} }
throw new InvalidOperationException("You are not participating in that war."); throw new InvalidOperationException("You are not participating in that war.");
} }
private async Task ClearArray()
{
while (!endTokenSource.IsCancellationRequested)
{
await Task.Delay(5000).ConfigureAwait(false);
for (var i = 0; i < bases.Length; i++)
{
if (bases[i] == null) continue;
if (!bases[i].BaseDestroyed && DateTime.Now - bases[i].TimeAdded >= callExpire)
{
OnUserTimeExpired(bases[i].CallUser);
bases[i] = null;
}
}
}
}
public string ShortPrint() => public string ShortPrint() =>
$"`{EnemyClan}` ({Size} v {Size})"; $"`{EnemyClan}` ({Size} v {Size})";
@ -143,24 +135,24 @@ namespace NadekoBot.Classes.ClashOfClans
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**"); sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
if (!Started) if (WarState == WarState.Created)
sb.AppendLine("`not started`"); sb.AppendLine("`not started`");
for (var i = 0; i < bases.Length; i++) for (var i = 0; i < Bases.Length; i++)
{ {
if (bases[i] == null) if (Bases[i] == null)
{ {
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*"); sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
} }
else else
{ {
if (bases[i].BaseDestroyed) if (Bases[i].BaseDestroyed)
{ {
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {new string('⭐', bases[i].Stars)}"); sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
} }
else else
{ {
var left = Started ? callExpire - (DateTime.Now - bases[i].TimeAdded) : callExpire; var left = (WarState == WarState.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left"); sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
} }
} }
@ -171,11 +163,11 @@ namespace NadekoBot.Classes.ClashOfClans
internal int FinishClaim(string user, int stars = 3) internal int FinishClaim(string user, int stars = 3)
{ {
user = user.Trim(); user = user.Trim();
for (var i = 0; i < bases.Length; i++) for (var i = 0; i < Bases.Length; i++)
{ {
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue; if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true; Bases[i].BaseDestroyed = true;
bases[i].Stars = stars; Bases[i].Stars = stars;
return i; return i;
} }
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base."); throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");

View File

@ -1,12 +1,15 @@
using Discord.Commands; using Discord.Commands;
using Discord.Modules; using Discord.Modules;
using NadekoBot.Classes.ClashOfClans; using NadekoBot.Classes.ClashOfClans;
using NadekoBot.Modules.Permissions.Classes;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using NadekoBot.Modules.Permissions.Classes;
namespace NadekoBot.Modules.ClashOfClans namespace NadekoBot.Modules.ClashOfClans
{ {
@ -14,10 +17,128 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>(); public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
private readonly object writeLock = new object(); private readonly object writeLock = new object();
public ClashOfClansModule()
{
NadekoBot.OnReady += () => Task.Run(async () =>
{
if (File.Exists("data/clashofclans/wars.json"))
{
try
{
var content = File.ReadAllText("data/clashofclans/wars.json");
var dict = JsonConvert.DeserializeObject<Dictionary<ulong, List<ClashWar>>>(content);
foreach (var cw in dict)
{
cw.Value.ForEach(war =>
{
war.Channel = NadekoBot.Client.GetServer(war.ServerId)?.GetChannel(war.ChannelId);
if (war.Channel == null)
{
cw.Value.Remove(war);
}
}
);
}
//urgh
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(dict);
}
catch (Exception e)
{
Console.WriteLine("Could not load coc wars: " + e.Message);
}
}
//Can't this be disabled if the modules is disabled too :)
var callExpire = new TimeSpan(2, 0, 0);
var warExpire = new TimeSpan(23, 0, 0);
while (true)
{
try
{
var hash = ClashWars.GetHashCode();
foreach (var cw in ClashWars)
{
foreach (var war in cw.Value)
{
await CheckWar(callExpire, war);
}
List<ClashWar> newVal = new List<ClashWar>();
foreach (var w in cw.Value)
{
//We add when A: the war is not ended
if (w.WarState != WarState.Ended)
{
//and B: the war has not expired
if ((w.WarState == WarState.Started && DateTime.UtcNow - w.StartedAt <= warExpire) || w.WarState == WarState.Created)
{
newVal.Add(w);
}
}
}
//var newVal = cw.Value.Where(w => !(w.Ended || DateTime.UtcNow - w.StartedAt >= warExpire)).ToList();
foreach (var exWar in cw.Value.Except(newVal))
{
await exWar.Channel.SendMessage($"War against {exWar.EnemyClan} ({exWar.Size}v{exWar.Size}) has ended");
}
if (newVal.Count == 0)
{
List<ClashWar> obj;
ClashWars.TryRemove(cw.Key, out obj);
}
else
{
ClashWars.AddOrUpdate(cw.Key, newVal, (x, s) => newVal);
}
}
if (hash != ClashWars.GetHashCode()) //something changed
{
Save();
}
}
catch { }
await Task.Delay(5000);
}
});
}
private static void Save()
{
try
{
Directory.CreateDirectory("data/clashofclans");
File.WriteAllText("data/clashofclans/wars.json", JsonConvert.SerializeObject(ClashWars, Formatting.Indented));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
{
var Bases = war.Bases;
for (var i = 0; i < Bases.Length; i++)
{
if (Bases[i] == null) continue;
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
{
await war.Channel.SendMessage($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
Bases[i] = null;
}
}
}
#region commands
public override void Install(ModuleManager manager) public override void Install(ModuleManager manager)
{ {
manager.CreateCommands("", cgb => manager.CreateCommands("", cgb =>
@ -34,13 +155,6 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
if (!e.User.ServerPermissions.ManageChannels) if (!e.User.ServerPermissions.ManageChannels)
return; return;
List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars))
return;
}
var enemyClan = e.GetArg("enemy_clan"); var enemyClan = e.GetArg("enemy_clan");
if (string.IsNullOrWhiteSpace(enemyClan)) if (string.IsNullOrWhiteSpace(enemyClan))
{ {
@ -52,29 +166,21 @@ namespace NadekoBot.Modules.ClashOfClans
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false); await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
return; return;
} }
var cw = new ClashWar(enemyClan, size, e); List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars))
return;
}
var cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
//cw.Start(); //cw.Start();
wars.Add(cw); wars.Add(cw);
cw.OnUserTimeExpired += async (u) =>
{
try
{
await
e.Channel.SendMessage(
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**")
.ConfigureAwait(false);
}
catch { }
};
cw.OnWarEnded += async () =>
{
try
{
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**").ConfigureAwait(false);
}
catch { }
};
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false); await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
Save();
//war with the index X started. //war with the index X started.
}); });
@ -93,14 +199,14 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
try try
{ {
var startTask = war.Start(); war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false); await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
await startTask.ConfigureAwait(false);
} }
catch catch
{ {
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**").ConfigureAwait(false); await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
} }
Save();
}); });
cgb.CreateCommand(Prefix + "listwar") cgb.CreateCommand(Prefix + "listwar")
@ -132,6 +238,7 @@ namespace NadekoBot.Modules.ClashOfClans
} }
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false); await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
return; return;
} }
//if number is not null, print the war needed //if number is not null, print the war needed
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
@ -173,6 +280,7 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
war.Call(usr, baseNum - 1); war.Call(usr, baseNum - 1);
await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}").ConfigureAwait(false); await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -206,7 +314,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "unclaim") cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall") .Alias(Prefix + "uncall")
.Alias(Prefix + "uc") .Alias(Prefix + "uc")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | {Prefix}uc [war_number] [optional_other_name]") .Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -226,6 +334,7 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
var baseNumber = war.Uncall(usr); var baseNumber = war.Uncall(usr);
await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false); await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -246,12 +355,17 @@ namespace NadekoBot.Modules.ClashOfClans
return; return;
} }
warsInfo.Item1[warsInfo.Item2].End(); warsInfo.Item1[warsInfo.Item2].End();
await e.Channel.SendMessage($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
var size = warsInfo.Item1[warsInfo.Item2].Size; var size = warsInfo.Item1[warsInfo.Item2].Size;
warsInfo.Item1.RemoveAt(warsInfo.Item2); warsInfo.Item1.RemoveAt(warsInfo.Item2);
Save();
}); });
}); });
} }
#endregion
private async Task FinishClaim(CommandEventArgs e, int stars = 3) private async Task FinishClaim(CommandEventArgs e, int stars = 3)
{ {
@ -271,6 +385,7 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
var baseNum = war.FinishClaim(usr, stars); var baseNum = war.FinishClaim(usr, stars);
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Conversations
cgb.AddCheck(PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand("..") cgb.CreateCommand("..")
.Description("Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message") .Description("Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`")
.Parameter("keyword", ParameterType.Required) .Parameter("keyword", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -54,7 +54,7 @@ namespace NadekoBot.Modules.Conversations
}); });
cgb.CreateCommand("...") cgb.CreateCommand("...")
.Description("Shows a random quote with a specified name. | .. abc") .Description("Shows a random quote with a specified name. | `... abc`")
.Parameter("keyword", ParameterType.Required) .Parameter("keyword", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {

View File

@ -0,0 +1,289 @@
using NadekoBot.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Extensions;
using System.Threading;
namespace NadekoBot.Modules.Gambling.Commands
{
class AnimalRacing : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces = new ConcurrentDictionary<ulong, AnimalRace>();
public AnimalRacing(DiscordModule module) : base(module)
{
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Prefix + "race")
.Description("Starts a new animal race.")
.Do(e => {
var ar = new AnimalRace(e.Server.Id, e.Channel);
if (ar.Fail)
{
return;
}
});
cgb.CreateCommand(Prefix + "joinrace")
.Alias(Prefix + "jr")
.Description("Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`")
.Parameter("amount", ParameterType.Optional)
.Do(async e => {
int amount;
if (!int.TryParse(e.GetArg("amount"), out amount) || amount < 0)
amount = 0;
var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
if (userFlowers < amount)
{
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
return;
}
if (amount > 0)
await FlowersHandler.RemoveFlowers(e.User, "BetRace", (int)amount, true).ConfigureAwait(false);
AnimalRace ar;
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar)) {
await e.Channel.SendMessage("No race exists on this server");
}
await ar.JoinRace(e.User, amount);
});
}
public class AnimalRace
{
private ConcurrentQueue<string> animals = new ConcurrentQueue<string>(NadekoBot.Config.RaceAnimals.Shuffle());
public bool Fail { get; internal set; }
public List<Participant> participants = new List<Participant>();
private ulong serverId;
private int messagesSinceGameStarted = 0;
public Channel raceChannel { get; set; }
public bool Started { get; private set; } = false;
public AnimalRace(ulong serverId, Channel ch)
{
this.serverId = serverId;
this.raceChannel = ch;
if (!AnimalRaces.TryAdd(serverId, this))
{
Fail = true;
return;
}
var cancelSource = new CancellationTokenSource();
var token = cancelSource.Token;
var fullgame = CheckForFullGameAsync(token);
Task.Run(async () =>
{
try
{
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type $jr to join the race.`");
var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
Started = true;
cancelSource.Cancel();
if (t == fullgame)
{
await raceChannel.SendMessage("🏁`Race full, starting right now!`");
}
else if (participants.Count > 1)
{
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " praticipants.`");
}
else
{
await raceChannel.SendMessage("🏁`Race failed to start since there was not enough participants.`");
var p = participants.FirstOrDefault();
if (p != null)
await FlowersHandler.AddFlowersAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false);
End();
return;
}
await Task.Run(StartRace);
End();
}
catch { }
});
}
private void End()
{
AnimalRace throwaway;
AnimalRaces.TryRemove(serverId, out throwaway);
}
private async Task StartRace() {
var rng = new Random();
Participant winner = null;
Message msg = null;
int place = 1;
try
{
NadekoBot.Client.MessageReceived += Client_MessageReceived;
while (!participants.All(p => p.Total >= 60))
{
//update the state
participants.ForEach(p =>
{
p.Total += 1 + rng.Next(0, 10);
if (p.Total > 60)
{
p.Total = 60;
if (winner == null)
{
winner = p;
}
if (p.Place == 0)
p.Place = place++;
}
});
//draw the state
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
{
if(msg != null)
try { await msg.Delete(); } catch { }
msg = await raceChannel.SendMessage(text);
messagesSinceGameStarted = 0;
}
else
await msg.Edit(text);
await Task.Delay(2500);
}
}
finally
{
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
}
if (winner.AmountBet > 0)
{
var wonAmount = winner.AmountBet * (participants.Count - 1);
await FlowersHandler.AddFlowersAsync(winner.User, "Won a Race", wonAmount).ConfigureAwait(false);
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{NadekoBot.Config.CurrencySign}!**");
}
else
{
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race!**");
}
}
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
if (e.Message.IsAuthor || e.Channel.IsPrivate || e.Channel != raceChannel)
return;
messagesSinceGameStarted++;
}
private async Task CheckForFullGameAsync(CancellationToken cancelToken) {
while (animals.Count > 0)
{
await Task.Delay(100,cancelToken);
}
}
public async Task<bool> JoinRace(User u, int amount = 0)
{
var animal = "";
if (!animals.TryDequeue(out animal))
{
await raceChannel.SendMessage($"{u.Mention} `There is no running race on this server.`");
return false;
}
var p = new Participant(u, animal, amount);
if (participants.Contains(p))
{
await raceChannel.SendMessage($"{u.Mention} `You already joined this race.`");
return false;
}
if (Started)
{
await raceChannel.SendMessage($"{u.Mention} `Race is already started`");
return false;
}
participants.Add(p);
await raceChannel.SendMessage($"{u.Mention} **joined the race as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {NadekoBot.Config.CurrencyName.SnPl(amount)}!**" : "**"));
return true;
}
}
public class Participant
{
public User User { get; set; }
public string Animal { get; set; }
public int AmountBet { get; set; }
public float Coeff { get; set; }
public int Total { get; set; }
public int Place { get; set; } = 0;
public Participant(User u, string a, int amount)
{
this.User = u;
this.Animal = a;
this.AmountBet = amount;
}
public override int GetHashCode()
{
return User.GetHashCode();
}
public override bool Equals(object obj)
{
var p = obj as Participant;
return p == null?
false:
p.User == User;
}
public override string ToString()
{
var str = new string('‣', Total) + Animal;
if (Place == 0)
return str;
if (Place == 1)
{
return str + "🏆";
}
else if (Place == 2)
{
return str + "`2nd`";
}
else if (Place == 3)
{
return str + "`3rd`";
}
else {
return str + $"`{Place}th`";
}
}
}
}
}

View File

@ -4,6 +4,7 @@ using Discord.Modules;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.DataModels; using NadekoBot.DataModels;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules.Gambling.Commands;
using NadekoBot.Modules.Permissions.Classes; using NadekoBot.Modules.Permissions.Classes;
using System; using System;
using System.Linq; using System.Linq;
@ -18,6 +19,7 @@ namespace NadekoBot.Modules.Gambling
commands.Add(new DrawCommand(this)); commands.Add(new DrawCommand(this));
commands.Add(new FlipCoinCommand(this)); commands.Add(new FlipCoinCommand(this));
commands.Add(new DiceRollCommand(this)); commands.Add(new DiceRollCommand(this));
commands.Add(new AnimalRacing(this));
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling;
@ -31,7 +33,7 @@ namespace NadekoBot.Modules.Gambling
commands.ForEach(com => com.Init(cgb)); commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand(Prefix + "raffle") cgb.CreateCommand(Prefix + "raffle")
.Description("Prints a name and ID of a random user from the online list from the (optional) role.") .Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName")
.Parameter("role", ParameterType.Optional) .Parameter("role", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -61,7 +63,7 @@ namespace NadekoBot.Modules.Gambling
}); });
cgb.CreateCommand(Prefix + "give") cgb.CreateCommand(Prefix + "give")
.Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)) .Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)+ $"|`{Prefix}give 1 \"@SomeGuy\"`")
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed) .Parameter("receiver", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -93,7 +95,7 @@ namespace NadekoBot.Modules.Gambling
}); });
cgb.CreateCommand(Prefix + "award") cgb.CreateCommand(Prefix + "award")
.Description("Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`") .Description($"Gives someone a certain amount of flowers. **Bot Owner Only!** | `{Prefix}award 100 @person`")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed) .Parameter("receiver", ParameterType.Unparsed)
@ -115,7 +117,7 @@ namespace NadekoBot.Modules.Gambling
}); });
cgb.CreateCommand(Prefix + "take") cgb.CreateCommand(Prefix + "take")
.Description("Takes a certain amount of flowers from someone. **Bot Owner Only!**") .Description($"Takes a certain amount of flowers from someone. **Bot Owner Only!** | `{Prefix}take 1 \"@someguy\"`")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
.Parameter("rektperson", ParameterType.Unparsed) .Parameter("rektperson", ParameterType.Unparsed)

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Modules.Games.Commands namespace NadekoBot.Modules.Games.Commands
@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Games.Commands
//channelid/messageid pair //channelid/messageid pair
ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>(); ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>();
private object locker = new object(); private SemaphoreSlim locker = new SemaphoreSlim(1,1);
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
@ -78,38 +79,47 @@ namespace NadekoBot.Modules.Games.Commands
await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false); await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false);
var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false); var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false);
ThreadPool.QueueUserWorkItem(async (state) =>
{
try
{
await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
await msg.Delete().ConfigureAwait(false); await msg.Delete().ConfigureAwait(false);
}
catch { }
});
}); });
cgb.CreateCommand(Module.Prefix + "plant") cgb.CreateCommand(Module.Prefix + "plant")
.Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)") .Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)")
.Do(e => .Do(async e =>
{ {
lock (locker) await locker.WaitAsync().ConfigureAwait(false);
try
{ {
if (plantedFlowerChannels.ContainsKey(e.Channel.Id)) if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
{ {
e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel."); await e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false);
return; return;
} }
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).GetAwaiter().GetResult(); var removed = await FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).ConfigureAwait(false);
if (!removed) if (!removed)
{ {
e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait(); await e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false);
return; return;
} }
var file = GetRandomCurrencyImagePath(); var file = GetRandomCurrencyImagePath();
Message msg; Message msg;
if (file == null) if (file == null)
msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult(); msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false);
else else
msg = e.Channel.SendFile(file).GetAwaiter().GetResult(); msg = await e.Channel.SendFile(file).ConfigureAwait(false);
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]); var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
var msg2 = e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").GetAwaiter().GetResult(); var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false);
plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 }); plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
} }
finally { locker.Release(); }
}); });
cgb.CreateCommand(Prefix + "gencurrency") cgb.CreateCommand(Prefix + "gencurrency")
@ -129,12 +139,12 @@ namespace NadekoBot.Modules.Games.Commands
int throwaway; int throwaway;
if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway)) if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
{ {
await e.Channel.SendMessage("`Currency generation disabled on this channel.`"); await e.Channel.SendMessage("`Currency generation disabled on this channel.`").ConfigureAwait(false);
} }
else else
{ {
if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd)) if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`"); await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false);
} }
}); });
} }

View File

@ -15,11 +15,6 @@ namespace NadekoBot.Modules.Games.Commands
public static ConcurrentDictionary<Server, Poll> ActivePolls = new ConcurrentDictionary<Server, Poll>(); public static ConcurrentDictionary<Server, Poll> ActivePolls = new ConcurrentDictionary<Server, Poll>();
public Func<CommandEventArgs, Task> DoFunc()
{
throw new NotImplementedException();
}
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "poll") cgb.CreateCommand(Module.Prefix + "poll")

View File

@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
{ {
internal class TriviaGame internal class TriviaGame
{ {
private readonly object _guessLock = new object(); private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1);
private Server server { get; } private Server server { get; }
private Channel channel { get; } private Channel channel { get; }
@ -113,7 +113,8 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
var guess = false; var guess = false;
lock (_guessLock) await _guessLock.WaitAsync().ConfigureAwait(false);
try
{ {
if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested) if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested)
{ {
@ -122,6 +123,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
guess = true; guess = true;
} }
} }
finally { _guessLock.Release(); }
if (!guess) return; if (!guess) return;
triviaCancelSource.Cancel(); triviaCancelSource.Cancel();
await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Games
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "choose") cgb.CreateCommand(Prefix + "choose")
.Description("Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more") .Description($"Chooses a thing from a list of things | `{Prefix}choose Get up;Sleep;Sleep more`")
.Parameter("list", ParameterType.Unparsed) .Parameter("list", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Games
}); });
cgb.CreateCommand(Prefix + "8ball") cgb.CreateCommand(Prefix + "8ball")
.Description("Ask the 8ball a yes/no question.") .Description($"Ask the 8ball a yes/no question. | `{Prefix}8ball should i do something`")
.Parameter("question", ParameterType.Unparsed) .Parameter("question", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -60,14 +60,14 @@ namespace NadekoBot.Modules.Games
try try
{ {
await e.Channel.SendMessage( await e.Channel.SendMessage(
$":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`") $":question: `Question` __**{question}**__ \n🎱 `8Ball Answers` __**{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}**__")
.ConfigureAwait(false); .ConfigureAwait(false);
} }
catch { } catch { }
}); });
cgb.CreateCommand(Prefix + "rps") cgb.CreateCommand(Prefix + "rps")
.Description("Play a game of rocket paperclip scissors with Nadeko. | >rps scissors") .Description($"Play a game of rocket paperclip scissors with Nadeko. | `{Prefix}rps scissors`")
.Parameter("input", ParameterType.Required) .Parameter("input", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {

View File

@ -49,7 +49,8 @@ namespace NadekoBot.Classes.Help.Commands
{ {
string helpstr = string helpstr =
$@"######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/** $@"######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/**
######You can donate on paypal: `nadekodiscordbot@gmail.com` ######You can donate on patreon: `https://patreon.com/nadekobot`
######or paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands #NadekoBot List Of Commands
Version: `{NadekoStats.Instance.BotVersion}`"; Version: `{NadekoStats.Instance.BotVersion}`";

View File

@ -113,17 +113,10 @@ namespace NadekoBot.Modules.Music.Classes
if (CurrentSong == null) if (CurrentSong == null)
continue; continue;
try
{
OnStarted(this, CurrentSong); OnStarted(this, CurrentSong);
await CurrentSong.Play(audioClient, cancelToken); await CurrentSong.Play(audioClient, cancelToken);
}
catch (OperationCanceledException)
{
Console.WriteLine("Song canceled");
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
}
OnCompleted(this, CurrentSong); OnCompleted(this, CurrentSong);
if (RepeatPlaylist) if (RepeatPlaylist)
@ -135,8 +128,14 @@ namespace NadekoBot.Modules.Music.Classes
} }
finally finally
{ {
await Task.Delay(300).ConfigureAwait(false); if (!cancelToken.IsCancellationRequested)
{
SongCancelSource.Cancel();
}
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
CurrentSong = null; CurrentSong = null;
await Task.Delay(300).ConfigureAwait(false);
} }
} }
} }

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Music.Classes
public int BufferSize { get; } public int BufferSize { get; }
private readonly object readWriteLock = new object(); private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1);
public PoopyBuffer(int size) public PoopyBuffer(int size)
{ {
@ -32,12 +32,15 @@ namespace NadekoBot.Modules.Music.Classes
ringBuffer = new byte[size]; ringBuffer = new byte[size];
} }
public int Read(byte[] buffer, int count) public Task<int> ReadAsync(byte[] buffer, int count)
{
return Task.Run(async () =>
{ {
if (buffer.Length < count) if (buffer.Length < count)
throw new ArgumentException(); throw new ArgumentException();
//Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
lock (readWriteLock) await readWriteLock.WaitAsync().ConfigureAwait(false);
try
{ {
//read as much as you can if you're reading too much //read as much as you can if you're reading too much
if (count > ContentLength) if (count > ContentLength)
@ -77,6 +80,9 @@ namespace NadekoBot.Modules.Music.Classes
ReadPosition = readFromStart; ReadPosition = readFromStart;
return count; return count;
} }
finally { readWriteLock.Release(); }
});
} }
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken) public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken)
@ -89,9 +95,12 @@ namespace NadekoBot.Modules.Music.Classes
if (cancelToken.IsCancellationRequested) if (cancelToken.IsCancellationRequested)
return; return;
} }
await Task.Run(async () =>
{
//the while above assures that i cannot write past readposition with my write, so i don't have to check //the while above assures that i cannot write past readposition with my write, so i don't have to check
// *unless its multithreaded or task is not awaited // *unless its multithreaded or task is not awaited
lock (readWriteLock) await readWriteLock.WaitAsync().ConfigureAwait(false);
try
{ {
// if i can just write without hitting buffer.length, do it // if i can just write without hitting buffer.length, do it
if (WritePosition + count < BufferSize) if (WritePosition + count < BufferSize)
@ -115,6 +124,8 @@ namespace NadekoBot.Modules.Music.Classes
WritePosition = wroteFromStart; WritePosition = wroteFromStart;
} }
finally { readWriteLock.Release(); }
});
} }
} }
} }

View File

@ -3,6 +3,7 @@ using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -31,9 +32,7 @@ namespace NadekoBot.Modules.Music.Classes
public SongInfo SongInfo { get; } public SongInfo SongInfo { get; }
public string QueuerName { get; set; } public string QueuerName { get; set; }
private PoopyBuffer songBuffer { get; set; } private bool bufferingCompleted { get; set; } = false;
private bool prebufferingComplete { get; set; } = false;
public MusicPlayer MusicPlayer { get; set; } public MusicPlayer MusicPlayer { get; set; }
public string PrettyCurrentTime() public string PrettyCurrentTime()
@ -74,7 +73,7 @@ namespace NadekoBot.Modules.Music.Classes
return this; return this;
} }
private Task BufferSong(CancellationToken cancelToken) => private Task BufferSong(string filename, CancellationToken cancelToken) =>
Task.Factory.StartNew(async () => Task.Factory.StartNew(async () =>
{ {
Process p = null; Process p = null;
@ -89,40 +88,38 @@ namespace NadekoBot.Modules.Music.Classes
RedirectStandardError = false, RedirectStandardError = false,
CreateNoWindow = true, CreateNoWindow = true,
}); });
const int blockSize = 3840; var prebufferSize = 100ul.MiB();
var buffer = new byte[blockSize]; using (var outStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read))
var attempt = 0;
while (!cancelToken.IsCancellationRequested)
{ {
var read = 0; byte[] buffer = new byte[81920];
try int bytesRead;
while ((bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false)) != 0)
{ {
read = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, blockSize, cancelToken) await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
.ConfigureAwait(false); while ((ulong)outStream.Length - bytesSent > prebufferSize)
await Task.Delay(100, cancelToken);
} }
catch
{
return;
} }
if (read == 0)
if (attempt++ == 50) bufferingCompleted = true;
break;
else
await Task.Delay(100, cancelToken).ConfigureAwait(false);
else
attempt = 0;
await songBuffer.WriteAsync(buffer, read, cancelToken).ConfigureAwait(false);
if (songBuffer.ContentLength > 2.MB())
prebufferingComplete = true;
} }
catch (System.ComponentModel.Win32Exception) {
var oldclr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
Please install and configure FFMPEG to play music.
Check the guides for your platform on how to setup ffmpeg correctly:
Windows Guide: https://goo.gl/SCv72y
Linux Guide: https://goo.gl/rRhjCp");
Console.ForegroundColor = oldclr;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Buffering errored: {ex.Message}"); Console.WriteLine($"Buffering stopped: {ex.Message}");
} }
finally finally
{ {
Console.WriteLine($"Buffering done." + $" [{songBuffer.ContentLength}]"); Console.WriteLine($"Buffering done.");
if (p != null) if (p != null)
{ {
try try
@ -137,25 +134,41 @@ namespace NadekoBot.Modules.Music.Classes
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
{ {
// initialize the buffer here because if this song was playing before (requeued), we must delete old buffer data var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
songBuffer = new PoopyBuffer(NadekoBot.Config.BufferSize);
var bufferTask = BufferSong(cancelToken).ConfigureAwait(false); var bufferTask = BufferSong(filename, cancelToken).ConfigureAwait(false);
var bufferAttempts = 0;
const int waitPerAttempt = 500; var inStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);
var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9;
while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes) bytesSent = 0;
try
{ {
await Task.Delay(waitPerAttempt, cancelToken).ConfigureAwait(false); var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken);
var sw = new Stopwatch();
sw.Start();
var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken));
if (t != prebufferingTask)
{
Console.WriteLine("Prebuffering timed out or canceled. Cannot get any data from the stream.");
return;
} }
Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}"); else if(prebufferingTask.IsCanceled)
{
Console.WriteLine("Prebuffering timed out. Cannot get any data from the stream.");
return;
}
sw.Stop();
Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed);
const int blockSize = 3840; const int blockSize = 3840;
var attempt = 0; var attempt = 0;
byte[] buffer = new byte[blockSize];
while (!cancelToken.IsCancellationRequested) while (!cancelToken.IsCancellationRequested)
{ {
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
byte[] buffer = new byte[blockSize]; var read = inStream.Read(buffer, 0, buffer.Length);
var read = songBuffer.Read(buffer, blockSize); //await inStream.CopyToAsync(voiceClient.OutputStream);
unchecked unchecked
{ {
bytesSent += (ulong)read; bytesSent += (ulong)read;
@ -164,7 +177,6 @@ namespace NadekoBot.Modules.Music.Classes
if (attempt++ == 20) if (attempt++ == 20)
{ {
voiceClient.Wait(); voiceClient.Wait();
Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]");
break; break;
} }
else else
@ -174,16 +186,30 @@ namespace NadekoBot.Modules.Music.Classes
while (this.MusicPlayer.Paused) while (this.MusicPlayer.Paused)
await Task.Delay(200, cancelToken).ConfigureAwait(false); await Task.Delay(200, cancelToken).ConfigureAwait(false);
buffer = AdjustVolume(buffer, MusicPlayer.Volume); buffer = AdjustVolume(buffer, MusicPlayer.Volume);
voiceClient.Send(buffer, 0, read); voiceClient.Send(buffer, 0, read);
} }
Console.WriteLine("Awiting buffer task"); }
finally
{
await bufferTask; await bufferTask;
Console.WriteLine("Buffer task done."); await Task.Run(() => voiceClient.Clear());
voiceClient.Clear(); inStream.Dispose();
cancelToken.ThrowIfCancellationRequested(); try { File.Delete(filename); } catch { }
}
} }
private async Task CheckPrebufferingAsync(Stream inStream, CancellationToken cancelToken)
{
while (!bufferingCompleted && inStream.Length < 2.MiB())
{
await Task.Delay(100, cancelToken);
}
Console.WriteLine("Buffering successfull");
}
/*
//stackoverflow ftw //stackoverflow ftw
private static byte[] AdjustVolume(byte[] audioSamples, float volume) private static byte[] AdjustVolume(byte[] audioSamples, float volume)
{ {
@ -210,6 +236,33 @@ namespace NadekoBot.Modules.Music.Classes
} }
return array; return array;
} }
*/
//aidiakapi ftw
public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume)
{
Contract.Requires(audioSamples != null);
Contract.Requires(audioSamples.Length % 2 == 0);
Contract.Requires(volume >= 0f && volume <= 1f);
Contract.Assert(BitConverter.IsLittleEndian);
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
// 16-bit precision for the multiplication
int volumeFixed = (int)Math.Round(volume * 65536d);
int count = audioSamples.Length / 2;
fixed (byte* srcBytes = audioSamples)
{
short* src = (short*)srcBytes;
for (int i = count; i != 0; i--, src++)
*src = (short)(((*src) * volumeFixed) >> 16);
}
return audioSamples;
}
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal) public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
{ {

View File

@ -18,11 +18,16 @@ namespace NadekoBot.Modules.Music
{ {
internal class MusicModule : DiscordModule internal class MusicModule : DiscordModule
{ {
public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>(); public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
public const string MusicDataPath = "data/musicdata";
public MusicModule() public MusicModule()
{ {
//it can fail if its currenctly opened or doesn't exist. Either way i don't care
try { Directory.Delete(MusicDataPath, true); } catch { }
Directory.CreateDirectory(MusicDataPath);
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music;
@ -713,7 +718,7 @@ namespace NadekoBot.Modules.Music
}); });
cgb.CreateCommand(Prefix + "goto") cgb.CreateCommand(Prefix + "goto")
.Description("Goes to a specific time in seconds in a song.") .Description($"Goes to a specific time in seconds in a song. | `{Prefix}goto 30`")
.Parameter("time") .Parameter("time")
.Do(async e => .Do(async e =>
{ {
@ -856,7 +861,7 @@ namespace NadekoBot.Modules.Music
} }
if (!silent) if (!silent)
{ {
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count}`").ConfigureAwait(false); var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(async () => Task.Run(async () =>
{ {

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.NSFW
cgb.AddCheck(PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "hentai") cgb.CreateCommand(Prefix + "hentai")
.Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~hentai yuri+kissing") .Description($"Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}hentai yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -39,7 +39,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage("`No results.`"); await e.Channel.SendMessage("`No results.`");
}); });
cgb.CreateCommand(Prefix + "danbooru") cgb.CreateCommand(Prefix + "danbooru")
.Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing") .Description($"Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}danbooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -51,7 +51,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false); await e.Channel.SendMessage(link).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "gelbooru") cgb.CreateCommand(Prefix + "gelbooru")
.Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~gelbooru yuri+kissing") .Description($"Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}gelbooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -64,7 +64,7 @@ namespace NadekoBot.Modules.NSFW
}); });
cgb.CreateCommand(Prefix + "rule34") cgb.CreateCommand(Prefix + "rule34")
.Description("Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~rule34 yuri+kissing") .Description($"Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}rule34 yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false); await e.Channel.SendMessage(link).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "e621") cgb.CreateCommand(Prefix + "e621")
.Description("Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | ~e621 yuri kissing") .Description($"Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | `{Prefix}e621 yuri kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -150,21 +150,21 @@ namespace NadekoBot.Modules.Permissions.Classes
return PermissionBanType.None; return PermissionBanType.None;
} }
private static void WriteServerToJson(ServerPermissions serverPerms) private static Task WriteServerToJson(ServerPermissions serverPerms) => Task.Run(() =>
{ {
string pathToFile = $"data/permissions/{serverPerms.Id}.json"; string pathToFile = $"data/permissions/{serverPerms.Id}.json";
File.WriteAllText(pathToFile, File.WriteAllText(pathToFile,
Newtonsoft.Json.JsonConvert.SerializeObject(serverPerms, Newtonsoft.Json.Formatting.Indented)); Newtonsoft.Json.JsonConvert.SerializeObject(serverPerms, Newtonsoft.Json.Formatting.Indented));
} });
public static void WriteToJson() public static Task WriteToJson() => Task.Run(() =>
{ {
Directory.CreateDirectory("data/permissions/"); Directory.CreateDirectory("data/permissions/");
foreach (var kvp in PermissionsDict) foreach (var kvp in PermissionsDict)
{ {
WriteServerToJson(kvp.Value); WriteServerToJson(kvp.Value);
} }
} });
public static string GetServerPermissionsRoleName(Server server) public static string GetServerPermissionsRoleName(Server server)
{ {
@ -174,25 +174,25 @@ namespace NadekoBot.Modules.Permissions.Classes
return serverPerms.PermissionsControllerRole; return serverPerms.PermissionsControllerRole;
} }
internal static void SetPermissionsRole(Server server, string roleName) internal static async Task SetPermissionsRole(Server server, string roleName)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
serverPerms.PermissionsControllerRole = roleName; serverPerms.PermissionsControllerRole = roleName;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
internal static void SetVerbosity(Server server, bool val) internal static async Task SetVerbosity(Server server, bool val)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
serverPerms.Verbose = val; serverPerms.Verbose = val;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
internal static void CopyRolePermissions(Role fromRole, Role toRole) internal static async Task CopyRolePermissions(Role fromRole, Role toRole)
{ {
var server = fromRole.Server; var server = fromRole.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -207,10 +207,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from); to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
internal static void CopyChannelPermissions(Channel fromChannel, Channel toChannel) internal static async Task CopyChannelPermissions(Channel fromChannel, Channel toChannel)
{ {
var server = fromChannel.Server; var server = fromChannel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -225,10 +225,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from); to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
internal static void CopyUserPermissions(User fromUser, User toUser) internal static async Task CopyUserPermissions(User fromUser, User toUser)
{ {
var server = fromUser.Server; var server = fromUser.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -243,10 +243,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from); to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetServerModulePermission(Server server, string moduleName, bool value) public static async Task SetServerModulePermission(Server server, string moduleName, bool value)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
@ -256,10 +256,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value; modules[moduleName] = value;
else else
modules.TryAdd(moduleName, value); modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetServerCommandPermission(Server server, string commandName, bool value) public static async Task SetServerCommandPermission(Server server, string commandName, bool value)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
@ -269,10 +269,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value; commands[commandName] = value;
else else
commands.TryAdd(commandName, value); commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetChannelModulePermission(Channel channel, string moduleName, bool value) public static async Task SetChannelModulePermission(Channel channel, string moduleName, bool value)
{ {
var server = channel.Server; var server = channel.Server;
@ -288,10 +288,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value; modules[moduleName] = value;
else else
modules.TryAdd(moduleName, value); modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetChannelCommandPermission(Channel channel, string commandName, bool value) public static async Task SetChannelCommandPermission(Channel channel, string commandName, bool value)
{ {
var server = channel.Server; var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -306,10 +306,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value; commands[commandName] = value;
else else
commands.TryAdd(commandName, value); commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetRoleModulePermission(Role role, string moduleName, bool value) public static async Task SetRoleModulePermission(Role role, string moduleName, bool value)
{ {
var server = role.Server; var server = role.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -324,10 +324,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value; modules[moduleName] = value;
else else
modules.TryAdd(moduleName, value); modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetRoleCommandPermission(Role role, string commandName, bool value) public static async Task SetRoleCommandPermission(Role role, string commandName, bool value)
{ {
var server = role.Server; var server = role.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -342,10 +342,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value; commands[commandName] = value;
else else
commands.TryAdd(commandName, value); commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetUserModulePermission(User user, string moduleName, bool value) public static async Task SetUserModulePermission(User user, string moduleName, bool value)
{ {
var server = user.Server; var server = user.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -360,10 +360,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value; modules[moduleName] = value;
else else
modules.TryAdd(moduleName, value); modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetUserCommandPermission(User user, string commandName, bool value) public static async Task SetUserCommandPermission(User user, string commandName, bool value)
{ {
var server = user.Server; var server = user.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -377,19 +377,19 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value; commands[commandName] = value;
else else
commands.TryAdd(commandName, value); commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetServerWordPermission(Server server, bool value) public static async Task SetServerWordPermission(Server server, bool value)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
serverPerms.Permissions.FilterWords = value; serverPerms.Permissions.FilterWords = value;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetChannelWordPermission(Channel channel, bool value) public static async Task SetChannelWordPermission(Channel channel, bool value)
{ {
var server = channel.Server; var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -399,19 +399,19 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name)); serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
serverPerms.ChannelPermissions[channel.Id].FilterWords = value; serverPerms.ChannelPermissions[channel.Id].FilterWords = value;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetServerFilterInvitesPermission(Server server, bool value) public static async Task SetServerFilterInvitesPermission(Server server, bool value)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
serverPerms.Permissions.FilterInvites = value; serverPerms.Permissions.FilterInvites = value;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetChannelFilterInvitesPermission(Channel channel, bool value) public static async Task SetChannelFilterInvitesPermission(Channel channel, bool value)
{ {
var server = channel.Server; var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -421,10 +421,10 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name)); serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
serverPerms.ChannelPermissions[channel.Id].FilterInvites = value; serverPerms.ChannelPermissions[channel.Id].FilterInvites = value;
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void SetCommandCooldown(Server server, string commandName, int value) public static async Task SetCommandCooldown(Server server, string commandName, int value)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
@ -436,26 +436,26 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.CommandCooldowns.AddOrUpdate(commandName, value, (str, v) => value); serverPerms.CommandCooldowns.AddOrUpdate(commandName, value, (str, v) => value);
} }
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void AddFilteredWord(Server server, string word) public static async Task AddFilteredWord(Server server, string word)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
if (serverPerms.Words.Contains(word)) if (serverPerms.Words.Contains(word))
throw new InvalidOperationException("That word is already banned."); throw new InvalidOperationException("That word is already banned.");
serverPerms.Words.Add(word); serverPerms.Words.Add(word);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
public static void RemoveFilteredWord(Server server, string word) public static async Task RemoveFilteredWord(Server server, string word)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name)); new ServerPermissions(server.Id, server.Name));
if (!serverPerms.Words.Contains(word)) if (!serverPerms.Words.Contains(word))
throw new InvalidOperationException("That word is not banned."); throw new InvalidOperationException("That word is not banned.");
serverPerms.Words.Remove(word); serverPerms.Words.Remove(word);
Task.Run(() => WriteServerToJson(serverPerms)); await WriteServerToJson(serverPerms).ConfigureAwait(false);
} }
} }
/// <summary> /// <summary>

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var chan = string.IsNullOrWhiteSpace(chanStr) var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel ? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr); : PermissionHelper.ValidateChannel(e.Server, chanStr);
PermissionsHandler.SetChannelFilterInvitesPermission(chan, state); await PermissionsHandler.SetChannelFilterInvitesPermission(chan, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.") await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.")
.ConfigureAwait(false); .ConfigureAwait(false);
return; return;
@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Permissions.Commands
foreach (var curChannel in e.Server.TextChannels) foreach (var curChannel in e.Server.TextChannels)
{ {
PermissionsHandler.SetChannelFilterInvitesPermission(curChannel, state); await PermissionsHandler.SetChannelFilterInvitesPermission(curChannel, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.") await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.")
.ConfigureAwait(false); .ConfigureAwait(false);
@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Permissions.Commands
try try
{ {
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerFilterInvitesPermission(e.Server, state); await PermissionsHandler.SetServerFilterInvitesPermission(e.Server, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for this server.") await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for this server.")
.ConfigureAwait(false); .ConfigureAwait(false);

View File

@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var chan = string.IsNullOrWhiteSpace(chanStr) var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel ? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr); : PermissionHelper.ValidateChannel(e.Server, chanStr);
PermissionsHandler.SetChannelWordPermission(chan, state); await PermissionsHandler.SetChannelWordPermission(chan, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.").ConfigureAwait(false);
return; return;
} }
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.Permissions.Commands
foreach (var curChannel in e.Server.TextChannels) foreach (var curChannel in e.Server.TextChannels)
{ {
PermissionsHandler.SetChannelWordPermission(curChannel, state); await PermissionsHandler.SetChannelWordPermission(curChannel, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.").ConfigureAwait(false); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.").ConfigureAwait(false);
} }
@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()); await PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
await e.Channel.SendMessage($"Successfully added new filtered word.").ConfigureAwait(false); await e.Channel.SendMessage($"Successfully added new filtered word.").ConfigureAwait(false);
} }
@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()); await PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
await e.Channel.SendMessage($"Successfully removed filtered word.").ConfigureAwait(false); await e.Channel.SendMessage($"Successfully removed filtered word.").ConfigureAwait(false);
} }
@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Permissions.Commands
try try
{ {
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerWordPermission(e.Server, state); await PermissionsHandler.SetServerWordPermission(e.Server, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.") await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.")
.ConfigureAwait(false); .ConfigureAwait(false);

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Permissions
await e.Channel.SendMessage($"Role `{arg}` probably doesn't exist. Create the role with that name first.").ConfigureAwait(false); await e.Channel.SendMessage($"Role `{arg}` probably doesn't exist. Create the role with that name first.").ConfigureAwait(false);
return; return;
} }
PermissionsHandler.SetPermissionsRole(e.Server, role.Name); await PermissionsHandler.SetPermissionsRole(e.Server, role.Name).ConfigureAwait(false);
await e.Channel.SendMessage($"Role `{role.Name}` is now required in order to change permissions.").ConfigureAwait(false); await e.Channel.SendMessage($"Role `{role.Name}` is now required in order to change permissions.").ConfigureAwait(false);
}); });
@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Permissions
var args = arg.Split('~').Select(a => a.Trim()).ToArray(); var args = arg.Split('~').Select(a => a.Trim()).ToArray();
if (args.Length > 2) if (args.Length > 2)
{ {
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument."); await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
return; return;
} }
try try
@ -79,12 +79,12 @@ namespace NadekoBot.Modules.Permissions
var fromRole = PermissionHelper.ValidateRole(e.Server, args[0]); var fromRole = PermissionHelper.ValidateRole(e.Server, args[0]);
var toRole = PermissionHelper.ValidateRole(e.Server, args[1]); var toRole = PermissionHelper.ValidateRole(e.Server, args[1]);
PermissionsHandler.CopyRolePermissions(fromRole, toRole); await PermissionsHandler.CopyRolePermissions(fromRole, toRole).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**."); await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**.").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
await e.Channel.SendMessage($"💢{ex.Message}"); await e.Channel.SendMessage($"💢{ex.Message}").ConfigureAwait(false);
} }
}); });
cgb.CreateCommand(Prefix + "chnlpermscopy") cgb.CreateCommand(Prefix + "chnlpermscopy")
@ -107,8 +107,8 @@ namespace NadekoBot.Modules.Permissions
var fromChannel = PermissionHelper.ValidateChannel(e.Server, args[0]); var fromChannel = PermissionHelper.ValidateChannel(e.Server, args[0]);
var toChannel = PermissionHelper.ValidateChannel(e.Server, args[1]); var toChannel = PermissionHelper.ValidateChannel(e.Server, args[1]);
PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel); await PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**."); await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**.").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -127,7 +127,7 @@ namespace NadekoBot.Modules.Permissions
var args = arg.Split('~').Select(a => a.Trim()).ToArray(); var args = arg.Split('~').Select(a => a.Trim()).ToArray();
if (args.Length > 2) if (args.Length > 2)
{ {
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument."); await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
return; return;
} }
try try
@ -135,8 +135,8 @@ namespace NadekoBot.Modules.Permissions
var fromUser = PermissionHelper.ValidateUser(e.Server, args[0]); var fromUser = PermissionHelper.ValidateUser(e.Server, args[0]);
var toUser = PermissionHelper.ValidateUser(e.Server, args[1]); var toUser = PermissionHelper.ValidateUser(e.Server, args[1]);
PermissionsHandler.CopyUserPermissions(fromUser, toUser); await PermissionsHandler.CopyUserPermissions(fromUser, toUser).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**."); await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**.").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -146,13 +146,13 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "verbose") cgb.CreateCommand(Prefix + "verbose")
.Alias(Prefix + "v") .Alias(Prefix + "v")
.Description("Sets whether to show when a command/module is blocked. | ;verbose true") .Description($"Sets whether to show when a command/module is blocked. | `{Prefix}verbose true`")
.Parameter("arg", ParameterType.Required) .Parameter("arg", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
var arg = e.GetArg("arg"); var arg = e.GetArg("arg");
var val = PermissionHelper.ValidateBool(arg); var val = PermissionHelper.ValidateBool(arg);
PermissionsHandler.SetVerbosity(e.Server, val); await PermissionsHandler.SetVerbosity(e.Server, val).ConfigureAwait(false);
await e.Channel.SendMessage($"Verbosity set to {val}.").ConfigureAwait(false); await e.Channel.SendMessage($"Verbosity set to {val}.").ConfigureAwait(false);
}); });
@ -169,7 +169,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "roleperms") cgb.CreateCommand(Prefix + "roleperms")
.Alias(Prefix + "rp") .Alias(Prefix + "rp")
.Description("Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole") .Description($"Shows banned permissions for a certain role. No argument means for everyone. | `{Prefix}rp AwesomeRole`")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -195,7 +195,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "chnlperms") cgb.CreateCommand(Prefix + "chnlperms")
.Alias(Prefix + "cp") .Alias(Prefix + "cp")
.Description("Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev") .Description($"Shows banned permissions for a certain channel. No argument means for this channel. | `{Prefix}cp #dev`")
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -220,7 +220,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "userperms") cgb.CreateCommand(Prefix + "userperms")
.Alias(Prefix + "up") .Alias(Prefix + "up")
.Description("Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth") .Description($"Shows banned permissions for a certain user. No argument means for yourself. | `{Prefix}up Kwoth`")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -246,7 +246,7 @@ namespace NadekoBot.Modules.Permissions
.Alias(Prefix + "sm") .Alias(Prefix + "sm")
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Description("Sets a module's permission at the server level. | ;sm \"module name\" enable") .Description($"Sets a module's permission at the server level. | `{Prefix}sm \"module name\" enable`")
.Do(async e => .Do(async e =>
{ {
try try
@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Permissions
var module = PermissionHelper.ValidateModule(e.GetArg("module")); var module = PermissionHelper.ValidateModule(e.GetArg("module"));
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerModulePermission(e.Server, module, state); await PermissionsHandler.SetServerModulePermission(e.Server, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
} }
catch (ArgumentException exArg) catch (ArgumentException exArg)
@ -270,7 +270,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc") cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc")
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Description("Sets a command's permission at the server level. | ;sc \"command name\" disable") .Description($"Sets a command's permission at the server level. | `{Prefix}sc \"command name\" disable`")
.Do(async e => .Do(async e =>
{ {
try try
@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Permissions
var command = PermissionHelper.ValidateCommand(e.GetArg("command")); var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerCommandPermission(e.Server, command, state); await PermissionsHandler.SetServerCommandPermission(e.Server, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
} }
catch (ArgumentException exArg) catch (ArgumentException exArg)
@ -295,7 +295,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Description("Sets a module's permission at the role level. | ;rm \"module name\" enable MyRole") .Description($"Sets a module's permission at the role level. | `{Prefix}rm \"module name\" enable MyRole`")
.Do(async e => .Do(async e =>
{ {
try try
@ -307,7 +307,7 @@ namespace NadekoBot.Modules.Permissions
{ {
foreach (var role in e.Server.Roles) foreach (var role in e.Server.Roles)
{ {
PermissionsHandler.SetRoleModulePermission(role, module, state); await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
} }
@ -315,7 +315,7 @@ namespace NadekoBot.Modules.Permissions
{ {
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role")); var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
PermissionsHandler.SetRoleModulePermission(role, module, state); await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
} }
} }
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Description("Sets a command's permission at the role level. | ;rc \"command name\" disable MyRole") .Description($"Sets a command's permission at the role level. | `{Prefix}rc \"command name\" disable MyRole`")
.Do(async e => .Do(async e =>
{ {
try try
@ -345,7 +345,7 @@ namespace NadekoBot.Modules.Permissions
{ {
foreach (var role in e.Server.Roles) foreach (var role in e.Server.Roles)
{ {
PermissionsHandler.SetRoleCommandPermission(role, command, state); await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
} }
@ -353,7 +353,7 @@ namespace NadekoBot.Modules.Permissions
{ {
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role")); var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
PermissionsHandler.SetRoleCommandPermission(role, command, state); await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
} }
} }
@ -371,7 +371,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Description("Sets a module's permission at the channel level. | ;cm \"module name\" enable SomeChannel") .Description($"Sets a module's permission at the channel level. | `{Prefix}cm \"module name\" enable SomeChannel`")
.Do(async e => .Do(async e =>
{ {
try try
@ -383,20 +383,20 @@ namespace NadekoBot.Modules.Permissions
{ {
foreach (var channel in e.Server.TextChannels) foreach (var channel in e.Server.TextChannels)
{ {
PermissionsHandler.SetChannelModulePermission(channel, module, state); await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
} }
else if (string.IsNullOrWhiteSpace(channelArg)) else if (string.IsNullOrWhiteSpace(channelArg))
{ {
PermissionsHandler.SetChannelModulePermission(e.Channel, module, state); await PermissionsHandler.SetChannelModulePermission(e.Channel, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{e.Channel.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{e.Channel.Name}** channel.").ConfigureAwait(false);
} }
else else
{ {
var channel = PermissionHelper.ValidateChannel(e.Server, channelArg); var channel = PermissionHelper.ValidateChannel(e.Server, channelArg);
PermissionsHandler.SetChannelModulePermission(channel, module, state); await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
} }
} }
@ -414,7 +414,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Description("Sets a command's permission at the channel level. | ;cc \"command name\" enable SomeChannel") .Description($"Sets a command's permission at the channel level. | `{Prefix}cc \"command name\" enable SomeChannel`")
.Do(async e => .Do(async e =>
{ {
try try
@ -426,7 +426,7 @@ namespace NadekoBot.Modules.Permissions
{ {
foreach (var channel in e.Server.TextChannels) foreach (var channel in e.Server.TextChannels)
{ {
PermissionsHandler.SetChannelCommandPermission(channel, command, state); await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
} }
@ -434,7 +434,7 @@ namespace NadekoBot.Modules.Permissions
{ {
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel")); var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
PermissionsHandler.SetChannelCommandPermission(channel, command, state); await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
} }
} }
@ -452,7 +452,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Description("Sets a module's permission at the user level. | ;um \"module name\" enable SomeUsername") .Description($"Sets a module's permission at the user level. | `{Prefix}um \"module name\" enable SomeUsername`")
.Do(async e => .Do(async e =>
{ {
try try
@ -461,7 +461,7 @@ namespace NadekoBot.Modules.Permissions
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user")); var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
PermissionsHandler.SetUserModulePermission(user, module, state); await PermissionsHandler.SetUserModulePermission(user, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false); await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
} }
catch (ArgumentException exArg) catch (ArgumentException exArg)
@ -478,7 +478,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Description("Sets a command's permission at the user level. | ;uc \"command name\" enable SomeUsername") .Description($"Sets a command's permission at the user level. | `{Prefix}uc \"command name\" enable SomeUsername`")
.Do(async e => .Do(async e =>
{ {
try try
@ -487,7 +487,7 @@ namespace NadekoBot.Modules.Permissions
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user")); var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
PermissionsHandler.SetUserCommandPermission(user, command, state); await PermissionsHandler.SetUserCommandPermission(user, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
} }
catch (ArgumentException exArg) catch (ArgumentException exArg)
@ -502,7 +502,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm") cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm")
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all modules at the server level. | ;asm [enable/disable]") .Description($"Sets permissions for all modules at the server level. | `{Prefix}asm [enable/disable]`")
.Do(async e => .Do(async e =>
{ {
try try
@ -511,7 +511,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules) foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{ {
PermissionsHandler.SetServerModulePermission(e.Server, module.Name, state); await PermissionsHandler.SetServerModulePermission(e.Server, module.Name, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false); await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
} }
@ -528,7 +528,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc") cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc")
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all commands from a certain module at the server level. | ;asc \"module name\" [enable/disable]") .Description($"Sets permissions for all commands from a certain module at the server level. | `{Prefix}asc \"module name\" [enable/disable]`")
.Do(async e => .Do(async e =>
{ {
try try
@ -538,7 +538,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module)) foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{ {
PermissionsHandler.SetServerCommandPermission(e.Server, command.Text, state); await PermissionsHandler.SetServerCommandPermission(e.Server, command.Text, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false); await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
} }
@ -555,7 +555,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm") cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm")
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel") .Description($"Sets permissions for all modules at the channel level. | `{Prefix}acm [enable/disable] SomeChannel`")
.Do(async e => .Do(async e =>
{ {
try try
@ -565,7 +565,7 @@ namespace NadekoBot.Modules.Permissions
var channel = string.IsNullOrWhiteSpace(chArg) ? e.Channel : PermissionHelper.ValidateChannel(e.Server, chArg); var channel = string.IsNullOrWhiteSpace(chArg) ? e.Channel : PermissionHelper.ValidateChannel(e.Server, chArg);
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules) foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{ {
PermissionsHandler.SetChannelModulePermission(channel, module.Name, state); await PermissionsHandler.SetChannelModulePermission(channel, module.Name, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
@ -584,7 +584,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the channel level. | ;acc \"module name\" [enable/disable] SomeChannel") .Description($"Sets permissions for all commands from a certain module at the channel level. | `{Prefix}acc \"module name\" [enable/disable] SomeChannel`")
.Do(async e => .Do(async e =>
{ {
try try
@ -594,7 +594,7 @@ namespace NadekoBot.Modules.Permissions
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel")); var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module)) foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{ {
PermissionsHandler.SetChannelCommandPermission(channel, command.Text, state); await PermissionsHandler.SetChannelCommandPermission(channel, command.Text, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false); await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
} }
@ -611,7 +611,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm") cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm")
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole") .Description($"Sets permissions for all modules at the role level. | `{Prefix}arm [enable/disable] MyRole`")
.Do(async e => .Do(async e =>
{ {
try try
@ -620,7 +620,7 @@ namespace NadekoBot.Modules.Permissions
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role")); var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules) foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{ {
PermissionsHandler.SetRoleModulePermission(role, module.Name, state); await PermissionsHandler.SetRoleModulePermission(role, module.Name, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false); await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
@ -639,7 +639,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the role level. | ;arc \"module name\" [enable/disable] MyRole") .Description($"Sets permissions for all commands from a certain module at the role level. | `{Prefix}arc \"module name\" [enable/disable] MyRole`")
.Do(async e => .Do(async e =>
{ {
try try
@ -652,7 +652,7 @@ namespace NadekoBot.Modules.Permissions
{ {
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module)) foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{ {
PermissionsHandler.SetRoleCommandPermission(role, command.Text, state); await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
} }
} }
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **all roles** role.").ConfigureAwait(false); await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **all roles** role.").ConfigureAwait(false);
@ -663,7 +663,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module)) foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{ {
PermissionsHandler.SetRoleCommandPermission(role, command.Text, state); await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
} }
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false); await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
} }
@ -679,7 +679,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "ubl") cgb.CreateCommand(Prefix + "ubl")
.Description("Blacklists a mentioned user. | ;ubl [user_mention]") .Description($"Blacklists a mentioned user. | `{Prefix}ubl [user_mention]`")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -689,13 +689,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedUsers.Any()) return; if (!e.Message.MentionedUsers.Any()) return;
var usr = e.Message.MentionedUsers.First(); var usr = e.Message.MentionedUsers.First();
NadekoBot.Config.UserBlacklist.Add(usr.Id); NadekoBot.Config.UserBlacklist.Add(usr.Id);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false); }).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "uubl") cgb.CreateCommand(Prefix + "uubl")
.Description($"Unblacklists a mentioned user. | {Prefix}uubl [user_mention]") .Description($"Unblacklists a mentioned user. | `{Prefix}uubl [user_mention]`")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -707,7 +707,7 @@ namespace NadekoBot.Modules.Permissions
if (NadekoBot.Config.UserBlacklist.Contains(usr.Id)) if (NadekoBot.Config.UserBlacklist.Contains(usr.Id))
{ {
NadekoBot.Config.UserBlacklist.Remove(usr.Id); NadekoBot.Config.UserBlacklist.Remove(usr.Id);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully unblacklisted user {usr.Name}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully unblacklisted user {usr.Name}`").ConfigureAwait(false);
} }
else else
@ -718,7 +718,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "cbl") cgb.CreateCommand(Prefix + "cbl")
.Description("Blacklists a mentioned channel (#general for example). | ;cbl #some_channel") .Description($"Blacklists a mentioned channel (#general for example). | `{Prefix}cbl #some_channel`")
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -727,13 +727,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedChannels.Any()) return; if (!e.Message.MentionedChannels.Any()) return;
var ch = e.Message.MentionedChannels.First(); var ch = e.Message.MentionedChannels.First();
NadekoBot.Config.UserBlacklist.Add(ch.Id); NadekoBot.Config.UserBlacklist.Add(ch.Id);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false); }).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "cubl") cgb.CreateCommand(Prefix + "cubl")
.Description("Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel") .Description($"Unblacklists a mentioned channel (#general for example). | `{Prefix}cubl #some_channel`")
.Parameter("channel", ParameterType.Unparsed) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -742,13 +742,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedChannels.Any()) return; if (!e.Message.MentionedChannels.Any()) return;
var ch = e.Message.MentionedChannels.First(); var ch = e.Message.MentionedChannels.First();
NadekoBot.Config.UserBlacklist.Remove(ch.Id); NadekoBot.Config.UserBlacklist.Remove(ch.Id);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false); }).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "sbl") cgb.CreateCommand(Prefix + "sbl")
.Description("Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]") .Description($"Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | `{Prefix}sbl [servername/serverid]`")
.Parameter("server", ParameterType.Unparsed) .Parameter("server", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -767,7 +767,7 @@ namespace NadekoBot.Modules.Permissions
} }
var serverId = server.Id; var serverId = server.Id;
NadekoBot.Config.ServerBlacklist.Add(serverId); NadekoBot.Config.ServerBlacklist.Add(serverId);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
//cleanup trivias and typeracing //cleanup trivias and typeracing
Modules.Games.Commands.Trivia.TriviaGame trivia; Modules.Games.Commands.Trivia.TriviaGame trivia;
TriviaCommands.RunningTrivias.TryRemove(serverId, out trivia); TriviaCommands.RunningTrivias.TryRemove(serverId, out trivia);
@ -795,7 +795,7 @@ namespace NadekoBot.Modules.Permissions
throw new ArgumentOutOfRangeException("secs", "Invalid second parameter. (Must be a number between 0 and 3600)"); throw new ArgumentOutOfRangeException("secs", "Invalid second parameter. (Must be a number between 0 and 3600)");
PermissionsHandler.SetCommandCooldown(e.Server, command, secs); await PermissionsHandler.SetCommandCooldown(e.Server, command, secs).ConfigureAwait(false);
if(secs == 0) if(secs == 0)
await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false); await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false);
else else

View File

@ -30,8 +30,6 @@ namespace NadekoBot.Modules.Searches.Commands
} }
private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>(); private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>();
private readonly object cacheLock = new object();
private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer(); private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer();
public LoLCommands(DiscordModule module) : base(module) public LoLCommands(DiscordModule module) : base(module)
@ -42,7 +40,6 @@ namespace NadekoBot.Modules.Searches.Commands
{ {
try try
{ {
lock (cacheLock)
CachedChampionImages = CachedChampionImages CachedChampionImages = CachedChampionImages
.Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0)) .Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
@ -87,10 +84,8 @@ namespace NadekoBot.Modules.Searches.Commands
var resolvedRole = role; var resolvedRole = role;
var name = e.GetArg("champ").Replace(" ", "").ToLower(); var name = e.GetArg("champ").Replace(" ", "").ToLower();
CachedChampion champ = null; CachedChampion champ = null;
lock (cacheLock)
{ if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
}
if (champ != null) if (champ != null)
{ {
champ.ImageStream.Position = 0; champ.ImageStream.Position = 0;
@ -121,13 +116,9 @@ namespace NadekoBot.Modules.Searches.Commands
role = allData[0]["role"].ToString(); role = allData[0]["role"].ToString();
resolvedRole = ResolvePos(role); resolvedRole = ResolvePos(role);
} }
lock (cacheLock) if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
{
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
}
if (champ != null) if (champ != null)
{ {
Console.WriteLine("Sending lol image from cache.");
champ.ImageStream.Position = 0; champ.ImageStream.Position = 0;
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
return; return;

View File

@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Searches.Commands
} }
} }
catch { } catch { }
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
}; };
checkTimer.Start(); checkTimer.Start();
} }
@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Searches.Commands
} }
config.ObservingStreams.Remove(toRemove); config.ObservingStreams.Remove(toRemove);
ConfigHandler.SaveConfig(); await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false); await e.Channel.SendMessage($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false);
}); });

View File

@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Searches
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "we") cgb.CreateCommand(Prefix + "we")
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | {Prefix}we Moscow RF") .Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `{Prefix}we Moscow RF`")
.Parameter("city", ParameterType.Required) .Parameter("city", ParameterType.Required)
.Parameter("country", ParameterType.Required) .Parameter("country", ParameterType.Required)
.Do(async e => .Do(async e =>
@ -69,7 +69,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "yt") cgb.CreateCommand(Prefix + "yt")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Description("Searches youtubes and shows the first result") .Description($"Searches youtubes and shows the first result | `{Prefix}yt query`")
.Do(async e => .Do(async e =>
{ {
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return; if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -106,7 +106,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "imdb") cgb.CreateCommand(Prefix + "imdb")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Description("Queries imdb for movies or series, show first result.") .Description($"Queries imdb for movies or series, show first result. | `{Prefix}imdb query`")
.Do(async e => .Do(async e =>
{ {
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return; if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -130,7 +130,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "mang") cgb.CreateCommand(Prefix + "mang")
.Alias(Prefix + "manga").Alias(Prefix + "mq") .Alias(Prefix + "manga").Alias(Prefix + "mq")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Description("Queries anilist for a manga and shows the first result.") .Description($"Queries anilist for a manga and shows the first result. | `{Prefix}mq query`")
.Do(async e => .Do(async e =>
{ {
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return; if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -157,8 +157,16 @@ $@"🌍 **Weather for** 【{obj["target"]}】
.ConfigureAwait(false); .ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "randomdog")
.Alias(Prefix + "woof")
.Description("Shows a random dog image.")
.Do(async e =>
{
await e.Channel.SendMessage("http://random.dog/" + await SearchHelper.GetResponseStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "i") cgb.CreateCommand(Prefix + "i")
.Description("Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten") .Description($"Pulls the first image found using a search parameter. Use ~ir for different results. | `{Prefix}i cute kitten`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -184,7 +192,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "ir") cgb.CreateCommand(Prefix + "ir")
.Description("Pulls a random image using a search parameter. | ~ir cute kitten") .Description($"Pulls a random image using a search parameter. | `{Prefix}ir cute kitten`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -211,7 +219,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "lmgtfy") cgb.CreateCommand(Prefix + "lmgtfy")
.Description("Google something for an idiot.") .Description($"Google something for an idiot. | `{Prefix}lmgtfy query`")
.Parameter("ffs", ParameterType.Unparsed) .Parameter("ffs", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -222,7 +230,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "google") cgb.CreateCommand(Prefix + "google")
.Alias(Prefix + "g") .Alias(Prefix + "g")
.Description("Get a google search link for some terms.") .Description($"Get a google search link for some terms. | `{Prefix}google query`")
.Parameter("terms", ParameterType.Unparsed) .Parameter("terms", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -234,7 +242,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "hs") cgb.CreateCommand(Prefix + "hs")
.Description("Searches for a Hearthstone card and shows its image. Takes a while to complete. |~hs Ysera") .Description($"Searches for a Hearthstone card and shows its image. Takes a while to complete. | `{Prefix}hs Ysera`")
.Parameter("name", ParameterType.Unparsed) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -275,7 +283,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "ud") cgb.CreateCommand(Prefix + "ud")
.Description("Searches Urban Dictionary for a word. |~ud Pineapple") .Description($"Searches Urban Dictionary for a word. | `{Prefix}ud Pineapple`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -304,7 +312,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
// thanks to Blaubeerwald // thanks to Blaubeerwald
cgb.CreateCommand(Prefix + "#") cgb.CreateCommand(Prefix + "#")
.Description("Searches Tagdef.com for a hashtag. |~# ff") .Description($"Searches Tagdef.com for a hashtag. | `{Prefix}# ff`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -389,7 +397,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "revav") cgb.CreateCommand(Prefix + "revav")
.Description("Returns a google reverse image search for someone's avatar.") .Description($"Returns a google reverse image search for someone's avatar. | `{Prefix}revav \"@SomeGuy\"")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -406,7 +414,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "revimg") cgb.CreateCommand(Prefix + "revimg")
.Description("Returns a google reverse image search for an image from a link.") .Description($"Returns a google reverse image search for an image from a link. | `{Prefix}revav Image link`")
.Parameter("image", ParameterType.Unparsed) .Parameter("image", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -418,7 +426,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "safebooru") cgb.CreateCommand(Prefix + "safebooru")
.Description("Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~safebooru yuri+kissing") .Description($"Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}safebooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -431,7 +439,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "wiki") cgb.CreateCommand(Prefix + "wiki")
.Description("Gives you back a wikipedia link") .Description($"Gives you back a wikipedia link | `{Prefix}wiki query`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -445,7 +453,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "clr") cgb.CreateCommand(Prefix + "clr")
.Description("Shows you what color corresponds to that hex. | `~clr 00ff00`") .Description($"Shows you what color corresponds to that hex. | `{Prefix}clr 00ff00`")
.Parameter("color", ParameterType.Unparsed) .Parameter("color", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -470,7 +478,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "videocall") cgb.CreateCommand(Prefix + "videocall")
.Description("Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message.") .Description($"Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `{Prefix}videocall \"@SomeGuy\"`")
.Parameter("arg", ParameterType.Unparsed) .Parameter("arg", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -494,7 +502,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "av") cgb.CreateCommand(Prefix + "av")
.Alias(Prefix + "avatar") .Alias(Prefix + "avatar")
.Parameter("mention", ParameterType.Required) .Parameter("mention", ParameterType.Required)
.Description("Shows a mentioned person's avatar. | ~av @X") .Description($"Shows a mentioned person's avatar. | `{Prefix}av @X`")
.Do(async e => .Do(async e =>
{ {
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault(); var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Translator
{ {
cgb.CreateCommand(Module.Prefix + "translate") cgb.CreateCommand(Module.Prefix + "translate")
.Alias(Module.Prefix + "trans") .Alias(Module.Prefix + "trans")
.Description($"Translates from>to text. From the given language to the destiation language. | {Module.Prefix}trans en>fr Hello") .Description($"Translates from>to text. From the given language to the destiation language. | `{Module.Prefix}trans en>fr Hello`")
.Parameter("langs", ParameterType.Required) .Parameter("langs", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.Do(TranslateFunc()); .Do(TranslateFunc());

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Trello
cgb.CreateCommand(Prefix + "bind") cgb.CreateCommand(Prefix + "bind")
.Description("Bind a trello bot to a single channel. " + .Description("Bind a trello bot to a single channel. " +
"You will receive notifications from your board when something is added or edited." + "You will receive notifications from your board when something is added or edited." +
" | bind [board_id]") $" | `{Prefix}bind [board_id]`")
.Parameter("board_id", Discord.Commands.ParameterType.Required) .Parameter("board_id", Discord.Commands.ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Trello
}); });
cgb.CreateCommand(Prefix + "cards") cgb.CreateCommand(Prefix + "cards")
.Description("Lists all cards from the supplied list. You can supply either a name or an index.") .Description($"Lists all cards from the supplied list. You can supply either a name or an index. | `{Prefix}cards index`")
.Parameter("list_name", Discord.Commands.ParameterType.Unparsed) .Parameter("list_name", Discord.Commands.ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Utility
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "whoplays") cgb.CreateCommand(Prefix + "whoplays")
.Description("Shows a list of users who are playing the specified game.") .Description($"Shows a list of users who are playing the specified game. | `{Prefix}whoplays Overwatch`")
.Parameter("game", ParameterType.Unparsed) .Parameter("game", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -52,16 +52,15 @@ namespace NadekoBot.Modules.Utility
}); });
cgb.CreateCommand(Prefix + "inrole") cgb.CreateCommand(Prefix + "inrole")
.Description("Lists every person from the provided role or roles (separated by a ',') on this server.") .Description($"Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `{Prefix}inrole Role`")
.Parameter("roles", ParameterType.Unparsed) .Parameter("roles", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
await Task.Run(async () => await Task.Run(async () =>
{ {
if (!e.User.ServerPermissions.MentionEveryone) return;
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim()); var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
string send = $"`Here is a list of users in a specfic role:`"; string send = $"`Here is a list of users in a specfic role:`";
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str))) foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@everyone" && str != "everyone"))
{ {
var role = e.Server.FindRoles(roleStr).FirstOrDefault(); var role = e.Server.FindRoles(roleStr).FirstOrDefault();
if (role == null) continue; if (role == null) continue;
@ -71,6 +70,11 @@ namespace NadekoBot.Modules.Utility
while (send.Length > 2000) while (send.Length > 2000)
{ {
if (!e.User.ServerPermissions.ManageMessages)
{
await e.Channel.SendMessage($"{e.User.Mention} you are not allowed to use this command on roles with a lot of users in them to prevent abuse.");
return;
}
var curstr = send.Substring(0, 2000); var curstr = send.Substring(0, 2000);
await await
e.Channel.Send(curstr.Substring(0, e.Channel.Send(curstr.Substring(0,
@ -110,7 +114,7 @@ namespace NadekoBot.Modules.Utility
}); });
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid") cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
.Description("Shows user ID.") .Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -122,11 +126,11 @@ namespace NadekoBot.Modules.Utility
}); });
cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid") cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
.Description("Shows current channel ID.") .Description($"Shows current channel ID. | `{Prefix}cid`")
.Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false)); .Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid") cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
.Description("Shows current server ID.") .Description($"Shows current server ID. | `{Prefix}sid`")
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false)); .Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
cgb.CreateCommand(Prefix + "roles") cgb.CreateCommand(Prefix + "roles")
@ -144,6 +148,18 @@ namespace NadekoBot.Modules.Utility
} }
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false); await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "channeltopic")
.Alias(Prefix + "ct")
.Description($"Sends current channel's topic as a message. | `{Prefix}ct`")
.Do(async e =>
{
var topic = e.Channel.Topic;
if (string.IsNullOrWhiteSpace(topic))
return;
await e.Channel.SendMessage(topic).ConfigureAwait(false);
});
}); });
} }
} }

View File

@ -197,7 +197,7 @@ namespace NadekoBot
return; return;
} }
#if NADEKO_RELEASE #if NADEKO_RELEASE
await Task.Delay(90000).ConfigureAwait(false); await Task.Delay(100000).ConfigureAwait(false);
#else #else
await Task.Delay(1000).ConfigureAwait(false); await Task.Delay(1000).ConfigureAwait(false);
#endif #endif

View File

@ -46,6 +46,7 @@
<Prefer32Bit>true</Prefer32Bit> <Prefer32Bit>true</Prefer32Bit>
<NoWarn> <NoWarn>
</NoWarn> </NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -55,6 +56,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -78,13 +80,14 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants> <DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit> <Prefer32Bit>true</Prefer32Bit>
<Optimize>false</Optimize>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath> <OutputPath>bin\x64\Release\</OutputPath>
@ -115,6 +118,7 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit> <Prefer32Bit>true</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="libvideo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="libvideo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@ -186,6 +190,7 @@
<Compile Include="Classes\FlowersHandler.cs" /> <Compile Include="Classes\FlowersHandler.cs" />
<Compile Include="Modules\Conversations\Commands\RipCommand.cs" /> <Compile Include="Modules\Conversations\Commands\RipCommand.cs" />
<Compile Include="Modules\CustomReactions\CustomReactions.cs" /> <Compile Include="Modules\CustomReactions\CustomReactions.cs" />
<Compile Include="Modules\Gambling\Commands\AnimalRacing.cs" />
<Compile Include="Modules\Music\Classes\PlaylistFullException.cs" /> <Compile Include="Modules\Music\Classes\PlaylistFullException.cs" />
<Compile Include="Modules\Programming\Commands\HaskellRepl.cs" /> <Compile Include="Modules\Programming\Commands\HaskellRepl.cs" />
<Compile Include="Modules\Programming\ProgrammingModule.cs" /> <Compile Include="Modules\Programming\ProgrammingModule.cs" />
@ -197,6 +202,7 @@
<Compile Include="Modules\Searches\Commands\OsuCommands.cs" /> <Compile Include="Modules\Searches\Commands\OsuCommands.cs" />
<Compile Include="Modules\Searches\Commands\PokemonSearchCommands.cs" /> <Compile Include="Modules\Searches\Commands\PokemonSearchCommands.cs" />
<Compile Include="Modules\Utility\UtilityModule.cs" /> <Compile Include="Modules\Utility\UtilityModule.cs" />
<Compile Include="_Models\DataModels\TestDataModel.cs" />
<Compile Include="_Models\DataModels\Incident.cs" /> <Compile Include="_Models\DataModels\Incident.cs" />
<Compile Include="_Models\JSONModels\AnimeResult.cs" /> <Compile Include="_Models\JSONModels\AnimeResult.cs" />
<Compile Include="_Models\JSONModels\Configuration.cs" /> <Compile Include="_Models\JSONModels\Configuration.cs" />
@ -259,7 +265,6 @@
<Compile Include="Modules\Gambling\DrawCommand.cs" /> <Compile Include="Modules\Gambling\DrawCommand.cs" />
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" /> <Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
<Compile Include="Modules\Help\Commands\HelpCommand.cs" /> <Compile Include="Modules\Help\Commands\HelpCommand.cs" />
<Compile Include="Modules\Administration\Commands\VoiceNotificationCommand.cs" />
<Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" /> <Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" />
<Compile Include="Modules\Administration\AdministrationModule.cs" /> <Compile Include="Modules\Administration\AdministrationModule.cs" />
<Compile Include="Modules\Conversations\Conversations.cs" /> <Compile Include="Modules\Conversations\Conversations.cs" />

View File

@ -0,0 +1,8 @@
namespace NadekoBot.DataModels
{
internal class TestDataModel : IDataModel
{
public long TestNumber { get; set; }
public string TestString { get; set; }
}
}

View File

@ -4,6 +4,8 @@ using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Classes.JSONModels namespace NadekoBot.Classes.JSONModels
{ {
@ -88,6 +90,17 @@ namespace NadekoBot.Classes.JSONModels
public bool IsRotatingStatus { get; set; } = false; public bool IsRotatingStatus { get; set; } = false;
public int BufferSize { get; set; } = 4.MiB(); public int BufferSize { get; set; } = 4.MiB();
public string[] RaceAnimals { get; internal set; } = {
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄" };
[JsonIgnore]
public List<Quote> Quotes { get; set; } = new List<Quote>(); public List<Quote> Quotes { get; set; } = new List<Quote>();
[JsonIgnore] [JsonIgnore]
@ -187,13 +200,17 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>";
public static class ConfigHandler public static class ConfigHandler
{ {
private static readonly object configLock = new object(); private static readonly SemaphoreSlim configLock = new SemaphoreSlim(1, 1);
public static void SaveConfig() public static async Task SaveConfig()
{ {
lock (configLock) await configLock.WaitAsync();
try
{ {
File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented)); File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented));
} }
finally {
configLock.Release();
}
} }
public static bool IsBlackListed(MessageEventArgs evArgs) => IsUserBlacklisted(evArgs.User.Id) || public static bool IsBlackListed(MessageEventArgs evArgs) => IsUserBlacklisted(evArgs.User.Id) ||

View File

@ -4,7 +4,16 @@
"ForwardToAllOwners": false, "ForwardToAllOwners": false,
"IsRotatingStatus": false, "IsRotatingStatus": false,
"BufferSize": 4194304, "BufferSize": 4194304,
"Quotes": [], "RaceAnimals": [
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄"
],
"RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗", "RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗",
"CustomReactions": { "CustomReactions": {
"\\o\\": [ "\\o\\": [

View File

@ -1,8 +1,9 @@
######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/** ######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/**
######You can donate on paypal: `nadekodiscordbot@gmail.com` ######You can donate on patreon: `https://patreon.com/nadekobot`
######or paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands #NadekoBot List Of Commands
Version: `NadekoBot v0.9.6048.2992` Version: `NadekoBot v0.9.6053.28429`
### Help ### Help
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
@ -57,38 +58,38 @@ Command and aliases | Description | Usage
`.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read. `.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read.
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only. `.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.
`.restart` | Restarts the bot. Might not work. **Bot Owner Only** `.restart` | Restarts the bot. Might not work. **Bot Owner Only**
`.setrole`, `.sr` | Sets a role for a given user. | .sr @User Guest `.setrole`, `.sr` | Sets a role for a given user. | `.sr @User Guest`
`.removerole`, `.rr` | Removes a role from a given user. | .rr @User Admin `.removerole`, `.rr` | Removes a role from a given user. | `.rr @User Admin`
`.renamerole`, `.renr` | Renames a role. Role you are renaming must be lower than bot's highest role. | `.renr "First role" SecondRole` `.renamerole`, `.renr` | Renames a role. Role you are renaming must be lower than bot's highest role. | `.renr "First role" SecondRole`
`.removeallroles`, `.rar` | Removes all roles from a mentioned user. | .rar @User `.removeallroles`, `.rar` | Removes all roles from a mentioned user. | `.rar @User`
`.createrole`, `.cr` | Creates a role with a given name. | `.r Awesome Role` `.createrole`, `.cr` | Creates a role with a given name. | `.cr Awesome Role`
`.rolecolor`, `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55` `.rolecolor`, `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. | `.rc Admin 255 200 100` or `.rc Admin ffba55`
`.ban`, `.b` | Bans a user by id or name with an optional message. | .b "@some Guy" Your behaviour is toxic. `.ban`, `.b` | Bans a user by id or name with an optional message. | `.b "@some Guy" Your behaviour is toxic.`
`.softban`, `.sb` | Bans and then unbans a user by id or name with an optional message. | .sb "@some Guy" Your behaviour is toxic. `.softban`, `.sb` | Bans and then unbans a user by id or name with an optional message. | `.sb "@some Guy" Your behaviour is toxic.`
`.kick`, `.k` | Kicks a mentioned user. `.kick`, `.k` | Kicks a mentioned user. | `.k "@some Guy" Your behaviour is toxic.`
`.mute` | Mutes mentioned user or users. `.mute` | Mutes mentioned user or users. | `.mute "@Someguy"` or `.mute "@Someguy" "@Someguy"`
`.unmute` | Unmutes mentioned user or users. `.unmute` | Unmutes mentioned user or users. | `.unmute "@Someguy"` or `.unmute "@Someguy" "@Someguy"`
`.deafen`, `.deaf` | Deafens mentioned user or users `.deafen`, `.deaf` | Deafens mentioned user or users | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"`
`.undeafen`, `.undef` | Undeafens mentioned user or users `.undeafen`, `.undef` | Undeafens mentioned user or users | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"`
`.delvoichanl`, `.dvch` | Deletes a voice channel with a given name. `.delvoichanl`, `.dvch` | Deletes a voice channel with a given name. | `.dvch VoiceChannelName`
`.creatvoichanl`, `.cvch` | Creates a new voice channel with a given name. `.creatvoichanl`, `.cvch` | Creates a new voice channel with a given name. | `.cvch VoiceChannelName`
`.deltxtchanl`, `.dtch` | Deletes a text channel with a given name. `.deltxtchanl`, `.dtch` | Deletes a text channel with a given name. | `.dtch TextChannelName`
`.creatxtchanl`, `.ctch` | Creates a new text channel with a given name. `.creatxtchanl`, `.ctch` | Creates a new text channel with a given name. | `.ctch TextChannelName`
`.settopic`, `.st` | Sets a topic on the current channel. | `.st My new topic` `.settopic`, `.st` | Sets a topic on the current channel. | `.st My new topic`
`.setchanlname`, `.schn` | Changed the name of the current channel. `.setchanlname`, `.schn` | Changed the name of the current channel.| `.schn NewName`
`.heap` | Shows allocated memory - **Bot Owner Only!** `.heap` | Shows allocated memory - **Bot Owner Only!**
`.prune`, `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` `.prune`, `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
`.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!** `.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!**
`.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!** `.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!** | .newnm BotName
`.newavatar`, `.setavatar` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg` `.newavatar`, `.setavatar` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`
`.setgame` | Sets the bots game. **Bot Owner Only!** `.setgame` | Sets the bots game. **Bot Owner Only!** | `.setgame Playing with kwoth`
`.send` | Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!` `.send` | Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`
`.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. `.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `.menro RoleName`
`.unstuck` | Clears the message queue. **Bot Owner Only!** `.unstuck` | Clears the message queue. **Bot Owner Only!**
`.donators` | List of lovely people who donated to keep this project alive. `.donators` | List of lovely people who donated to keep this project alive.
`.donadd` | Add a donator to the database. `.donadd` | Add a donator to the database. | `.donadd Donate Amount`
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | .announce Useless spam `.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `.announce Useless spam`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150` `.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.savechat 150`
### Utility ### Utility
Command and aliases | Description | Usage Command and aliases | Description | Usage
@ -98,15 +99,16 @@ Command and aliases | Description | Usage
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | .sinfo Some Server `.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
`.whoplays` | Shows a list of users who are playing the specified game. `.whoplays` | Shows a list of users who are playing the specified game. | `.whoplays Overwatch`
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. `.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role`
`.checkmyperms` | Checks your userspecific permissions on this channel. `.checkmyperms` | Checks your userspecific permissions on this channel.
`.stats` | Shows some basic stats for Nadeko. `.stats` | Shows some basic stats for Nadeko.
`.dysyd` | Shows some basic stats for Nadeko. `.dysyd` | Shows some basic stats for Nadeko.
`.userid`, `.uid` | Shows user ID. `.userid`, `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"
`.channelid`, `.cid` | Shows current channel ID. `.channelid`, `.cid` | Shows current channel ID. | `.cid`
`.serverid`, `.sid` | Shows current server ID. `.serverid`, `.sid` | Shows current server ID. | `.sid`
`.roles` | List all roles on this server or a single user if specified. `.roles` | List all roles on this server or a single user if specified.
`.channeltopic`, `.ct` | Sends current channel's topic as a message. | `.ct`
### Permissions ### Permissions
Command and aliases | Description | Usage Command and aliases | Description | Usage
@ -122,38 +124,38 @@ Command and aliases | Description | Usage
`;rolepermscopy`, `;rpc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;rpc Some Role ~ Some other role` `;rolepermscopy`, `;rpc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;rpc Some Role ~ Some other role`
`;chnlpermscopy`, `;cpc` | Copies BOT PERMISSIONS (not discord permissions) from one channel to another. | `;cpc Some Channel ~ Some other channel` `;chnlpermscopy`, `;cpc` | Copies BOT PERMISSIONS (not discord permissions) from one channel to another. | `;cpc Some Channel ~ Some other channel`
`;usrpermscopy`, `;upc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;upc @SomeUser ~ @SomeOtherUser` `;usrpermscopy`, `;upc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;upc @SomeUser ~ @SomeOtherUser`
`;verbose`, `;v` | Sets whether to show when a command/module is blocked. | ;verbose true `;verbose`, `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
`;srvrperms`, `;sp` | Shows banned permissions for this server. `;srvrperms`, `;sp` | Shows banned permissions for this server.
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole `;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | `;rp AwesomeRole`
`;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev `;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | `;cp #dev`
`;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth `;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | `;up Kwoth`
`;srvrmdl`, `;sm` | Sets a module's permission at the server level. | ;sm "module name" enable `;srvrmdl`, `;sm` | Sets a module's permission at the server level. | `;sm "module name" enable`
`;srvrcmd`, `;sc` | Sets a command's permission at the server level. | ;sc "command name" disable `;srvrcmd`, `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable`
`;rolemdl`, `;rm` | Sets a module's permission at the role level. | ;rm "module name" enable MyRole `;rolemdl`, `;rm` | Sets a module's permission at the role level. | `;rm "module name" enable MyRole`
`;rolecmd`, `;rc` | Sets a command's permission at the role level. | ;rc "command name" disable MyRole `;rolecmd`, `;rc` | Sets a command's permission at the role level. | `;rc "command name" disable MyRole`
`;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | ;cm "module name" enable SomeChannel `;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | `;cm "module name" enable SomeChannel`
`;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | ;cc "command name" enable SomeChannel `;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | `;cc "command name" enable SomeChannel`
`;usrmdl`, `;um` | Sets a module's permission at the user level. | ;um "module name" enable SomeUsername `;usrmdl`, `;um` | Sets a module's permission at the user level. | `;um "module name" enable SomeUsername`
`;usrcmd`, `;uc` | Sets a command's permission at the user level. | ;uc "command name" enable SomeUsername `;usrcmd`, `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername`
`;allsrvrmdls`, `;asm` | Sets permissions for all modules at the server level. | ;asm [enable/disable] `;allsrvrmdls`, `;asm` | Sets permissions for all modules at the server level. | `;asm [enable/disable]`
`;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | ;asc "module name" [enable/disable] `;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | `;asc "module name" [enable/disable]`
`;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel `;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | `;acm [enable/disable] SomeChannel`
`;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | ;acc "module name" [enable/disable] SomeChannel `;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | `;acc "module name" [enable/disable] SomeChannel`
`;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole `;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | `;arm [enable/disable] MyRole`
`;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | ;arc "module name" [enable/disable] MyRole `;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | `;arc "module name" [enable/disable] MyRole`
`;ubl` | Blacklists a mentioned user. | ;ubl [user_mention] `;ubl` | Blacklists a mentioned user. | `;ubl [user_mention]`
`;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention] `;uubl` | Unblacklists a mentioned user. | `;uubl [user_mention]`
`;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl #some_channel `;cbl` | Blacklists a mentioned channel (#general for example). | `;cbl #some_channel`
`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel `;cubl` | Unblacklists a mentioned channel (#general for example). | `;cubl #some_channel`
`;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid] `;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | `;sbl [servername/serverid]`
`;cmdcooldown`, `;cmdcd` | Sets a cooldown per user for a command. Set 0 to clear. | `;cmdcd "some cmd" 5` `;cmdcooldown`, `;cmdcd` | Sets a cooldown per user for a command. Set 0 to clear. | `;cmdcd "some cmd" 5`
`;allcmdcooldowns`, `;acmdcds` | Shows a list of all commands and their respective cooldowns. `;allcmdcooldowns`, `;acmdcds` | Shows a list of all commands and their respective cooldowns.
### Conversations ### Conversations
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message `..` | Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`
`...` | Shows a random quote with a specified name. | .. abc `...` | Shows a random quote with a specified name. | `... abc`
`..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc` `..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`
`@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000 `@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000
`@BotName die` | Works only for the owner. Shuts the bot down. `@BotName die` | Works only for the owner. Shuts the bot down.
@ -173,11 +175,13 @@ Command and aliases | Description | Usage
`$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5 `$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5
`$rolluo` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered). If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5 `$rolluo` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered). If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. `$race` | Starts a new animal race.
`$joinrace`, `$jr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName
`$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @Someone` `$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @Someone`
`$give` | Give someone a certain amount of NadekoFlowers `$give` | Give someone a certain amount of NadekoFlowers|`$give 1 "@SomeGuy"`
`$award` | Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person` `$award` | Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`
`$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!** `$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!** | `$take 1 "@someguy"`
`$betroll`, `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | $br 5 `$betroll`, `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | $br 5
`$leaderboard`, `$lb` | `$leaderboard`, `$lb` |
@ -196,9 +200,9 @@ Command and aliases | Description | Usage
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost) `>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)
`>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60` `>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60`
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | >leet 3 Hello `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | >leet 3 Hello
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
`>8ball` | Ask the 8ball a yes/no question. `>8ball` | Ask the 8ball a yes/no question. | `>8ball should i do something`
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | >rps scissors `>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
### Music ### Music
@ -234,7 +238,7 @@ Command and aliases | Description | Usage
`!!load` | Loads a playlist under a certain name. | `!!load classical-1` `!!load` | Loads a playlist under a certain name. | `!!load classical-1`
`!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1` `!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1`
`!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5` `!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
`!!goto` | Goes to a specific time in seconds in a song. `!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
`!!getlink`, `!!gl` | Shows a link to the currently playing song. `!!getlink`, `!!gl` | Shows a link to the currently playing song.
`!!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) `!!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)
@ -262,41 +266,42 @@ Command and aliases | Description | Usage
`~pokemonability`, `~pokeab` | Searches for a pokemon ability. `~pokemonability`, `~pokeab` | Searches for a pokemon ability.
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ `~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"` `~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
`~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | ~we Moscow RF `~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `~we Moscow RF`
`~yt` | Searches youtubes and shows the first result `~yt` | Searches youtubes and shows the first result | `~yt query`
`~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result. `~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result.
`~imdb` | Queries imdb for movies or series, show first result. `~imdb` | Queries imdb for movies or series, show first result. | `~imdb query`
`~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result. `~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result. | `~mq query`
`~randomcat`, `~meow` | Shows a random cat image. `~randomcat`, `~meow` | Shows a random cat image.
`~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten `~randomdog`, `~woof` | Shows a random dog image.
`~ir` | Pulls a random image using a search parameter. | ~ir cute kitten `~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | `~i cute kitten`
`~lmgtfy` | Google something for an idiot. `~ir` | Pulls a random image using a search parameter. | `~ir cute kitten`
`~google`, `~g` | Get a google search link for some terms. `~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
`~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | ~hs Ysera `~google`, `~g` | Get a google search link for some terms. | `~google query`
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
`~#` | Searches Tagdef.com for a hashtag. | ~# ff `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
`~quote` | Shows a random quote. `~quote` | Shows a random quote.
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> `~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>
`~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/> `~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/>
`~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> `~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random>
`~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> `~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>
`~magicitem`, `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> `~magicitem`, `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>
`~revav` | Returns a google reverse image search for someone's avatar. `~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"
`~revimg` | Returns a google reverse image search for an image from a link. `~revimg` | Returns a google reverse image search for an image from a link. | `~revav Image link`
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~safebooru yuri+kissing `~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~safebooru yuri+kissing`
`~wiki` | Gives you back a wikipedia link `~wiki` | Gives you back a wikipedia link | `~wiki query`
`~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. `~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"`
`~av`, `~avatar` | Shows a mentioned person's avatar. | ~av @X `~av`, `~avatar` | Shows a mentioned person's avatar. | `~av @X`
### NSFW ### NSFW
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`~hentai` | Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~hentai yuri+kissing `~hentai` | Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~hentai yuri+kissing`
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing `~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~danbooru yuri+kissing`
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~gelbooru yuri+kissing `~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~rule34 yuri+kissing `~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~rule34 yuri+kissing`
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | ~e621 yuri kissing `~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | `~e621 yuri kissing`
`~cp` | We all know where this will lead you to. `~cp` | We all know where this will lead you to.
`~boobs` | Real adult content. `~boobs` | Real adult content.
`~butts`, `~ass`, `~butt` | Real adult content. `~butts`, `~ass`, `~butt` | Real adult content.
@ -311,7 +316,7 @@ Command and aliases | Description | Usage
`,claimfinish`, `,cf`, `,cf3`, `,claimfinish3` | Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name] `,claimfinish`, `,cf`, `,cf3`, `,claimfinish3` | Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish2`, `,cf2` | Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name] `,claimfinish2`, `,cf2` | Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish1`, `,cf1` | Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name] `,claimfinish1`, `,cf1` | Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | ,uc [war_number] [optional_other_name] `,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | ,uc [war_number] [optional_other_name]
`,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number] `,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number]
### Pokegame ### Pokegame
@ -326,7 +331,7 @@ Command and aliases | Description | Usage
### Translator ### Translator
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | ~trans en>fr Hello `~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | `~trans en>fr Hello`
`~translangs` | List the valid languages for translation. `~translangs` | List the valid languages for translation.
### Customreactions ### Customreactions
@ -352,7 +357,7 @@ Command and aliases | Description | Usage
### Trello ### Trello
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | bind [board_id] `trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | `trello bind [board_id]`
`trello unbind` | Unbinds a bot from the channel and board. `trello unbind` | Unbinds a bot from the channel and board.
`trello lists`, `trello list` | Lists all lists yo ;) `trello lists`, `trello list` | Lists all lists yo ;)
`trello cards` | Lists all cards from the supplied list. You can supply either a name or an index. `trello cards` | Lists all cards from the supplied list. You can supply either a name or an index. | `trello cards index`

@ -1 +1 @@
Subproject commit 3e519b5e0b33175e5a5ca247322b7082de484e15 Subproject commit 3a33731135f1b7dd2efdb51b16158c84bb22da66

1
ffmpeg-installer Submodule

@ -0,0 +1 @@
Subproject commit d593fe3a86be7da9e4177865446f2f5ca58b6be4