Made events run async where needed, fixed .startevent flowerreaction and running commands in DMs
This commit is contained in:
		
							
								
								
									
										34
									
								
								src/NadekoBot/Command Errors 2017-06-05.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/NadekoBot/Command Errors 2017-06-05.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
[16:25-2017-06-05]
 | 
			
		||||
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: The server name or address could not be resolved
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at System.Net.Http.WinHttpHandler.<StartRequest>d__105.MoveNext()
 | 
			
		||||
   --- End of inner exception stack trace ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at System.Net.Http.HttpClient.<FinishSendAsync>d__58.MoveNext()
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at System.Net.Http.HttpClient.<GetContentAsync>d__32`1.MoveNext()
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
 | 
			
		||||
   at NadekoBot.Modules.Searches.Searches.JokeCommands.<Randjoke>d__3.MoveNext() in C:\Users\Kwoth\Documents\projekti\NadekoBot1.0\src\NadekoBot\Modules\Searches\Commands\JokeCommands.cs:line 40
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at Discord.Commands.ModuleClassBuilder.<>c__DisplayClass6_1.<<BuildCommand>b__1>d.MoveNext()
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at Discord.Commands.CommandInfo.<ExecuteAsyncInternal>d__38.MoveNext()
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at Discord.Commands.CommandInfo.<ExecuteAsyncInternal>d__38.MoveNext()
 | 
			
		||||
--- End of stack trace from previous location where exception was thrown ---
 | 
			
		||||
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 | 
			
		||||
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 | 
			
		||||
   at Discord.Commands.CommandInfo.<ExecuteAsync>d__37.MoveNext()
 | 
			
		||||
------
 | 
			
		||||
@@ -16,8 +16,6 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class LocalizationCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            //Română, România
 | 
			
		||||
            //Bahasa Indonesia, Indonesia
 | 
			
		||||
            private static ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
 | 
			
		||||
            {
 | 
			
		||||
                {"ar", "العربية" },
 | 
			
		||||
 
 | 
			
		||||
@@ -255,7 +255,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    if ((msg.Author.Id == _client.CurrentUser.Id) || !(imsg.Channel is ITextChannel) || imsg.Channel != _raceChannel)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    _messagesSinceGameStarted++;
 | 
			
		||||
                    Interlocked.Increment(ref _messagesSinceGameStarted);
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -194,10 +194,10 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            StartingMessage = umsg;
 | 
			
		||||
            _client.MessageDeleted += MessageDeletedEventHandler;
 | 
			
		||||
 | 
			
		||||
            try { await StartingMessage.AddReactionAsync(Emote.Parse("🌸")).ConfigureAwait(false); }
 | 
			
		||||
            try { await StartingMessage.AddReactionAsync(new Emoji("🌸")).ConfigureAwait(false); }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                try { await StartingMessage.AddReactionAsync(Emote.Parse("🌸")).ConfigureAwait(false); }
 | 
			
		||||
                try { await StartingMessage.AddReactionAsync(new Emoji("🌸")).ConfigureAwait(false); }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    try { await StartingMessage.DeleteAsync().ConfigureAwait(false); }
 | 
			
		||||
 
 | 
			
		||||
@@ -186,101 +186,105 @@ $@"--
 | 
			
		||||
 | 
			
		||||
            private async Task PotentialAcro(SocketMessage arg)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                await Task.Yield();
 | 
			
		||||
                var _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    var msg = arg as SocketUserMessage;
 | 
			
		||||
                    if (msg == null || msg.Author.IsBot || msg.Channel.Id != _channel.Id)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ++_spamCount;
 | 
			
		||||
 | 
			
		||||
                    var guildUser = (IGuildUser)msg.Author;
 | 
			
		||||
 | 
			
		||||
                    var input = msg.Content.ToUpperInvariant().Trim();
 | 
			
		||||
 | 
			
		||||
                    if (phase == AcroPhase.Submitting)
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_spamCount > 10)
 | 
			
		||||
                        {
 | 
			
		||||
                            _spamCount = 0;
 | 
			
		||||
                            try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
                        var inputWords = input.Split(' '); //get all words
 | 
			
		||||
 | 
			
		||||
                        if (inputWords.Length != _startingLetters.Length) // number of words must be the same as the number of the starting letters
 | 
			
		||||
                        var msg = arg as SocketUserMessage;
 | 
			
		||||
                        if (msg == null || msg.Author.IsBot || msg.Channel.Id != _channel.Id)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        for (int i = 0; i < _startingLetters.Length; i++)
 | 
			
		||||
                        {
 | 
			
		||||
                            var letter = _startingLetters[i];
 | 
			
		||||
                        ++_spamCount;
 | 
			
		||||
 | 
			
		||||
                            if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
 | 
			
		||||
                        var guildUser = (IGuildUser)msg.Author;
 | 
			
		||||
 | 
			
		||||
                        var input = msg.Content.ToUpperInvariant().Trim();
 | 
			
		||||
 | 
			
		||||
                        if (phase == AcroPhase.Submitting)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (_spamCount > 10)
 | 
			
		||||
                            {
 | 
			
		||||
                                _spamCount = 0;
 | 
			
		||||
                                try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
 | 
			
		||||
                                catch { }
 | 
			
		||||
                            }
 | 
			
		||||
                            var inputWords = input.Split(' '); //get all words
 | 
			
		||||
 | 
			
		||||
                            if (inputWords.Length != _startingLetters.Length) // number of words must be the same as the number of the starting letters
 | 
			
		||||
                                return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                            for (int i = 0; i < _startingLetters.Length; i++)
 | 
			
		||||
                            {
 | 
			
		||||
                                var letter = _startingLetters[i];
 | 
			
		||||
 | 
			
		||||
                                if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
 | 
			
		||||
                                    return;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                        if (!_usersWhoSubmitted.Add(guildUser.Id))
 | 
			
		||||
                            return;
 | 
			
		||||
                        //try adding it to the list of answers
 | 
			
		||||
                        if (!_submissions.TryAdd(input, guildUser))
 | 
			
		||||
                        {
 | 
			
		||||
                            _usersWhoSubmitted.TryRemove(guildUser.Id);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // all good. valid input. answer recorded
 | 
			
		||||
                        await _channel.SendConfirmAsync(GetText("acrophobia"),
 | 
			
		||||
                            GetText("acro_submit", guildUser.Mention,
 | 
			
		||||
                                _submissions.Count));
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await msg.DeleteAsync();
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
                            await msg.DeleteAsync(); //try twice
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (phase == AcroPhase.Voting)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_spamCount > 10)
 | 
			
		||||
                        {
 | 
			
		||||
                            _spamCount = 0;
 | 
			
		||||
                            try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
 | 
			
		||||
                        //{
 | 
			
		||||
                        //    if (!usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                        //        return;
 | 
			
		||||
                        //    votes.AddOrUpdate(input, 1, (key, old) => ++old);
 | 
			
		||||
                        //    await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                        //    await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                        //    return;
 | 
			
		||||
                        //}
 | 
			
		||||
 | 
			
		||||
                        int num;
 | 
			
		||||
                        if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count)
 | 
			
		||||
                        {
 | 
			
		||||
                            var kvp = _submissions.Skip(num - 1).First();
 | 
			
		||||
                            var usr = kvp.Value;
 | 
			
		||||
                            //can't vote for yourself, can't vote multiple times
 | 
			
		||||
                            if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                            if (!_usersWhoSubmitted.Add(guildUser.Id))
 | 
			
		||||
                                return;
 | 
			
		||||
                            _votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
 | 
			
		||||
                            //try adding it to the list of answers
 | 
			
		||||
                            if (!_submissions.TryAdd(input, guildUser))
 | 
			
		||||
                            {
 | 
			
		||||
                                _usersWhoSubmitted.TryRemove(guildUser.Id);
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // all good. valid input. answer recorded
 | 
			
		||||
                            await _channel.SendConfirmAsync(GetText("acrophobia"),
 | 
			
		||||
                                GetText("acro_vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false);
 | 
			
		||||
                            await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                                GetText("acro_submit", guildUser.Mention,
 | 
			
		||||
                                    _submissions.Count));
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await msg.DeleteAsync();
 | 
			
		||||
                            }
 | 
			
		||||
                            catch
 | 
			
		||||
                            {
 | 
			
		||||
                                await msg.DeleteAsync(); //try twice
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (phase == AcroPhase.Voting)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (_spamCount > 10)
 | 
			
		||||
                            {
 | 
			
		||||
                                _spamCount = 0;
 | 
			
		||||
                                try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
 | 
			
		||||
                                catch { }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
 | 
			
		||||
                            //{
 | 
			
		||||
                            //    if (!usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                            //        return;
 | 
			
		||||
                            //    votes.AddOrUpdate(input, 1, (key, old) => ++old);
 | 
			
		||||
                            //    await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                            //    await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            //    return;
 | 
			
		||||
                            //}
 | 
			
		||||
 | 
			
		||||
                            int num;
 | 
			
		||||
                            if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count)
 | 
			
		||||
                            {
 | 
			
		||||
                                var kvp = _submissions.Skip(num - 1).First();
 | 
			
		||||
                                var usr = kvp.Value;
 | 
			
		||||
                                //can't vote for yourself, can't vote multiple times
 | 
			
		||||
                                if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                                    return;
 | 
			
		||||
                                _votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
 | 
			
		||||
                                await _channel.SendConfirmAsync(GetText("acrophobia"),
 | 
			
		||||
                                    GetText("acro_vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false);
 | 
			
		||||
                                await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex);
 | 
			
		||||
                }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        _log.Warn(ex);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task End()
 | 
			
		||||
 
 | 
			
		||||
@@ -119,77 +119,81 @@ namespace NadekoBot.Modules.Games.Hangman
 | 
			
		||||
 | 
			
		||||
        private async Task PotentialGuess(SocketMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            await Task.Yield();
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                if (!(msg is SocketUserMessage))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                if (msg.Channel != GameChannel)
 | 
			
		||||
                    return; // message's channel has to be the same as game's
 | 
			
		||||
                if (msg.Content.Length == 1) // message must be 1 char long
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    if (++MessagesSinceLastPost > 10)
 | 
			
		||||
                    if (!(msg is SocketUserMessage))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (msg.Channel != GameChannel)
 | 
			
		||||
                        return; // message's channel has to be the same as game's
 | 
			
		||||
                    if (msg.Content.Length == 1) // message must be 1 char long
 | 
			
		||||
                    {
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        try
 | 
			
		||||
                        if (++MessagesSinceLastPost > 10)
 | 
			
		||||
                        {
 | 
			
		||||
                            await GameChannel.SendConfirmAsync("Hangman Game",
 | 
			
		||||
                                ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            MessagesSinceLastPost = 0;
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await GameChannel.SendConfirmAsync("Hangman Game",
 | 
			
		||||
                                    ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                    footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!(char.IsLetter(msg.Content[0]) || char.IsDigit(msg.Content[0])))// and a letter or a digit
 | 
			
		||||
                        return;
 | 
			
		||||
                        if (!(char.IsLetter(msg.Content[0]) || char.IsDigit(msg.Content[0])))// and a letter or a digit
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                    var guess = char.ToUpperInvariant(msg.Content[0]);
 | 
			
		||||
                    if (Guesses.Contains(guess))
 | 
			
		||||
                    {
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        ++Errors;
 | 
			
		||||
                        if (Errors < MaxErrors)
 | 
			
		||||
                            await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await End().ConfigureAwait(false);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Guesses.Add(guess);
 | 
			
		||||
 | 
			
		||||
                    if (Term.Word.ToUpperInvariant().Contains(guess))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (GuessedAll)
 | 
			
		||||
                        var guess = char.ToUpperInvariant(msg.Content[0]);
 | 
			
		||||
                        if (Guesses.Contains(guess))
 | 
			
		||||
                        {
 | 
			
		||||
                            try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
 | 
			
		||||
 | 
			
		||||
                            await End().ConfigureAwait(false);
 | 
			
		||||
                            MessagesSinceLastPost = 0;
 | 
			
		||||
                            ++Errors;
 | 
			
		||||
                            if (Errors < MaxErrors)
 | 
			
		||||
                                await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                    footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            else
 | 
			
		||||
                                await End().ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        try
 | 
			
		||||
 | 
			
		||||
                        Guesses.Add(guess);
 | 
			
		||||
 | 
			
		||||
                        if (Term.Word.ToUpperInvariant().Contains(guess))
 | 
			
		||||
                        {
 | 
			
		||||
                            await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                          footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            if (GuessedAll)
 | 
			
		||||
                            {
 | 
			
		||||
                                try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
 | 
			
		||||
 | 
			
		||||
                                await End().ConfigureAwait(false);
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                            MessagesSinceLastPost = 0;
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                              footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch { }
 | 
			
		||||
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        ++Errors;
 | 
			
		||||
                        if (Errors < MaxErrors)
 | 
			
		||||
                            await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await End().ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                        {
 | 
			
		||||
                            MessagesSinceLastPost = 0;
 | 
			
		||||
                            ++Errors;
 | 
			
		||||
                            if (Errors < MaxErrors)
 | 
			
		||||
                                await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                    footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                            else
 | 
			
		||||
                                await End().ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetHangman() => $@". ┌─────┐
 | 
			
		||||
 
 | 
			
		||||
@@ -109,38 +109,42 @@ namespace NadekoBot.Modules.Games.Models
 | 
			
		||||
 | 
			
		||||
        private async Task AnswerReceived(SocketMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            await Task.Yield();
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                if (imsg.Author.IsBot)
 | 
			
		||||
                    return;
 | 
			
		||||
                var msg = imsg as SocketUserMessage;
 | 
			
		||||
                if (msg == null)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                if (this.Channel == null || this.Channel.Id != msg.Channel.Id) return;
 | 
			
		||||
 | 
			
		||||
                var guess = msg.Content;
 | 
			
		||||
 | 
			
		||||
                var distance = CurrentSentence.LevenshteinDistance(guess);
 | 
			
		||||
                var decision = Judge(distance, guess.Length);
 | 
			
		||||
                if (decision && !finishedUserIds.Contains(msg.Author.Id))
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var elapsed = sw.Elapsed;
 | 
			
		||||
                    var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
 | 
			
		||||
                    finishedUserIds.Add(msg.Author.Id);
 | 
			
		||||
                    await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                        .WithTitle($"{msg.Author} finished the race!")
 | 
			
		||||
                        .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
 | 
			
		||||
                        .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*").WithIsInline(true))
 | 
			
		||||
                        .AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true)))
 | 
			
		||||
                            .ConfigureAwait(false);
 | 
			
		||||
                    if (finishedUserIds.Count % 4 == 0)
 | 
			
		||||
                    if (imsg.Author.IsBot)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var msg = imsg as SocketUserMessage;
 | 
			
		||||
                    if (msg == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (this.Channel == null || this.Channel.Id != msg.Channel.Id) return;
 | 
			
		||||
 | 
			
		||||
                    var guess = msg.Content;
 | 
			
		||||
 | 
			
		||||
                    var distance = CurrentSentence.LevenshteinDistance(guess);
 | 
			
		||||
                    var decision = Judge(distance, guess.Length);
 | 
			
		||||
                    if (decision && !finishedUserIds.Contains(msg.Author.Id))
 | 
			
		||||
                    {
 | 
			
		||||
                        await this.Channel.SendConfirmAsync($":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
 | 
			
		||||
                        var elapsed = sw.Elapsed;
 | 
			
		||||
                        var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
 | 
			
		||||
                        finishedUserIds.Add(msg.Author.Id);
 | 
			
		||||
                        await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                            .WithTitle($"{msg.Author} finished the race!")
 | 
			
		||||
                            .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
 | 
			
		||||
                            .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*").WithIsInline(true))
 | 
			
		||||
                            .AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true)))
 | 
			
		||||
                                .ConfigureAwait(false);
 | 
			
		||||
                        if (finishedUserIds.Count % 4 == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            await this.Channel.SendConfirmAsync($":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool Judge(int errors, int textLength) => errors <= textLength / 25;
 | 
			
		||||
 
 | 
			
		||||
@@ -237,7 +237,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task Client_MessageReceived(Discord.WebSocket.SocketMessage msg)
 | 
			
		||||
            private Task Client_MessageReceived(SocketMessage msg)
 | 
			
		||||
            {
 | 
			
		||||
                var _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -180,64 +180,68 @@ namespace NadekoBot.Modules.Games.Trivia
 | 
			
		||||
 | 
			
		||||
        private async Task PotentialGuess(SocketMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            await Task.Yield();
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                if (imsg.Author.IsBot)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var umsg = imsg as SocketUserMessage;
 | 
			
		||||
 | 
			
		||||
                var textChannel = umsg?.Channel as ITextChannel;
 | 
			
		||||
                if (textChannel == null || textChannel.Guild != Guild)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var guildUser = (IGuildUser)umsg.Author;
 | 
			
		||||
 | 
			
		||||
                var guess = false;
 | 
			
		||||
                await _guessLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    if (GameActive && CurrentQuestion.IsAnswerCorrect(umsg.Content) && !triviaCancelSource.IsCancellationRequested)
 | 
			
		||||
                    {
 | 
			
		||||
                        Users.AddOrUpdate(guildUser, 1, (gu, old) => ++old);
 | 
			
		||||
                        guess = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                finally { _guessLock.Release(); }
 | 
			
		||||
                if (!guess) return;
 | 
			
		||||
                triviaCancelSource.Cancel();
 | 
			
		||||
                    if (imsg.Author.IsBot)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var umsg = imsg as SocketUserMessage;
 | 
			
		||||
 | 
			
		||||
                if (Users[guildUser] == WinRequirement)
 | 
			
		||||
                {
 | 
			
		||||
                    ShouldStopGame = true;
 | 
			
		||||
                    var textChannel = umsg?.Channel as ITextChannel;
 | 
			
		||||
                    if (textChannel == null || textChannel.Guild != Guild)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var guildUser = (IGuildUser)umsg.Author;
 | 
			
		||||
 | 
			
		||||
                    var guess = false;
 | 
			
		||||
                    await _guessLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                            .WithTitle(GetText("trivia_game"))
 | 
			
		||||
                            .WithDescription(GetText("trivia_win",
 | 
			
		||||
                                guildUser.Mention,
 | 
			
		||||
                                Format.Bold(CurrentQuestion.Answer)))
 | 
			
		||||
                            .WithImageUrl(CurrentQuestion.AnswerImageUrl))
 | 
			
		||||
                            .ConfigureAwait(false);
 | 
			
		||||
                        if (GameActive && CurrentQuestion.IsAnswerCorrect(umsg.Content) && !triviaCancelSource.IsCancellationRequested)
 | 
			
		||||
                        {
 | 
			
		||||
                            Users.AddOrUpdate(guildUser, 1, (gu, old) => ++old);
 | 
			
		||||
                            guess = true;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
                        // ignored
 | 
			
		||||
                    }
 | 
			
		||||
                    var reward = _bc.TriviaCurrencyReward;
 | 
			
		||||
                    if (reward > 0)
 | 
			
		||||
                        await _cs.AddAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                    finally { _guessLock.Release(); }
 | 
			
		||||
                    if (!guess) return;
 | 
			
		||||
                    triviaCancelSource.Cancel();
 | 
			
		||||
 | 
			
		||||
                await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                    .WithTitle(GetText("trivia_game"))
 | 
			
		||||
                    .WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer)))
 | 
			
		||||
                    .WithImageUrl(CurrentQuestion.AnswerImageUrl))
 | 
			
		||||
                    .ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
 | 
			
		||||
                    if (Users[guildUser] == WinRequirement)
 | 
			
		||||
                    {
 | 
			
		||||
                        ShouldStopGame = true;
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                                .WithTitle(GetText("trivia_game"))
 | 
			
		||||
                                .WithDescription(GetText("trivia_win",
 | 
			
		||||
                                    guildUser.Mention,
 | 
			
		||||
                                    Format.Bold(CurrentQuestion.Answer)))
 | 
			
		||||
                                .WithImageUrl(CurrentQuestion.AnswerImageUrl))
 | 
			
		||||
                                .ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
                            // ignored
 | 
			
		||||
                        }
 | 
			
		||||
                        var reward = _bc.TriviaCurrencyReward;
 | 
			
		||||
                        if (reward > 0)
 | 
			
		||||
                            await _cs.AddAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                        .WithTitle(GetText("trivia_game"))
 | 
			
		||||
                        .WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer)))
 | 
			
		||||
                        .WithImageUrl(CurrentQuestion.AnswerImageUrl))
 | 
			
		||||
                        .ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetLeaderboard()
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,9 @@ using Discord;
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Attributes;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Modules.Searches.Models;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using NadekoBot.Services.Searches;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
@@ -21,37 +17,11 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class AnimeSearchCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            private static readonly Timer anilistTokenRefresher;
 | 
			
		||||
            private static string anilistToken { get; set; }
 | 
			
		||||
            private readonly AnimeSearchService _service;
 | 
			
		||||
 | 
			
		||||
            static AnimeSearchCommands()
 | 
			
		||||
            public AnimeSearchCommands(AnimeSearchService service)
 | 
			
		||||
            {
 | 
			
		||||
                anilistTokenRefresher = new Timer(async (state) =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var headers = new Dictionary<string, string>
 | 
			
		||||
                        {
 | 
			
		||||
                            {"grant_type", "client_credentials"},
 | 
			
		||||
                            {"client_id", "kwoth-w0ki9"},
 | 
			
		||||
                            {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        using (var http = new HttpClient())
 | 
			
		||||
                        {
 | 
			
		||||
                            //http.AddFakeHeaders();
 | 
			
		||||
                            http.DefaultRequestHeaders.Clear();
 | 
			
		||||
                            var formContent = new FormUrlEncodedContent(headers);
 | 
			
		||||
                            var response = await http.PostAsync("https://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false);
 | 
			
		||||
                            var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
 | 
			
		||||
                            anilistToken = JObject.Parse(stringContent)["access_token"].ToString();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
                        // ignored
 | 
			
		||||
                    }
 | 
			
		||||
                }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
 | 
			
		||||
                _service = service;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
@@ -171,7 +141,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var animeData = await GetAnimeData(query).ConfigureAwait(false);
 | 
			
		||||
                var animeData = await _service.GetAnimeData(query).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                if (animeData == null)
 | 
			
		||||
                {
 | 
			
		||||
@@ -198,7 +168,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var mangaData = await GetMangaData(query).ConfigureAwait(false);
 | 
			
		||||
                var mangaData = await _service.GetMangaData(query).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                if (mangaData == null)
 | 
			
		||||
                {
 | 
			
		||||
@@ -218,52 +188,6 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
 | 
			
		||||
                await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async Task<AnimeResult> GetAnimeData(string query)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                    throw new ArgumentNullException(nameof(query));
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
 | 
			
		||||
                    using (var http = new HttpClient())
 | 
			
		||||
                    {
 | 
			
		||||
                        var res = await http.GetStringAsync(link + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
                        var smallObj = JArray.Parse(res)[0];
 | 
			
		||||
                        var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        return await Task.Run(() => { try { return JsonConvert.DeserializeObject<AnimeResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex, "Failed anime search for {0}", query);
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async Task<MangaResult> GetMangaData(string query)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                    throw new ArgumentNullException(nameof(query));
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    using (var http = new HttpClient())
 | 
			
		||||
                    {
 | 
			
		||||
                        var res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
                        var smallObj = JArray.Parse(res)[0];
 | 
			
		||||
                        var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        return await Task.Run(() => { try { return JsonConvert.DeserializeObject<MangaResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex, "Failed anime search for {0}", query);
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -132,6 +132,7 @@ namespace NadekoBot
 | 
			
		||||
            #region Searches
 | 
			
		||||
            var searchesService = new SearchesService(Client, GoogleApi, Db);
 | 
			
		||||
            var streamNotificationService = new StreamNotificationService(Db, Client, Strings);
 | 
			
		||||
            var animeSearchService = new AnimeSearchService();
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            var clashService = new ClashOfClansService(Client, Db, Localization, Strings);
 | 
			
		||||
@@ -184,6 +185,7 @@ namespace NadekoBot
 | 
			
		||||
                    .Add(converterService)
 | 
			
		||||
                .Add<SearchesService>(searchesService)
 | 
			
		||||
                    .Add(streamNotificationService)
 | 
			
		||||
                    .Add(animeSearchService)
 | 
			
		||||
                .Add<ClashOfClansService>(clashService)
 | 
			
		||||
                .Add<MusicService>(musicService)
 | 
			
		||||
                .Add<GreetSettingsService>(greetSettingsService)
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,9 @@
 | 
			
		||||
  
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Remove="data\**\*;credentials.json" />
 | 
			
		||||
    <Compile Remove="Modules\Utility\Models\**" />
 | 
			
		||||
    <EmbeddedResource Remove="Modules\Utility\Models\**" />
 | 
			
		||||
    <None Remove="Modules\Utility\Models\**" />
 | 
			
		||||
    <None Update="credentials_example.json">
 | 
			
		||||
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
@@ -87,6 +90,5 @@
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="Modules\Music\Classes\" />
 | 
			
		||||
    <Folder Include="Modules\Utility\Models\" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.Administration
 | 
			
		||||
{
 | 
			
		||||
@@ -25,21 +26,25 @@ namespace NadekoBot.Services.Administration
 | 
			
		||||
                gcs.Where(x => x.AutoAssignRoleId != 0)
 | 
			
		||||
                    .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
 | 
			
		||||
 | 
			
		||||
            _client.UserJoined += async (user) =>
 | 
			
		||||
            _client.UserJoined += (user) =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                var _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
 | 
			
		||||
 | 
			
		||||
                    if (roleId == 0)
 | 
			
		||||
                        return;
 | 
			
		||||
                        if (roleId == 0)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                    var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
 | 
			
		||||
                        var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
 | 
			
		||||
 | 
			
		||||
                    if (role != null)
 | 
			
		||||
                        await user.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                        if (role != null)
 | 
			
		||||
                            await user.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -71,20 +71,21 @@ namespace NadekoBot.Services.Administration
 | 
			
		||||
            _client.UserJoined += Client_UserJoined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task Client_UserJoined(IGuildUser usr)
 | 
			
		||||
        private Task Client_UserJoined(IGuildUser usr)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted);
 | 
			
		||||
 | 
			
		||||
                if (muted == null || !muted.Contains(usr.Id))
 | 
			
		||||
                    return;
 | 
			
		||||
                await MuteUser(usr).ConfigureAwait(false);
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                Task.Run(() => MuteUser(usr).ConfigureAwait(false));
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                LogManager.GetCurrentClassLogger().Warn(ex);
 | 
			
		||||
                _log.Warn(ex);
 | 
			
		||||
            }
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task MuteUser(IGuildUser usr, MuteType type = MuteType.All)
 | 
			
		||||
 
 | 
			
		||||
@@ -258,7 +258,7 @@ namespace NadekoBot.Services
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            var prefix = GetPrefix(guild.Id);
 | 
			
		||||
            var prefix = GetPrefix(guild?.Id);
 | 
			
		||||
            // execute the command and measure the time it took
 | 
			
		||||
            if (messageContent.StartsWith(prefix))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
 | 
			
		||||
        private async Task PotentialFlowerGeneration(SocketMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            await Task.Yield();
 | 
			
		||||
            var msg = imsg as SocketUserMessage;
 | 
			
		||||
            if (msg == null || msg.Author.IsBot)
 | 
			
		||||
                return;
 | 
			
		||||
@@ -109,48 +110,51 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
 | 
			
		||||
            if (!GenerationChannels.Contains(channel.Id))
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            try
 | 
			
		||||
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
 | 
			
		||||
                var rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
                if (DateTime.Now - TimeSpan.FromSeconds(_bc.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var num = rng.Next(1, 101) + _bc.CurrencyGenerationChance * 100;
 | 
			
		||||
                if (num > 100 && LastGenerations.TryUpdate(channel.Id, DateTime.Now, lastGeneration))
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var dropAmount = _bc.CurrencyDropAmount;
 | 
			
		||||
                    var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
 | 
			
		||||
                    var rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
                    if (dropAmount > 0)
 | 
			
		||||
                    if (DateTime.Now - TimeSpan.FromSeconds(_bc.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var num = rng.Next(1, 101) + _bc.CurrencyGenerationChance * 100;
 | 
			
		||||
                    if (num > 100 && LastGenerations.TryUpdate(channel.Id, DateTime.Now, lastGeneration))
 | 
			
		||||
                    {
 | 
			
		||||
                        var msgs = new IUserMessage[dropAmount];
 | 
			
		||||
                        var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
 | 
			
		||||
                        var toSend = dropAmount == 1
 | 
			
		||||
                            ? GetText(channel, "curgen_sn", _bc.CurrencySign)
 | 
			
		||||
                                + " " + GetText(channel, "pick_sn", prefix)
 | 
			
		||||
                            : GetText(channel, "curgen_pl", dropAmount, _bc.CurrencySign)
 | 
			
		||||
                                + " " + GetText(channel, "pick_pl", prefix);
 | 
			
		||||
                        var file = GetRandomCurrencyImage();
 | 
			
		||||
                        using (var fileStream = file.Data.ToStream())
 | 
			
		||||
                        var dropAmount = _bc.CurrencyDropAmount;
 | 
			
		||||
 | 
			
		||||
                        if (dropAmount > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            var sent = await channel.SendFileAsync(
 | 
			
		||||
                                fileStream,
 | 
			
		||||
                                file.Name,
 | 
			
		||||
                                toSend).ConfigureAwait(false);
 | 
			
		||||
                            var msgs = new IUserMessage[dropAmount];
 | 
			
		||||
                            var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
 | 
			
		||||
                            var toSend = dropAmount == 1
 | 
			
		||||
                                ? GetText(channel, "curgen_sn", _bc.CurrencySign)
 | 
			
		||||
                                    + " " + GetText(channel, "pick_sn", prefix)
 | 
			
		||||
                                : GetText(channel, "curgen_pl", dropAmount, _bc.CurrencySign)
 | 
			
		||||
                                    + " " + GetText(channel, "pick_pl", prefix);
 | 
			
		||||
                            var file = GetRandomCurrencyImage();
 | 
			
		||||
                            using (var fileStream = file.Data.ToStream())
 | 
			
		||||
                            {
 | 
			
		||||
                                var sent = await channel.SendFileAsync(
 | 
			
		||||
                                    fileStream,
 | 
			
		||||
                                    file.Name,
 | 
			
		||||
                                    toSend).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                            msgs[0] = sent;
 | 
			
		||||
                                msgs[0] = sent;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            PlantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        PlantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                LogManager.GetCurrentClassLogger().Warn(ex);
 | 
			
		||||
            }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    LogManager.GetCurrentClassLogger().Warn(ex);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								src/NadekoBot/Services/Searches/AnimeSearchService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/NadekoBot/Services/Searches/AnimeSearchService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using NLog;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.Searches
 | 
			
		||||
{
 | 
			
		||||
    public class AnimeSearchService
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Timer _anilistTokenRefresher;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        private static string anilistToken { get; set; }
 | 
			
		||||
 | 
			
		||||
        public AnimeSearchService()
 | 
			
		||||
        {
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            _anilistTokenRefresher = new Timer(async (state) =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var headers = new Dictionary<string, string>
 | 
			
		||||
                        {
 | 
			
		||||
                            {"grant_type", "client_credentials"},
 | 
			
		||||
                            {"client_id", "kwoth-w0ki9"},
 | 
			
		||||
                            {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                    using (var http = new HttpClient())
 | 
			
		||||
                    {
 | 
			
		||||
                        //http.AddFakeHeaders();
 | 
			
		||||
                        http.DefaultRequestHeaders.Clear();
 | 
			
		||||
                        var formContent = new FormUrlEncodedContent(headers);
 | 
			
		||||
                        var response = await http.PostAsync("https://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false);
 | 
			
		||||
                        var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
 | 
			
		||||
                        anilistToken = JObject.Parse(stringContent)["access_token"].ToString();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // ignored
 | 
			
		||||
                }
 | 
			
		||||
            }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<AnimeResult> GetAnimeData(string query)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                throw new ArgumentNullException(nameof(query));
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    var res = await http.GetStringAsync(link + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
                    var smallObj = JArray.Parse(res)[0];
 | 
			
		||||
                    var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    return await Task.Run(() => { try { return JsonConvert.DeserializeObject<AnimeResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                _log.Warn(ex, "Failed anime search for {0}", query);
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<MangaResult> GetMangaData(string query)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                throw new ArgumentNullException(nameof(query));
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    var res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
                    var smallObj = JArray.Parse(res)[0];
 | 
			
		||||
                    var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    return await Task.Run(() => { try { return JsonConvert.DeserializeObject<MangaResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                _log.Warn(ex, "Failed anime search for {0}", query);
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Searches.Models
 | 
			
		||||
namespace NadekoBot.Services.Searches
 | 
			
		||||
{
 | 
			
		||||
    public class AnimeResult
 | 
			
		||||
    {
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace NadekoBot.Modules.Searches.Models
 | 
			
		||||
namespace NadekoBot.Services.Searches
 | 
			
		||||
{
 | 
			
		||||
    public class MangaResult
 | 
			
		||||
    {
 | 
			
		||||
@@ -41,32 +41,35 @@ namespace NadekoBot.Services.Searches
 | 
			
		||||
            //translate commands
 | 
			
		||||
            _client.MessageReceived += async (msg) =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                await Task.Yield();
 | 
			
		||||
                var _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    var umsg = msg as SocketUserMessage;
 | 
			
		||||
                    if (umsg == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out var autoDelete))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var key = new UserChannelPair()
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        UserId = umsg.Author.Id,
 | 
			
		||||
                        ChannelId = umsg.Channel.Id,
 | 
			
		||||
                    };
 | 
			
		||||
                        var umsg = msg as SocketUserMessage;
 | 
			
		||||
                        if (umsg == null)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                    string langs;
 | 
			
		||||
                    if (!UserLanguages.TryGetValue(key, out langs))
 | 
			
		||||
                        return;
 | 
			
		||||
                        if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out var autoDelete))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                    var text = await Translate(langs, umsg.Resolve(TagHandling.Ignore))
 | 
			
		||||
                                        .ConfigureAwait(false);
 | 
			
		||||
                    if (autoDelete)
 | 
			
		||||
                        try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                    await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
                        var key = new UserChannelPair()
 | 
			
		||||
                        {
 | 
			
		||||
                            UserId = umsg.Author.Id,
 | 
			
		||||
                            ChannelId = umsg.Channel.Id,
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        if (!UserLanguages.TryGetValue(key, out string langs))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var text = await Translate(langs, umsg.Resolve(TagHandling.Ignore))
 | 
			
		||||
                                            .ConfigureAwait(false);
 | 
			
		||||
                        if (autoDelete)
 | 
			
		||||
                            try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                        await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            //pokemon commands
 | 
			
		||||
 
 | 
			
		||||
@@ -21,42 +21,46 @@ namespace NadekoBot.Services.Utility
 | 
			
		||||
            _client.MessageReceived += Client_MessageReceived;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task Client_MessageReceived(SocketMessage imsg)
 | 
			
		||||
        private Task Client_MessageReceived(SocketMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (imsg.Author.IsBot)
 | 
			
		||||
                    return;
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                if (msg.Author.Id == _client.CurrentUser.Id) return;
 | 
			
		||||
                foreach (var subscriber in Subscribers)
 | 
			
		||||
            var _ = Task.Run(async () => {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var set = subscriber.Value;
 | 
			
		||||
                    if (!set.Contains(channel))
 | 
			
		||||
                        continue;
 | 
			
		||||
                    foreach (var chan in set.Except(new[] { channel }))
 | 
			
		||||
                    if (imsg.Author.IsBot)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var msg = imsg as IUserMessage;
 | 
			
		||||
                    if (msg == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    if (msg.Author.Id == _client.CurrentUser.Id) return;
 | 
			
		||||
                    foreach (var subscriber in Subscribers)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        var set = subscriber.Value;
 | 
			
		||||
                        if (!set.Contains(channel))
 | 
			
		||||
                            continue;
 | 
			
		||||
                        foreach (var chan in set.Except(new[] { channel }))
 | 
			
		||||
                        {
 | 
			
		||||
                            await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author,
 | 
			
		||||
                                msg)).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
                            // ignored
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author,
 | 
			
		||||
                                    msg)).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch
 | 
			
		||||
                            {
 | 
			
		||||
                                // ignored
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                // ignored
 | 
			
		||||
            }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // ignored
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) =>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user