Example #1
0
 /// <summary>
 /// Logs a specific string, as given in message.
 /// </summary>
 /// <param name="message">The message to log.</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 public static async Task Log(string message)
 {
     PrintWithTime(message);
     if (loggingFilePath != null)
     {
         await WriteLogWithTime(message, false);
     }
     DiscordLogQueue.Enqueue(new Task(
                                 () =>
     {
         var sendMessageAsync = loggingChannel?.SendMessageAsync(message);
         if (sendMessageAsync == null)
         {
             return;
         }
         try
         {
             sendMessageAsync.GetAwaiter().GetResult();
         }
         catch (Exception e)
         {
             StopLoggingToChannel();
             LogError(e.ToString()).GetAwaiter().GetResult();
             Task.Delay(TimeSpan.FromMinutes(1)).GetAwaiter().GetResult();
             Shinoa.TryReenableLogging().GetAwaiter().GetResult();
         }
     }));
 }
Example #2
0
        private void CheckLevelIncreases(IMessageChannel battleChannel)
        {
            var nextLevel = NinjaLevel.Levels[Level.Number + 1];

            if (ExpLevel < nextLevel.ExpRequirements)
            {
                return;
            }
            ExpLevel = 0; Level = nextLevel;
            var loc            = Skills.AddNewSkill();
            var levelUpMessage = "<@!" + UserId + "> has leveled up to a " + Level.Name + ".";

            if (loc != -1)
            {
                var skill = Skills[loc];
                if (skill.Level == 1)
                {
                    levelUpMessage += " Obtained new skill **" + skill.BaseSkill.Name + "**!";
                }
                else
                {
                    levelUpMessage += " Upgraded skill to **" + skill.BaseSkill.Name + " " + skill.GetLevelText() + "**!";
                }
            }
            battleChannel?.SendMessageAsync(levelUpMessage);
        }
Example #3
0
 private async Task SendLogMessageAsync(string[] parts, IMessageChannel channel)
 {
     for (var i = 0; i < parts.Length; i++)
     {
         await channel?.SendMessageAsync($"```{parts[i]}```");
     }
 }
Example #4
0
 /// <summary>
 /// Sends a message to a Discord channel
 /// </summary>
 /// <param name="message">message to send to Discord channel</param>
 public void Send(string message)
 {
     try
     {
         // channel? checks if object is null prior to sending message
         channel?.SendMessageAsync(message);
     }
     catch (Exception e)
     {
         Util.Log($"Unable to send Discord message: {e.Message}", Util.Severity.Error);
         throw;
     }
 }
Example #5
0
        private async void ProcessQueue()
        {
            while (await _songQueue.OutputAvailableAsync())
            {
                while (!_isPlaying)
                {
                    Log.Information("Waiting for songs");
                    NowPlaying = await _songQueue.ReceiveAsync();

                    _concurrentQueue.TryDequeue(out _);
                    _isPlaying = true;
                    try
                    {
                        if (_messageChannel != null)
                        {
                            await _messageChannel?.SendMessageAsync(
                                $"Now playing **{NowPlaying.Title}** | `{NowPlaying.DurationString}` | requested by {NowPlaying.Requester} | {NowPlaying.Url}");
                        }

                        Log.Information("Connecting to voice channel");
                        using (var audioClient = await _voiceChannel.ConnectAsync())
                        {
                            Log.Information("Connected!");
                            await _audioPlaybackService.SendAsync(audioClient, NowPlaying.Uri, NowPlaying.Speed);
                        }

                        NowPlaying.OnPostPlay();
                    }
                    catch (Exception e)
                    {
                        Log.Information($"Error while playing song: {e}");
                    }
                    finally
                    {
                        _isPlaying = false;
                    }
                }
            }
        }
        /// <summary>
        /// Say a servere notification to the correct channels
        /// </summary>
        /// <param name="job"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        async Task SayNotificationJob(NotificationJob job, MethodContext context)
        {
            SetContext(context);
            foreach (string channel in job.Channels)
            {
                switch (channel)
                {
                case "pm":
                case "dm":
                case "me":
                    IGuildUser user = GetUser(job.Creator, true);
                    await user?.SendMessageAsync(job.Message);

                    break;

                default:
                    IMessageChannel messageChannel = GetChannel <SocketGuildChannel>(channel, false) as IMessageChannel;
                    await messageChannel?.SendMessageAsync(job.Message);

                    break;
                }
            }
        }
Example #7
0
 public static Task <IUserMessage> SendToAsync(this EmbedBuilder e, IMessageChannel c) =>
 c.SendMessageAsync(string.Empty, false, e.Build());
Example #8
0
            public async Task AddWarn(string reason, IGuildUser User, IUser mod, IMessageChannel channel)
            {
                ModerationSetup.Warns.Add(new Moderation.warn
                {
                    modID    = mod.Id,
                    modname  = mod.Username,
                    reason   = reason,
                    userID   = User.Id,
                    username = User.Username
                });

                var embed = new EmbedBuilder
                {
                    Title = $"{User.Username} has been Warned",

                    /*Description = $"User: {User.Username}#{User.Discriminator}\n" +
                     *            $"UserID: {User.Id}\n" +
                     *            $"Mod: {mod.Username}#{mod.Discriminator}\n" +
                     *            $"Mod ID: {mod.Id}\n" +
                     *            "Reason:\n" +
                     *            $"{reason}",*/
                    Color = Color.DarkPurple
                }
                .AddField("User", $"{User.Username}#{User.Discriminator} ({User.Mention})\n" +
                          $"`[{User.Id}]`", true)
                .AddField("Moderator", $"{mod.Username}#{mod.Discriminator}", true)
                .AddField("Reason", $"{reason ?? "N/A"}");

                var replymsg = await channel.SendMessageAsync("", false, embed.Build());

                await ModLog(embed, User.Guild);

                if (ModerationSetup.Warns.Count(x => x.userID == User.Id) > ModerationSetup.Settings.warnlimit && ModerationSetup.Settings.WarnLimitAction != Moderation.msettings.warnLimitAction.NoAction)
                {
                    var embedmsg = new EmbedBuilder();
                    if (ModerationSetup.Settings.WarnLimitAction == Moderation.msettings.warnLimitAction.Ban)
                    {
                        ModerationSetup.Bans.Add(new Moderation.ban
                        {
                            modID    = mod.Id,
                            modname  = mod.Username,
                            reason   = reason,
                            userID   = User.Id,
                            username = User.Username,
                            Expires  = false
                        });
                        await User.Guild.AddBanAsync(User, 1, "AutoBan, Warnlimit Exceeded by user!");

                        embedmsg.Title       = $"{User.Username} has been Auto banned";
                        embedmsg.Description = $"User: {User.Username}#{User.Discriminator}\n" +
                                               $"UserID: {User.Id}\n" +
                                               $"Mod: {mod.Username}#{mod.Discriminator}\n" +
                                               $"Mod ID: {mod.Id}\n" +
                                               "Reason:\n" +
                                               "AutoBan, Warnlimit Exceeded by user!";
                        embedmsg.Color = Color.DarkRed;
                    }
                    else
                    {
                        ModerationSetup.Kicks.Add(new Moderation.kick
                        {
                            modID    = mod.Id,
                            modname  = mod.Username,
                            reason   = reason,
                            userID   = User.Id,
                            username = User.Username
                        });
                        await User.KickAsync("AutoKick, WarnLimit Exceeded by user!");

                        embedmsg.Title       = $"{User.Username} has been Auto Kicked";
                        embedmsg.Description = $"User: {User.Username}#{User.Discriminator}\n" +
                                               $"UserID: {User.Id}\n" +
                                               $"Mod: {mod.Username}#{mod.Discriminator}\n" +
                                               $"Mod ID: {mod.Id}\n" +
                                               "Reason:\n" +
                                               "Auto Kick, Warnlimit Exceeded by user!";
                        embedmsg.Color = Color.DarkMagenta;
                    }

                    await channel.SendMessageAsync("", false, embedmsg.Build());
                    await ModLog(embedmsg, User.Guild);
                }

                if (ModerationSetup.Settings.hidewarnafterdelay)
                {
                    await Task.Delay(5000);

                    await replymsg.DeleteAsync();
                }
            }
        public async Task BuildStream(
            IGuild guild,
            IMessageChannel channel,
            IUserMessage display,
            string path)
        {
            var songBase = songPath + path;

            if (!File.Exists(songBase))
            {
                await channel.SendMessageAsync($"`Audio file path mentioned does not exist.`\n`{path}`");

                return;
            }
            if (CurrentChannels.TryGetValue(guild.Id, out IAudioClient client))
            {
                var queue  = data.GetQueue(guild);
                var ffmpeg = CreateFfmpegProcess(songBase);
                using (var output = ffmpeg.StandardOutput.BaseStream)
                {
                    using (var stream = client.CreatePCMStream(AudioApplication.Music))
                    {
                        var(BufferSize, BufferRate, Offset) = StreamRate().Item1;
                        var closeStream = false;
                        var sentBytes   = 0;
                        data.SetStreamState(guild, true);
                        while (!closeStream)
                        {
                            try
                            {
                                //This reads the stream output until there is nothing remaining.
                                var readBytes = await output.ReadAsync(BufferRate, Offset, BufferSize, token.Token);

                                if (readBytes.Equals(0))
                                {
                                    closeStream = true; break;
                                }

                                await stream.WriteAsync(BufferRate, Offset, readBytes, token.Token);

                                sentBytes += readBytes;

                                //A state to determine when the song is paused.
                                while (!data.GetOutputState(guild))
                                {
                                    SpinWait.SpinUntil(() => true != !data.GetOutputState(guild));
                                }

                                //A skip request in use for skipping unwanted songs.
                                if (data.GetSkipState(guild))
                                {
                                    Console.WriteLine("Skip requested.");
                                    data.SetSkipState(guild, false);
                                    closeStream = true;
                                    break;
                                }

                                //A forced exit request in use with stopping ASAP.
                                if (token.IsCancellationRequested)
                                {
                                    Console.WriteLine("Force quit requested.");
                                    data.SetOutputState(guild, false);
                                    data.SetStreamState(guild, false);
                                    await stream.FlushAsync();

                                    closeStream = true;
                                    return;
                                }
                            }
                            catch (Exception x)
                            {
                                if ((x is TaskCanceledException || x is OperationCanceledException))
                                {
                                    Console.WriteLine("Voice force disconnected.");
                                    data.SetOutputState(guild, false);
                                    data.SetStreamState(guild, false);
                                    await stream.FlushAsync();

                                    closeStream = true;
                                }
                            }
                        }
                        Console.WriteLine("Song ended.");
                        await stream.FlushAsync();

                        data.SetStreamState(guild, false);
                        data.RemoveFromQueue(guild, path);
                        await CheckQueue(guild, channel, display);
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Lets only a certain role use a command
        /// </summary>
        /// <param name="command"></param>
        /// <param name="roles"></param>
        /// <param name="channel"></param>
        /// <param name="guild"></param>
        /// <returns></returns>
        public async Task AddPerm(string command, string[] roles, IMessageChannel channel, SocketGuild guild)
        {
            if (!CanModifyPerm(command))
            {
                await channel.SendMessageAsync($"Cannot set the permission of **{command}**");

                return;
            }

            if (!DoesCmdExist(command))
            {
                await channel.SendMessageAsync($"The command **{command}** doesn't exist!");

                return;
            }

            List <IRole> iRoles = new List <IRole>();

            ServerList server = ServerListsManager.GetServer(guild);

            //Check all roles to see if they actually exists
            foreach (string role in roles)
            {
                if (RoleUtils.GetGuildRole(guild, role) != null)
                {
                    //Add all the roles Ids
                    iRoles.Add(RoleUtils.GetGuildRole(guild, role));
                    continue;
                }

                await channel.SendMessageAsync($"The role **{role}** doesn't exist!");

                return;
            }

            if (server.GetCommandInfo(command) == null)
            {
                //The command didn't exist before, so we will create a new one and just add the roles
                List <ulong> rolesIds = iRoles.Select(iRole => iRole.Id).ToList();

                server.CommandPermissions.Add(new ServerList.CommandPermission
                {
                    Command = command,
                    Roles   = rolesIds
                });

                ServerListsManager.SaveServerList();

                await channel.SendMessageAsync(AddPermMessage(roles, command));
            }
            else             //The command already exists
            {
                //Check to see if all the roles we are adding are non-existing roles assigned to the command
                foreach (IRole iRole in iRoles.Where(iRole => server.GetCommandInfo(command).GetRole(iRole.Id) != 0))
                {
                    await channel.SendMessageAsync(
                        $"The command `{command}` already has the role **{iRole.Name}**.");

                    return;
                }

                //Since we now know that all the roles we are assigning are not assigned, we add them to the list of roles
                foreach (IRole iRole in iRoles)
                {
                    server.GetCommandInfo(command).Roles.Add(iRole.Id);
                }

                ServerListsManager.SaveServerList();
                await channel.SendMessageAsync(AddPermMessage(roles, command));
            }
        }
Example #11
0
 public static Task <IUserMessage> SendConfirmAsync(this IMessageChannel ch, string text)
 => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text));
Example #12
0
 public static Task <IUserMessage> EmbedAsync(this IMessageChannel ch, Discord.API.Embed embed)
 => ch.SendMessageAsync("", embed: embed);
Example #13
0
 public static Task <IUserMessage> SendErrorAsync(this IMessageChannel ch, string title, string error, string url = null, string footer = null)
 => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.ErrorColor).WithDescription(error)
                        .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer)));
Example #14
0
 /// <inheritdoc/>
 protected override async Task <IUserMessage> OnDisplayAsync([NotNull] IMessageChannel channel)
 {
     return(await channel.SendMessageAsync(string.Empty, embed : _loadingEmbed));
 }
Example #15
0
        public static async Task RunTrades(HtmlDocument feed, string leagueId, IMessageChannel channel)
        {
            var   feedString   = "//*[@id='newsfeed_page']/ol/li[1]";
            var   tempDateTime = "";
            var   systemIcon   = "";
            Embed embed        = null;

            if (leagueId == "73")
            {
                systemIcon =
                    "https://cdn.discordapp.com/attachments/689119430021873737/711030693743820800/220px-PlayStation_logo.svg.jpg";
            }
            else if (leagueId == "53")
            {
                systemIcon =
                    "https://cdn.discordapp.com/attachments/689119430021873737/711030386775293962/120px-Xbox_one_logo.svg.jpg";
            }

            var nodes = feed.DocumentNode.SelectNodes(feedString);

            foreach (var item in nodes)
            {
                tempDateTime = item.SelectSingleNode("//*[@id='newsfeed_page']/ol/li[1]/div/abbr").InnerText;
                var line    = item.SelectSingleNode("//*[@id='newsfeed_page']/ol/li[1]/div/h3").InnerText;
                var newLine = "";
                if (line.Contains("The "))
                {
                    newLine = line.Replace("The ", string.Empty);
                }
                if (line.Contains("the "))
                {
                    newLine = newLine.Replace("the ", string.Empty);
                }

                var splits = newLine.Split(new[] { "have traded", " to ", "for" }, StringSplitOptions.None);


                var splitStr = newLine.Split(new[] { "to " }, StringSplitOptions.None);
                splitStr[1] = splitStr[1].Replace("  ", " ");
                var tradeIcon = item.SelectSingleNode("//*[@id='newsfeed_page']/ol/li[1]/a[2]/img")
                                .Attributes["src"].Value;
                var lastNews = DateTime.Parse(tempDateTime);

                if (!NewsWriter.SaveTrade(lastNews, splitStr[0], splitStr[1], leagueId))
                {
                    break;
                }
                try
                {
                    using var newsDb = new LiteDatabase(@"Filename=Database/LGFA.db;connection=shared");
                    var news   = newsDb.GetCollection <LeagueNews.News>("Trades");
                    var result = news.Find(x => x.Date.Equals(lastNews));
                    foreach (var headline in result)
                    {
                        var builder = new EmbedBuilder()
                                      .WithColor(new Color(0xFF0019))
                                      .WithTimestamp(lastNews)
                                      .WithFooter(footer =>
                        {
                            footer
                            .WithText("leaguegaming.com")
                            .WithIconUrl("https://www.leaguegaming.com/images/logo/logonew.png");
                        })
                                      .WithThumbnailUrl("https://www.leaguegaming.com/images/feed/trade.png")
                                      .WithAuthor(author =>
                        {
                            author
                            .WithName("LGFA Breaking News")
                            .WithIconUrl(systemIcon);
                        })
                                      .WithDescription("**New Trade**")
                                      .AddField($"**To {splits[0].Trim()}**", $"{splits[3].Trim()}", true)
                                      .AddField($"**To {splits[2].Trim()}**", $"{splits[1].Trim()}", true);

                        embed = builder.Build();
                    }

                    await channel.SendMessageAsync(null, embed : embed).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    Log.Logger.Error($"{e}");
                    throw;
                }
            }
        }
Example #16
0
        public static async Task RunWaivers(HtmlDocument feed, string leagueId, IMessageChannel channel)
        {
            var waiverWeb            = new HtmlWeb();
            var systemIcon           = "";
            var tempDateTime         = "";
            HtmlNodeCollection nodes = null;
            Embed embed = null;

            if (leagueId == "73")
            {
                systemIcon =
                    "https://cdn.discordapp.com/attachments/689119430021873737/711030693743820800/220px-PlayStation_logo.svg.jpg";
                nodes = feed.DocumentNode.SelectNodes("//*[@id='newsfeed_page']/ol/li[1]");
            }
            else if (leagueId == "53")
            {
                systemIcon =
                    "https://cdn.discordapp.com/attachments/689119430021873737/711030386775293962/120px-Xbox_one_logo.svg.jpg";
                nodes = feed.DocumentNode.SelectNodes("//*[@id='newsfeed_page']/ol/li[1]/div/h3");
            }

            foreach (var items in nodes)
            {
                tempDateTime = items.SelectSingleNode("//*[@id='newsfeed_page']/ol/li[1]/div/abbr").InnerText;
                var line    = items.SelectSingleNode("//*[@id='newsfeed_page']/ol/li[1]/div/h3").InnerText;
                var newLine = "";

                if (line.Contains("The "))
                {
                    newLine = line.Replace("The ", string.Empty);
                }
                if (line.Contains("the "))
                {
                    newLine = newLine.Replace("the ", string.Empty);
                }
                if (newLine == string.Empty)
                {
                    newLine = line;
                }
                IList <string> waiverLine = new List <string>();

                var lastNews = DateTime.Parse(tempDateTime);
                if (!NewsWriter.SaveWaiver(lastNews, newLine, leagueId))
                {
                    break;
                }
                EmbedBuilder builder = null;

                if (line.Contains("has cleared"))
                {
                    waiverLine = newLine.Split(new[] { "has", "cleared", "and put onto" }, StringSplitOptions.None);
                    if (waiverLine.Any())
                    {
                        builder = new EmbedBuilder()
                                  .WithColor(new Color(0xFF0019))
                                  .WithTimestamp(lastNews)
                                  .WithFooter(footer =>
                        {
                            footer
                            .WithText("leaguegaming.com/fifa")
                            .WithIconUrl("https://www.leaguegaming.com/images/league/icon/l53.png");
                        })
                                  .WithAuthor(author =>
                        {
                            author
                            .WithName("LGFA Waiver News")
                            .WithIconUrl(systemIcon);
                        })
                                  .WithDescription("**Player cleared waivers.**")
                                  .AddField("User", waiverLine[0], true)
                                  .AddField("Status", "Cleared", true)
                                  .AddField("Placement", "Training Camp", true);
                        embed = builder.Build();
                    }
                }
                else if (line.Contains("have claimed"))
                {
                    waiverLine = newLine.Split(new[] { "have claimed", "off of waivers" }, StringSplitOptions.None);
                    if (waiverLine.Any())
                    {
                        builder = new EmbedBuilder()
                                  .WithColor(new Color(0xFF0019))
                                  .WithTimestamp(lastNews)
                                  .WithFooter(footer =>
                        {
                            footer
                            .WithText("leaguegaming.com/fifa")
                            .WithIconUrl("https://www.leaguegaming.com/images/league/icon/l53.png");
                        })
                                  .WithAuthor(author =>
                        {
                            author
                            .WithName("LGFA Waiver News")
                            .WithIconUrl(systemIcon);
                        })
                                  .WithDescription("**Player Claimed off waivers.**")
                                  .AddField("New Team", waiverLine[0], true)
                                  .AddField("User", waiverLine[1], true)
                                  .AddField("Status", "Claimed", true);
                        //.AddField("Placement", placement, true);
                        embed = builder.Build();
                    }
                }
                else if (line.Contains("have placed"))
                {
                    waiverLine = newLine.Split(new[] { "have placed", "on waivers" }, StringSplitOptions.None);
                    if (waiverLine.Any())
                    {
                        builder = new EmbedBuilder()
                                  .WithColor(new Color(0xFF0019))
                                  .WithTimestamp(lastNews)
                                  .WithFooter(footer =>
                        {
                            footer
                            .WithText("leaguegaming.com/fifa")
                            .WithIconUrl("https://www.leaguegaming.com/images/league/icon/l53.png");
                        })
                                  .WithAuthor(author =>
                        {
                            author
                            .WithName("LGFA Waiver News")
                            .WithIconUrl(systemIcon);
                        })
                                  .WithDescription("**Player placed on waivers.**")
                                  .AddField("User", waiverLine[1], true)
                                  .AddField("Current Team", waiverLine[0], true)
                                  .AddField("Status", "On Waivers", true);
                        embed = builder.Build();
                    }
                }

                await channel.SendMessageAsync(null, embed : embed).ConfigureAwait(false);
            }
        }
Example #17
0
        /// <summary>
        /// Plays a song in a given voice channel
        /// </summary>
        /// <param name="guild">The <see cref="SocketGuild"/> where we are playing in</param>
        /// <param name="channel">The <see cref="IMessageChannel"/> to log messages to</param>
        /// <param name="target">The target <see cref="IVoiceChannel"/> to play music in</param>
        /// <param name="user">The <see cref="IUser"/> who requested this command</param>
        /// <param name="search">The query to search for</param>
        /// <returns></returns>
        public async Task SendAudio(SocketGuild guild, IMessageChannel channel, IVoiceChannel target, IUser user,
                                    string search)
        {
            //Join the voice channel the user is in if we are already not in a voice channel
            if (!CheckIfServerIsPlayingMusic(guild, out ServerMusicItem serverMusicList))
            {
                await JoinAudio(guild, target, channel, user);

                serverMusicList = GetMusicList(guild.Id);
            }

            //Check to see if the user is in the playing audio channel
            if (!await CheckIfUserInChat(user, channel, serverMusicList))
            {
                return;
            }

            //Make sure the search isn't empty or null
            if (string.IsNullOrWhiteSpace(search))
            {
                await channel.SendMessageAsync("You need to input a search!");

                return;
            }

            IUserMessage message =
                await channel.SendMessageAsync($":musical_note: Preparing to search for '{search}'");

            string songFileLocation;
            string songName;

            search.RemoveIllegalChars();

            try
            {
                songFileLocation = await GetOrDownloadSong(search, message, guild, serverMusicList);

                //It failed
                if (songFileLocation == null)
                {
                    return;
                }

                Logger.Log($"Playing song from {songFileLocation}", LogVerbosity.Debug);

                //This is so we say "Now playing 'Epic Song'" instead of "Now playing 'Epic Song.mp3'"
                songName = Path.GetFileName(songFileLocation).Replace($".{fileFormat.GetFormatExtension()}", "");

                //If there is already a song playing, cancel it
                await StopPlayingAudioOnServer(serverMusicList);
            }
            catch (Exception ex)
            {
                Logger.Log(ex.ToString(), LogVerbosity.Error);
                return;
            }

            //Create music playback for our music format
            IMusicPlaybackInterface playbackInterface = serverMusicList.MusicPlayback = CreateMusicPlayback(songFileLocation);

            //Log (if enabled) to the console that we are playing a new song
            if (Config.bot.AudioSettings.LogPlayStopSongToConsole)
            {
                Logger.Log($"The song '{songName}' on server {guild.Name}({guild.Id}) has started.",
                           LogVerbosity.Music);
            }

            serverMusicList.CancellationSource = new CancellationTokenSource();
            CancellationToken token = serverMusicList.CancellationSource.Token;

            serverMusicList.IsPlaying = true;

            //Create an outgoing pcm stream
            await using (AudioOutStream outStream = serverMusicList.AudioClient.CreatePCMStream(AudioApplication.Music))
            {
                bool      fail       = false;
                bool      exit       = false;
                const int bufferSize = 1024;
                byte[]    buffer     = new byte[bufferSize];

                await MessageUtils.ModifyMessage(message, $":musical_note: Now playing **{songName}**.");

                while (!fail && !exit)
                {
                    try
                    {
                        if (token.IsCancellationRequested)
                        {
                            exit = true;
                            break;
                        }

                        //Read from stream
                        int read = await playbackInterface.ReadAudioStream(buffer, bufferSize, token);

                        if (read == 0)
                        {
                            exit = true;
                            break;
                        }

                        //Flush
                        await playbackInterface.Flush();

                        //Write it to outgoing pcm stream
                        await outStream.WriteAsync(buffer, 0, read, token);

                        //If we are still playing
                        if (serverMusicList.IsPlaying)
                        {
                            continue;
                        }

                        //For pausing the song
                        do
                        {
                            //Do nothing, wait till is playing is true
                            await Task.Delay(100, token);
                        } while (serverMusicList.IsPlaying == false);
                    }
                    catch (OperationCanceledException)
                    {
                        //User canceled
                    }
                    catch (Exception ex)
                    {
                        await channel.SendMessageAsync("Sorry, but an error occured while playing!");

                        if (Config.bot.ReportErrorsToOwner)
                        {
                            await Global.BotOwner.SendMessageAsync(
                                $"ERROR: {ex.Message}\nError occured while playing music on guild `{guild.Id}`.");
                        }

                        fail = true;
                    }
                }

                if (Config.bot.AudioSettings.LogPlayStopSongToConsole)
                {
                    Logger.Log($"The song '{songName}' on server {guild.Name}({guild.Id}) has stopped.",
                               LogVerbosity.Music);
                }

                //There wasn't a request to cancel
                if (!token.IsCancellationRequested)
                {
                    await channel.SendMessageAsync($":musical_note: **{songName}** ended.");
                }

                //Clean up
                // ReSharper disable MethodSupportsCancellation
                await outStream.FlushAsync();

                outStream.Dispose();
                serverMusicList.IsPlaying = false;

                playbackInterface.EndAudioStream();
                serverMusicList.MusicPlayback = null;
                // ReSharper restore MethodSupportsCancellation

                serverMusicList.CancellationSource.Dispose();
                serverMusicList.CancellationSource = null;
            }
        }
Example #18
0
        public static async Task <IUserMessage> PlayersRemoved(IMessageChannel channel, InhouseQueue queue, List <Player> list)
        {
            string players = string.Join("\r\n", queue.Players.Select(p => p.Value.Username));

            return(await channel.SendMessageAsync($"Players were removed succesfully!\r\n\r\n Queue: {players}"));
        }
Example #19
0
 public static async Task <IUserMessage> QueueStarted(IMessageChannel channel, InhouseQueue queue)
 {
     return(await channel.SendMessageAsync($"New Inhouse Queue created named {queue.Name}!"));
 }
Example #20
0
        internal async Task PollStreamers(SocketMessage message)
        {
            Console.WriteLine("Polling streamers.");
            foreach (string streamer in streamers)
            {
                try
                {
                    Console.WriteLine($"Looking up user id {streamer}");
                    var request = (HttpWebRequest)WebRequest.Create($"https://api.twitch.tv/helix/streams?user_id={streamer}");
                    request.Method      = "Get";
                    request.Timeout     = 12000;
                    request.ContentType = "application/vnd.twitchtv.v5+json";
                    request.Headers.Add("Client-ID", streamAPIClientID);

                    try
                    {
                        using (var s = request.GetResponse().GetResponseStream())
                        {
                            using (var sr = new System.IO.StreamReader(s))
                            {
                                var    jsonObject = JObject.Parse(sr.ReadToEnd());
                                JToken jsonStream = jsonObject["data"];
                                if (jsonStream.HasValues)
                                {
                                    jsonStream = jsonStream[0];
                                }

                                JToken jData = RetrieveUserIdFromUserName(streamIDtoUserName[streamer]);
                                if (jData != null && jData.HasValues)
                                {
                                    EmbedBuilder embedBuilder   = null;
                                    string       streamAnnounce = "";
                                    if (!streamStatus[streamer] && jsonStream.HasValues)
                                    {
                                        streamStatus[streamer] = true;
                                        streamAnnounce         = $"{jData["display_name"].ToString()} has started streaming.";
                                        embedBuilder           = MakeAuthorEmbed(jData, jsonStream);
                                    }
                                    else if (streamStatus[streamer] && !jsonStream.HasValues)
                                    {
                                        streamStatus[streamer] = false;
                                        streamAnnounce         = $"{jData["display_name"].ToString()} has stopped streaming.";
                                        embedBuilder           = MakeAuthorEmbed(jData, jsonStream);
                                    }
                                    if (embedBuilder != null)
                                    {
                                        foreach (KeyValuePair <UInt64, UInt64> streamChannel in streamChannelIds)
                                        {
                                            IMessageChannel channel = Program.Client.GetChannel(streamChannel.Value) as IMessageChannel;
                                            await channel.SendMessageAsync(streamAnnounce, false, embedBuilder);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (WebException e)
                    {
                        Console.WriteLine(e);
                    }
                }
                catch (Exception e)
                {
                    await message.Channel.SendMessageAsync($"I tried to poll {streamer} for stream info, but I got an exception instead. ({e.Message})");
                }
            }
        }
Example #21
0
 public static Task <IUserMessage> SendErrorAsync(this IMessageChannel ch, string error, string title = null, string url = null)
 => ch.SendMessageAsync("", embed: new Embed()
 {
     Description = error, Title = title, Url = url, Color = FaultyBot.ErrorColor
 });
Example #22
0
 public static Task <IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
 => ch.SendMessageAsync(msg, embed: embed);
Example #23
0
 public override async Task Perform(IMessageChannel channel)
 {
     await channel.SendMessageAsync($"{self.name} does nothing.");
 }
Example #24
0
 public static Task <IUserMessage> SendErrorAsync(this IMessageChannel ch, string error)
 => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error));
Example #25
0
        /// <summary>
        /// Stops a role from being able to use a command
        /// </summary>
        /// <param name="command"></param>
        /// <param name="roles"></param>
        /// <param name="channel"></param>
        /// <param name="guild"></param>
        /// <returns></returns>
        public async Task RemovePerm(string command, string[] roles, IMessageChannel channel, SocketGuild guild)
        {
            if (!CanModifyPerm(command))
            {
                await channel.SendMessageAsync($"Cannot set the permission of the command `{command}`.");

                return;
            }

            if (!DoesCmdExist(command))
            {
                await channel.SendMessageAsync($"The command `{command}` doesn't exist!");

                return;
            }

            List <IRole> iRoles = new List <IRole>();

            ServerList server = ServerListsManager.GetServer(guild);

            //Check all the imputed roles to see if they exists
            foreach (string role in roles)
            {
                IRole iRole = RoleUtils.GetGuildRole(guild, role);
                if (iRole == null)
                {
                    await channel.SendMessageAsync($"The role **{role}** doesn't exist!");

                    return;
                }

                iRoles.Add(iRole);
            }

            //Doesn't exist
            if (server.GetCommandInfo(command) == null)
            {
                await channel.SendMessageAsync($"The command `{command}` already has no roles assigned to it!");
            }
            else
            {
                //Check all roles and make sure they are assigned to the command
                foreach (IRole role in iRoles.Where(role => server.GetCommandInfo(command).GetRole(role.Id) == 0))
                {
                    await channel.SendMessageAsync(
                        $"The command `{command}` doesn't have the role **{role}** assigned to it!");

                    return;
                }

                //Now begin removing all the roles, since we know all the entered roles are already assigned to the command
                foreach (IRole role in iRoles)
                {
                    server.GetCommandInfo(command).Roles.Remove(server.GetCommandInfo(command).GetRole(role.Id));
                }

                //There are no more roles assigned to the command so remove it entirely
                RemoveAllCommandsWithNoRoles(server);

                ServerListsManager.SaveServerList();
                await channel.SendMessageAsync(RemovePermMessage(roles, command, server));
            }
        }
Example #26
0
        public async Task SendMessage(string chatId, string content)
        {
            IMessageChannel channel = await GetChannel(chatId);

            await channel.SendMessageAsync(content);
        }
Example #27
0
 public static Task <IUserMessage> SendConfirmAsync(this IMessageChannel ch, string title, string text, string url = null, string footer = null)
 => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text)
                        .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer)));
Example #28
0
        internal void CheckAlerts()
        {
            if (warframeChannelIds.Count <= 0)
            {
                return;
            }

            var request = (HttpWebRequest)WebRequest.Create("http://content.warframe.com/dynamic/worldState.php");

            request.Method = "Get";

            try
            {
                using (var s = request.GetResponse().GetResponseStream())
                {
                    using (var sr = new System.IO.StreamReader(s))
                    {
                        Dictionary <string, Dictionary <string, string> > updatedAlerts = new Dictionary <string, Dictionary <string, string> >();
                        List <string> newAlerts  = new List <string>();
                        var           jsonObject = JObject.Parse(sr.ReadToEnd());
                        foreach (var alert in jsonObject["Alerts"])
                        {
                            string alertId = alert["_id"]["$oid"].ToString();
                            Dictionary <string, string> alertInfoToSave = new Dictionary <string, string>();
                            if (!alerts.ContainsKey(alertId))
                            {
                                newAlerts.Add(alertId);
                            }

                            var    alertData    = alert["MissionInfo"];
                            string expiryString = "unknown";

                            try
                            {
                                DateTime convertedTime = FromUnixTime(Convert.ToInt64(alert["Expiry"]["$date"]["$numberLong"].ToString()));
                                TimeSpan diff          = convertedTime - DateTime.UtcNow;

                                string hourString = null;
                                if (diff.Hours == 1)
                                {
                                    hourString = "1 hour";
                                }
                                else if (diff.Hours > 1)
                                {
                                    hourString = $"{diff.Hours} hours";
                                }

                                string minuteString = null;
                                if (diff.Minutes == 1)
                                {
                                    minuteString = "1 minute";
                                }
                                else if (diff.Minutes > 1)
                                {
                                    minuteString = $"{diff.Minutes} minutes";
                                }

                                string secondString = null;
                                if (diff.Seconds == 1)
                                {
                                    secondString = "1 second";
                                }
                                else if (diff.Seconds > 1)
                                {
                                    secondString = $"{diff.Seconds} seconds";
                                }

                                if (hourString != null && minuteString != null && secondString != null)
                                {
                                    expiryString = $"{hourString}, {minuteString} and {secondString}";
                                }
                                else if (hourString != null && minuteString != null)
                                {
                                    expiryString = $"{hourString} and {minuteString}";
                                }
                                else if (minuteString != null && secondString != null)
                                {
                                    expiryString = $"{minuteString} and {secondString}";
                                }
                                else if (hourString != null && secondString != null)
                                {
                                    expiryString = $"{hourString} and {secondString}";
                                }
                                else if (hourString != null)
                                {
                                    expiryString = hourString;
                                }
                                else if (minuteString != null)
                                {
                                    expiryString = minuteString;
                                }
                                else if (secondString != null)
                                {
                                    expiryString = secondString;
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine($"Couldn't convert time ({e.Message}).");
                            }

                            string rewardString = "";
                            if (alertData["missionReward"] != null)
                            {
                                if (alertData["missionReward"]["items"] != null)
                                {
                                    foreach (var item in alertData["missionReward"]["items"])
                                    {
                                        rewardString += $"\n- {ConvertToken(item.ToString())}";
                                    }
                                }
                                if (alertData["missionReward"]["countedItems"] != null)
                                {
                                    foreach (var item in alertData["missionReward"]["countedItems"])
                                    {
                                        rewardString += $"\n- {item["ItemCount"].ToString()} x {ConvertToken(item["ItemType"].ToString())}";
                                    }
                                }
                                if (alertData["missionReward"]["credits"] != null)
                                {
                                    rewardString += $"\n- {alertData["missionReward"]["credits"].ToString()} credits";
                                }
                            }

                            string alertHeader = alertData["location"].ToString();
                            if (nodes.ContainsKey(alertHeader))
                            {
                                alertHeader = nodes[alertHeader];
                            }

                            alertInfoToSave.Add("Header", alertHeader);
                            alertInfoToSave.Add("Level", $"Level {alertData["minEnemyLevel"].ToString()} - {alertData["maxEnemyLevel"].ToString()}");
                            alertInfoToSave.Add("Mission Type", $"{ConvertToken(alertData["missionType"].ToString())}");
                            alertInfoToSave.Add("Faction", ConvertToken(alertData["faction"].ToString()));
                            alertInfoToSave.Add("Rewards", rewardString);
                            alertInfoToSave.Add("Expires", expiryString);
                            updatedAlerts.Add(alertId, alertInfoToSave);
                        }
                        alerts = updatedAlerts;
                        EmbedBuilder embedBuilder = new EmbedBuilder();
                        if (newAlerts.Count > 0)
                        {
                            foreach (string alert in newAlerts)
                            {
                                if (!alerts.ContainsKey(alert))
                                {
                                    continue;
                                }
                                Dictionary <string, string> alertInfo = alerts[alert];
                                if (alertInfo["Expires"] != "unknown")
                                {
                                    embedBuilder.AddField($"{alertInfo["Header"]} - {alertInfo["Mission Type"]} ({alertInfo["Faction"]})", $"{alertInfo["Level"]}. Expires in {alertInfo["Expires"]}.\nRewards:{alertInfo["Rewards"]}");
                                }
                            }
                            foreach (KeyValuePair <UInt64, UInt64> channelId in warframeChannelIds)
                            {
                                IMessageChannel channel = Program.Client.GetChannel(channelId.Value) as IMessageChannel;
                                if (channel != null)
                                {
                                    channel.SendMessageAsync($"There are new mission alerts available, Tenno.", false, embedBuilder);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception in Warframe worldstate lookup: {e.ToString()}.");
            }
        }
Example #29
0
        public WeekUpdate(IMessageChannel chnl)
        {
            var update = new Action(async() =>
            {
                var system = new[] { "xbox", "psn" };

                var seasonCount = system.Select(s => new ConsoleInformation
                {
                    System          = s,
                    CurrentSeason   = int.Parse(GetCurrentSeason.GetSeason(s)),
                    PreviousSeason  = int.Parse(GetPreviousSeason.GetPrevious(s)),
                    NumberOfSeasons = Math.Abs(int.Parse(GetCurrentSeason.GetSeason(s)) -
                                               int.Parse(GetPreviousSeason.GetPrevious(s)) + 1)
                }).ToList();

                var options = new ProgressBarOptions
                {
                    ForegroundColorDone   = ConsoleColor.DarkBlue,
                    ForegroundColor       = ConsoleColor.Yellow,
                    BackgroundColor       = ConsoleColor.Gray,
                    BackgroundCharacter   = '\u2593',
                    ShowEstimatedDuration = true,
                    DisplayTimeInRealTime = false,
                    CollapseWhenFinished  = false
                };
                var childOptions = new ProgressBarOptions
                {
                    ForegroundColor       = ConsoleColor.Green,
                    BackgroundColor       = ConsoleColor.DarkGreen,
                    ProgressCharacter     = '\u2593',
                    CollapseWhenFinished  = false,
                    DisplayTimeInRealTime = false
                };

                Log.Logger.Warning("Running Weekly Update.");

                try
                {
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        foreach (var t in seasonCount)
                        {
                            var currentSeason = LeagueInfo.GetSeason(t.System);

                            await chnl.SendMessageAsync($"Starting update for {t.System.ToUpper()}.").ConfigureAwait(false);
                            foreach (var leagueProp in currentSeason)
                            {
                                for (var j = int.Parse(leagueProp.Season); j >= 1; j--)
                                {
                                    Get.GetPlayerIds(t.System, "player", j);
                                    //await chnl.SendMessageAsync(
                                    //    $"Ran Season {j} Update for {t.System.ToUpper()}.  Remaining: {j}/{t.NumberOfSeasons}");
                                }
                                await chnl.SendMessageAsync($"Update for {t.System.ToUpper()} completed.");
                                break;
                            }
                        }
                    }
                    else
                    {
                        foreach (var t in seasonCount)
                        {
                            await chnl.SendMessageAsync($"Starting update for {t.System.ToUpper()}.").ConfigureAwait(false);

                            using var pbar    = new ProgressBar(t.NumberOfSeasons, $"Running Database Update {t.System}", options);
                            var currentSeason = LeagueInfo.GetSeason(t.System);

                            foreach (var leagueProp in currentSeason)
                            {
                                for (var j = int.Parse(leagueProp.Season); j >= 1; j--)
                                {
                                    pbar.EstimatedDuration = TimeSpan.FromMilliseconds(t.NumberOfSeasons * 5000);

                                    pbar.Tick(
                                        $"Running Season {j} Update for {t.System.ToUpper()}.  Remaining: {j}/{leagueProp.Season}");
                                    Get.GetPlayerIds(t.System, "player", j, pbar);
                                    //await chnl.SendMessageAsync(
                                    //    $"Ran Season {j} Update for {t.System.ToUpper()}.  Remaining: {j}/{t.NumberOfSeasons}");
                                    Thread.Sleep(250);
                                }
                                await chnl.SendMessageAsync($"Update for {t.System.ToUpper()} completed.");

                                var estimatedDuration = TimeSpan.FromSeconds(60 * seasonCount.Count) +
                                                        TimeSpan.FromSeconds(30 * t.NumberOfSeasons);
                                pbar.Tick(estimatedDuration, $"Completed {t.System} updated");
                                break;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            });

            Schedule(update).ToRunEvery(1).Weeks().On(DayOfWeek.Saturday).At(3, 0);
        }
Example #30
0
        public static async Task<IUserMessage> ReplyAsync(SocketUser user, IMessageChannel channel, string text, bool mentionUser)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(text))
                {
                    if (channel as IPrivateChannel != null || !mentionUser)
                        return await channel.SendMessageAsync(text);
                    else
                        return await channel.SendMessageAsync($"{user.Mention}: {text}");
                }
            }
            catch (Exception e)
            {
                LogError("Couldn't send message.", e.Message);
            }

            return null;
        }
Example #31
0
        internal static void AddCommands(Commands.CommandGroupBuilder group)
        {
            group.CreateCommand("ping")
            .Description("I'll reply with 'Pong!'")
            .Do(e => e.Channel.SendMessageAsync($"{e.User.Mention}, Pong!{DoPing(e.Message)}"));

            group.CreateCommand("pong")
            .Hide()     // More of an easter egg, don't show in help.
            .Description("I'll reply with 'Ping?'")
            .Do(e => e.Channel.SendMessageAsync($"{e.User.Mention}, Ping?{DoPing(e.Message)}"));

            group.CreateCommand("uptime")
            .Description("I'll tell you how long I've been awake~")
            .Do(e => e.Channel.SendMessageAsync(Format.Code(Helpers.Uptime().ToString())));

            EmbedFieldBuilder role_info(SocketRole r)
            {
                string ret = $"ID is {r.Id}, has {r.Members.Count()} members, color is {r.Color}, perms are {r.Permissions.RawValue}, and position is {r.Position}";

                if (r.IsManaged)
                {
                    ret += "; it is managed by the server";
                }
                ret += $"\nIt was created on {r.CreatedAt}";
                return(new EmbedFieldBuilder().WithName(r.Name).WithValue(ret));
            }

            group.CreateCommand("whois")
            .Alias("getinfo")
            .Parameter("[@User1] [@User2] [...]", Commands.ParameterType.Unparsed)
            .Description("I'll give you information about the mentioned user(s).")
            .Do(async e =>
            {
                if (e.Args[0].Length == 0 || (!e.Message.MentionedUserIds.Any() && !e.Message.MentionedRoleIds.Any()))
                {
                    return;
                }
                bool oniicheck = e.User.Id == 63299786798796800;
                var embed      = Helpers.EmbedDesc("WhoIs Response");
                async Task <IUserMessage> send() => await e.Channel.SendMessageAsync(embed: embed.Build());
                foreach (var t in e.Message.Tags)
                {
                    if (embed.Fields.Count == EmbedBuilder.MaxFieldCount)
                    {
                        await send();
                        embed.Fields.Clear();
                    }
                    switch (t.Type)
                    {
                    case TagType.RoleMention:
                        embed.AddField(role_info(t.Value as SocketRole));
                        break;

                    case TagType.UserMention:
                        var u             = t.Value as IGuildUser;
                        bool onii         = oniicheck && u.Id == 63296013791666176;
                        string possessive = onii ? "His" : "Their";
                        string pronoun    = onii ? "He" : "They";
                        var field         = new EmbedFieldBuilder();
                        string reply      = string.Empty;
                        if (onii)
                        {
                            reply += "is your onii-chan <3\n";
                        }
                        if (!string.IsNullOrEmpty(u.Nickname))
                        {
                            reply += $"Nick: {u.Nickname}\n";
                        }
                        reply += $"ID: {u.Id}\n{possessive} discriminator is {u.Discriminator}. {possessive} permission level is {Helpers.GetPermissions(u, e.Channel)}.";
                        reply += $"\n{pronoun} joined Discord on {u.CreatedAt}.\n{pronoun} joined this server on {u.JoinedAt}.\n";
                        if (u.IsBot)
                        {
                            reply += $" {pronoun} are also a bot!";
                        }
                        reply += $" {possessive} status is {u.Status}.\n";
                        if (u.Activity != null)
                        {
                            reply += $"\n{pronoun} {(onii ? "is" : "are")} {u.Activity.Type} {u.Activity.Name}.";
                        }
                        if (u.VoiceChannel != null)
                        {
                            reply += $"Current voice channel: {u.VoiceChannel.Name}";
                        }
                        embed.AddField(u.Username, reply);
                        break;
                    }
                }
                if (embed.Fields.Count != 0)
                {
                    await send();
                }
            });

            group.CreateCommand("whois role")
            .Alias("getinfo role")
            .Parameter("role(s)", Commands.ParameterType.Unparsed)
            .Description("I'll give you info on particular roles by name (comma separated)")
            .Do(e =>
            {
                string reply = "";
                if (e.Args[0].Length == 0)
                {
                    reply = "You need to provide at least one role name!";
                }
                else
                {
                    Helpers.CommaSeparateRoleNames(e, (roles, str) =>
                    {
                        foreach (var r in roles)
                        {
                            reply += role_info(r);
                        }
                    });
                }
                e.Channel.SendMessageAsync(reply);
            });

            Music.AddCommands(group);

            Image.AddCommands(group);

            Func <Commands.CommandEventArgs, Task <bool> > lookup_nothing = async e =>
            {
                var args = e.Args[0];
                if (args.Length == 0)
                {
                    await Helpers.SendEmbed(e, Helpers.EmbedDesc("I cannot lookup nothing, silly!"));

                    return(true);
                }
                return(false);
            };

            group.CreateCommand("urban")
            .Alias("urbandictionary")
            .Alias("ud")
            .Parameter("phrase", Commands.ParameterType.Unparsed)
            .Description("I'll give you the urban dictionary definition of a phrase.")
            .Do(async e =>
            {
                if (await lookup_nothing(e))
                {
                    return;
                }
                var req = new RestRequest("define", Method.GET);
                req.AddQueryParameter("term", e.Args[0]);
                var json = JObject.Parse(Helpers.GetRestClient("http://api.urbandictionary.com/v0").Execute(req).Content);
                var list = json["list"];
                if (!list.HasValues)
                {
                    await Helpers.SendEmbed(e, Helpers.EmbedDesc("No results found."));
                    return;
                }
                var resp  = list[0];
                var embed = Helpers.EmbedDesc(resp["definition"].ToString())
                            .WithTitle(resp["word"].ToString())
                            .WithUrl(resp["permalink"].ToString())
                            .WithFooter($"⬆{resp["thumbs_up"]} ⬇{resp["thumbs_down"]}")
                            .WithTimestamp(DateTime.Parse(resp["written_on"].ToString(), null, System.Globalization.DateTimeStyles.RoundtripKind))
                            .AddField("Example", resp["example"]);
                var sounds = resp["sound_urls"];
                if (sounds.HasValues)
                {
                    embed.AddField(sounds.Count() > 1 ? "Sounds" : "Sound", string.Join("\n", sounds));     // I wish we could embed just one of these and have an audio player, but this works too.
                }
                await Helpers.SendEmbed(e, embed);
            });

            if (Helpers.FieldExists("WolframAlpha", "appid"))
            {
                group.CreateCommand("wolfram")
                .Parameter("input", Commands.ParameterType.Unparsed)
                .Description("I'll look something up for you on WolframAlpha")
                .Do(async e =>
                {
                    if (await lookup_nothing(e))
                    {
                        return;
                    }
                    var rc = Helpers.GetRestClient("http://api.wolframalpha.com/v2/");     // TODO: Do we want this static?
                    rc.AddDefaultParameter("appid", Program.config["WolframAlpha"]["appid"]);
                    var req = new RestRequest("query", Method.GET);
                    req.AddQueryParameter("input", e.Args[0]);
                    var json = Helpers.XmlToJson(rc.Execute(req).Content)["queryresult"];
                    if (!json["@success"].ToObject <bool>())
                    {
                        const string didyoumeans = "didyoumeans";
                        if (Helpers.FieldExists(json, didyoumeans))
                        {
                            var embed  = Helpers.EmbedBuilder.WithTitle("Perhaps you meant");
                            json       = json[didyoumeans];
                            int count  = json["@count"].ToObject <int>();
                            string ret = "";
                            Func <JToken, string> format_suggestion = suggestion => $" `{suggestion["#text"]}`";
                            json = json["didyoumean"];
                            if (count == 1)
                            {
                                ret += format_suggestion(json);
                            }
                            else
                            {
                                for (int i = 0; i < count; ++i)
                                {
                                    ret += (i == 0 ? "" : i == count - 1 ? ", or " : ",") + format_suggestion(json[i]);
                                }
                            }
                            ret += '?';
                            await Helpers.SendEmbed(e, embed.WithDescription(ret.TrimStart()));
                        }
                        await Helpers.SendEmbed(e, Helpers.EmbedDesc("Sorry, I couldn't find anything for your input."));
                    }
                    else
                    {
                        int show   = 4;   // Show the first four results
                        json       = json["pod"];
                        string ret = "";
                        //var embed = Helpers.EmbedBuilder.WithTitle($"Results for {e.Args}");
                        for (int i = 0, count = json.Count(); show != 0 && i < count; ++i)
                        {
                            var pod        = json[i];
                            int numsubpods = pod["@numsubpods"].ToObject <int>();
                            if (numsubpods == 1)
                            {
                                ret += $"{pod["subpod"]["img"]["@src"]}\n";
                                --show;
                            }
                            else
                            {
                                for (int j = 0; show != 0 && j < numsubpods; ++j, --show)
                                {
                                    ret += $"{pod["subpod"][j]["img"]["@src"]}\n";
                                }
                            }
                        }
                        await e.Channel.SendMessageAsync(ret);
                        //await Helpers.SendEmbed(e, embed.WithDescription(ret)); // I don't know how this would look good, at this point.
                    }
                });
            }

            var quote_site = "http://bacon.mlgdoor.uk/";

            group.CreateCommand("quote")
            .Description($"I'll give you a random quote from {quote_site}quotes")
            .Do(async e =>
            {
                var result = JObject.Parse(Helpers.GetRestClient(quote_site).Execute <JObject>(new RestRequest("api/v1/quotes/random", Method.GET)).Content)["quotes"][0];
                await e.Channel.SendMessageAsync($"\"{result["quote"]}\" - {result["author"]} {result["year"]}");
            });

            Func <string, string, string, string> add_quote = (quote, author, year) =>
            {
                var result = JObject.Parse(Helpers.GetRestClient(quote_site)
                                           .Execute <JObject>(new RestRequest("api/v1/quotes", Method.POST)
                                                              .AddParameter("quote", quote)
                                                              .AddParameter("author", author)
                                                              .AddParameter("year", year))
                                           .Content);
                return(result["success"].ToObject <bool>() ? "Quote added." : $"Adding quote failed: {result["data"]}");
            };

            group.CreateCommand("addquote")
            .Parameter("<quote>|<author>[|year]", Commands.ParameterType.MultipleUnparsed)
            .Description($"I'll add a quote to {quote_site}quotes, mentions will be garbage text in this.")
            .Do(async e =>
            {
                // TODO: Resolve mentions?
                var args = string.Join(" ", e.Args).Split('|');
                if (args.Length < 2)
                {
                    await e.Channel.SendMessageAsync("I need a quote and its author, silly!");
                    return;
                }
                await e.Channel.SendMessageAsync(add_quote(args[0], args[1], args.Length == 2 ? DateTime.Now.Year.ToString() : args[2]));
            });
            group.CreateCommand("quotemessage")
            .Parameter("messageid", Commands.ParameterType.Required)
            .Description($"I'll add a message from this channel as a quote on {quote_site}quotes, mentions will be resolved.")
            .Do(async e =>
            {
                IMessage message = await e.Channel.GetMessageAsync(Convert.ToUInt64(e.Args[0]));
                if (message == null)     // It's missing, report failure.
                {
                    await e.Channel.SendMessageAsync("Sorry, I couldn't find that message!");
                    return;
                }
                await e.Channel.SendMessageAsync(add_quote(Helpers.ResolveTags(message), Helpers.Nickname(message.Author as SocketGuildUser), message.Timestamp.Date.ToShortDateString()));
            });

            Google.AddCommands(group);

            group.CreateCommand("8ball")
            .Parameter("question", Commands.ParameterType.Optional)
            .Parameter("?", Commands.ParameterType.Multiple)
            .Description("The magic eightball can answer any question!")
            .Do(async e =>
            {
                // TODO: Decide if we want to load this will all the other response commands, if so this check could be bypassed
                // Note: We'd also need to put all responses in asterisks.
                if (!string.Join(" ", e.Args).EndsWith("?"))
                {
                    await e.Channel.SendMessageAsync("You must ask a proper question!");
                    return;
                }
                string[] eightball =
                {
                    "It is certain.",             "It is decidedly so.",   "Without a doubt.",
                    "Yes, definitely.",           "You may rely on it.",   "As I see it, yes.",           "Most likely.",          "Outlook good.",
                    "Yes.",                       "Signs point to yes.",   "Reply hazy try again...",     "Ask again later...",
                    "Better not tell you now...", "Cannot predict now...", "Concentrate and ask again...",
                    "Don't count on it.",         "My reply is no.",       "My sources say no.",          "Outlook not so good.",
                    "Very doubtful.",             "Nyas.",                 "Why not?",                    "zzzzz...",              "No."
                };
                await e.Channel.SendMessageAsync($"*{Helpers.Pick(eightball)}*");
            });

            AddResponseCommands(group, "response_commands.json");
            AddResponseCommands(group, "custom_response_commands.json");

            group.CreateCommand("say")
            .Alias("forward")
            .Alias("echo")
            .Parameter("[#channel or @User (or user/channel id in PMs)] text...", Commands.ParameterType.Unparsed)
            .Description("I'll repeat what you said. (To a given user or channel)")
            .Do(async e =>
            {
                IMessageChannel channel = e.Channel;
                string message          = e.Args[0];
                if (message.Length == 0)
                {
                    return;                          // Unparsed can be empty
                }

                /* Liru Note: I don't think we have to do this anymore.
                 * message = e.Message.MentionedChannels.Aggregate(
                 *  e.Message.MentionedUsers.Aggregate(message, (m, u) => m.Replace($"@{u.Name}", u.Mention)),
                 *  (m, c) => m.Replace($"#{c.Name}", c.Mention));
                 */

                if (message.StartsWith("<@") || message.StartsWith("<#"))
                {
                    bool selfmention = e.Message.MentionedUserIds.Contains(Program.Self.Id);
                    var tag          = e.Message.Tags.Skip(selfmention ? 1 : 0).FirstOrDefault();
                    var usermention  = tag.Type == TagType.UserMention;
                    if (tag != null && (usermention || tag.Type == TagType.ChannelMention))
                    {
                        // FIXME: This will fail in some cases, like mentioning a channel way later... we should check the mention is directly after, aside from spacing
                        int index = message.IndexOf('>', selfmention ? message.IndexOf('>') : 0);
                        if (index + 2 < message.Length)
                        {
                            ulong mentionid = tag.Key;
                            if (mentionid != Program.client.CurrentUser.Id)
                            {
                                channel = usermention ? await(tag.Value as IUser).GetOrCreateDMChannelAsync() : tag.Value as IMessageChannel;
                                if (Helpers.CanSay(ref channel, await channel.GetUserAsync(e.User.Id), e.Channel))
                                {
                                    message = message.Substring(index + 2);
                                }
                            }
                        }
                    }
                }
                else if (channel is IPrivateChannel)
                {
                    try
                    {
                        var index = message.IndexOf(' ');
                        if (index != -1 && index + 2 < message.Length)
                        {
                            channel = await Program.GetChannel(Convert.ToUInt64(message.Substring(0, index)));
                            if (Helpers.CanSay(ref channel, (IGuildUser)channel.GetUserAsync(e.User.Id), e.Channel))
                            {
                                message = message.Substring(index + 1);
                            }
                        }
                    } catch { }
                }
                if (message.TrimEnd() != "")
                {
                    await channel.SendMessageAsync(message);
                }
            });

            group.CreateCommand("reverse")
            .Alias("backward")
            .Alias("flip")
            .Parameter("text...", Commands.ParameterType.Unparsed)
            .Description("I'll repeat what you said, in reverse!")
            .Do(async e =>
            {
                var text = e.Args[0];
                if (text.Length != 0)
                {
                    await e.Channel.SendMessageAsync(string.Join("", Helpers.GraphemeClusters(text).Reverse().ToArray()));
                }
            });

            group.CreateCommand("whereami")
            .Alias("channelinfo")
            .Alias("channel")
            .Alias("location")
            .Alias("where")
            .Description("I'll tell you information about the channel and server you're asking me this from.")
            .Do(async e =>
            {
                if (e.Channel is IPrivateChannel)
                {
                    await e.Channel.SendMessageAsync("You're in a private message with me, baka.");
                }
                else
                {
                    var owner      = await e.Server.GetOwnerAsync();
                    var chan       = e.Channel as ITextChannel;
                    string message = $@"You are currently in {e.Channel.Name} (id: {e.Channel.Id})
on server **{e.Server.Name}** (id: {e.Server.Id}) (region: {Program.client.GetVoiceRegion(e.Server.VoiceRegionId).Name} (id: {e.Server.VoiceRegionId}))
owned by {owner.Nickname ?? owner.Username} (id: {e.Server.OwnerId}).";
                    if (!string.IsNullOrEmpty(chan.Topic))
                    {
                        message = message + $@"
The current topic is: {chan.Topic}";
                    }
                    await e.Channel.SendMessageAsync(message);
                }
            });

            group.CreateCommand("avatar")
            .Parameter("[@User1] [@User2] [...]", Commands.ParameterType.Unparsed)
            .Description("I'll give you the avatars of every mentioned users.")
            .Do(async e =>
            {
                if (e.Args[0].Length == 0)
                {
                    return;
                }
                foreach (var t in e.Message.Tags)
                {
                    if (t.Type == TagType.UserMention)
                    {
                        var u   = t.Value as IUser;
                        var url = u.GetAvatarUrl();
                        await e.Channel.SendMessageAsync(u.Mention + (url == null ? " has no avatar." : $"'s avatar is: {url.Substring(0, url.LastIndexOf('?'))}"));
                    }
                }
            });

            group.CreateCommand("lastlog")
            .Parameter("few (default 4)", Commands.ParameterType.Optional)
            .Parameter("string to search for (case-sensitive)", Commands.ParameterType.Unparsed)
            .Description("I'll search for and return the last `few` messages in this channel with your search string in them (This may take a while, depending on history size and `few`)")
            .Do(async e =>
            {
                var args = e.Args;
                if (!Helpers.HasArg(args))
                {
                    await e.Channel.SendMessageAsync("Just read the last messages yourself, baka!");
                }
                else
                {
                    int few = 4;
                    if (Helpers.HasArg(args, 1))
                    {
                        if (int.TryParse(args[0], out few))
                        {
                            if (few <= 0)
                            {
                                await e.Channel.SendMessageAsync("You're silly!");
                                return;
                            }
                            args = args.Skip(1).ToArray();
                        }
                        else
                        {
                            few = 4;
                        }
                    }

                    var search = string.Join(" ", args).TrimEnd();
                    var found  = new List <IMessage>();
                    await Helpers.DoToMessages((e.Channel as SocketTextChannel), few, (msgs, has_cmd_msg) =>
                    {
                        Func <IMessage, bool> find = s => Helpers.ResolveTags(s).Contains(search);
                        found.AddRange(has_cmd_msg ? msgs.Where(s => s.Id != e.Message.Id && find(s)) : msgs.Where(find));
                        return(found.Count());
                    });

                    if ((few = Math.Min(found.Count(), few)) == 0)
                    {
                        await e.Channel.SendMessageAsync("None found...");
                    }
                    else
                    {
                        foreach (var msg in found.Take(few))
                        {
                            var extradata = $"[[{msg.Timestamp}]({msg.GetJumpUrl()})]{msg.Author.Username}:";
                            //if (msg.Content.Length > EmbedBuilder.MaxDescriptionLength) // This should never happen, unless we decide to start searching embeds.
                            {
                                var builder = Helpers.EmbedBuilder;
                                builder.WithTimestamp(msg.Timestamp).WithDescription(msg.Content);
                                builder.WithTitle($"{msg.Author.ToString()}'s message").WithUrl(msg.GetJumpUrl());
                                await e.Channel.SendMessageAsync(embed: builder.Build());
                            }
                            //else await e.Channel.SendMessageAsync($"Content too long to show, message here: <{msg.GetJumpUrl()}>");
                        }
                    }
                }
            });

            RPG.AddCommands(group);

            group.CreateCommand("lotto")
            .Description("I'll give you a set of 6 lucky numbers!")
            .Do(async e =>
            {
                List <int> lotto = new List <int>();
                Random rnd       = new Random();
                for (var i = 0; i != 6; ++i)
                {
                    var number = rnd.Next(1, 60);
                    if (!lotto.Contains(number))
                    {
                        lotto.Add(number);
                    }
                }
                await e.Channel.SendMessageAsync($"Your lucky numbers are **{lotto[0]}, {lotto[1]}, {lotto[2]}, {lotto[3]}, {lotto[4]}, {lotto[5]}**.");
            });

            // TODO: Decide if PerformAction commands should be moved to their own json file like response_commands.json
            group.CreateCommand("pet")
            .Alias("pets")
            .Parameter("[@User1] [@User2] [...]", Commands.ParameterType.Unparsed)
            .Description("Everyone loves being pet, right!?! Pets each *@user*. Leave empty (or mention me too) to pet me!")
            .Do(e => Helpers.PerformAction(e, "pet", "*purrs*", false));

            group.CreateCommand("hug")
            .Alias("hugs")
            .Parameter("[@User1] [@User2] [...]", Commands.ParameterType.Unparsed)
            .Description("Hug someone! Hugs each *@user*. Leave empty to get a hug!")
            .Do(e => Helpers.PerformAction(e, "hug", "<3", true));
        }