Exemple #1
0
            private async Task ConnectAndAddToQueueAsync(CommandContext ctx, SongInfo si)
            {
                VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

                if (vnext == null)
                {
                    throw new CommandFailedException("VNext is not enabled or configured.");
                }

                VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

                if (vnc == null)
                {
                    await this.ConnectAsync(ctx);

                    vnc = vnext.GetConnection(ctx.Guild);
                }

                if (MusicPlayers.ContainsKey(ctx.Guild.Id))
                {
                    MusicPlayers[ctx.Guild.Id].Enqueue(si);
                    await ctx.RespondAsync("Added to queue:", embed : si.ToDiscordEmbed(this.ModuleColor));
                }
                else
                {
                    if (!MusicPlayers.TryAdd(ctx.Guild.Id, new MusicPlayer(ctx.Client, ctx.Channel, vnc)))
                    {
                        throw new ConcurrentOperationException("Failed to initialize music player!");
                    }
                    MusicPlayers[ctx.Guild.Id].Enqueue(si);
                    var t = Task.Run(() => MusicPlayers[ctx.Guild.Id].StartAsync());
                }
            }
        private async Task VoiceStateUpdated(DiscordClient client, VoiceStateUpdateEventArgs e)
        {
            VoiceNextConnection vnc = _voiceNextExtension.GetConnection(e.Guild);

            if (vnc == null)
            {
                return;
            }

            if (e.User.Id == client.CurrentUser.Id)
            {
                if (!e.After.IsServerDeafened)
                {
                    DiscordMember member = await e.Guild.GetMemberAsync(e.User.Id);

                    await member.ModifyAsync(member => member.Deafened = true);
                }
            }
            else
            {
                if (e.Before?.Channel != null && e.Before.Channel.Id == vnc.TargetChannel.Id && e.Before.Channel.Users.Where(u => !u.IsBot).Count() == 0)
                {
                    vnc.Disconnect();
                }
            }
        }
Exemple #3
0
            public async Task PlayFileAsync(CommandContext ctx,
                                            [RemainingText, Description("Full path to the file to play.")] string filename)
            {
                VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

                if (vnext == null)
                {
                    throw new CommandFailedException("VNext is not enabled or configured.");
                }

                VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

                if (vnc == null)
                {
                    await this.ConnectAsync(ctx);

                    vnc = vnext.GetConnection(ctx.Guild);
                }

                if (!File.Exists(filename))
                {
                    throw new CommandFailedException($"File {Formatter.InlineCode(filename)} does not exist.");
                }

                var si = new SongInfo()
                {
                    Title    = filename,
                    Provider = "Server file system",
                    Query    = ctx.Client.CurrentUser.AvatarUrl,
                    Queuer   = ctx.User.Mention,
                    Uri      = filename
                };

                if (MusicPlayers.ContainsKey(ctx.Guild.Id))
                {
                    MusicPlayers[ctx.Guild.Id].Enqueue(si);
                    await ctx.RespondAsync("Added to queue:", embed : si.ToDiscordEmbed(this.ModuleColor));
                }
                else
                {
                    if (!MusicPlayers.TryAdd(ctx.Guild.Id, new MusicPlayer(ctx.Client, ctx.Channel, vnc)))
                    {
                        throw new ConcurrentOperationException("Failed to initialize music player!");
                    }
                    MusicPlayers[ctx.Guild.Id].Enqueue(si);
                    await MusicPlayers[ctx.Guild.Id].StartAsync();
                }
            }
Exemple #4
0
        public Task DisconnectAsync(CommandContext ctx)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            if (vnext == null)
            {
                throw new CommandFailedException("VNext is not enabled or configured.");
            }

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc == null)
            {
                throw new CommandFailedException("Not connected in this guild.");
            }

            if (MusicPlayers.ContainsKey(ctx.Guild.Id))
            {
                MusicPlayers[ctx.Guild.Id].Stop();
                MusicPlayers.TryRemove(ctx.Guild.Id, out _);
            }

            // TODO check await Task.Delay(500);
            vnc.Disconnect();

            return(this.InformAsync(ctx, StaticDiscordEmoji.Headphones, "Disconnected.", important: false));
        }
Exemple #5
0
 private async Task Client_MessageCreatedAsync(DSharpPlus.EventArgs.MessageCreateEventArgs e)
 {
     if (e.Message.Content.Contains(":foodReview:"))
     {
         VoiceNextExtension voiceNextClient = Program.Client.GetVoiceNext();
         VoiceNextConnection voiceNextCon = voiceNextClient.GetConnection(e.Guild);
         if (voiceNextCon == null)
         {
             foreach (DiscordVoiceState vs in e.Guild.VoiceStates)
             {
                 if (vs.User.Username.Equals(e.Author.Username))
                 {
                     voiceNextCon = await voiceNextClient.ConnectAsync(vs.Channel);
                 }
             }
         }
         if (voiceNextCon == null)
         {
             // user wasnt in a voice channel
             return;
         }
         else
         {
             // await PlayAudio(voiceNextCon, @"AudioFiles\foodReview.mp3");
             voiceNextCon.Disconnect();
         }
     }
 }
Exemple #6
0
        public async Task Leave(CommandContext ctx)
        {
            DiscordMessage tmp = await ctx.RespondAsync("DC");

            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("DC: GVNC");

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("DC: CVNC");

            if (vnc == null)
            {
                throw new InvalidOperationException("Not connected in this guild.");
            }
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("DC: DCXC");

            vnc.Disconnect();
            await tmp.DeleteAsync();

            await ctx.RespondAsync("👌");
        }
Exemple #7
0
        public async Task Join(CommandContext ctx,
                               DiscordChannel chn = null)
        {
            _vnext = ctx.Client.GetVoiceNext();
            if (_vnext == null)
            {
                await ctx.RespondAsync(":x: VNext is not enabled or configured.");

                return;
            }
            VoiceNextConnection vnc = _vnext.GetConnection(ctx.Guild);

            if (vnc != null)
            {
                await ctx.RespondAsync("Already connected.");

                return;
            }
            DiscordVoiceState vstat = ctx.Member?.VoiceState;

            if (vstat?.Channel == null && chn == null)
            {
                await ctx.RespondAsync("You are not in a voice channel.");

                return;
            }
            if (chn == null)
            {
                chn = vstat.Channel;
            }
            await chn.ConnectAsync();

            await ctx.RespondAsync($"Connected to `{chn.Name}`");
        }
Exemple #8
0
        public async Task ConnectAsync(CommandContext ctx,
                                       [Description("Channel.")] DiscordChannel channel = null)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            if (vnext == null)
            {
                throw new CommandFailedException("VNext is not enabled or configured.");
            }

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc != null)
            {
                throw new CommandFailedException("Already connected in this guild.");
            }

            DiscordVoiceState vstat = ctx.Member?.VoiceState;

            if ((vstat == null || vstat.Channel == null) && channel == null)
            {
                throw new CommandFailedException("You are not in a voice channel.");
            }

            if (channel == null)
            {
                channel = vstat.Channel;
            }

            vnc = await vnext.ConnectAsync(channel);

            await this.InformAsync(ctx, StaticDiscordEmoji.Headphones, $"Connected to {Formatter.Bold(channel.Name)}.", important : false);
        }
Exemple #9
0
        public async Task Play(CommandContext ctx, [RemainingText] string queryString)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc == null)
            {
                DiscordChannel chn = ctx.Member?.VoiceState?.Channel;
                if (chn == null)
                {
                    throw new OutputException("You need to be in a voice channel.");
                }

                await vnext.ConnectAsync(chn);
            }

            if (!string.IsNullOrWhiteSpace(queryString))
            {
                await this.Queue(ctx, queryString);

                if (!GuildMusicStatuses.TryGetValue(ctx.Guild.Id, out MusicStatus musicStatus))
                {
                    GuildMusicStatuses.Add(ctx.Guild.Id, new MusicStatus
                    {
                        Skip = false
                    });

                    if (ctx.Client.GetVoiceNext().GetConnection(ctx.Guild) != null)
                    {
                        PlayMusic(ctx);
                    }
                }
                else
                {
                    if (!musicStatus.Skip && ctx.Client.GetVoiceNext().GetConnection(ctx.Guild) != null)
                    {
                        PlayMusic(ctx);
                    }
                }

                return;
            }

            if (!GuildMusicStatuses.TryGetValue(ctx.Guild.Id, out MusicStatus _))
            {
                GuildMusicStatuses.Add(ctx.Guild.Id, new MusicStatus {
                    Skip = false
                });
            }

            PlayMusic(ctx);
        }
Exemple #10
0
        /// <summary>
        /// Plays music through the music process
        /// </summary>
        /// <param name="vnext">VoiceNext instance</param>
        /// <param name="guild">Guild reference</param>
        /// <param name="song_path">Path to MP3 music file</param>
        /// <returns></returns>
        public async Task PlayFromMemory(VoiceNextExtension vnext, DiscordGuild guild, DiscordMember requested_by, string song_path)
        {
            var vnc = vnext.GetConnection(guild);

            if (vnc == null)
            {
                throw new InvalidOperationException($"I'm not connected to any voice channel! {DiscordEmoji.FromName(vnext.Client, ":thinking:")}");
            }

            if (!File.Exists(song_path))
            {
                throw new FileNotFoundException($"Music file not found! {DiscordEmoji.FromName(vnext.Client, ":(")}");
            }

            if (!this.MusicChannels.TryGetValue(guild.Id, out GuildMusicChannel channel))
            {
                throw new InvalidOperationException("No music channel associated with this guild!");
            }

            this.EnqueueSong(channel, new MusicData
            {
                Source      = song_path,
                Channel     = channel,
                RequestedBy = requested_by,
                MusicType   = MusicTypes.MEMORY
            });

            // Something it's being already played, limit to just enqueueing
            if (channel.IsPlaying)
            {
                return;
            }

            var txStream = vnc.GetTransmitStream();

            txStream.VolumeModifier = channel.Volume / 100f;

            // Start speaking
            channel.IsPlaying = true;
            channel.MusicProc = new MusicProcess(song_path, ProcessStartMode.OUTPUT);

            var ffout = channel.MusicProc.FFMpeg.StandardOutput.BaseStream;
            await ffout.CopyToAsync(txStream);

            await txStream.FlushAsync().ConfigureAwait(false);

            await vnc.WaitForPlaybackFinishAsync();

            // Stop speaking (also sets IsPlaying to false)
            await this.TryDequeueSong(channel);
        }
Exemple #11
0
        public async Task StartListen(CommandContext ctx)
        {
            await JoinIfNotConnected(ctx);

            VoiceNextExtension  voiceNextClient = ctx.Client.GetVoiceNext();
            VoiceNextConnection voiceNextCon    = voiceNextClient.GetConnection(ctx.Guild);

            if (voiceNextClient.IsIncomingEnabled)
            {
                this.ssrcMap                = new ConcurrentDictionary <uint, ulong>();
                this.ssrcFilemap            = new ConcurrentDictionary <uint, FileStream>();
                voiceNextCon.VoiceReceived += this.OnVoiceReceived;
                voiceNextCon.UserSpeaking  += this.OnUserSpeaking;
            }
        }
Exemple #12
0
        /// <summary>
        /// Stops any currently playing music but does not disconnect from the voice channel
        /// </summary>
        /// <param name="vnext">VoiceNext instance</param>
        /// <param name="guild">Guild reference</param>
        /// <returns></returns>
        public async Task Stop(VoiceNextExtension vnext, DiscordGuild guild)
        {
            var vnc = vnext.GetConnection(guild);

            if (vnc == null)
            {
                throw new InvalidOperationException($"I'm not connected to any voice channel! {DiscordEmoji.FromName(vnext.Client, ":thinking:")}");
            }

            if (!this.MusicChannels.TryGetValue(guild.Id, out GuildMusicChannel channel))
            {
                throw new InvalidOperationException("No music channel associated with this guild!");
            }

            await this.TryDequeueSong(channel);
        }
Exemple #13
0
        private async void AudioPlayingThread()
        {
            while (true)
            {
                try
                {
                    PlayQueueElement elementToPlay = playQueue.Take();
                    Program.Client.DebugLogger.Info($"Took [{elementToPlay.Filepath}] off the queue");

                    // Connect if not already
                    VoiceNextExtension  voiceNextClient = Program.Client.GetVoiceNext();
                    VoiceNextConnection voiceNextCon    = voiceNextClient.GetConnection(elementToPlay.GuildToJoin);
                    if (voiceNextCon == null)
                    {
                        Program.Client.DebugLogger.Info($"Not currently connected");
                        Task <VoiceNextConnection> voiceNextConTask = voiceNextClient.ConnectAsync(elementToPlay.ChannelToJoin);
                        voiceNextConTask.Wait(new TimeSpan(0, 0, 3));
                        if (voiceNextConTask.IsCompletedSuccessfully)
                        {
                            voiceNextCon = voiceNextConTask.Result;
                            Program.Client.DebugLogger.Info($"Joined: {voiceNextCon.Channel}");
                        }
                        else
                        {
                            Program.Client.DebugLogger.Error($"Could not join: {elementToPlay.ChannelToJoin.Name}");
                            continue;
                        }
                    }

                    await PlayAudio(voiceNextCon, elementToPlay.Filepath);

                    if (playQueue.Count == 0)
                    {
                        voiceNextCon.Disconnect();
                        Program.Client.DebugLogger.Info($"Leaving: {voiceNextCon.Channel}");
                    }
                }
                catch (Exception ex)
                {
                    Program.Client.DebugLogger.Critical($"Exception was caught in the Audio Thread: {ex}");
                }
            }
        }
Exemple #14
0
        private async Task <VoiceNextConnection> GetVNextConnection(CommandContext ctx)
        {
            if (ctx.Channel.IsPrivate)
            {
                await ctx.RespondAsync(":x: This command is only for server use.");

                return(null);
            }
            VoiceNextConnection vnc = null;

            if (_vnext != null)
            {
                vnc = _vnext.GetConnection(ctx.Guild);
            }
            if (vnc == null)
            {
                await ctx.Message.RespondAsync(":x: Voice is not connected in this guild.");
            }
            return(vnc);
        }
Exemple #15
0
        /// <summary>
        /// Leaves the voice channel where the bot is currently connected for a given guild
        /// </summary>
        /// <param name="vnext">VoiceNext instance</param>
        /// <param name="guild">Guild reference</param>
        public async Task LeaveVoiceChannel(VoiceNextExtension vnext, DiscordGuild guild)
        {
            var vnc = vnext.GetConnection(guild);

            if (vnc == null)
            {
                throw new InvalidOperationException($"I'm not connected to any voice channel! {DiscordEmoji.FromName(vnext.Client, ":thinking:")}");
            }

            if (!this.MusicChannels.TryGetValue(guild.Id, out GuildMusicChannel channel))
            {
                throw new InvalidOperationException("No music channel associated with this guild!");
            }

            if (await this.TryDequeueSong(channel) && !channel.Queue.IsEmpty)
            {
                channel.Queue.Clear();
            }

            channel.IsConnected = false;
            vnc.Dispose();
        }
Exemple #16
0
        /// <summary>
        /// Joins a voice channel
        /// </summary>
        /// <param name="vnext">VoiceNext instance</param>
        /// <param name="voiceChannel">Voice channel to join</param>
        /// <returns></returns>
        public async Task <GuildMusicChannel> JoinVoiceChannel(VoiceNextExtension vnext, DiscordChannel voiceChannel)
        {
            var vnc = vnext.GetConnection(voiceChannel.Guild);

            var channel = new GuildMusicChannel(voiceChannel.Guild);

            if (!this.MusicChannels.TryAdd(voiceChannel.GuildId, channel))
            {
                // If the add fails, it means there is already a channel for this guild, recover it
                this.MusicChannels.TryGetValue(voiceChannel.GuildId, out channel);
            }
            channel.IsConnected = true;

            if (vnc != null)
            {
                return(channel);
            }

            vnc = await vnext.ConnectAsync(voiceChannel);

            return(channel);
        }
Exemple #17
0
        public async Task Join(CommandContext ctx)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc != null)
            {
                throw new OutputException("Already connected in this guild.");
            }

            DiscordChannel chn = ctx.Member?.VoiceState?.Channel;

            if (chn == null)
            {
                throw new OutputException("You need to be in a voice channel.");
            }

            vnc = await vnext.ConnectAsync(chn);

            await ctx.RespondAsync($"Connected to channel {vnc.Channel.Name} successfully.");
        }
Exemple #18
0
        public async Task Join(CommandContext ctx)
        {
            DiscordMessage tmp = await ctx.RespondAsync("JN: GVNC");

            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("JN: GGLD");

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("JN: CVNC");

            if (vnc != null)
            {
                throw new InvalidOperationException("Already connected in this guild.");
            }
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("JN: CCHN");

            DiscordChannel chn = ctx.Member?.VoiceState?.Channel;

            if (chn == null)
            {
                throw new InvalidOperationException("You need to be in a voice channel.");
            }
            await tmp.DeleteAsync();

            tmp = await ctx.RespondAsync("JN: CTXC");

            vnc = await vnext.ConnectAsync(chn);

            await tmp.DeleteAsync();

            await ctx.RespondAsync("👌Connected");
        }
Exemple #19
0
        public async Task Leave(CommandContext ctx, bool clearQueue = false)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc == null)
            {
                throw new OutputException("Not connected in this guild.");
            }

            if (clearQueue)
            {
                GuildQueues[ctx.Guild.Id].Clear();
            }
            GuildMusicStatuses[ctx.Guild.Id].Skip = true;
            Thread.Sleep(500);
            GuildMusicStatuses.Remove(ctx.Guild.Id);
            Directory.Delete(Path.Combine(Globals.AppPath, "Queue", ctx.Guild.Id.ToString()), true);

            vnc.Disconnect();
            await ctx.RespondAsync("Left connected channel.");
        }
        public async Task Leave(CommandContext ctx)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            if (vnext == null)
            {
                await ctx.RespondAsync("VNext is not enabled or configured.");

                return;
            }

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc == null)
            {
                await ctx.RespondAsync("Not connected in this guild.");

                return;
            }

            vnc.Disconnect();
            await ctx.RespondAsync("Disconnected");
        }
        public async Task Join(CommandContext ctx, DiscordChannel chn = null)
        {
            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            if (vnext == null)
            {
                await ctx.RespondAsync("Plugin não está habilitado!");

                return;
            }

            var vnc = vnext.GetConnection(ctx.Guild);

            if (vnc != null)
            {
                await ctx.RespondAsync("Já estou conectado em um canal de voz.");

                return;
            }
            DiscordVoiceState stats = ctx.Member?.VoiceState;

            if (stats?.Channel == null && chn == null)
            {
                await ctx.RespondAsync("Você precisa entrar ou especificar um canal de voz");

                return;
            }
            if (chn == null)
            {
                chn = stats.Channel;
            }

            // connect
            await vnext.ConnectAsync(chn);

            return;
        }
Exemple #22
0
        private static async Task PlaySong(CommandContext ctx)
        {
            if (GuildMusicStatuses[ctx.Guild.Id].Playing)
            {
                return;
            }

            if (GuildQueues[ctx.Guild.Id].Count == 0)
            {
                throw new OutputException("No songs in queue! If you queued a song and this message shows, either it is still being locally queued or it silently failed to be retrieved.");
            }

            GuildMusicStatuses[ctx.Guild.Id].Playing = true;

            while (true)
            {
                VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

                VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

                if (vnc == null || !GuildQueues[ctx.Guild.Id].Any())
                {
                    break;
                }

                if (GuildQueues[ctx.Guild.Id].First().File == null)
                {
                    await ctx.RespondAsync("The next song is queuing, please wait...");

                    while (GuildQueues[ctx.Guild.Id].First().File == null)
                    {
                    }

                    if (GuildQueues[ctx.Guild.Id].First().File == "error")
                    {
                        await ctx.RespondAsync($"Failed to play **{GuildQueues[ctx.Guild.Id].First().Title}** by **{GuildQueues[ctx.Guild.Id].First().Artist}**, " +
                                               $"queued by {GuildQueues[ctx.Guild.Id].First().Queuer.Mention}");

                        GuildQueues[ctx.Guild.Id].RemoveAt(0);
                        await PlaySong(ctx);

                        return;
                    }
                }

                DiscordEmbedBuilder nowplayingBuilder = new DiscordEmbedBuilder
                {
                    Description = $"🎶 Now playing [{GuildQueues[ctx.Guild.Id].First().Title}](https://www.youtube.com/watch?v={GuildQueues[ctx.Guild.Id].First().Id}) 🎶\n\n" +
                                  $"[{GuildQueues[ctx.Guild.Id].First().Queuer.Mention}]{(GuildMusicStatuses[ctx.Guild.Id].Repeat == MusicStatus.RepeatType.None ? "" : " [🔁]")}"
                };

                GuildMusicStatuses[ctx.Guild.Id].Skip = false;

                await ctx.RespondAsync(null, false, nowplayingBuilder.Build());

                string songFile = GuildQueues[ctx.Guild.Id].First().File;

                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    FileName               = "ffmpeg",
                    Arguments              = $@"-i ""{songFile}"" -ac 2 -f s16le -ar 48000 pipe:1",
                    UseShellExecute        = false,
                    RedirectStandardOutput = true
                };

                Process ffmpeg = Process.Start(startInfo);

                Stream ffout = ffmpeg.StandardOutput.BaseStream;

                await vnc.SendSpeakingAsync(); // send a speaking indicator

                byte[] buff = new byte[3840];  // buffer to hold the PCM data
                while (await ffout.ReadAsync(buff, 0, buff.Length) > 0)
                {
                    if (GuildMusicStatuses[ctx.Guild.Id].Skip)
                    {
                        break;
                    }

                    await vnc.SendAsync(buff, 20); // we're sending 20ms of data

                    buff = new byte[3840];
                }

                try
                {
                    ffout.Flush();
                    ffout.Dispose();
                    ffmpeg.Dispose();
                    if (GuildMusicStatuses[ctx.Guild.Id].Repeat == MusicStatus.RepeatType.None)
                    {
                        while (true)
                        {
                            try
                            {
                                File.Delete(songFile);
                                break;
                            }
                            catch
                            {
                                // Wait for processes to release file.
                            }
                        }
                    }
                }
                catch
                {
                    // Consume errors.
                }

                await vnc.SendSpeakingAsync(false);

                switch (GuildMusicStatuses[ctx.Guild.Id].Repeat)
                {
                case MusicStatus.RepeatType.None:
                    GuildQueues[ctx.Guild.Id].RemoveAt(0);
                    break;

                case MusicStatus.RepeatType.All:
                    JigglySong jigglySong = GuildQueues[ctx.Guild.Id][0];
                    GuildQueues[ctx.Guild.Id].Add(jigglySong);
                    GuildQueues[ctx.Guild.Id].RemoveAt(0);
                    break;

                case MusicStatus.RepeatType.One:
                    // The Song is still number one in queue ;D
                    break;

                default:
                    GuildQueues[ctx.Guild.Id].RemoveAt(0);
                    break;
                }

                GuildMusicStatuses[ctx.Guild.Id].Skip = false;
            }

            ctx.Client.GetVoiceNext().GetConnection(ctx.Guild)?.Disconnect();

            Directory.Delete(Path.Combine(Globals.AppPath, "Queue", ctx.Guild.Id.ToString()), true);

            GuildMusicStatuses[ctx.Guild.Id].Playing = false;
        }
        static async Task MainAsync()
        {
            discord = new DiscordClient(new DiscordConfiguration
            {
                Token           = Environment.GetEnvironmentVariable("Bot_Token"),
                TokenType       = TokenType.Bot,
                MinimumLogLevel = Microsoft.Extensions.Logging.LogLevel.Debug
            });
            commands = discord.UseCommandsNext(new CommandsNextConfiguration
            {
                CaseSensitive  = false,
                EnableDms      = false,
                StringPrefixes = new string[] { "#", "$" }
            });
            commands.RegisterCommands <MedicCommands>();
            commands.CommandErrored  += Commands_CommandErrored;
            commands.CommandExecuted += Commands_CommandExecuted;
            interactivity             = discord.UseInteractivity(new InteractivityConfiguration
            {
                Timeout = TimeSpan.FromMinutes(1)
            });
            // EnableIncoming = true increases CPU usage and is not being used until Speech Recognition can be handled easily.
            voice = discord.UseVoiceNext(new VoiceNextConfiguration
            {
                AudioFormat    = new AudioFormat(48000, 2, VoiceApplication.LowLatency),
                EnableIncoming = false
            });

            AudioHelper.Load();
            AudioHelper.CheckForErrors();


            System.Timers.Timer timer = new System.Timers.Timer(900000); // change this to a larger value later: 900000
            timer.Elapsed += Timer_ElapsedAsync;
            timer.Enabled  = true;

            if (!File.Exists("safe-guilds.txt"))
            {
                File.WriteAllText("safe-guilds.txt", "386570547267502080");
            }

            discord.VoiceStateUpdated += async(client, e) =>
            {
                if (voice.GetConnection(e.Guild) != null) //Remove(d) second check so bot can play audio for itself??   (&& e.User != discord.CurrentUser)
                {
                    if (e.Channel == voice.GetConnection(e.Guild).TargetChannel&& !alreadyPlayedForUsers.Contains(e.User.Id))
                    { // If the user who triggered the event is in the same voice channel as the bot; AND the intro hasn't been played for the user yet
                        List <AudioEntry> intros     = AudioHelper.GetUniversalIntros();
                        List <AudioEntry> userIntros = AudioHelper.GetUserIntros(e.After.User.Id);
                        if (userIntros != null || userIntros.Count != 0) // Exception here
                        {
                            intros.AddRange(userIntros);
                        }

                        AudioEntry introEntry = intros.OrderBy(e => new Random().Next()).First();

                        await Task.Delay(1000);

                        await commands.ExecuteCommandAsync(commands.CreateFakeContext(e.User, e.Guild.Channels[505103389537992704], "#play " + introEntry.Name, "#", commands.RegisteredCommands["play"], introEntry.Name));

                        alreadyPlayedForUsers.Add(e.User.Id);
                    }
                    else if (e.Channel == null)
                    { // Someone left
                        alreadyPlayedForUsers.Remove(e.User.Id);
                        if (e.Before.Channel.Users.Count() == 1)
                        {
                            await commands.ExecuteCommandAsync(commands.CreateFakeContext(e.User, e.Guild.Channels[505103389537992704], "#leave", "#", commands.RegisteredCommands["leave"]));
                        }
                    }
                }
                else if (e.User.Id == client.CurrentUser.Id)
                {     // Bot did something
                    if ((e.Before == null || e.Before.Channel == null) && (e.After != null && e.After.Channel != null))
                    { // Bot joined
                        alreadyPlayedForUsers.AddRange(e.After.Channel.Users.Where(u => u.Id != client.CurrentUser.Id).Select(u => u.Id));
                    }
                    else
                    {
                        // Bot left
                    }
                }
            };

            discord.MessageCreated += async(client, e) =>
            {
                if (e.Author.Equals(discord.CurrentUser))
                {
                    return;
                }
                string messageContent = e.Message.Content.ToLower();
                if (e.Author.Id == 477504775907311619 && e.Message.Content == "wrong" && discord.GetVoiceNext().GetConnection(e.Guild) != null)
                {
                    DiscordUser medicUser = await discord.GetUserAsync(134336937224830977);

                    //await commands.SudoAsync(medicUser, e.Channel, "#play wrong");
                    await commands.ExecuteCommandAsync(commands.CreateFakeContext(medicUser, e.Channel, "#play wrong", "#", commands.RegisteredCommands.Where(c => c.Key == "play").FirstOrDefault().Value, "wrong"));
                }
                else if (messageContent.StartsWith("creeper"))
                {
                    await e.Channel.SendMessageAsync("Aww man!");

                    if (discord.GetVoiceNext().GetConnection(e.Guild) != null)
                    {
                        DiscordUser medicUser = await discord.GetUserAsync(134336937224830977);

                        await commands.ExecuteCommandAsync(commands.CreateFakeContext(medicUser, e.Channel, "#play aw man", "#", commands.RegisteredCommands.Where(c => c.Key == "play").FirstOrDefault().Value, "aw man"));
                    }
                }
                else if (messageContent.Contains("iftara") || messageContent.Contains("akşam ezanına"))
                {
                    DateTime iftarTime = GetIftarTime(cityScheduleLinks.Keys.Where(s => messageContent.ToLower().Contains(s)).FirstOrDefault());
                    TimeSpan timeLeft  = iftarTime.Subtract(DateTime.UtcNow.AddHours(3));
                    await e.Channel.SendMessageAsync("Akşam ezanı " + iftarTime.ToString("HH:mm") + " saatinde okunuyor, yani " + (timeLeft.Hours == 0 ? "" : timeLeft.Hours + " saat ") + timeLeft.Minutes + " dakika kaldı.");
                }
                else if (messageContent.Contains("sahura"))
                {
                    DateTime imsakTime = GetImsakTime(cityScheduleLinks.Keys.Where(s => messageContent.ToLower().Contains(s)).FirstOrDefault());
                    TimeSpan timeLeft  = imsakTime.Subtract(DateTime.UtcNow.AddHours(3));
                    await e.Channel.SendMessageAsync("İmsak " + imsakTime.ToString("HH:mm") + " saatinde, yani " + (timeLeft.Hours == 0 ? "" : timeLeft.Hours + " saat ") + timeLeft.Minutes + " dakika kaldı.");
                }
                else if (messageContent.Contains("okundu mu") || messageContent.Contains("kaçta oku"))
                {
                    DateTime iftarTime = GetIftarTime(cityScheduleLinks.Keys.Where(s => messageContent.ToLower().Contains(s)).FirstOrDefault());
                    if (iftarTime.Day == DateTime.Today.Day)
                    {
                        TimeSpan timeLeft = iftarTime.Subtract(DateTime.UtcNow.AddHours(3));
                        await e.Channel.SendMessageAsync("Akşam ezanı " + iftarTime.ToString("HH:mm") + " saatinde okunuyor, yani " + (timeLeft.Hours == 0 ? "" : timeLeft.Hours + " saat ") + timeLeft.Minutes + " dakika kaldı.");
                    }
                    else
                    {
                        DateTime imsakTime = GetImsakTime(cityScheduleLinks.Keys.Where(s => messageContent.ToLower().Contains(s)).FirstOrDefault());
                        TimeSpan timeLeft  = imsakTime.Subtract(DateTime.UtcNow.AddHours(3));
                        await e.Channel.SendMessageAsync("Okundu! Sahura " + (timeLeft.Hours == 0 ? "" : timeLeft.Hours + " saat ") + timeLeft.Minutes + " dakika kaldı.");
                    }
                }
                else if (e.Message.Content.ToUpper().StartsWith("HOFFMAN"))
                {
                    await e.Channel.SendMessageAsync("Yeah?");

                    var userReply = await interactivity.WaitForMessageAsync(m => m.Author.Id == e.Author.Id && m.Content.Contains(" call this"), TimeSpan.FromSeconds(5));

                    await e.Channel.SendMessageAsync("Uh, uhh...");

                    // TODO: Think of functionality for this HOFFMAN
                }
            };

            HttpListener listener = new HttpListener();

            if (!Debugger.IsAttached)
            {   // In production
                listener.Prefixes.Add("http://*:3131/medicbotapi/");
            }
            else
            {   // Debugging
                listener.Prefixes.Add("http://127.0.0.1:3131/medicbotapi/");
            }
            listener.Start();
            _ = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);

            await discord.ConnectAsync();

            await Task.Delay(-1);
        }
        public async Task Play(CommandContext ctx, [RemainingText, Description("Full path to the file to play.")] string path)
        {
            string filename = Path.Combine(Directory.GetCurrentDirectory(), "Audios", path);

            VoiceNextExtension vnext = ctx.Client.GetVoiceNext();

            if (vnext == null)
            {
                await ctx.RespondAsync("VNext is not enabled or configured.");

                return;
            }

            VoiceNextConnection vnc = vnext.GetConnection(ctx.Guild);

            if (vnc == null)
            {
                await ctx.RespondAsync("Not connected in this guild.");

                return;
            }

            if (!File.Exists(filename))
            {
                await ctx.RespondAsync($"File `{path}` does not exist.");

                return;
            }

            while (vnc.IsPlaying)
            {
                await vnc.WaitForPlaybackFinishAsync();
            }

            Exception exc = null;
            await ctx.Message.RespondAsync($"Playing `{path}`");

            try
            {
                await vnc.SendSpeakingAsync();

                Stream ffout = new FfmpegUtils().GetffmpegStream(filename);

                VoiceTransmitSink txStream = vnc.GetTransmitSink();
                await ffout.CopyToAsync(txStream);

                await txStream.FlushAsync();

                await vnc.WaitForPlaybackFinishAsync();
            }
            catch (Exception ex)
            {
                exc = ex;
            }
            finally
            {
                await vnc.SendSpeakingAsync(false);

                await ctx.Message.RespondAsync($"Finished playing `{path}`");
            }

            if (exc != null)
            {
                await ctx.RespondAsync($"An exception occured during playback: `{exc.GetType()}: {exc.Message}`");
            }
        }