示例#1
0
        public async Task LoadNextSong()
        {
            CurrentSong?.Stop();
            CurrentSong = null;
            if (SongQueue.Count != 0)
            {
                CurrentSong = SongQueue[0];
                SongQueue.RemoveAt(0);
            }
            else
            {
                VoiceClient?.Disconnect();
                VoiceClient = null;
                return;
            }

            try {
                if (VoiceClient == null)
                {
                    Console.WriteLine($"Joining voice channel [{DateTime.Now.Second}]");
                    //VoiceClient =


                    //todo add a new event, to tell people nadeko is trying to join
                    VoiceClient = await Discord.Audio.AudioExtensions.JoinAudio(VoiceChannel);

                    Console.WriteLine($"Joined voicechannel [{DateTime.Now.Second}]");
                }
                await Task.Factory.StartNew(async() => await CurrentSong?.Start(), TaskCreationOptions.LongRunning).Unwrap();
            } catch (Exception ex) {
                Console.WriteLine($"Starting failed: {ex}");
                CurrentSong?.Stop();
                CurrentSong = null;
            }
        }
示例#2
0
            public async Task StartPlaylist()
            {
                if (IsPlaying)
                {
                    return;
                }

                if (await IsPlaylistEmpty())
                {
                    return;
                }

                if (PlaybackChannel == null)
                {
                    await ChatChannel.SafeSendMessage("Audio playback channel has not been set.");

                    return;
                }

                if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel))
                {
                    return;
                }

                _voiceClient = await _client.Audio().Join(PlaybackChannel);

                while (true)
                {
                    if (_stopPlaylistFlag)
                    {
                        _stopPlaylistFlag = false;
                        break;
                    }

                    if (await IsPlaylistEmpty())
                    {
                        return;
                    }

                    await StartCurrentTrackPlayback();

                    if (_prevFlag)
                    {
                        _prevFlag = false;
                        TrackIndex--;
                    }
                    else if (!_skipToFlag)
                    {
                        TrackIndex++;
                    }
                }

                _voiceClient.Wait();
                await _voiceClient.Disconnect();
            }
示例#3
0
 private void leave()
 {
     commands.CreateCommand("leave")
     .Description("Leaves the voice channel")
     .Do(async =>
     {
         _vClient.Disconnect();
         playlist.Clear();
         inVoiceChannel = false;
     });
 }
示例#4
0
    public void SendAudio(string filePath)                                             // Audio sending control
    {
        var channelCount = bot.GetService <AudioService>().Config.Channels;            // Get the number of AudioChannels our AudioService has been configured to use.
        var OutFormat    = new WaveFormat(48000, 16, channelCount);                    // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports.

        using (var MP3Reader = new Mp3FileReader(filePath))                            // Create a new Disposable MP3FileReader, to read audio from the filePath parameter
            using (var resampler = new MediaFoundationResampler(MP3Reader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format
            {
                resampler.ResamplerQuality = 60;                                       // Set the quality of the resampler to 60, the highest quality
                int    blockSize = OutFormat.AverageBytesPerSecond / 50;               // Establish the size of our AudioBuffer
                byte[] buffer    = new byte[blockSize];
                int    byteCount;
                while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present
                {
                    if (byteCount < blockSize)
                    {
                        // Incomplete Frame
                        for (int i = byteCount; i < blockSize; i++)
                        {
                            buffer[i] = 0;
                        }
                    }
                    _vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord
                    if (_isPaused)
                    {
                        do
                        {
                        } while (_isPaused);
                    }
                    if (_isStopped)
                    {
                        break;
                    }
                }
                _vClient.Disconnect();
                _isStopped = true;
                _isPaused  = false;
                Connected  = false;
            }
    }
示例#5
0
        public static async Task SendAudio(string filepath, Channel voiceChannel)
        {
            vClient = await discord.GetService <AudioService>().Join(voiceChannel);

            try
            {
                var channelCount = discord.GetService <AudioService>().Config.Channels;         // Get the number of AudioChannels our AudioService has been configured to use.
                var OutFormat    = new WaveFormat(48000, 16, channelCount);                     // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports.
                using (var WaveReader = new WaveFileReader(filepath))                           // Create a new Disposable MP3FileReader, to read audio from the filePath parameter
                    using (var resampler = new MediaFoundationResampler(WaveReader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format
                    {
                        resampler.ResamplerQuality = 60;                                        // Set the quality of the resampler to 60, the highest quality
                        int    blockSize = OutFormat.AverageBytesPerSecond / 50;                // Establish the size of our AudioBuffer
                        byte[] buffer    = new byte[blockSize];
                        int    byteCount;

                        while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0 && playingSong) // Read audio into our buffer, and keep a loop open while data is present
                        {
                            if (byteCount < blockSize)
                            {
                                // Incomplete Frame
                                for (int i = byteCount; i < blockSize; i++)
                                {
                                    buffer[i] = 0;
                                }
                            }
                            vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord
                        }
                        await vClient.Disconnect();
                    }
            }
            catch
            {
                //if something goes wrong.
                System.Console.WriteLine("lol oops");
            }
            await vClient.Disconnect();
        }
示例#6
0
        private async Task Play(Discord.Commands.CommandEventArgs e)
        {
            if (playing)
            {
                return;
            }
            if (discordAudio == null || discordAudio.Channel != e.User.VoiceChannel)
            {
                await Summon(e);
            }
            playing = true;
            Console.WriteLine(queue.Count);
            while (queue.Count > 0)
            {
                await SendAudio(e.Channel, queue[0]);

                queue.RemoveAt(0);
            }
            await discordAudio.Disconnect();

            queue   = new List <Song>();
            playing = false;
            await e.Channel.SendMessage("Queue empty!");
        }
示例#7
0
        private void PlayYouTube(IAudioClient audioClient, string youtubeURL)
        {
            IEnumerable <VideoInfo> downloadUrls = DownloadUrlResolver.GetDownloadUrls(youtubeURL);
            VideoInfo targetVideoInfo            = downloadUrls.First(info => info.VideoType == VideoType.Mp4 && info.Resolution == 720);

            if (targetVideoInfo.RequiresDecryption)
            {
                DownloadUrlResolver.DecryptDownloadUrl(targetVideoInfo);
            }
            Console.WriteLine("Found download url {0}", targetVideoInfo.DownloadUrl);

            Process process = Process.Start(new ProcessStartInfo
            {
                FileName               = "ffmpeg",
                Arguments              = $"-i {targetVideoInfo.DownloadUrl} -f s16le -ar 48000 -ac 2 pipe:1",
                UseShellExecute        = false,
                RedirectStandardOutput = true
            });

            Console.WriteLine("Started ffmpeg");
            Thread.Sleep(5000);

            int blockSize = 3840;

            byte[] buffer = new byte[blockSize];
            int    byteCount;


            while (!shouldStop)
            {
                byteCount = process.StandardOutput.BaseStream.Read(buffer, 0, blockSize);

                if (byteCount == 0)
                {
                    break;
                }

                audioClient.Send(buffer, 0, byteCount);
            }
            audioClient.Wait();

            if (shouldStop)
            {
                process.Kill();
                shouldStop = false;
                audioClient.Disconnect();
            }
        }
示例#8
0
 private Task <string> GetNextSong()
 {
     _skipThis = false;
     return(Task.Run(async() =>
     {
         if (queue.Count == 0)
         {
             _playing = false;
             await _vclient.Disconnect();
             return null;
         }
         else
         {
             string nsong = queue[0];
             queue.RemoveAt(0);
             return Play(nsong);
         }
     }));
 }
示例#9
0
文件: Discord.cs 项目: eshcrow/Mirai
        public async Task Stream(string Chat, byte[] Sound)
        {
            IAudioClient AudioClient = null;

            try
            {
                var ChatId = ulong.Parse(Chat);

                if (!AudioClients.TryGetValue(ChatId, out AudioClient) || AudioClient.CancelToken.IsCancellationRequested)
                {
                    var Channel = Client.Servers.SelectMany(x => x.VoiceChannels).Where(x => x.Id == ChatId).FirstOrDefault();
                    if (Channel == null)
                    {
                        return;
                    }

                    AudioClients.TryRemove(ChatId, out AudioClient);
                    AudioClient = await Channel.JoinAudio();

                    if (AudioClients.TryAdd(ChatId, AudioClient))
                    {
                        SendAudio = false;
                        Task.Delay(750).ContinueWith(delegate { SendAudio = true; });
                    }
                }
                else if (AudioClient.State != ConnectionState.Connected)
                {
                    Bot.Log("Connecting to audio in voice chat #" + ChatId);
                    AudioClient = await AudioClient.Channel.JoinAudio();
                }
                else if (Sound != null && SendAudio)
                {
                    await AudioClient.OutputStream.WriteAsync(Sound, 0, Sound.Length);
                }
            }
            catch (Exception Ex)
            {
                Bot.Log(Ex);
                await AudioClient?.Disconnect();
            }
        }
示例#10
0
        public async Task DisconnectClient()
        {
            try
            {
                if (AudioClient != null)
                {
                    try
                    {
                        await AudioClient.Disconnect();
                    }
                    catch (Exception Ex)
                    {
                        Ex.Log();
                    }

                    Sending     = null;
                    AudioClient = null;
                }
            }
            catch { }
        }
示例#11
0
        // Private call
        private void SpeakCommand()
        {
            commands.CreateCommand(callCommand)
            .Do(async(e) =>
            {
                // Pick a random quote
                int randomFileIndex = rand.Next(reaperLines.Length);
                string fileToPost   = reaperLines[randomFileIndex];

                // Add file path to queue
                audioQueue.Enqueue(fileToPost);

                // If queue is not already undergoing the process of emptying its contents
                if (!isBeingEmptied)
                {
                    // Raise flag
                    isBeingEmptied = true;

                    // Connect to the voice channel
                    voiceClient = await discord.GetService <AudioService>()
                                  .Join(e.User.VoiceChannel);

                    // Dequeuing until the queue is empty
                    string queueItem;
                    while (audioQueue.TryDequeue(out queueItem))
                    {
                        VoiceFunctions.playAudio(queueItem, voiceClient, discord);
                    }

                    // Disconnecting from voice channel
                    await voiceClient.Disconnect();

                    // Lower flag
                    isBeingEmptied = false;
                }
            });
        }
示例#12
0
        private async void sendAudioQueue(Queue <Command> audioQueue)
        {
            IAudioClient _vClient = null;

            while (audioQueue.Count > 0)
            {
                Command current = audioQueue.Dequeue();
                try { _vClient = await current.VoiceChannel.JoinAudio(); }
                catch (Exception e)
                {
                    log.Error("Error joining channel: " + e.Message);
                    break;
                }
                audioPlaying = true;
                send(current.Path, current, _vClient);
            }
            try { await _vClient.Disconnect(); }
            catch (Exception e)
            {
                log.Error("Error disconnecting: " + e.Message);
                return;
            }
            audioPlaying = false;
        }
示例#13
0
        // Streaming service for the radio stream
        public async Task RadioStream(string pathOrUrl, CommandEventArgs e)
        {
            // Fires when no IAudioClient has been found
            if (_audio == null)
            {
                throw new MissingMemberException();
            }

            // Runs ffmpeg in another thread so it does not block non async methods like Createcommands effectively blocking everything
            new Thread(() =>
            {
                Process process = Process.Start(new ProcessStartInfo
                {
                    // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process
                    FileName  = "ffmpeg",
                    Arguments =
                        $"-i {pathOrUrl} -y " +
                        // Here we provide a list of arguments to feed into FFmpeg. -i means the location of the file/URL it will read from
                        "-f s16le -ar 48000 -ac 2 pipe:1",
                    // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout.
                    UseShellExecute        = false,
                    RedirectStandardOutput = true // Capture the stdout of the process
                });
                Thread.Sleep(2000);               // Sleep for a few seconds so FFmpeg can start processing data.

                int blockSize = 3840;             // The size of bytes to read per frame; 1920 for mono
                byte[] buffer = new byte[blockSize];
                int byteCount;

                while (true) // Loop forever, so data will always be read
                {
                    byteCount = process.StandardOutput.BaseStream
                                // Access the underlying MemoryStream from the stdout of FFmpeg
                                .Read(buffer, 0, blockSize); // Read stdout into the buffer

                    while (byteCount == 0)
                    {
                        Thread.Sleep(2500);
                    }
                    // Call from leave command consider making boolean a method and making it return
                    if (_stopAudio)
                    {
                        Process[] Processes = Process.GetProcessesByName("ffmpeg");
                        // gets all processes called ffmpeg if more than one instance of ffmpeg is present unstable effects WILL occur
                        if (Processes.Length != 0)
                        {
                            foreach (Process Proc in Processes)
                            {
                                Proc.Kill();     // gets the first process called ffmpeg
                            }
                            _audio.Disconnect(); // leaves the audio channel
                        }
                        else
                        {
                            throw new ArgumentNullException();
                        }
                        _stopAudio = false; // resets the soundstopcall
                    }
                    // call to change station, kills ffmpeg process to free up pipes otherwise the pipe will break or overflow
                    if (_changeStation)
                    {
                        // gets all processes named ffmpeg.
                        Process[] Processes = Process.GetProcessesByName("ffmpeg"); // gets all processes called ffmpeg
                        if (Processes.Length != 0)
                        {
                            // there is a possibility that there are multiple ffmpeg processes running kills them all
                            foreach (Process Proc in Processes)
                            {
                                Proc.Kill(); // kills the process
                            }
                        }
                        _changeStation = false; // resets the changestation call
                    }

                    _audio.Send(buffer, 0, byteCount); // Send our data to Discord
                }

                //Program._audio.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now.
            }).Start();
        }
示例#14
0
 //TODO: This isn't threadsafe
 internal async Task RemoveClient(Server server, IAudioClient client)
 {
     if (Config.EnableMultiserver && server != null)
     {
         if (_voiceClients.TryRemove(server.Id, out client))
         {
             await client.Disconnect();
             await (client as AudioClient).GatewaySocket.Disconnect();
         }
     }
 }
示例#15
0
        //m r,radio - init
        //m n,next - next in que
        //m p,pause - pauses, call again to unpause
        //m yq [key_words] - queue from yt by keywords
        //m s,stop - stop
        //m sh - shuffle songs
        //m pl - current playlist

        public override void Install(ModuleManager manager)
        {
            var client = NadekoBot.client;

            manager.CreateCommands("!m", cgb => {
                //queue all more complex commands
                commands.ForEach(cmd => cmd.Init(cgb));

                cgb.CreateCommand("n")
                .Alias("next")
                .Description("Goes to the next song in the queue.")
                .Do(e => {
                    if (Voice != null && Exit == false)
                    {
                        NextSong = true;
                    }
                });

                cgb.CreateCommand("s")
                .Alias("stop")
                .Description("Completely stops the music and unbinds the bot from the channel.")
                .Do(e => {
                    if (Voice != null && Exit == false)
                    {
                        Exit      = true;
                        SongQueue = new List <YouTubeVideo>();
                    }
                });

                cgb.CreateCommand("p")
                .Alias("pause")
                .Description("Pauses the song")
                .Do(async e => {
                    if (Voice != null && Exit == false && CurrentSong != null)
                    {
                        Pause = !Pause;
                        if (Pause)
                        {
                            await e.Send("Pausing. Run the command again to resume.");
                        }
                        else
                        {
                            await e.Send("Resuming...");
                        }
                    }
                });

                cgb.CreateCommand("q")
                .Alias("yq")
                .Description("Queue a song using a multi/single word name.\n**Usage**: `!m q Dream Of Venice`")
                .Parameter("Query", ParameterType.Unparsed)
                .Do(async e => {
                    var youtube = YouTube.Default;
                    var video   = youtube.GetAllVideos(Searches.FindYoutubeUrlByKeywords(e.Args[0]))
                                  .Where(v => v.AdaptiveKind == AdaptiveKind.Audio)
                                  .OrderByDescending(v => v.AudioBitrate).FirstOrDefault();

                    if (video?.Uri != "" && video.Uri != null)
                    {
                        SongQueue.Add(video);
                        if (SongQueue.Count > 1)
                        {
                            await e.Send("**Queued** " + video.FullName);
                        }
                    }
                });

                cgb.CreateCommand("lq")
                .Alias("ls").Alias("lp")
                .Description("Lists up to 10 currently queued songs.")
                .Do(async e => {
                    await e.Send(SongQueue.Count + " videos currently queued.");
                    await e.Send(string.Join("\n", SongQueue.Select(v => v.FullName).Take(10)));
                });

                cgb.CreateCommand("sh")
                .Description("Shuffles the current playlist.")
                .Do(async e => {
                    if (SongQueue.Count < 2)
                    {
                        await e.Send("Not enough songs in order to perform the shuffle.");
                        return;
                    }

                    SongQueue.Shuffle();
                    await e.Send("Songs shuffled!");
                });

                cgb.CreateCommand("radio")
                .Alias("music")
                .Description("Binds to a voice and text channel in order to play music.")
                .Parameter("ChannelName", ParameterType.Unparsed)
                .Do(async e => {
                    if (Voice != null)
                    {
                        return;
                    }
                    VoiceChannel = e.Server.FindChannels(e.GetArg("ChannelName").Trim(), ChannelType.Voice).FirstOrDefault();
                    Voice        = await client.Audio().Join(VoiceChannel);
                    Exit         = false;
                    NextSong     = false;
                    Pause        = false;
                    try {
                        while (true)
                        {
                            if (Exit)
                            {
                                break;
                            }
                            if (SongQueue.Count == 0 || Pause)
                            {
                                Thread.Sleep(100); continue;
                            }
                            if (!LoadNextSong())
                            {
                                break;
                            }

                            await Task.Run(async() => {
                                if (Exit)
                                {
                                    Voice = null;
                                    Exit  = false;
                                    await e.Send("Exiting...");
                                    return;
                                }

                                var streamer = new AudioStreamer(Music.CurrentSong.Uri);
                                streamer.Start();
                                while (streamer.BytesSentToTranscoder < 100 * 0x1000 || streamer.NetworkDone)
                                {
                                    await Task.Delay(500);
                                }

                                int blockSize = 1920 * client.Audio().Config.Channels;
                                byte[] buffer = new byte[blockSize];

                                var msg     = await e.Send("Playing " + Music.CurrentSong.FullName + " [00:00]");
                                int counter = 0;
                                int byteCount;

                                while ((byteCount = streamer.PCMOutput.Read(buffer, 0, blockSize)) > 0)
                                {
                                    Voice.Send(buffer, byteCount);
                                    counter += blockSize;
                                    if (NextSong)
                                    {
                                        NextSong = false;
                                        break;
                                    }
                                    if (Exit)
                                    {
                                        Exit = false;
                                        return;
                                    }
                                    while (Pause)
                                    {
                                        Thread.Sleep(100);
                                    }
                                }
                            });
                        }
                        Voice.Wait();
                    } catch (Exception ex) { Console.WriteLine(ex.ToString()); }
                    await Voice.Disconnect();
                    Voice        = null;
                    VoiceChannel = null;
                });
            });
        }
示例#16
0
 public void ForceStop()
 {
     _voiceClient?.Disconnect();
     IsPlaying = false;
 }
示例#17
0
        async Task StreamFunc()
        {
            CancellationToken cancellationToken = tokenSource.Token;
            IAudioClient      voiceClient       = null;
            TranscodingTask   streamer          = null;

            try {
                uint byteCounter = 0;

                // Download and read audio from the url
                streamer = new TranscodingTask(streamRequest, bufferingStream);
                streamer.Start();

                // Wait until we have at least a few kb transcoded or network stream done
                while (true)
                {
                    if (streamRequest.NetworkDone)
                    {
                        await Task.Delay(600);

                        break;
                    }
                    if (streamer.ReadyBytesLeft > 5 * 1024)
                    {
                        break;
                    }
                    await Task.Delay(200);
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                // Start streaming to voice
                await streamRequest.Channel.SendMessage($"Playing **{streamRequest.Title}** [{streamRequest.Length}]");

                var audioService = client.Audio();
                voiceClient = await audioService.Join(streamRequest.VoiceChannel);

                int    blockSize   = 1920 * audioService.Config.Channels;
                byte[] voiceBuffer = new byte[blockSize];
                var    ringBuffer  = streamer.PCMOutput;

                Stopwatch timeout = Stopwatch.StartNew();
                while (true)
                {
                    var readCount = ringBuffer.Read(voiceBuffer, 0, voiceBuffer.Length);

                    if (readCount == 0)
                    {
                        if (timeout.ElapsedMilliseconds > 1500)
                        {
                            Console.WriteLine("Audio stream timed out. Disconnecting.");
                            break;
                        }

                        await Task.Delay(200);

                        continue;
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    timeout.Restart();

                    byteCounter += (uint)voiceBuffer.Length;
                    voiceClient.Send(voiceBuffer, 0, voiceBuffer.Length);
                }

                streamer.Cancel();

                voiceClient.Wait();
            } catch (Exception ex) {
                await streamRequest.Channel.SendMessage($":musical_note: {streamRequest.User.Mention} Something went wrong, please report this. :angry: :anger:");

                Console.WriteLine("Exception while playing music: " + ex);
            } finally {
                if (voiceClient != null)
                {
                    await streamRequest.Channel.SendMessage($"Finished playing **{streamRequest.Title}**");

                    State = StreamTaskState.Completed;
                    streamer?.Cancel();
                    await voiceClient.Disconnect();

                    await Task.Delay(500);
                }
            }
        }
示例#18
0
            public async Task StartPlaylist()
            {
                if (IsPlaying) return;

                if (await IsPlaylistEmpty())
                    return;

                if (PlaybackChannel == null)
                {
                    await ChatChannel.SafeSendMessage("Audio playback channel has not been set.");
                    return;
                }

                if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel))
                    return;

                _voiceClient = await _client.Audio().Join(PlaybackChannel);

                while (true)
                {
                    if (_stopPlaylistFlag)
                    {
                        _stopPlaylistFlag = false;
                        break;
                    }

                    if (await IsPlaylistEmpty())
                        return;

                    await StartCurrentTrackPlayback();

                    if (_prevFlag)
                    {
                        _prevFlag = false;
                        TrackIndex--;
                    }
                    else if (!_skipToFlag)
                        TrackIndex++;
                }

                _voiceClient.Wait();
                await _voiceClient.Disconnect();
            }
示例#19
0
        // Start the bot, pulling the calendar service from the main thread.
        public DiscordBot(CalendarService calendarService, DriveService driveService)
        {
            // Properly initialise the client.
            client = new DiscordClient(xyz =>
            {
                // Set log severity.
                xyz.LogLevel = LogSeverity.Info;
            });
            // Display the log message to the terminal.
            client.Log.Message += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source} { e.Message}");
            // Grab the provided prefix
            prefix = Program.config[1].ToCharArray()[0];
            // Configure the command structure.
            client.UsingCommands(xyz =>
            {
                // Set prefix character so that the bot knows what to look for.
                xyz.PrefixChar         = prefix;
                xyz.AllowMentionPrefix = true;
            });
            client.UsingAudio(xyz =>
            {
                // We're only sending audio, not receiving.
                xyz.Mode = AudioMode.Outgoing;
            });
            // Properly initialise the command service for issuing the commands to the bot.
            commands = client.GetService <CommandService>();

            /*
             * ██████╗  █████╗ ███████╗██╗ ██████╗
             * ██╔══██╗██╔══██╗██╔════╝██║██╔════╝
             * ██████╔╝███████║███████╗██║██║
             * ██╔══██╗██╔══██║╚════██║██║██║
             * ██████╔╝██║  ██║███████║██║╚██████╗
             * ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝ ╚═════╝
             */
            commands.CreateCommand("help").Parameter("args", ParameterType.Multiple).Do(async(e) =>
            {
                // Command displays specified help text.
                // Delete the command message.
                await e.Message.Delete();
                // Initialise the arguments string
                string args = null;
                // If no arguments are passed, or 'all' is passed, we want to display all commands.
                if (e.Args.Length == 0 || e.Args.Contains("all"))
                {
                    args = "general beer events shitpost sound";
                }
                // Else we only want to display the ones that are specified.
                else
                {
                    args = string.Join(" ", e.Args).ToLower();
                }
                // Initialise the helptext list.
                List <string> helptext = new List <string>();
                // Add the basic usage to the helptext.
                helptext.Add($"Command usage : `{prefix}command <argument>`");
                // All text is pre-formatted when it's added to the list.
                // If general commands are specified, add them to the help text.
                if (args.Contains("general"))
                {
                    helptext.Add("**General**");
                    helptext.Add("```                info : display basic info about the bot.\n" +
                                 "        whois <user> : display <user>'s role on the server.\n" +
                                 "help <command group> : display help for specified command group.\n" +
                                 "         list groups : list the command groups.\n" +
                                 "         synchronise : sync the images & soundbytes with the Google Drive (Admin/OG FKTS only).\n" +
                                 "           changelog : show changelog.```");
                }
                // If beer commands are specified, add them to the help text.
                if (args.Contains("beer"))
                {
                    helptext.Add("**Beer**");
                    helptext.Add($"```  find <beername> : Search for <beername> and present to text channel.\n" +
                                 $"          suggest : get a random beer suggestion.\n" +
                                 $"giveme <beername> : grab the url of the store page of <beername> if possible.```");
                }
                // If event commands are specified, add them to the help text.
                if (args.Contains("event"))
                {
                    helptext.Add("**Event**");
                    helptext.Add("```      events : display upcoming events.\n" +
                                 "view <event> : display more information about <event>.```");
                }
                // If shitposting commands are specified, add them to the help text.
                if (args.Contains("image"))
                {
                    helptext.Add("**Random Image**");
                    helptext.Add("```         image : send a random shitpost.\n" +
                                 "     blacklist : display the current blacklist\n" +
                                 "clearblacklist : clear the shitpost blacklist.```");
                }
                // If sound commands are specified, add them to the help text.
                if (args.Contains("sound"))
                {
                    helptext.Add("**Sound**");
                    helptext.Add("```play <soundbyte> : play the specified soundbyte.\n" +
                                 "     list sounds : list available soundbytes.\n" +
                                 "           queue : display the current queue\n" +
                                 "     clear queue : clears the queue\n" +
                                 "      disconnect : force the bot to disconnect from the voice channel.```");
                }
                // Join the list into a continuous string, seperated by carriage returns
                string helpmessage = string.Join("\n", helptext.ToArray());
                // Inform the user help is on the way, and send the help.
                await e.Channel.SendMessage($"Sending requested help for {e.User.Mention}");
                await e.Channel.SendMessage($"{helpmessage}");
                // Inform the console of the command.
                Console.WriteLine($"[{e.Server}] Displaying help for {e.User.Name}");
            });
            commands.CreateCommand("whois").Parameter("otheruser", ParameterType.Multiple).Do(async(e) =>
            {
                // Command displas the primary role of the specified user.
                // Notes the command being issued and who issued it into the terminal.
                Console.WriteLine($"[{e.Server}] Command 'whois' called by {e.User.Name}");
                // Stores the provided name as a string.
                String name = string.Join(" ", e.Args);
                // Creates a DiscordUser object and finds the user in the server.
                Discord.User singleuser = e.Server.FindUsers(name).FirstOrDefault(t => t.Name == name);;
                // If the user exists...
                if (singleuser != null)
                {
                    // If the users role is not 'everyone'
                    if (singleuser.Roles.First().ToString() != "everyone")
                    {
                        // Converts role to a string, sends it to the FLIV function and tests if it begins with a vowel, this is for grammar.
                        if (functions.FLIV(singleuser.Roles.First().ToString().ToUpper()))
                        {
                            // Send the message back to the channel with correct grammar (eg. an Admin).
                            await e.Channel.SendMessage($"{singleuser.Name} is an {singleuser.Roles.First()}");
                        }
                        else
                        {
                            // Send the message back to the channel with correct grammar (eg. a Moderator).
                            await e.Channel.SendMessage($"{singleuser.Name} is a {singleuser.Roles.First()}");
                        }
                    }
                    else
                    {
                        // If the user has no special role, they're just a normal person.
                        await e.Channel.SendMessage($"{singleuser.Name} is just some random person.");
                    }
                }
                else
                {
                    // In the case of not finding the user, reports this to the terminal.
                    Console.WriteLine($"[{e.Server}] Command failed. No User '{e.GetArg("otheruser")}'");
                    // Also informs the command issuer by sending a message to the channel.
                    await e.Channel.SendMessage($"Could not find user: {e.GetArg("otheruser")}");
                }
            });
            // Command to display the author and status of this bot.
            commands.CreateCommand("info").Do(async(e) =>
            {
                // Command displays the bot info.
                // Delete the command message.
                await e.Message.Delete();
                // Notes the command being issued and who issued it into the terminal.
                Console.WriteLine($"[{e.Server}] Full bot info shown for {e.User.Name}");
                // Sends the information back to the channel
                await e.Channel.SendMessage($"CataBot v4, a Discord Bot made by Catalan.\n" +
                                            $"v4 adds Google Drive interaction.");
            });
            commands.CreateCommand("list").Parameter("args", ParameterType.Required).Do(async(e) =>
            {
                // Command lists the sounbytes or command groups
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user that their list will be shown.
                await e.Channel.SendMessage($"List shown for {e.User.Mention}");
                // Display the correct list.
                if (e.GetArg("args").ToLower() == "sounds")
                {
                    // List the available soundbytes to the text channel.
                    await e.Channel.SendMessage($"*Available soundbytes:*");
                    string[] sounds = Directory.GetFiles(location + "sounds/");
                    for (int i = 0; i < sounds.Length; i++)
                    {
                        sounds[i] = sounds[i].Substring(sounds[i].LastIndexOf('/') + 1);
                        sounds[i] = sounds[i].Substring(0, sounds[i].IndexOf(".mp3"));
                    }
                    await e.Channel.SendMessage($"```{string.Join("\n", sounds)}```");
                    Console.WriteLine($"[{e.Server}] Soundbyte list shown for {e.User.Name}");
                }
                else if (e.GetArg("args").ToLower() == "groups")
                {
                    // Display what the command groups are to the text channel.
                    await e.Channel.SendMessage($"*Command Groups:*");
                    await e.Channel.SendMessage($"```null" +
                                                $"\nGeneral" +
                                                $"\nBeer" +
                                                $"\nEvents" +
                                                $"\nImages" +
                                                $"\nSound```");
                    Console.WriteLine($"[{e.Server}] Command groups shown for {e.User.Name}");
                }
                else
                {
                    // Inform the user if the specified list does not exist.
                    await e.Channel.SendMessage($"{e.User.Mention} that list doesn't exist!");
                }
            });
            commands.CreateCommand("synchronise").Alias(new string[] { "sync" }).Do(async(e) =>
            {
                // Command send a random shitpost to the text channel.
                // Delete the command message.
                await e.Message.Delete();
                // Specificy the roles need to issue this command,
                string[] reqRoles = { "Admin", "OG FKTS" };
                // If the user has the required permissions, execute the command as normal.
                if (reqRoles.Any(s => e.User.Roles.Any(r => r.Name.Contains(s))))
                {
                    // Inform the user that the shitpost is being sent
                    await e.Channel.SendMessage($"Synchronising files for {e.User.Mention}");
                    // Set the file extensions.
                    string[] imageExtensions = { ".jpg", ".png" };
                    string[] soundExtensions = { ".mp3", ".wav" };
                    try
                    {
                        // Pull the metadata for all image/sound files.
                        List <Google.Apis.Drive.v3.Data.File> iFiles = drive.GetFiles(driveService, imageExtensions);
                        List <Google.Apis.Drive.v3.Data.File> sFiles = drive.GetFiles(driveService, soundExtensions);
                        // Synchronise the folders.
                        drive.syncFiles(driveService, iFiles, "images/", e.Channel);
                        drive.syncFiles(driveService, sFiles, "sounds/", e.Channel);
                        await e.Channel.SendMessage("GDrive synchronisation complete.");
                        Console.WriteLine($"[{e.Server}] Synchronised with GDrive ({e.User.Name})");
                    }
                    catch
                    {
                        // If it fails, throw an error message to the user & console.
                        Console.WriteLine($"[{e.Server}] Failed to sync");
                        await e.Channel.SendMessage("GDrive synchronisation failed.");
                    }
                }
                else
                {
                    // If the user doesn't have the correct permissions, inform them.
                    await e.Channel.SendMessage($"{e.User.Mention} Insufficient permissions to  sync files.");
                }
            });
            commands.CreateCommand("exit").Do(async(e) =>
            {
                // Command shuts down the bot.
                // Delete the command message.
                await e.Message.Delete();
                await e.Channel.SendMessage($"***Shutting down CataBot***");
                // If user is an admin.
                if (e.User.Roles.Any(s => s.Name.Contains("Admin")))
                {
                    Environment.Exit(0);
                }
                else
                {
                    await e.Channel.SendMessage($"**YOU DO NOT HAVE ENOUGH BADGES TO TRAIN ME** {e.User.Mention}");
                }
            });

            /*
             * ██████╗ █████╗ ██╗     ███████╗███╗   ██╗██████╗  █████╗ ██████╗
             * ██╔════╝██╔══██╗██║     ██╔════╝████╗  ██║██╔══██╗██╔══██╗██╔══██╗
             * ██║     ███████║██║     █████╗  ██╔██╗ ██║██║  ██║███████║██████╔╝
             * ██║     ██╔══██║██║     ██╔══╝  ██║╚██╗██║██║  ██║██╔══██║██╔══██╗
             * ╚██████╗██║  ██║███████╗███████╗██║ ╚████║██████╔╝██║  ██║██║  ██║
             * ╚═════╝╚═╝  ╚═╝╚══════╝╚══════╝╚═╝  ╚═══╝╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝
             */
            commands.CreateCommand("events").Do(async(e) =>
            {
                // Command displays all upcoming events.
                // Message handling for the command & log.
                Console.WriteLine($"[{e.Server}] Upcoming events shown for {e.User.Name}");
                await e.Message.Delete();
                // Set parameters and initial order for calendar events.
                calendarService = calendar.prepEvents(calendarService);
                // Begin the event feed.
                await e.Channel.SendMessage($"**Upcoming events:**");
                if (calendarService.Events.List("primary").Execute().Items != null && calendarService.Events.List("primary").Execute().Items.Count > 0)
                {
                    // Initialise event list
                    List <calendar.EventListItem> eventList = calendar.eshortDetails(calendarService);
                    // Create two new lists for events this month and next, Splitting the events list into the two new lists based on month.
                    List <calendar.EventListItem> ThisMonth = eventList.Where(x => x.ToString().Contains(functions.SanitiseMonth(DateTime.Now.Month.ToString()))).ToList();
                    List <calendar.EventListItem> NextMonth = eventList.Where(x => x.ToString().Contains(functions.SanitiseMonth((DateTime.Now.Month + 1).ToString()))).ToList();
                    // Builds the list into a multi-line string that can be printed.
                    string events          = string.Join("\n", eventList.ToArray());
                    string eventsthismonth = string.Join("\n", ThisMonth.ToArray());
                    string eventsnextmonth = string.Join("\n", NextMonth.ToArray());
                    // Print out the upcoming events, handling if there are none in the appropriate month.
                    await e.Channel.SendMessage($"*This Month:*");
                    if (ThisMonth.Count != 0)
                    {
                        await e.Channel.SendMessage($"```{eventsthismonth}```");
                    }
                    else
                    {
                        await e.Channel.SendMessage($"```*No events this month*```");
                    }
                    // Only display next month if there are any events.
                    if (ThisMonth.Count < 1)
                    {
                        await e.Channel.SendMessage($"*Later:*");
                        await e.Channel.SendMessage($"```{eventsnextmonth}```");
                    }
                }
                else
                {
                    // If there are no upcoming events at all, return this.
                    await e.Channel.SendMessage($"No upcoming events found.");
                }
            });
            commands.CreateCommand("view").Parameter("eventSearch", ParameterType.Multiple).Do(async(e) =>
            {
                // Command displays a specific event to the text channel.
                // Delete the command message.
                await e.Message.Delete();
                List <Event> events = new List <Event>(calendarService.Events.List("primary").Execute().Items);
                calendarService     = calendar.prepEvents(calendarService);
                if (events != null && events.Count > 0)
                {
                    string summaryMatch = calendar.matchEvent(calendarService, e.Args);
                    string[] details    = calendar.eventDetails(calendarService, summaryMatch);
                    await e.Channel.SendMessage($"**Event:** *{details[0]}*\n" +
                                                $"`Starts: {details[3]} | {details[2]}`\n" +
                                                $"`Ends:   {details[5]} | {details[4]}`\n" +
                                                $"Description:\n" +
                                                $"```{details[1]}```\n");
                }
                else
                {
                    await e.Channel.SendMessage($"No upcoming events to view");
                }
            });

            /*
             * ██████╗ ███████╗███████╗██████╗
             * ██╔══██╗██╔════╝██╔════╝██╔══██╗
             * ██████╔╝█████╗  █████╗  ██████╔╝
             * ██╔══██╗██╔══╝  ██╔══╝  ██╔══██╗
             * ██████╔╝███████╗███████╗██║  ██║
             * ╚═════╝ ╚══════╝╚══════╝╚═╝  ╚═╝
             */
            List <string> beers = new List <string>();

            beers.Add("brewery");
            beers.Add("country");
            beers.Add("styles");
            commands.CreateCommand("find").Parameter("beer", ParameterType.Multiple).Do(async(e) =>
            {
                // Command finds the specified beer and displays it.
                // Delete the command message.
                await e.Message.Delete();
                // Grab the name of the beer to look for.
                string BeerToSearch = string.Join(" ", e.Args);
                // Inform the user that a beer will be searched.
                await e.Channel.SendMessage($"Searching '*{BeerToSearch}*' for {e.User.Mention}");
                // Search for the beer and pull the URL.
                string url = beer.Search(BeerToSearch, beers);
                // Initialise lists to store beer info.
                List <string> MessageItem = new List <string>();
                List <string> Message     = new List <string>();
                if (url != "Not found!")
                {
                    // If beer was found, retrieve the details inc. image link
                    MessageItem = beer.Retrieve(url, e.Channel, "RandomBeer");
                    // Send beer name.
                    await e.Channel.SendMessage($"**{MessageItem[1]}**");
                    // Initialise a WebClient to grab the image.
                    WebClient webClient = new WebClient();
                    // Download the image and save it.
                    webClient.DownloadFile(MessageItem[0], "temp/beer-image.png");
                    // Dispose of the WebClient now that it is no longer needed.
                    webClient.Dispose();
                    // Send the image that was downloaded.
                    await e.Channel.SendFile("temp/beer-image.png");
                    // Send the remaining beer details.
                    string message = string.Join("\n", MessageItem.GetRange(2, MessageItem.Count - 2).ToArray());
                    await e.Channel.SendMessage($"{message}");
                    // Inform the console of the command.
                    Console.WriteLine($"[{e.Server}] beer found for {e.User.Name} ({MessageItem[1]})");
                }
                else
                {
                    await e.Channel.SendMessage($"Couldn't find '*{BeerToSearch}*'");
                    // Inform the console of the command.
                    Console.WriteLine($"[{e.Server}] beer not found for {e.User.Name} ({BeerToSearch})");
                }
            });
            commands.CreateCommand("suggest").Do(async(e) =>
            {
                // Command suggests a beer for the user and displays it.
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user that a beer will be suggested.
                await e.Channel.SendMessage($"Suggesting a beer for {e.User.Mention}");
                // Search for a random beer and pull the URL.
                string url = beer.Search("RandomBeer", beers);
                // Initialise lists to store beer info.
                List <string> MessageItem = new List <string>();
                List <string> Message     = new List <string>();
                // Error handling if no URL could be pulled for whatever reason.
                if (url != "Not found!")
                {
                    // If beer was found, retrieve the details inc. image link
                    MessageItem = beer.Retrieve(url, e.Channel, "RandomBeer");
                    // Send beer name.
                    await e.Channel.SendMessage($"**{MessageItem[1]}**");
                    // Initialise a WebClient to grab the image.
                    WebClient webClient = new WebClient();
                    // Download the image and save it.
                    webClient.DownloadFile(MessageItem[0], "temp/beer-image.png");
                    // Dispose of the WebClient now that it is no longer needed.
                    webClient.Dispose();
                    // Send the image that was downloaded.
                    await e.Channel.SendFile("temp/beer-image.png");
                    // Send the remaining beer details.
                    string message = string.Join("\n", MessageItem.GetRange(2, MessageItem.Count - 2).ToArray());
                    await e.Channel.SendMessage($"{message}");
                    // Inform the console of the command.
                    Console.WriteLine($"[{e.Server}] beer suggested for {e.User.Name} ({MessageItem[1]})");
                }
                else
                {
                    await e.Channel.SendMessage($"Couldn't suggest a beer");
                    // Inform the console of the command.
                    Console.WriteLine($"[{e.Server}] beer could not be suggested for {e.User.Name}");
                }
            });
            commands.CreateCommand("giveme").Parameter("BeerToSearch", ParameterType.Multiple).Do(async(e) =>
            {
                // Command provides URL to the specified beer.
                // Delete the command message.
                await e.Message.Delete();
                // Grab the name of the beer to look for.
                string BeerToSearch = string.Join(" ", e.Args);
                // Inform the user that the link is being grabbed.
                await e.Channel.SendMessage($"Grabbing store page for {BeerToSearch} for {e.User.Mention}");
                // Find and pull the URL for the beer.
                string url = beer.Search(BeerToSearch, beers);
                // Send the URL to the channel.
                await e.Channel.SendMessage($"**URL:** {url}");
                // Inform the console of the command.
                Console.WriteLine($"[{e.Server}] beer URL pulled for {e.User.Name} ({BeerToSearch})");
            });

            /*
             * ███████╗ ██████╗ ██╗   ██╗███╗   ██╗██████╗
             * ██╔════╝██╔═══██╗██║   ██║████╗  ██║██╔══██╗
             * ███████╗██║   ██║██║   ██║██╔██╗ ██║██║  ██║
             * ╚════██║██║   ██║██║   ██║██║╚██╗██║██║  ██║
             * ███████║╚██████╔╝╚██████╔╝██║ ╚████║██████╔╝
             * ╚══════╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚═════╝
             */
            commands.CreateCommand("play").Parameter("audiofile", ParameterType.Required).Do(async(e) =>
            {
                // Command plays a specified soundbyte.
                // Delete the command message.
                await e.Message.Delete();
                // Get audio file selection.
                string audiofile = e.GetArg("audiofile");
                // Check if the requested file exists.
                if (functions.fileExists(audiofile))
                {
                    // Inform the user that the soundbyte is being played.
                    await e.Channel.SendMessage($"Playing '*{audiofile}*' for {e.User.Mention}");
                    // Add the soundbyte to the queue.
                    queue.Add(audiofile);
                    // If we're not sending audio, we will need to start sending audio.
                    if (!sendingAudio)
                    {
                        sendingAudio = true;
                        // Check if the user is in a voice channel.
                        if (e.User.VoiceChannel != null)
                        {
                            try
                            {
                                // If file exists, and user is in a voice channel, play it using the SendAudio function (further down).
                                SendAudio(e.User.VoiceChannel, e.Channel, e.Server);
                                // Inform the console.
                                Console.WriteLine($"[{e.Server}] {audiofile} soundbyte played for {e.User.Name}");
                            }
                            catch
                            {
                                // Inform the console.
                                Console.WriteLine($"[{e.Server}] {audiofile} soundbyte could not be played for {e.User.Name}");
                            }
                        }
                        else
                        {
                            // If user not in a voice channel, inform the terminal and tell the user to join a voice channel.
                            Console.WriteLine($"[{e.Server}] user {e.User.Name} not in voice channel");
                            await e.Channel.SendMessage($"{e.User.Mention} join a voice channel to use the soundboard!");
                        }
                    }
                }
                else
                {
                    // If the file does not exist, inform the user and the terminal.
                    await e.Channel.SendMessage($"{e.User.Mention} Couldn't find sound '{audiofile}'");
                    // Inform the console of the command.
                    Console.WriteLine($"[{e.Server}] file {audiofile} could not be found, or does not exist.");
                }
            });
            commands.CreateCommand("queue").Do(async(e) =>
            {
                // Command displays the queue.
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user the queue will be shown.
                await e.Channel.SendMessage($"Showing queue for {e.User.Name}");
                // Grab the queue and turn it into a carriage return deliminated string.
                string Queue = string.Join("\n", queue.ToArray());
                // Send the list to the text channel and inform the console.
                await e.Channel.SendMessage("*Soundbyte queue:*");
                await e.Channel.SendMessage($"```{Queue}```");
                Console.WriteLine($"[{e.Server}] Showing soundbyte queue for {e.User.Name}");
            });
            commands.CreateCommand("clearqueue").Alias(new string[] { "cq" }).Do(async(e) =>
            {
                // Command clears the soundbyte queue.
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user the queue is being cleared.
                await e.Channel.SendMessage($"Clearing queue for {e.User.Mention}");
                // Clear the blacklist.
                queue.Clear();
                // Inform the console of the command.
                Console.WriteLine($"[{e.Server}] Queue cleared by {e.User.Name}");
            });
            commands.CreateCommand("disconnect").Do(async(s) =>
            {
                // Command forces the bot to disconnect from the voice channel.
                // Delete the command message.
                await s.Message.Delete();
                // Disconnect the client from the voice channel.
                await vClient.Disconnect();
                // Clear the queue to avoid confusion upon restart of audio sending.
                queue.Clear();
            });

            /*
             * ██╗███╗   ███╗ █████╗  ██████╗ ███████╗███████╗
             *          ██║████╗ ████║██╔══██╗██╔════╝ ██╔════╝██╔════╝
             *          ██║██╔████╔██║███████║██║  ███╗█████╗  ███████╗
             *          ██║██║╚██╔╝██║██╔══██║██║   ██║██╔══╝  ╚════██║
             *          ██║██║ ╚═╝ ██║██║  ██║╚██████╔╝███████╗███████║
             *          ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚══════╝
             */
            commands.CreateCommand("image").Do(async(e) =>
            {
                // Command send a random shitpost to the text channel.
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user that the shitpost is being sent
                await e.Channel.SendMessage($"Sending random image for {e.User.Mention}");
                // Get all the filenames of the correct filetype from the google drive.
                string[] files = Directory.GetFiles(location + "images/");
                // Initialise a string to hold the file.
                string chosenfile = null;
                do
                {
                    // Pick a random file.
                    chosenfile = files[functions.GenIndex(files.Length)];
                    // Check if the file is on the blacklist
                    if (!blacklist.ToArray().Contains(chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)))
                    {
                        // Add the sent file to the blacklist.
                        blacklist.Add(chosenfile.Substring(chosenfile.LastIndexOf('/') + 1));
                        // If it isn't, try to send the file.
                        try
                        {
                            // Send the file.
                            await e.Channel.SendFile(chosenfile);
                            // Inform the console.
                            Console.WriteLine($"[{e.Server}] Sending random image ('{chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)}') for {e.User.Name}");
                        }
                        catch
                        {
                            // Inform the console.
                            Console.WriteLine($"[{e.Server}] Sending random image failure. Failed to send '{chosenfile.Substring(chosenfile.LastIndexOf('/') + 1)}' for {e.User.Name}");
                        }
                        break;
                    }
                    // If it is, repeat until it a non-blacklisted file is found and sent.
                } while (true);
                // If the blacklist is full, forget the first item.
                if (blacklist.Count > 100)
                {
                    blacklist.RemoveAt(0);
                }
                // Inform the console of the command.
                Console.WriteLine($"[{e.Server}] Blacklist updated [{blacklist.Count}]");
            });
            commands.CreateCommand("blacklist").Do(async(e) =>
            {
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user the queue will be cleared.
                await e.Channel.SendMessage($"Showing blacklist for {e.User.Name}");
                string[] blcklst = blacklist.ToArray();
                for (int i = 0; i < blcklst.Length; i++)
                {
                    blcklst[i] = blcklst[i].Substring(blcklst[i].LastIndexOf('/'));
                }
                // Grab the queue and turn it into a carriage return deliminated string.
                string Blacklist = string.Join("\n", blcklst);
                // Send the list to the text channel and inform the console.
                await e.Channel.SendMessage("*Blacklist:*");
                await e.Channel.SendMessage($"```{string.Join("\n",blacklist.ToArray())}```");
                Console.WriteLine($"[{e.Server}] Showing blacklist for {e.User.Name}");
            });
            commands.CreateCommand("clearblacklist").Do(async(e) =>
            {
                // Command clears the shitpost blacklist.
                // Delete the command message.
                await e.Message.Delete();
                // Inform the user the blacklist is being cleared.
                await e.Channel.SendMessage($"Clearing random image blacklist for {e.User.Mention}");
                // Clear the blacklist.
                blacklist.Clear();
                // Inform the console of the command.
                Console.WriteLine($"[{e.Server}] Blacklist cleared by {e.User.Name}");
            });
            client.ExecuteAndWait(async() =>
            {
                // Connects the client using it's unique token.
                await client.Connect("BOT TOKEN HERE", TokenType.Bot);
                // Sets the game to be the help prompt, so users can easily issue the help command.
                client.SetGame($"v4 - {prefix}help for help.");
            });
        }
示例#20
0
 public static void disconnect(IAudioClient voiceClient)
 {
     voiceClient.Disconnect();
 }