diff --git a/.gitmodules b/.gitmodules index 9ff1a297..1fa69c2d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "discord.net"] path = discord.net - url = git://github.com/rogueexception/discord.net.git + url = git://github.com/kwoth/discord.net.git diff --git a/NadekoBot.sln b/NadekoBot.sln index 155512c4..eb9860d0 100644 --- a/NadekoBot.sln +++ b/NadekoBot.sln @@ -22,51 +22,95 @@ Global EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 FullDebug|Any CPU = FullDebug|Any CPU + FullDebug|x64 = FullDebug|x64 NadekoRelease|Any CPU = NadekoRelease|Any CPU + NadekoRelease|x64 = NadekoRelease|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.ActiveCfg = Debug|x64 + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.Build.0 = Debug|x64 {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.ActiveCfg = Debug|x64 + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.Build.0 = Debug|x64 {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.ActiveCfg = NadekoRelease|x64 + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.Build.0 = NadekoRelease|x64 {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.ActiveCfg = Release|Any CPU {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.Build.0 = Release|Any CPU + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.ActiveCfg = Release|x64 + {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.Build.0 = Release|x64 {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.ActiveCfg = Debug|x64 + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.Build.0 = Debug|x64 {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.ActiveCfg = Debug|x64 + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.Build.0 = Debug|x64 {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.ActiveCfg = Release|x64 + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.Build.0 = Release|x64 {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.Build.0 = Release|Any CPU + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.ActiveCfg = Release|x64 + {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.Build.0 = Release|x64 {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.ActiveCfg = Debug|x64 + {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.Build.0 = Debug|x64 {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.ActiveCfg = Debug|x64 + {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.Build.0 = Debug|x64 {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU + {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.ActiveCfg = Release|x64 + {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.Build.0 = Release|x64 {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU + {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.ActiveCfg = Release|x64 + {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.Build.0 = Release|x64 {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.ActiveCfg = Debug|x64 + {3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.Build.0 = Debug|x64 {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.ActiveCfg = Debug|x64 + {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.Build.0 = Debug|x64 {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU + {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.ActiveCfg = Release|x64 + {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.Build.0 = Release|x64 {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU + {3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.ActiveCfg = Release|x64 + {3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.Build.0 = Release|x64 {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.ActiveCfg = Debug|x64 + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.Build.0 = Debug|x64 {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.ActiveCfg = Debug|x64 + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.Build.0 = Debug|x64 {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.ActiveCfg = Release|x64 + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.Build.0 = Release|x64 {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.ActiveCfg = Release|x64 + {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NadekoBot/Classes/DBHandler.cs b/NadekoBot/Classes/DBHandler.cs index 9fb664f9..3f2963cc 100644 --- a/NadekoBot/Classes/DBHandler.cs +++ b/NadekoBot/Classes/DBHandler.cs @@ -161,9 +161,7 @@ namespace NadekoBot.Classes using (var conn = new SQLiteConnection(FilePath)) { foreach (var o in ocol) - { - conn.InsertOrReplace(o, typeof(T)); - } + conn.InsertOrReplace(o); } } diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs index 1b162209..a4071ded 100644 --- a/NadekoBot/Classes/Extensions.cs +++ b/NadekoBot/Classes/Extensions.cs @@ -46,10 +46,10 @@ namespace NadekoBot.Extensions if (num == 0) return string.Empty; if (num <= 3) - return string.Join("", str.Select(c => '.')); + return string.Concat(str.Select(c => '.')); if (str.Length < num) return str; - return string.Join("", str.Take(num - 3)) + (hideDots ? "" : "..."); + return string.Concat(str.Take(num - 3)) + (hideDots ? "" : "..."); } /// /// Removes trailing S or ES (if specified) on the given string if the num is 1 @@ -237,7 +237,7 @@ namespace NadekoBot.Extensions public static string Matrix(this string s) => - string.Join("", s.Select(c => c.ToString() + " ̵̢̬̜͉̞̭̖̰͋̉̎ͬ̔̇̌̀".TrimTo(rng.Next(0, 12), true))); + string.Concat(s.Select(c => c.ToString() + " ̵̢̬̜͉̞̭̖̰͋̉̎ͬ̔̇̌̀".TrimTo(rng.Next(0, 12), true))); //.Replace("`", ""); public static void ForEach(this IEnumerable source, Action action) diff --git a/NadekoBot/Classes/SearchHelper.cs b/NadekoBot/Classes/SearchHelper.cs index 77c46151..43bfbe37 100644 --- a/NadekoBot/Classes/SearchHelper.cs +++ b/NadekoBot/Classes/SearchHelper.cs @@ -384,7 +384,7 @@ namespace NadekoBot.Classes { var i = 0; return "```xl\n" + string.Join("\n", items.GroupBy(item => (i++) / cols) - .Select(ig => string.Join("", ig.Select(el => howToPrint(el))))) + .Select(ig => string.Concat(ig.Select(el => howToPrint(el))))) + $"\n```"; } } diff --git a/NadekoBot/Classes/ServerSpecificConfig.cs b/NadekoBot/Classes/ServerSpecificConfig.cs index ff42f0fd..9142e574 100644 --- a/NadekoBot/Classes/ServerSpecificConfig.cs +++ b/NadekoBot/Classes/ServerSpecificConfig.cs @@ -6,6 +6,8 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; namespace NadekoBot.Classes { @@ -27,9 +29,12 @@ namespace NadekoBot.Classes { configs = JsonConvert .DeserializeObject>( - File.ReadAllText(filePath), new JsonSerializerSettings() { - Error = (s,e) => { - if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") { + File.ReadAllText(filePath), new JsonSerializerSettings() + { + Error = (s, e) => + { + if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") + { e.ErrorContext.Handled = true; } } @@ -52,14 +57,19 @@ namespace NadekoBot.Classes public ServerSpecificConfig Of(ulong id) => 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)); } + finally + { + saveLock.Release(); + } } } @@ -245,7 +255,7 @@ namespace NadekoBot.Classes LogserverIgnoreChannels = new ObservableCollection(); } - 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) { diff --git a/NadekoBot/Modules/Administration/AdministrationModule.cs b/NadekoBot/Modules/Administration/AdministrationModule.cs index cff95af4..ad28d083 100644 --- a/NadekoBot/Modules/Administration/AdministrationModule.cs +++ b/NadekoBot/Modules/Administration/AdministrationModule.cs @@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Administration { var conf = SpecificConfigurations.Default.Of(e.Server.Id); conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand; - Classes.JSONModels.ConfigHandler.SaveConfig(); + await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false); if (conf.AutoDeleteMessagesOnCommand) await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`"); else @@ -738,7 +738,7 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(msg)) return; - var ids = e.GetArg("ids").Split('-'); + var ids = e.GetArg("ids").Split('|'); if (ids.Length != 2) return; var sid = ulong.Parse(ids[0]); diff --git a/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs b/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs index fcd970a7..a01f9a8d 100644 --- a/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs +++ b/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Administration.Commands NadekoBot.Config.CustomReactions[name].Add(message); else NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List() { 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); }); @@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration.Commands index = index - 1; 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); }); @@ -183,7 +183,7 @@ namespace NadekoBot.Modules.Administration.Commands NadekoBot.Config.CustomReactions.Remove(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); }); } diff --git a/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs b/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs index aa7570cb..2d22d870 100644 --- a/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs +++ b/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs @@ -7,8 +7,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Timers; +using Timer = System.Timers.Timer; namespace NadekoBot.Modules.Administration.Commands { @@ -36,7 +38,7 @@ namespace NadekoBot.Modules.Administration.Commands {"%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) { @@ -47,7 +49,9 @@ namespace NadekoBot.Modules.Administration.Commands { i++; var status = ""; - lock (playingPlaceholderLock) + //wtf am i doing, just use a queue ffs + await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); + try { if (PlayingPlaceholders.Count == 0 || NadekoBot.Config.RotatingStatuses.Count == 0 @@ -59,6 +63,7 @@ namespace NadekoBot.Modules.Administration.Commands status = PlayingPlaceholders.Aggregate(status, (current, kvp) => current.Replace(kvp.Key, kvp.Value())); } + finally { playingPlaceholderLock.Release(); } if (string.IsNullOrWhiteSpace(status)) return; await Task.Run(() => { NadekoBot.Client.SetGame(status); }); @@ -71,14 +76,18 @@ namespace NadekoBot.Modules.Administration.Commands public Func DoFunc() => async e => { - lock (playingPlaceholderLock) + await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); + try { if (timer.Enabled) timer.Stop(); else timer.Start(); 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); }; @@ -102,10 +111,15 @@ namespace NadekoBot.Modules.Administration.Commands var arg = e.GetArg("text"); if (string.IsNullOrWhiteSpace(arg)) return; - lock (playingPlaceholderLock) + await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); + try { NadekoBot.Config.RotatingStatuses.Add(arg); - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig(); + } + finally + { + playingPlaceholderLock.Release(); } 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"); int num; string str; - lock (playingPlaceholderLock) - { + await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); + try { if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count) return; str = NadekoBot.Config.RotatingStatuses[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); }); } diff --git a/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index 51bf8859..2ef54772 100644 --- a/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -1,6 +1,8 @@ using Discord.Commands; +using Discord.Net; using NadekoBot.Classes; using NadekoBot.Modules.Permissions.Classes; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -144,7 +146,10 @@ namespace NadekoBot.Modules.Administration.Commands { await e.User.AddRoles(role).ConfigureAwait(false); } - catch + catch(HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError) + { + } + catch (Exception) { 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); } diff --git a/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs b/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs index 9c383509..c5ba20fc 100644 --- a/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs +++ b/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using NadekoBot.Modules.Permissions.Classes; +using System.Threading; namespace NadekoBot.Modules.ClashOfClans { @@ -16,8 +17,6 @@ namespace NadekoBot.Modules.ClashOfClans public static ConcurrentDictionary> ClashWars { get; } = new ConcurrentDictionary>(); - private readonly object writeLock = new object(); - public override void Install(ModuleManager manager) { manager.CreateCommands("", cgb => diff --git a/NadekoBot/Modules/Conversations/Conversations.cs b/NadekoBot/Modules/Conversations/Conversations.cs index cdc6eb26..328be562 100644 --- a/NadekoBot/Modules/Conversations/Conversations.cs +++ b/NadekoBot/Modules/Conversations/Conversations.cs @@ -9,13 +9,14 @@ using System; using System.Diagnostics; using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; namespace NadekoBot.Modules.Conversations { internal class Conversations : DiscordModule { - private const string firestr = "🔥 ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้ 🔥"; + private const string firestr = "🔥 ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้ 🔥"; public Conversations() { commands.Add(new RipCommand(this)); @@ -153,22 +154,23 @@ namespace NadekoBot.Modules.Conversations .Parameter("times", ParameterType.Optional) .Do(async e => { - var count = 1; - int.TryParse(e.Args[0], out count); - if (count == 0) + int count; + if (string.IsNullOrWhiteSpace(e.Args[0])) count = 1; + else + int.TryParse(e.Args[0], out count); if (count < 1 || count > 12) { - await e.Channel.SendMessage("Number must be between 0 and 12").ConfigureAwait(false); + await e.Channel.SendMessage("Number must be between 1 and 12").ConfigureAwait(false); return; } - var str = ""; + var str = new StringBuilder(); for (var i = 0; i < count; i++) { - str += firestr; + str.Append(firestr); } - await e.Channel.SendMessage(str).ConfigureAwait(false); + await e.Channel.SendMessage(str.ToString()).ConfigureAwait(false); }); cgb.CreateCommand("dump") diff --git a/NadekoBot/Modules/Gambling/Helpers/Cards.cs b/NadekoBot/Modules/Gambling/Helpers/Cards.cs index 1cd4ba95..8408535e 100644 --- a/NadekoBot/Modules/Gambling/Helpers/Cards.cs +++ b/NadekoBot/Modules/Gambling/Helpers/Cards.cs @@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Gambling.Helpers var orderedPool = cardPool.OrderBy(x => r.Next()); cardPool = cardPool as List ?? orderedPool.ToList(); } - public override string ToString() => string.Join("", cardPool.Select(c => c.ToString())) + Environment.NewLine; + public override string ToString() => string.Concat(cardPool.Select(c => c.ToString())) + Environment.NewLine; private static void InitHandValues() { diff --git a/NadekoBot/Modules/Games/Commands/PlantPick.cs b/NadekoBot/Modules/Games/Commands/PlantPick.cs index ec56fc3c..e2bce2ec 100644 --- a/NadekoBot/Modules/Games/Commands/PlantPick.cs +++ b/NadekoBot/Modules/Games/Commands/PlantPick.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; +using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Games.Commands @@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Games.Commands //channelid/messageid pair ConcurrentDictionary> plantedFlowerChannels = new ConcurrentDictionary>(); - private object locker = new object(); + private SemaphoreSlim locker = new SemaphoreSlim(1,1); internal override void Init(CommandGroupBuilder cgb) { @@ -84,33 +85,34 @@ namespace NadekoBot.Modules.Games.Commands 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)") - .Do(e => + .Do(async e => { - lock (locker) + await locker.WaitAsync().ConfigureAwait(false); + try { 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; } - 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) { - 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; } var file = GetRandomCurrencyImagePath(); Message msg; - //todo send message after, not in lock if (file == null) - msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult(); + msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false); 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 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 }); } + finally { locker.Release(); } }); cgb.CreateCommand(Prefix + "gencurrency") @@ -130,12 +132,12 @@ namespace NadekoBot.Modules.Games.Commands int 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 { 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); } }); } diff --git a/NadekoBot/Modules/Games/Commands/SpeedTyping.cs b/NadekoBot/Modules/Games/Commands/SpeedTyping.cs index 8a807208..c224de1d 100644 --- a/NadekoBot/Modules/Games/Commands/SpeedTyping.cs +++ b/NadekoBot/Modules/Games/Commands/SpeedTyping.cs @@ -190,8 +190,6 @@ namespace NadekoBot.Modules.Games.Commands await e.Channel.SendMessage("Added new article for typing game.").ConfigureAwait(false); }); - - //todo add user submissions } } } diff --git a/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 683eb3d0..fc5dd361 100644 --- a/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia { internal class TriviaGame { - private readonly object _guessLock = new object(); + private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1); private Server server { get; } private Channel channel { get; } @@ -113,7 +113,8 @@ namespace NadekoBot.Modules.Games.Commands.Trivia if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; var guess = false; - lock (_guessLock) + await _guessLock.WaitAsync().ConfigureAwait(false); + try { if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested) { @@ -122,6 +123,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia guess = true; } } + catch { _guessLock.Release(); } if (!guess) return; triviaCancelSource.Cancel(); await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); diff --git a/NadekoBot/Modules/Help/Commands/HelpCommand.cs b/NadekoBot/Modules/Help/Commands/HelpCommand.cs index 3bf86435..4d3fa441 100644 --- a/NadekoBot/Modules/Help/Commands/HelpCommand.cs +++ b/NadekoBot/Modules/Help/Commands/HelpCommand.cs @@ -5,6 +5,7 @@ using NadekoBot.Modules.Permissions.Classes; using System; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace NadekoBot.Classes.Help.Commands @@ -24,8 +25,13 @@ namespace NadekoBot.Classes.Help.Commands var com = NadekoBot.Client.GetService().AllCommands .FirstOrDefault(c => c.Text.ToLowerInvariant().Equals(comToFind) || c.Aliases.Select(a => a.ToLowerInvariant()).Contains(comToFind)); + + var str = ""; + var alias = com.Aliases.FirstOrDefault(); + if (alias != null) + str = $" / `{ com.Aliases.FirstOrDefault()}`"; if (com != null) - await e.Channel.SendMessage($"**__Help for `{com.Text}`__ / __`{("" + com.Aliases.FirstOrDefault() + "" ?? "")}`__**\n**Desc:** {com.Description.Replace("|", "\n**Usage:**")}").ConfigureAwait(false); + await e.Channel.SendMessage($@"**__Help for:__ `{com.Text}`**" + str + $"\n**Desc:** {new Regex(@"\|").Replace(com.Description, "\n**Usage:**",1)}").ConfigureAwait(false); }).ConfigureAwait(false); }; public static string HelpString { diff --git a/NadekoBot/Modules/Music/Classes/MusicControls.cs b/NadekoBot/Modules/Music/Classes/MusicControls.cs index 7cc43771..b024ca47 100644 --- a/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Music.Classes private readonly List playlist = new List(); public IReadOnlyCollection Playlist => playlist; - private readonly object playlistLock = new object(); public Song CurrentSong { get; private set; } private CancellationTokenSource SongCancelSource { get; set; } @@ -136,8 +135,8 @@ namespace NadekoBot.Modules.Music.Classes } finally { - await Task.Delay(300).ConfigureAwait(false); CurrentSong = null; + await Task.Delay(300).ConfigureAwait(false); } } } diff --git a/NadekoBot/Modules/Music/Classes/PoopyBuffer.cs b/NadekoBot/Modules/Music/Classes/PoopyBuffer.cs index 15dc4977..c4a95daa 100644 --- a/NadekoBot/Modules/Music/Classes/PoopyBuffer.cs +++ b/NadekoBot/Modules/Music/Classes/PoopyBuffer.cs @@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Music.Classes public int BufferSize { get; } - private readonly object readWriteLock = new object(); + private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1); public PoopyBuffer(int size) { @@ -32,51 +32,57 @@ namespace NadekoBot.Modules.Music.Classes ringBuffer = new byte[size]; } - public int Read(byte[] buffer, int count) + public Task ReadAsync(byte[] buffer, int count) { - if (buffer.Length < count) - throw new ArgumentException(); - //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); - lock (readWriteLock) + return Task.Run(async () => { - //read as much as you can if you're reading too much - if (count > ContentLength) - count = ContentLength; - //if nothing to read, return 0 - if (WritePosition == ReadPosition) - return 0; - // if buffer is in the "normal" state, just read - if (WritePosition > ReadPosition) + if (buffer.Length < count) + throw new ArgumentException(); + //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); + await readWriteLock.WaitAsync().ConfigureAwait(false); + try { - Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); - ReadPosition += count; - //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]"); + //read as much as you can if you're reading too much + if (count > ContentLength) + count = ContentLength; + //if nothing to read, return 0 + if (WritePosition == ReadPosition) + return 0; + // if buffer is in the "normal" state, just read + if (WritePosition > ReadPosition) + { + Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); + ReadPosition += count; + //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]"); + return count; + } + //else ReadPos { - // if i can just write without hitting buffer.length, do it - if (WritePosition + count < BufferSize) + //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 + await readWriteLock.WaitAsync().ConfigureAwait(false); + try { - Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); - WritePosition += count; - //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]"); - return; + // if i can just write without hitting buffer.length, do it + if (WritePosition + count < BufferSize) + { + Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); + WritePosition += count; + //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]"); + return; + } + // otherwise, i have to write to the end, then write the rest from the start + + var wroteNormaly = BufferSize - WritePosition; + Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly); + + //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]"); + + var wroteFromStart = count - wroteNormaly; + Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart); + + //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}"); + + WritePosition = wroteFromStart; } - // otherwise, i have to write to the end, then write the rest from the start - - var wroteNormaly = BufferSize - WritePosition; - Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly); - - //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]"); - - var wroteFromStart = count - wroteNormaly; - Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart); - - //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}"); - - WritePosition = wroteFromStart; - } + finally { readWriteLock.Release(); } + }); } } } diff --git a/NadekoBot/Modules/Music/Classes/Song.cs b/NadekoBot/Modules/Music/Classes/Song.cs index 025863e0..9f2fb382 100644 --- a/NadekoBot/Modules/Music/Classes/Song.cs +++ b/NadekoBot/Modules/Music/Classes/Song.cs @@ -155,7 +155,7 @@ namespace NadekoBot.Modules.Music.Classes { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); byte[] buffer = new byte[blockSize]; - var read = songBuffer.Read(buffer, blockSize); + var read = await songBuffer.ReadAsync(buffer, blockSize).ConfigureAwait(false); unchecked { bytesSent += (ulong)read; diff --git a/NadekoBot/Modules/Music/MusicModule.cs b/NadekoBot/Modules/Music/MusicModule.cs index 18b8966c..1780dcf0 100644 --- a/NadekoBot/Modules/Music/MusicModule.cs +++ b/NadekoBot/Modules/Music/MusicModule.cs @@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "next") .Alias(Prefix + "n") .Alias(Prefix + "skip") - .Description("Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n`") + .Description($"Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `{Prefix}n`") .Do(e => { MusicPlayer musicPlayer; @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "stop") .Alias(Prefix + "s") - .Description("Stops the music and clears the playlist. Stays in the channel. | `!m s`") + .Description($"Stops the music and clears the playlist. Stays in the channel. | `{Prefix}s`") .Do(e => { MusicPlayer musicPlayer; @@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "destroy") .Alias(Prefix + "d") .Description("Completely stops the music and unbinds the bot from the channel. " + - "(may cause weird behaviour) | `!m d`") + $"(may cause weird behaviour) | `{Prefix}d`") .Do(e => { MusicPlayer musicPlayer; @@ -78,7 +78,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "pause") .Alias(Prefix + "p") - .Description("Pauses or Unpauses the song. | `!m p`") + .Description($"Pauses or Unpauses the song. | `{Prefix}p`") .Do(async e => { MusicPlayer musicPlayer; @@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Music .Alias(Prefix + "q") .Alias(Prefix + "yq") .Description("Queue a song using keywords or a link. Bot will join your voice channel." + - "**You must be in a voice channel**. | `!m q Dream Of Venice`") + $"**You must be in a voice channel**. | `{Prefix}q Dream Of Venice`") .Parameter("query", ParameterType.Unparsed) .Do(async e => { @@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "soundcloudqueue") .Alias(Prefix + "sq") .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." + - "**You must be in a voice channel**. | `!m sq Dream Of Venice`") + $"**You must be in a voice channel**. | `{Prefix}sq Dream Of Venice`") .Parameter("query", ParameterType.Unparsed) .Do(async e => { @@ -125,7 +125,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "listqueue") .Alias(Prefix + "lq") - .Description("Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2`") + .Description($"Lists 15 currently queued songs per page. Default page is 1. | `{Prefix}lq` or `{Prefix}lq 2`") .Parameter("page", ParameterType.Optional) .Do(async e => { @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Music else if (musicPlayer.RepeatPlaylist) toSend += "🔁"; toSend += $" **{musicPlayer.Playlist.Count}** `tracks currently queued. Showing page {page}` "; - if (musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) + if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) toSend += "**Song queue is full!**\n"; else toSend += "\n"; @@ -163,7 +163,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "nowplaying") .Alias(Prefix + "np") - .Description("Shows the song currently playing. | `!m np`") + .Description($"Shows the song currently playing. | `{Prefix}np`") .Do(async e => { MusicPlayer musicPlayer; @@ -178,7 +178,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "volume") .Alias(Prefix + "vol") - .Description("Sets the music volume 0-100% | `!m vol 50`") + .Description($"Sets the music volume 0-100% | `{Prefix}vol 50`") .Parameter("val", ParameterType.Required) .Do(async e => { @@ -201,7 +201,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "defvol") .Alias(Prefix + "dv") .Description("Sets the default music volume when music playback is started (0-100)." + - " Persists through restarts. | `!m dv 80`") + $" Persists through restarts. | `{Prefix}dv 80`") .Parameter("val", ParameterType.Required) .Do(async e => { @@ -219,7 +219,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "mute") .Alias(Prefix + "min") - .Description("Sets the music volume to 0% | `!m min`") + .Description($"Sets the music volume to 0% | `{Prefix}min`") .Do(e => { MusicPlayer musicPlayer; @@ -231,7 +231,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "max") - .Description("Sets the music volume to 100%. | `!m max`") + .Description($"Sets the music volume to 100%. | `{Prefix}max`") .Do(e => { MusicPlayer musicPlayer; @@ -243,7 +243,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "half") - .Description("Sets the music volume to 50%. | `!m half`") + .Description($"Sets the music volume to 50%. | `{Prefix}half`") .Do(e => { MusicPlayer musicPlayer; @@ -256,7 +256,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "shuffle") .Alias(Prefix + "sh") - .Description("Shuffles the current playlist. | `!m sh`") + .Description($"Shuffles the current playlist. | `{Prefix}sh`") .Do(async e => { MusicPlayer musicPlayer; @@ -276,7 +276,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "playlist") .Alias(Prefix + "pl") - .Description("Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`") + .Description($"Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `{Prefix}pl playlist link or name`") .Parameter("playlist", ParameterType.Unparsed) .Do(async e => { @@ -300,7 +300,6 @@ namespace NadekoBot.Modules.Music await e.Channel.SendMessage($"🎵 `Failed to find any songs.`").ConfigureAwait(false); return; } - //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE var idArray = ids as string[] ?? ids.ToArray(); var count = idArray.Length; var msg = @@ -320,7 +319,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "soundcloudpl") .Alias(Prefix + "scpl") - .Description("Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`") + .Description($"Queue a soundcloud playlist using a link. | `{Prefix}scpl https://soundcloud.com/saratology/sets/symphony`") .Parameter("pl", ParameterType.Unparsed) .Do(async e => { @@ -355,7 +354,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "localplaylst") .Alias(Prefix + "lopl") - .Description("Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`") + .Description($"Queues all songs from a directory. **Bot Owner Only!** | `{Prefix}lopl C:/music/classical`") .Parameter("directory", ParameterType.Unparsed) .AddCheck(SimpleCheckers.OwnerOnly()) .Do(async e => @@ -385,7 +384,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "radio").Alias(Prefix + "ra") - .Description("Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!m ra radio link here`") + .Description($"Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `{Prefix}ra radio link here`") .Parameter("radio_link", ParameterType.Required) .Do(async e => { @@ -404,7 +403,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "local") .Alias(Prefix + "lo") - .Description("Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3`") + .Description($"Queues a local file by specifying a full path. **Bot Owner Only!** | `{Prefix}lo C:/music/mysong.mp3`") .Parameter("path", ParameterType.Unparsed) .AddCheck(SimpleCheckers.OwnerOnly()) .Do(async e => @@ -417,7 +416,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "move") .Alias(Prefix + "mv") - .Description("Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`") + .Description($"Moves the bot to your voice channel. (works only if music is already playing) | `{Prefix}mv`") .Do(e => { MusicPlayer musicPlayer; @@ -429,7 +428,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "remove") .Alias(Prefix + "rm") - .Description("Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`") + .Description($"Remove a song by its # in the queue, or 'all' to remove whole queue. | `{Prefix}rm 5`") .Parameter("num", ParameterType.Required) .Do(async e => { @@ -498,7 +497,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "setmaxqueue") .Alias(Prefix + "smq") - .Description($"Sets a maximum queue size. Supply 0 or no argument to have no limit. | `{Prefix} smq` 50 or `{Prefix} smq`") + .Description($"Sets a maximum queue size. Supply 0 or no argument to have no limit. | `{Prefix}smq` 50 or `{Prefix}smq`") .Parameter("size", ParameterType.Unparsed) .Do(async e => { @@ -520,7 +519,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "cleanup") - .Description("Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`") + .Description($"Cleans up hanging voice connections. **Bot Owner Only!** | `{Prefix}cleanup`") .AddCheck(SimpleCheckers.OwnerOnly()) .Do(e => { @@ -539,7 +538,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "reptcursong") .Alias(Prefix + "rcs") - .Description("Toggles repeat of current song. | `!m rcs`") + .Description($"Toggles repeat of current song. | `{Prefix}rcs`") .Do(async e => { MusicPlayer musicPlayer; @@ -557,7 +556,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "rpeatplaylst") .Alias(Prefix + "rpl") - .Description("Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`") + .Description($"Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `{Prefix}rpl`") .Do(async e => { MusicPlayer musicPlayer; @@ -568,7 +567,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "save") - .Description("Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1`") + .Description($"Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `{Prefix}save classical1`") .Parameter("name", ParameterType.Unparsed) .Do(async e => { @@ -621,7 +620,7 @@ namespace NadekoBot.Modules.Music }); cgb.CreateCommand(Prefix + "load") - .Description("Loads a playlist under a certain name. | `!m load classical-1`") + .Description($"Loads a playlist under a certain name. | `{Prefix}load classical-1`") .Parameter("name", ParameterType.Unparsed) .Do(async e => { @@ -681,7 +680,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "playlists") .Alias(Prefix + "pls") - .Description("Lists all playlists. Paginated. 20 per page. Default page is 0. |`!m pls 1`") + .Description($"Lists all playlists. Paginated. 20 per page. Default page is 0. |`{Prefix}pls 1`") .Parameter("num", ParameterType.Optional) .Do(e => { @@ -698,7 +697,7 @@ namespace NadekoBot.Modules.Music cgb.CreateCommand(Prefix + "deleteplaylist") .Alias(Prefix + "delpls") - .Description("Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`") + .Description($"Deletes a saved playlist. Only if you made it or if you are the bot owner. | `{Prefix}delpls animu-5`") .Parameter("pl", ParameterType.Required) .Do(async e => { @@ -857,7 +856,7 @@ namespace NadekoBot.Modules.Music } 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 Task.Run(async () => { diff --git a/NadekoBot/Modules/Permissions/Classes/PermissionChecker.cs b/NadekoBot/Modules/Permissions/Classes/PermissionChecker.cs index 94de43f6..412ce69a 100644 --- a/NadekoBot/Modules/Permissions/Classes/PermissionChecker.cs +++ b/NadekoBot/Modules/Permissions/Classes/PermissionChecker.cs @@ -26,8 +26,8 @@ namespace NadekoBot.Modules.Permissions.Classes { while (true) { - //blacklist is cleared every 1.75 seconds. That is the most time anyone will be blocked - await Task.Delay(1750).ConfigureAwait(false); + //blacklist is cleared every 1.00 seconds. That is the most time anyone will be blocked + await Task.Delay(1000).ConfigureAwait(false); timeBlackList.Clear(); } }); diff --git a/NadekoBot/Modules/Permissions/Classes/PermissionsHandler.cs b/NadekoBot/Modules/Permissions/Classes/PermissionsHandler.cs index c5d2e64c..d7c9e784 100644 --- a/NadekoBot/Modules/Permissions/Classes/PermissionsHandler.cs +++ b/NadekoBot/Modules/Permissions/Classes/PermissionsHandler.cs @@ -150,21 +150,21 @@ namespace NadekoBot.Modules.Permissions.Classes return PermissionBanType.None; } - private static void WriteServerToJson(ServerPermissions serverPerms) + private static Task WriteServerToJson(ServerPermissions serverPerms) => Task.Run(() => { string pathToFile = $"data/permissions/{serverPerms.Id}.json"; File.WriteAllText(pathToFile, Newtonsoft.Json.JsonConvert.SerializeObject(serverPerms, Newtonsoft.Json.Formatting.Indented)); - } + }); - public static void WriteToJson() + public static Task WriteToJson() => Task.Run(() => { Directory.CreateDirectory("data/permissions/"); foreach (var kvp in PermissionsDict) { WriteServerToJson(kvp.Value); } - } + }); public static string GetServerPermissionsRoleName(Server server) { @@ -174,25 +174,25 @@ namespace NadekoBot.Modules.Permissions.Classes 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, new ServerPermissions(server.Id, server.Name)); 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, new ServerPermissions(server.Id, server.Name)); 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -207,10 +207,10 @@ namespace NadekoBot.Modules.Permissions.Classes 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -225,10 +225,10 @@ namespace NadekoBot.Modules.Permissions.Classes 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -243,10 +243,10 @@ namespace NadekoBot.Modules.Permissions.Classes 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, new ServerPermissions(server.Id, server.Name)); @@ -256,10 +256,10 @@ namespace NadekoBot.Modules.Permissions.Classes modules[moduleName] = value; else 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, new ServerPermissions(server.Id, server.Name)); @@ -269,10 +269,10 @@ namespace NadekoBot.Modules.Permissions.Classes commands[commandName] = value; else 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; @@ -288,10 +288,10 @@ namespace NadekoBot.Modules.Permissions.Classes modules[moduleName] = value; else 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -306,10 +306,10 @@ namespace NadekoBot.Modules.Permissions.Classes commands[commandName] = value; else 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -324,10 +324,10 @@ namespace NadekoBot.Modules.Permissions.Classes modules[moduleName] = value; else 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -342,10 +342,10 @@ namespace NadekoBot.Modules.Permissions.Classes commands[commandName] = value; else 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -360,10 +360,10 @@ namespace NadekoBot.Modules.Permissions.Classes modules[moduleName] = value; else 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 serverPerms = PermissionsDict.GetOrAdd(server.Id, @@ -377,19 +377,19 @@ namespace NadekoBot.Modules.Permissions.Classes commands[commandName] = value; else 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, new ServerPermissions(server.Id, server.Name)); 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 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[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, new ServerPermissions(server.Id, server.Name)); 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 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[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, new ServerPermissions(server.Id, server.Name)); @@ -436,26 +436,26 @@ namespace NadekoBot.Modules.Permissions.Classes 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, new ServerPermissions(server.Id, server.Name)); if (serverPerms.Words.Contains(word)) throw new InvalidOperationException("That word is already banned."); 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, new ServerPermissions(server.Id, server.Name)); if (!serverPerms.Words.Contains(word)) throw new InvalidOperationException("That word is not banned."); serverPerms.Words.Remove(word); - Task.Run(() => WriteServerToJson(serverPerms)); + await WriteServerToJson(serverPerms).ConfigureAwait(false); } } /// diff --git a/NadekoBot/Modules/Permissions/Commands/FilterWordsCommand.cs b/NadekoBot/Modules/Permissions/Commands/FilterWordsCommand.cs index 3764245d..c187d398 100644 --- a/NadekoBot/Modules/Permissions/Commands/FilterWordsCommand.cs +++ b/NadekoBot/Modules/Permissions/Commands/FilterWordsCommand.cs @@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Permissions.Commands var chan = string.IsNullOrWhiteSpace(chanStr) ? e.Channel : 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); return; } @@ -76,7 +76,7 @@ namespace NadekoBot.Modules.Permissions.Commands 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); } @@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Permissions.Commands var word = e.GetArg("word"); if (string.IsNullOrWhiteSpace(word)) 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); } @@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Permissions.Commands var word = e.GetArg("word"); if (string.IsNullOrWhiteSpace(word)) 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); } @@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Permissions.Commands try { 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.") .ConfigureAwait(false); diff --git a/NadekoBot/Modules/Permissions/PermissionsModule.cs b/NadekoBot/Modules/Permissions/PermissionsModule.cs index 4c13b9ff..463520a5 100644 --- a/NadekoBot/Modules/Permissions/PermissionsModule.cs +++ b/NadekoBot/Modules/Permissions/PermissionsModule.cs @@ -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); 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); }); @@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Permissions var args = arg.Split('~').Select(a => a.Trim()).ToArray(); 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; } try @@ -79,12 +79,12 @@ namespace NadekoBot.Modules.Permissions var fromRole = PermissionHelper.ValidateRole(e.Server, args[0]); var toRole = PermissionHelper.ValidateRole(e.Server, args[1]); - PermissionsHandler.CopyRolePermissions(fromRole, toRole); - await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**."); + await PermissionsHandler.CopyRolePermissions(fromRole, toRole).ConfigureAwait(false); + await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**.").ConfigureAwait(false); } catch (Exception ex) { - await e.Channel.SendMessage($"💢{ex.Message}"); + await e.Channel.SendMessage($"💢{ex.Message}").ConfigureAwait(false); } }); cgb.CreateCommand(Prefix + "chnlpermscopy") @@ -107,8 +107,8 @@ namespace NadekoBot.Modules.Permissions var fromChannel = PermissionHelper.ValidateChannel(e.Server, args[0]); var toChannel = PermissionHelper.ValidateChannel(e.Server, args[1]); - PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel); - await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**."); + await PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel).ConfigureAwait(false); + await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**.").ConfigureAwait(false); } catch (Exception ex) { @@ -127,7 +127,7 @@ namespace NadekoBot.Modules.Permissions var args = arg.Split('~').Select(a => a.Trim()).ToArray(); 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; } try @@ -135,8 +135,8 @@ namespace NadekoBot.Modules.Permissions var fromUser = PermissionHelper.ValidateUser(e.Server, args[0]); var toUser = PermissionHelper.ValidateUser(e.Server, args[1]); - PermissionsHandler.CopyUserPermissions(fromUser, toUser); - await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**."); + await PermissionsHandler.CopyUserPermissions(fromUser, toUser).ConfigureAwait(false); + await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**.").ConfigureAwait(false); } catch (Exception ex) { @@ -152,7 +152,7 @@ namespace NadekoBot.Modules.Permissions { var arg = e.GetArg("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); }); @@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Permissions var module = PermissionHelper.ValidateModule(e.GetArg("module")); 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); } catch (ArgumentException exArg) @@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Permissions var command = PermissionHelper.ValidateCommand(e.GetArg("command")); 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); } catch (ArgumentException exArg) @@ -307,7 +307,7 @@ namespace NadekoBot.Modules.Permissions { 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); } @@ -315,7 +315,7 @@ namespace NadekoBot.Modules.Permissions { 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); } } @@ -345,7 +345,7 @@ namespace NadekoBot.Modules.Permissions { 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); } @@ -353,7 +353,7 @@ namespace NadekoBot.Modules.Permissions { 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); } } @@ -383,20 +383,20 @@ namespace NadekoBot.Modules.Permissions { 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); } 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); } else { 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); } } @@ -426,7 +426,7 @@ namespace NadekoBot.Modules.Permissions { 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); } @@ -434,7 +434,7 @@ namespace NadekoBot.Modules.Permissions { 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); } } @@ -461,7 +461,7 @@ namespace NadekoBot.Modules.Permissions var state = PermissionHelper.ValidateBool(e.GetArg("bool")); 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); } catch (ArgumentException exArg) @@ -487,7 +487,7 @@ namespace NadekoBot.Modules.Permissions var state = PermissionHelper.ValidateBool(e.GetArg("bool")); 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); } catch (ArgumentException exArg) @@ -511,7 +511,7 @@ namespace NadekoBot.Modules.Permissions foreach (var module in NadekoBot.Client.GetService().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); } @@ -538,7 +538,7 @@ namespace NadekoBot.Modules.Permissions foreach (var command in NadekoBot.Client.GetService().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); } @@ -565,7 +565,7 @@ namespace NadekoBot.Modules.Permissions var channel = string.IsNullOrWhiteSpace(chArg) ? e.Channel : PermissionHelper.ValidateChannel(e.Server, chArg); foreach (var module in NadekoBot.Client.GetService().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); @@ -594,7 +594,7 @@ namespace NadekoBot.Modules.Permissions var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel")); foreach (var command in NadekoBot.Client.GetService().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); } @@ -620,7 +620,7 @@ namespace NadekoBot.Modules.Permissions var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role")); foreach (var module in NadekoBot.Client.GetService().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); @@ -652,7 +652,7 @@ namespace NadekoBot.Modules.Permissions { foreach (var command in NadekoBot.Client.GetService().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); @@ -663,7 +663,7 @@ namespace NadekoBot.Modules.Permissions foreach (var command in NadekoBot.Client.GetService().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); } @@ -689,7 +689,7 @@ namespace NadekoBot.Modules.Permissions if (!e.Message.MentionedUsers.Any()) return; var usr = e.Message.MentionedUsers.First(); NadekoBot.Config.UserBlacklist.Add(usr.Id); - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig().ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false); }).ConfigureAwait(false); }); @@ -707,7 +707,7 @@ namespace NadekoBot.Modules.Permissions if (NadekoBot.Config.UserBlacklist.Contains(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); } else @@ -727,7 +727,7 @@ namespace NadekoBot.Modules.Permissions if (!e.Message.MentionedChannels.Any()) return; var ch = e.Message.MentionedChannels.First(); NadekoBot.Config.UserBlacklist.Add(ch.Id); - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig().ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); }).ConfigureAwait(false); }); @@ -742,7 +742,7 @@ namespace NadekoBot.Modules.Permissions if (!e.Message.MentionedChannels.Any()) return; var ch = e.Message.MentionedChannels.First(); NadekoBot.Config.UserBlacklist.Remove(ch.Id); - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig().ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); }).ConfigureAwait(false); }); @@ -767,7 +767,7 @@ namespace NadekoBot.Modules.Permissions } var serverId = server.Id; NadekoBot.Config.ServerBlacklist.Add(serverId); - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig().ConfigureAwait(false); //cleanup trivias and typeracing Modules.Games.Commands.Trivia.TriviaGame 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)"); - PermissionsHandler.SetCommandCooldown(e.Server, command, secs); + await PermissionsHandler.SetCommandCooldown(e.Server, command, secs).ConfigureAwait(false); if(secs == 0) await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false); else diff --git a/NadekoBot/Modules/Searches/Commands/LoLCommands.cs b/NadekoBot/Modules/Searches/Commands/LoLCommands.cs index bbe2eca9..8826beaf 100644 --- a/NadekoBot/Modules/Searches/Commands/LoLCommands.cs +++ b/NadekoBot/Modules/Searches/Commands/LoLCommands.cs @@ -30,8 +30,6 @@ namespace NadekoBot.Modules.Searches.Commands } private static Dictionary CachedChampionImages = new Dictionary(); - private readonly object cacheLock = new object(); - private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer(); public LoLCommands(DiscordModule module) : base(module) @@ -42,7 +40,6 @@ namespace NadekoBot.Modules.Searches.Commands { try { - lock (cacheLock) CachedChampionImages = CachedChampionImages .Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0)) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); @@ -87,16 +84,14 @@ namespace NadekoBot.Modules.Searches.Commands var resolvedRole = role; var name = e.GetArg("champ").Replace(" ", "").ToLower(); CachedChampion champ = null; - lock (cacheLock) - { - CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); - } - if (champ != null) - { - champ.ImageStream.Position = 0; - await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); - return; - } + + if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ)) + if (champ != null) + { + champ.ImageStream.Position = 0; + await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); + return; + } var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}").ConfigureAwait(false)); JToken data = null; if (role != null) @@ -121,17 +116,13 @@ namespace NadekoBot.Modules.Searches.Commands role = allData[0]["role"].ToString(); resolvedRole = ResolvePos(role); } - lock (cacheLock) - { - CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); - } - if (champ != null) - { - Console.WriteLine("Sending lol image from cache."); - champ.ImageStream.Position = 0; - await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); - return; - } + if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ)) + if (champ != null) + { + champ.ImageStream.Position = 0; + await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); + return; + } //name = data["title"].ToString(); // get all possible roles, and "select" the shown one var roles = new string[allData.Count]; diff --git a/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs b/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs index ebbdbf34..5eff7c78 100644 --- a/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs +++ b/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs @@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Searches.Commands string.Join("\n", JsonConvert.DeserializeObject>(await SearchHelper.GetResponseStringAsync("http://memegen.link/templates/")) .Select(kvp => Path.GetFileName(kvp.Value)) .GroupBy(item => (i++) / 4) - .Select(ig => string.Join("", ig.Select(el => $"{el,-17}")))) + .Select(ig => string.Concat(ig.Select(el => $"{el,-17}")))) + $"\n```").ConfigureAwait(false); }); diff --git a/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs b/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs index d5c6c755..efe521ff 100644 --- a/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs +++ b/NadekoBot/Modules/Searches/Commands/StreamNotifications.cs @@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Searches.Commands } } catch { } - ConfigHandler.SaveConfig(); + await ConfigHandler.SaveConfig().ConfigureAwait(false); }; checkTimer.Start(); } @@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Searches.Commands } 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); }); diff --git a/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs b/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs index 1743af45..b1a10a8c 100644 --- a/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs +++ b/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs @@ -60,7 +60,7 @@ namespace NadekoBot.Modules.Translator.Helpers text = await http.GetStringAsync(url).ConfigureAwait(false); } - return JArray.Parse(text)[0][0][0].ToString(); + return (string.Concat(JArray.Parse(text)[0].Select(x => x[0]))); } #endregion diff --git a/NadekoBot/Modules/Utility/UtilityModule.cs b/NadekoBot/Modules/Utility/UtilityModule.cs index c85348aa..999ec44a 100644 --- a/NadekoBot/Modules/Utility/UtilityModule.cs +++ b/NadekoBot/Modules/Utility/UtilityModule.cs @@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Utility if (arr.Length == 0) await e.Channel.SendMessage("Nobody. (not 100% sure)").ConfigureAwait(false); else - await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Join("", ig.Select(el => $" {el,-35}")))) + "\n```").ConfigureAwait(false); + await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Concat(ig.Select(el => $" {el,-35}")))) + "\n```").ConfigureAwait(false); }); cgb.CreateCommand(Prefix + "inrole") @@ -144,6 +144,18 @@ namespace NadekoBot.Modules.Utility } 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); + }); }); } } diff --git a/NadekoBot/NadekoBot.cs b/NadekoBot/NadekoBot.cs index 4a091e3e..ad68beca 100644 --- a/NadekoBot/NadekoBot.cs +++ b/NadekoBot/NadekoBot.cs @@ -197,7 +197,7 @@ namespace NadekoBot return; } #if NADEKO_RELEASE - await Task.Delay(90000).ConfigureAwait(false); + await Task.Delay(100000).ConfigureAwait(false); #else await Task.Delay(1000).ConfigureAwait(false); #endif diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index 7feefb56..4e16fee4 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -76,6 +76,47 @@ MinimumRecommendedRules.ruleset true + + true + bin\Debug\ + TRACE;DEBUG + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + false + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + true + bin\x64\PRIVATE\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\Release\ + TRACE;NADEKO_RELEASE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + ..\packages\VideoLibrary.1.3.3\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\libvideo.dll diff --git a/NadekoBot/_Models/JSONModels/Configuration.cs b/NadekoBot/_Models/JSONModels/Configuration.cs index 295134fe..d39c6e00 100644 --- a/NadekoBot/_Models/JSONModels/Configuration.cs +++ b/NadekoBot/_Models/JSONModels/Configuration.cs @@ -4,6 +4,8 @@ using Newtonsoft.Json; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; namespace NadekoBot.Classes.JSONModels { @@ -187,13 +189,17 @@ Nadeko Support Server: "; public static class ConfigHandler { - private static readonly object configLock = new object(); - public static void SaveConfig() + private static readonly SemaphoreSlim configLock = new SemaphoreSlim(1, 1); + public static async Task SaveConfig() { - lock (configLock) + await configLock.WaitAsync(); + try { File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented)); } + finally { + configLock.Release(); + } } public static bool IsBlackListed(MessageEventArgs evArgs) => IsUserBlacklisted(evArgs.User.Id) || diff --git a/commandlist.md b/commandlist.md index 48ad48d5..50cb13cc 100644 --- a/commandlist.md +++ b/commandlist.md @@ -2,7 +2,7 @@ ######You can donate on paypal: `nadekodiscordbot@gmail.com` #NadekoBot List Of Commands -Version: `NadekoBot v0.9.6045.36710` +Version: `NadekoBot v0.9.6048.2992` ### Help Command and aliases | Description | Usage ----------------|--------------|------- @@ -204,36 +204,36 @@ Command and aliases | Description | Usage ### Music Command and aliases | Description | Usage ----------------|--------------|------- -`!!next`, `!!n`, `!!skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n` -`!!stop`, `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!m s` -`!!destroy`, `!!d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!m d` -`!!pause`, `!!p` | Pauses or Unpauses the song. | `!m p` -`!!queue`, `!!q`, `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!m q Dream Of Venice` -`!!soundcloudqueue`, `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. | `!m sq Dream Of Venice` -`!!listqueue`, `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2` -`!!nowplaying`, `!!np` | Shows the song currently playing. | `!m np` -`!!volume`, `!!vol` | Sets the music volume 0-100% | `!m vol 50` -`!!defvol`, `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!m dv 80` -`!!mute`, `!!min` | Sets the music volume to 0% | `!m min` -`!!max` | Sets the music volume to 100%. | `!m max` -`!!half` | Sets the music volume to 50%. | `!m half` -`!!shuffle`, `!!sh` | Shuffles the current playlist. | `!m sh` -`!!playlist`, `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name` -`!!soundcloudpl`, `!!scpl` | Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony` -`!!localplaylst`, `!!lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical` -`!!radio`, `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!m ra radio link here` -`!!local`, `!!lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3` -`!!move`, `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv` -`!!remove`, `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5` +`!!next`, `!!n`, `!!skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!!n` +`!!stop`, `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s` +`!!destroy`, `!!d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!!d` +`!!pause`, `!!p` | Pauses or Unpauses the song. | `!!p` +`!!queue`, `!!q`, `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!!q Dream Of Venice` +`!!soundcloudqueue`, `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. | `!!sq Dream Of Venice` +`!!listqueue`, `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!!lq` or `!!lq 2` +`!!nowplaying`, `!!np` | Shows the song currently playing. | `!!np` +`!!volume`, `!!vol` | Sets the music volume 0-100% | `!!vol 50` +`!!defvol`, `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!!dv 80` +`!!mute`, `!!min` | Sets the music volume to 0% | `!!min` +`!!max` | Sets the music volume to 100%. | `!!max` +`!!half` | Sets the music volume to 50%. | `!!half` +`!!shuffle`, `!!sh` | Shuffles the current playlist. | `!!sh` +`!!playlist`, `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name` +`!!soundcloudpl`, `!!scpl` | Queue a soundcloud playlist using a link. | `!!scpl https://soundcloud.com/saratology/sets/symphony` +`!!localplaylst`, `!!lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!!lopl C:/music/classical` +`!!radio`, `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!!ra radio link here` +`!!local`, `!!lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!!lo C:/music/mysong.mp3` +`!!move`, `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!!mv` +`!!remove`, `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5` `!!movesong`, `!!ms` | Moves a song from one position to another. | `!! ms` 5>3 -`!!setmaxqueue`, `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!! smq` 50 or `!! smq` -`!!cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup` -`!!reptcursong`, `!!rcs` | Toggles repeat of current song. | `!m rcs` -`!!rpeatplaylst`, `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl` -`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1` -`!!load` | Loads a playlist under a certain name. | `!m load classical-1` -`!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!m pls 1` -`!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5` +`!!setmaxqueue`, `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq` 50 or `!!smq` +`!!cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!!cleanup` +`!!reptcursong`, `!!rcs` | Toggles repeat of current song. | `!!rcs` +`!!rpeatplaylst`, `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl` +`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!!save classical1` +`!!load` | Loads a playlist under a certain name. | `!!load classical-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` `!!goto` | Goes to a specific time in seconds in a 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) diff --git a/discord.net b/discord.net index 6bfeaadd..3e519b5e 160000 --- a/discord.net +++ b/discord.net @@ -1 +1 @@ -Subproject commit 6bfeaaddf0cbc83fe0ca44e6164f61c6f8fdaf27 +Subproject commit 3e519b5e0b33175e5a5ca247322b7082de484e15