Replacements. Converted music, not tested.
This commit is contained in:
		@@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Restart(IMessage imsg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    await channel.SendMessageAsync("`Restarting in 2 seconds...`");
 | 
			
		||||
        //    await Task.Delay(2000);
 | 
			
		||||
@@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequirePermission(GuildPermission.ManageGuild)]
 | 
			
		||||
        //public async Task Delmsgoncmd(IMessage imsg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    var conf = SpecificConfigurations.Default.Of(channel.Guild.Id);
 | 
			
		||||
        //    conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
 | 
			
		||||
@@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task Setrole(IMessage imsg, IGuildUser usr, [Remainder] IRole role)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await usr.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
@@ -76,7 +76,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task Removerole(IMessage imsg, IGuildUser usr, [Remainder] IRole role)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await usr.RemoveRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
@@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task RenameRole(IMessage imsg, IRole roleToEdit, string newname)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (roleToEdit.Position > (await channel.Guild.GetCurrentUserAsync().ConfigureAwait(false)).Roles.Max(r => r.Position))
 | 
			
		||||
@@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task RemoveAllRoles(IMessage imsg, [Remainder] IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task CreateRole(IMessage imsg, [Remainder] string roleName = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(roleName))
 | 
			
		||||
@@ -154,7 +154,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
        public async Task RoleColor(IMessage imsg, params string[] args)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (args.Count() != 2 && args.Count() != 4)
 | 
			
		||||
            {
 | 
			
		||||
@@ -192,7 +192,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.BanMembers)]
 | 
			
		||||
        public async Task Ban(IMessage imsg, IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var msg = "";
 | 
			
		||||
 | 
			
		||||
@@ -219,7 +219,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.BanMembers)]
 | 
			
		||||
        public async Task Softban(IMessage imsg, IGuildUser user, [Remainder] string msg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
            {
 | 
			
		||||
@@ -244,7 +244,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Kick(IMessage imsg, IGuildUser user, [Remainder] string msg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (user == null)
 | 
			
		||||
            {
 | 
			
		||||
@@ -273,7 +273,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.MuteMembers)]
 | 
			
		||||
        public async Task Mute(IMessage imsg, params IGuildUser[] users)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
@@ -296,7 +296,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.MuteMembers)]
 | 
			
		||||
        public async Task Unmute(IMessage imsg, params IGuildUser[] users)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
@@ -319,7 +319,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.DeafenMembers)]
 | 
			
		||||
        public async Task Deafen(IMessage imsg, params IGuildUser[] users)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
@@ -342,7 +342,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.DeafenMembers)]
 | 
			
		||||
        public async Task UnDeafen(IMessage imsg, params IGuildUser[] users)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
@@ -374,7 +374,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageChannels)]
 | 
			
		||||
        public async Task CreatVoiChanl(IMessage imsg, [Remainder] string channelName)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            //todo actually print info about created channel
 | 
			
		||||
            await channel.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false);
 | 
			
		||||
            await channel.SendMessageAsync($"Created voice channel **{channelName}**.").ConfigureAwait(false);
 | 
			
		||||
@@ -394,7 +394,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageChannels)]
 | 
			
		||||
        public async Task CreaTxtChanl(IMessage imsg, [Remainder] string channelName)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            //todo actually print info about created channel
 | 
			
		||||
            var txtCh = await channel.Guild.CreateTextChannelAsync(channelName).ConfigureAwait(false);
 | 
			
		||||
            await channel.SendMessageAsync($"Added text channel **{channelName}**.").ConfigureAwait(false);
 | 
			
		||||
@@ -405,7 +405,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageChannels)]
 | 
			
		||||
        public async Task SetTopic(IMessage imsg, [Remainder] string topic = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            topic = topic ?? "";
 | 
			
		||||
            await (channel as ITextChannel).ModifyAsync(c => c.Topic = topic);
 | 
			
		||||
            //await (channel).ModifyAsync(c => c).ConfigureAwait(false);
 | 
			
		||||
@@ -417,7 +417,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.ManageChannels)]
 | 
			
		||||
        public async Task SetChanlName(IMessage imsg, [Remainder] string name)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.ModifyAsync(c => c.Name = name).ConfigureAwait(false);
 | 
			
		||||
            await channel.SendMessageAsync(":ok: **New channel name set.**").ConfigureAwait(false);
 | 
			
		||||
@@ -429,7 +429,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Prune(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var user = await channel.Guild.GetCurrentUserAsync();
 | 
			
		||||
            
 | 
			
		||||
@@ -471,7 +471,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Die(IMessage imsg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    await channel.SendMessageAsync("`Shutting down.`").ConfigureAwait(false);
 | 
			
		||||
        //    await Task.Delay(2000).ConfigureAwait(false);
 | 
			
		||||
@@ -483,7 +483,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Setname(IMessage imsg, [Remainder] string newName = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
@@ -492,7 +492,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task NewAvatar(IMessage imsg, [Remainder] string img = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    if (string.IsNullOrWhiteSpace(img))
 | 
			
		||||
        //        return;
 | 
			
		||||
@@ -511,7 +511,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task SetGame(IMessage imsg, [Remainder] string game = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    game = game ?? "";
 | 
			
		||||
 | 
			
		||||
@@ -523,7 +523,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Send(IMessage imsg, string where, [Remainder] string msg = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    if (string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
        //        return;
 | 
			
		||||
@@ -569,7 +569,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Donadd(IMessage imsg, IUser donator, int amount)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    var donator = channel.Guild.FindUsers(donator).FirstOrDefault();
 | 
			
		||||
        //    var amount = int.Parse(amount);
 | 
			
		||||
        //    if (donator == null) return;
 | 
			
		||||
@@ -592,7 +592,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Announce(IMessage imsg, [Remainder] string message)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    foreach (var ch in (await _client.GetGuildsAsync().ConfigureAwait(false)).Select(async g => await g.GetDefaultChannelAsync().ConfigureAwait(false)))
 | 
			
		||||
        //    {
 | 
			
		||||
@@ -607,7 +607,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task SaveChat(IMessage imsg, int cnt)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    ulong? lastmsgId = null;
 | 
			
		||||
        //    var sb = new StringBuilder();
 | 
			
		||||
@@ -640,7 +640,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [RequirePermission(GuildPermission.MentionEveryone)]
 | 
			
		||||
        public async Task MentionRole(IMessage imsg, params IRole[] roles)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            string send = $"--{imsg.Author.Mention} has invoked a mention on the following roles--";
 | 
			
		||||
            foreach (var role in roles)
 | 
			
		||||
@@ -665,7 +665,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Donators(IMessage imsg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    var rows = DbHandler.Instance.GetAllRows<Donator>();
 | 
			
		||||
        //    var donatorsOrdered = rows.OrderByDescending(d => d.Amount);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            //[RequirePermission(GuildPermission.ManageRoles)]
 | 
			
		||||
            //public async Task AutoAssignRole(IMessage imsg, IRole role)
 | 
			
		||||
            //{
 | 
			
		||||
            //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            //    var config = SpecificConfigurations.Default.Of(e.Server.Id);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
               _client.MessageReceived += async (imsg) =>
 | 
			
		||||
                {
 | 
			
		||||
                    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                    if (channel == null || await imsg.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Slowmode(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                ConcurrentDictionary<ulong, DateTime> throwaway;
 | 
			
		||||
                if (RatelimitingChannels.TryRemove(channel.Id, out throwaway))
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
//            [RequireContext(ContextType.Guild)]
 | 
			
		||||
//            public async Task Leave(IMessage imsg, [Remainder] string guildStr)
 | 
			
		||||
//            {
 | 
			
		||||
//                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
//                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
//                guildStr = guildStr.ToUpperInvariant();
 | 
			
		||||
//                var server = _client.GetGuilds().FirstOrDefault(g => g.Id.ToString() == guildStr) ?? _client.GetGuilds().FirstOrDefault(g => g.Name.ToUpperInvariant() == guildStr);
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task CreateWar(IMessage imsg, int size, [Remainder] string enemyClan = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!(imsg.Author as IGuildUser).GuildPermissions.ManageChannels)
 | 
			
		||||
                return;
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task StartWar(IMessage imsg, [Remainder] string number = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            int num = 0;
 | 
			
		||||
            int.TryParse(number, out num);
 | 
			
		||||
@@ -100,7 +100,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ListWar(IMessage imsg, [Remainder] string number = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            // if number is null, print all wars in a short way
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(number))
 | 
			
		||||
@@ -143,7 +143,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Claim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var warsInfo = GetWarInfo(imsg, number);
 | 
			
		||||
            if (warsInfo == null || warsInfo.Item1.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -170,7 +170,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ClaimFinish1(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            await FinishClaim(imsg, number, baseNumber, other_name, 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -178,7 +178,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ClaimFinish2(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            await FinishClaim(imsg, number, baseNumber, other_name, 2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -186,7 +186,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ClaimFinish(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            await FinishClaim(imsg, number, baseNumber, other_name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -194,7 +194,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task EndWar(IMessage imsg, int number)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var warsInfo = GetWarInfo(imsg,number);
 | 
			
		||||
            if (warsInfo == null)
 | 
			
		||||
@@ -213,7 +213,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Unclaim(IMessage imsg, int number, [Remainder] string otherName = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var warsInfo = GetWarInfo(imsg, number);
 | 
			
		||||
            if (warsInfo == null || warsInfo.Item1.Count == 0)
 | 
			
		||||
@@ -239,7 +239,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
 | 
			
		||||
        private async Task FinishClaim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name, int stars = 3)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var warInfo = GetWarInfo(imsg, number);
 | 
			
		||||
            if (warInfo == null || warInfo.Item1.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -265,7 +265,7 @@ namespace NadekoBot.Modules.ClashOfClans
 | 
			
		||||
 | 
			
		||||
        private static Tuple<List<ClashWar>, int> GetWarInfo(IMessage imsg, int num)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            //check if there are any wars
 | 
			
		||||
            List<ClashWar> wars = null;
 | 
			
		||||
            ClashWars.TryGetValue(channel.Guild.Id, out wars);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Race(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                var ar = new AnimalRace(channel.Guild.Id, channel);
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task JoinRace(IMessage imsg, int amount = 0)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                if (amount < 0)
 | 
			
		||||
                    amount = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //    InternalRoll(imsg, arg, false);
 | 
			
		||||
 | 
			
		||||
        //private async Task InternalRoll(IMessage imsg, string arg, bool ordered) {
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    var r = new Random();
 | 
			
		||||
        //    if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
        //    {
 | 
			
		||||
@@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task NRoll(IMessage imsg, [Remainder] string range)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Raffle(IMessage imsg, [Remainder] IRole role = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            role = role ?? channel.Guild.EveryoneRole;
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Cash(IMessage imsg, [Remainder] string arg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    var usr = e.Message.MentionedUsers.FirstOrDefault() ?? imsg.Author;
 | 
			
		||||
        //    var pts = GetUserFlowers(usr.Id);
 | 
			
		||||
@@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Give(IMessage imsg, long amount, [Remainder] IUser receiver)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    if (amount <= 0)
 | 
			
		||||
        //        return;
 | 
			
		||||
        //    var userFlowers = GetUserFlowers(imsg.Author.Id);
 | 
			
		||||
@@ -81,7 +81,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Award(IMessage imsg, long amount, [Remainder] ulong usrId)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    if (amount <= 0)
 | 
			
		||||
        //        return;
 | 
			
		||||
@@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Take(IMessage imsg, long amount, [Remainder] ulong usrId)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    if (amount <= 0)
 | 
			
		||||
        //        return;
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task BetRoll(IMessage imsg, int amount)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    if (amount < 1)
 | 
			
		||||
        //        return;
 | 
			
		||||
@@ -160,7 +160,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
//        [RequireContext(ContextType.Guild)]
 | 
			
		||||
//        public async Task Leaderboard(IMessage imsg)
 | 
			
		||||
//        {
 | 
			
		||||
//            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
//            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
//            var richestTemp = DbHandler.Instance.GetTopRichest();
 | 
			
		||||
//            var richest = richestTemp as CurrencyState[] ?? richestTemp.ToArray();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Leet(IMessage imsg, int level, [Remainder] string text = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            text = text.Trim();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(text))
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Poll(IMessage imsg, [Remainder] string arg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!(imsg.Author as IGuildUser).GuildPermissions.ManageChannels)
 | 
			
		||||
                return;
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Pollend(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!(imsg.Author as IGuildUser).GuildPermissions.ManageChannels)
 | 
			
		||||
                return;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Trivia(IMessage imsg, string[] args)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                TriviaGame trivia;
 | 
			
		||||
                if (!RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
 | 
			
		||||
@@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Tl(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                TriviaGame trivia;
 | 
			
		||||
                if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
 | 
			
		||||
@@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Tq(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                TriviaGame trivia;
 | 
			
		||||
                if (RunningTrivias.TryRemove(channel.Guild.Id, out trivia))
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Choose(IMessage imsg, [Remainder] string list = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(list))
 | 
			
		||||
                return;
 | 
			
		||||
            var listArr = list.Split(';');
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task _8Ball(IMessage imsg, [Remainder] string question = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(question))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Rps(IMessage imsg, string input)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            Func<int,string> GetRPSPick = (p) =>
 | 
			
		||||
            {
 | 
			
		||||
@@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Linux(IMessage imsg, string guhnoo, string loonix)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync(
 | 
			
		||||
$@"I'd just like to interject for moment. What you're refering to as {loonix}, is in fact, {guhnoo}/{loonix}, or as I've recently taken to calling it, {guhnoo} plus {loonix}. {loonix} is not an operating system unto itself, but rather another free component of a fully functioning {guhnoo} system made useful by the {guhnoo} corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Modules(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync("`List of modules:` \n• " + string.Join("\n• ", _commands.Modules.Select(m => m.Name)) + $"\n`Type \"-commands module_name\" to get a list of commands in that module.`")
 | 
			
		||||
                                       .ConfigureAwait(false);
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Commands(IMessage imsg, [Remainder] string module = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            module = module?.Trim().ToUpperInvariant();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(module))
 | 
			
		||||
@@ -69,7 +69,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task H(IMessage imsg, [Remainder] string comToFind = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            comToFind = comToFind?.ToLowerInvariant();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(comToFind))
 | 
			
		||||
@@ -117,7 +117,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Guide(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync(
 | 
			
		||||
@"**LIST OF COMMANDS**: <http://nadekobot.readthedocs.io/en/latest/Commands%20List/>
 | 
			
		||||
@@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Donate(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync(
 | 
			
		||||
$@"You can support the project on patreon. <https://patreon.com/nadekobot> or
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        public event EventHandler<Song> OnCompleted = delegate { };
 | 
			
		||||
        public event EventHandler<Song> OnStarted = delegate { };
 | 
			
		||||
 | 
			
		||||
        public Channel PlaybackVoiceChannel { get; private set; }
 | 
			
		||||
        public IVoiceChannel PlaybackVoiceChannel { get; private set; }
 | 
			
		||||
 | 
			
		||||
        private bool Destroyed { get; set; } = false;
 | 
			
		||||
        public bool RepeatSong { get; private set; } = false;
 | 
			
		||||
@@ -54,12 +54,10 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        private ConcurrentQueue<Action> actionQueue { get; set; } = new ConcurrentQueue<Action>();
 | 
			
		||||
 | 
			
		||||
        public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
 | 
			
		||||
        public MusicPlayer(IVoiceChannel startingVoiceChannel, float? defaultVolume)
 | 
			
		||||
        {
 | 
			
		||||
            if (startingVoiceChannel == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(startingVoiceChannel));
 | 
			
		||||
            if (startingVoiceChannel.Type != ChannelType.Voice)
 | 
			
		||||
                throw new ArgumentException("Channel must be of type voice");
 | 
			
		||||
            Volume = defaultVolume ?? 1.0f;
 | 
			
		||||
 | 
			
		||||
            PlaybackVoiceChannel = startingVoiceChannel;
 | 
			
		||||
@@ -101,9 +99,9 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            if (audioClient?.State != ConnectionState.Connected)
 | 
			
		||||
                            if (audioClient?.ConnectionState != ConnectionState.Connected)
 | 
			
		||||
                            {
 | 
			
		||||
                                audioClient = await PlaybackVoiceChannel.JoinAudio();
 | 
			
		||||
                                audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false);
 | 
			
		||||
                                continue;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
@@ -246,7 +244,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void Destroy()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            actionQueue.Enqueue(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                RepeatPlaylist = false;
 | 
			
		||||
                RepeatSong = false;
 | 
			
		||||
@@ -254,16 +252,16 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                playlist.Clear();
 | 
			
		||||
                if (!SongCancelSource.IsCancellationRequested)
 | 
			
		||||
                    SongCancelSource.Cancel();
 | 
			
		||||
                audioClient.Disconnect();
 | 
			
		||||
                await audioClient.DisconnectAsync();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal Task MoveToVoiceChannel(Channel voiceChannel)
 | 
			
		||||
        internal Task MoveToVoiceChannel(IVoiceChannel voiceChannel)
 | 
			
		||||
        {
 | 
			
		||||
            if (audioClient?.State != ConnectionState.Connected)
 | 
			
		||||
            if (audioClient?.ConnectionState != ConnectionState.Connected)
 | 
			
		||||
                throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
 | 
			
		||||
            PlaybackVoiceChannel = voiceChannel;
 | 
			
		||||
            return PlaybackVoiceChannel.JoinAudio();
 | 
			
		||||
            return PlaybackVoiceChannel.ConnectAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong;
 | 
			
		||||
@@ -6,6 +6,7 @@ using System.Diagnostics;
 | 
			
		||||
using System.Diagnostics.Contracts;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@@ -104,6 +105,9 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                sw.Stop();
 | 
			
		||||
                Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                var outStream = voiceClient.CreatePCMStream(3840);
 | 
			
		||||
                
 | 
			
		||||
                const int blockSize = 3840;
 | 
			
		||||
                byte[] buffer = new byte[blockSize];
 | 
			
		||||
                while (!cancelToken.IsCancellationRequested)
 | 
			
		||||
@@ -130,7 +134,6 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                                break;
 | 
			
		||||
                            if (attempt++ == 20)
 | 
			
		||||
                            {
 | 
			
		||||
                                voiceClient.Wait();
 | 
			
		||||
                                MusicPlayer.SongCancelSource.Cancel();
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
@@ -147,13 +150,12 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                        await Task.Delay(200, cancelToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    buffer = AdjustVolume(buffer, MusicPlayer.Volume);
 | 
			
		||||
                    voiceClient.Send(buffer, 0, read);
 | 
			
		||||
                    await outStream.WriteAsync(buffer, 0, read);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                await bufferTask;
 | 
			
		||||
                await Task.Run(() => voiceClient.Clear());
 | 
			
		||||
                if(inStream != null)
 | 
			
		||||
                    inStream.Dispose();
 | 
			
		||||
                Console.WriteLine("l");
 | 
			
		||||
@@ -285,10 +287,10 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var link = await SearchHelper.FindYoutubeUrlByKeywords(query).ConfigureAwait(false);
 | 
			
		||||
                var link = (await NadekoBot.Google.GetVideosByKeywordsAsync(query).ConfigureAwait(false)).FirstOrDefault();
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                    throw new OperationCanceledException("Not a valid youtube query.");
 | 
			
		||||
                var allVideos = await Task.Factory.StartNew(async () => await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false)).Unwrap().ConfigureAwait(false);
 | 
			
		||||
                var allVideos = await Task.Run(async () => await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio);
 | 
			
		||||
                var video = videos
 | 
			
		||||
                    .Where(v => v.AudioBitrate < 192)
 | 
			
		||||
@@ -324,7 +326,10 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
            string file = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                file = await http.GetStringAsync(query).ConfigureAwait(false);
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    file = await http.GetStringAsync(query).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
@@ -18,10 +19,17 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(url))
 | 
			
		||||
                throw new ArgumentNullException(nameof(url));
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientID))
 | 
			
		||||
                throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientID));
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
 | 
			
		||||
                throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
 | 
			
		||||
 | 
			
		||||
            var response = await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.Credentials.SoundCloudClientID}").ConfigureAwait(false);
 | 
			
		||||
            string response = "";
 | 
			
		||||
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                response = await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.Credentials.SoundCloudClientId}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
            var responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<SoundCloudVideo>(response);
 | 
			
		||||
            if (responseObj?.Kind != "track")
 | 
			
		||||
@@ -37,10 +45,14 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                throw new ArgumentNullException(nameof(query));
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientID))
 | 
			
		||||
                throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientID));
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
 | 
			
		||||
                throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
 | 
			
		||||
 | 
			
		||||
            var response = await http.GetStringAsync($"http://api.soundcloud.com/tracks?q={Uri.EscapeDataString(query)}&client_id={NadekoBot.Credentials.SoundCloudClientID}").ConfigureAwait(false);
 | 
			
		||||
            var response = "";
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                await http.GetStringAsync($"http://api.soundcloud.com/tracks?q={Uri.EscapeDataString(query)}&client_id={NadekoBot.Credentials.SoundCloudClientId}").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var responseObj = JsonConvert.DeserializeObject<SoundCloudVideo[]>(response).Where(s => s.Streamable).FirstOrDefault();
 | 
			
		||||
            if (responseObj?.Kind != "track")
 | 
			
		||||
@@ -62,7 +74,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        [JsonProperty("permalink_url")]
 | 
			
		||||
        public string TrackLink { get; set; } = "";
 | 
			
		||||
        [JsonIgnore]
 | 
			
		||||
        public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Credentials.SoundCloudClientID}";
 | 
			
		||||
        public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Credentials.SoundCloudClientId}";
 | 
			
		||||
    }
 | 
			
		||||
    public class SoundCloudUser
 | 
			
		||||
    {
 | 
			
		||||
							
								
								
									
										724
									
								
								src/NadekoBot/Modules/Music/MusicModule.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										724
									
								
								src/NadekoBot/Modules/Music/MusicModule.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,724 @@
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Modules.Music.Classes;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Discord;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using NadekoBot.Attributes;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Music
 | 
			
		||||
{
 | 
			
		||||
    [Module("!!", AppendSpace = false)]
 | 
			
		||||
    public partial class MusicModule : DiscordModule
 | 
			
		||||
    {
 | 
			
		||||
        public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers = new ConcurrentDictionary<ulong, MusicPlayer>();
 | 
			
		||||
 | 
			
		||||
        public const string MusicDataPath = "data/musicdata";
 | 
			
		||||
        private IGoogleApiService _google;
 | 
			
		||||
 | 
			
		||||
        public MusicModule(ILocalization loc, CommandService cmds, IBotConfiguration config, DiscordSocketClient client, IGoogleApiService google) : base(loc, cmds, config, client)
 | 
			
		||||
        {
 | 
			
		||||
            //it can fail if its currenctly opened or doesn't exist. Either way i don't care
 | 
			
		||||
            try { Directory.Delete(MusicDataPath, true); } catch { }
 | 
			
		||||
 | 
			
		||||
            Directory.CreateDirectory(MusicDataPath);
 | 
			
		||||
 | 
			
		||||
            _google = google;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Next(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return;
 | 
			
		||||
            if (musicPlayer.PlaybackVoiceChannel == ((IGuildUser)imsg.Author).VoiceChannel)
 | 
			
		||||
                musicPlayer.Next();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Stop(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
            {
 | 
			
		||||
                musicPlayer.Autoplay = false;
 | 
			
		||||
                musicPlayer.Stop();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Destroy(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryRemove(channel.Guild.Id, out musicPlayer)) return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                musicPlayer.Destroy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Pause(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            musicPlayer.TogglePause();
 | 
			
		||||
            if (musicPlayer.Paused)
 | 
			
		||||
                await channel.SendMessageAsync("🎵`Music Player paused.`").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync("🎵`Music Player unpaused.`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Queue(IMessage imsg, [Remainder] string query)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, query).ConfigureAwait(false);
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await imsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SoundCloudQueue(IMessage imsg, [Remainder] string query)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, query, musicType: MusicType.Soundcloud).ConfigureAwait(false);
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await imsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ListQueue(IMessage imsg, int page = 1)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("🎵 No active music player.").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (page <= 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
            if (currentSong == null)
 | 
			
		||||
                return;
 | 
			
		||||
            var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n";
 | 
			
		||||
            if (musicPlayer.RepeatSong)
 | 
			
		||||
                toSend += "🔂";
 | 
			
		||||
            else if (musicPlayer.RepeatPlaylist)
 | 
			
		||||
                toSend += "🔁";
 | 
			
		||||
            toSend += $" **{musicPlayer.Playlist.Count}** `tracks currently queued. Showing page {page}` ";
 | 
			
		||||
            if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
 | 
			
		||||
                toSend += "**Song queue is full!**\n";
 | 
			
		||||
            else
 | 
			
		||||
                toSend += "\n";
 | 
			
		||||
            const int itemsPerPage = 15;
 | 
			
		||||
            int startAt = itemsPerPage * (page - 1);
 | 
			
		||||
            var number = 1 + startAt;
 | 
			
		||||
            await channel.SendMessageAsync(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task NowPlaying(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
            if (currentSong == null)
 | 
			
		||||
                return;
 | 
			
		||||
            await channel.SendMessageAsync($"🎵`Now Playing` {currentSong.PrettyName} " +
 | 
			
		||||
                                        $"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Volume(IMessage imsg, int val)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            if (val < 0)
 | 
			
		||||
                return;
 | 
			
		||||
            var volume = musicPlayer.SetVolume(val);
 | 
			
		||||
            await channel.SendMessageAsync($"🎵 `Volume set to {volume}%`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
        ////todo DB
 | 
			
		||||
        //[LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Defvol(IMessage imsg, [Remainder] int val)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    var arg = val;
 | 
			
		||||
        //    float volume;
 | 
			
		||||
        //    if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100)
 | 
			
		||||
        //    {
 | 
			
		||||
        //        await channel.SendMessageAsync("Volume number invalid.").ConfigureAwait(false);
 | 
			
		||||
        //        return;
 | 
			
		||||
        //    }
 | 
			
		||||
        //    var conf = SpecificConfigurations.Default.Of(channel.Guild.Id);
 | 
			
		||||
        //    conf.DefaultMusicVolume = volume / 100;
 | 
			
		||||
        //    await channel.SendMessageAsync($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Mute(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            musicPlayer.SetVolume(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Max(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            musicPlayer.SetVolume(100);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Shuffle(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            if (musicPlayer.Playlist.Count < 2)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            musicPlayer.Shuffle();
 | 
			
		||||
            await channel.SendMessageAsync("🎵 `Songs shuffled.`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Playlist(IMessage imsg, [Remainder] string playlist)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var arg = playlist;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel?.Guild != channel.Guild)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var plId = (await _google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
 | 
			
		||||
            if (plId == null)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("No search results for that query.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var ids = await _google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false);
 | 
			
		||||
            if (!ids.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync($"🎵 `Failed to find any songs.`").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var idArray = ids as string[] ?? ids.ToArray();
 | 
			
		||||
            var count = idArray.Length;
 | 
			
		||||
            var msg =
 | 
			
		||||
                await channel.SendMessageAsync($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`").ConfigureAwait(false);
 | 
			
		||||
            foreach (var id in idArray)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, id, true).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (PlaylistFullException)
 | 
			
		||||
                { break; }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
            await msg.ModifyAsync(m => m.Content = "🎵 `Playlist queue complete.`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SoundCloudPl(IMessage imsg, [Remainder] string pl)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            pl = pl?.Trim();
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(pl))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                var scvids = JObject.Parse(await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Credentials.SoundCloudClientId}").ConfigureAwait(false))["tracks"].ToObject<SoundCloudVideo[]>();
 | 
			
		||||
                await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                MusicPlayer mp;
 | 
			
		||||
                if (!MusicPlayers.TryGetValue(channel.Guild.Id, out mp))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                foreach (var svideo in scvids.Skip(1))
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        mp.AddSong(new Song(new Classes.SongInfo
 | 
			
		||||
                        {
 | 
			
		||||
                            Title = svideo.FullName,
 | 
			
		||||
                            Provider = "SoundCloud",
 | 
			
		||||
                            Uri = svideo.StreamLink,
 | 
			
		||||
                            ProviderType = MusicType.Normal,
 | 
			
		||||
                            Query = svideo.TrackLink,
 | 
			
		||||
                        }), ((IGuildUser)imsg.Author).Username);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (PlaylistFullException) { break; }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task LocalPl(IMessage imsg, [Remainder] string directory)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var arg = directory;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var fileEnum = new DirectoryInfo(arg).GetFiles()
 | 
			
		||||
                                    .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
 | 
			
		||||
                foreach (var file in fileEnum)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (PlaylistFullException)
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                }
 | 
			
		||||
                await channel.SendMessageAsync("🎵 `Directory queue complete.`").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Radio(IMessage imsg, string radio_link)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel?.Guild != channel.Guild)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false);
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await imsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Local(IMessage imsg, [Remainder] string path)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var arg = path;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                return;
 | 
			
		||||
            await QueueSong(((IGuildUser)imsg.Author), channel, ((IGuildUser)imsg.Author).VoiceChannel, path, musicType: MusicType.Local).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Move(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            var voiceChannel = ((IGuildUser)imsg.Author).VoiceChannel;
 | 
			
		||||
            if (voiceChannel == null || voiceChannel.Guild != channel.Guild || !MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            musicPlayer.MoveToVoiceChannel(voiceChannel);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Remove(IMessage imsg, int num)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
            if (num <= 0 || num > musicPlayer.Playlist.Count)
 | 
			
		||||
                return;
 | 
			
		||||
            var song = (musicPlayer.Playlist as List<Song>)?[num - 1];
 | 
			
		||||
            musicPlayer.RemoveSongAt(num - 1);
 | 
			
		||||
            await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
        //todo fix
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Remove(IMessage imsg, string all)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (all.Trim().ToUpperInvariant() != "ALL")
 | 
			
		||||
                return;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return;
 | 
			
		||||
            musicPlayer.ClearQueue();
 | 
			
		||||
            await channel.SendMessageAsync($"🎵`Queue cleared!`").ConfigureAwait(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task MoveSong(IMessage imsg, [Remainder] string fromto)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            fromto = fromto?.Trim();
 | 
			
		||||
            var fromtoArr = fromto.Split('>');
 | 
			
		||||
 | 
			
		||||
            int n1;
 | 
			
		||||
            int n2;
 | 
			
		||||
 | 
			
		||||
            var playlist = musicPlayer.Playlist as List<Song> ?? musicPlayer.Playlist.ToList();
 | 
			
		||||
 | 
			
		||||
            if (fromtoArr.Length != 2 || !int.TryParse(fromtoArr[0], out n1) ||
 | 
			
		||||
                !int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
 | 
			
		||||
                n1 > playlist.Count || n2 > playlist.Count)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("`Invalid input.`").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var s = playlist[n1 - 1];
 | 
			
		||||
            playlist.Insert(n2 - 1, s);
 | 
			
		||||
            var nn1 = n2 < n1 ? n1 : n1 - 1;
 | 
			
		||||
            playlist.RemoveAt(nn1);
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync($"🎵`Moved` {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SetMaxQueue(IMessage imsg, uint size)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            musicPlayer.MaxQueueSize = size;
 | 
			
		||||
            await channel.SendMessageAsync($"🎵 `Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}`");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ReptCurSong(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
            if (currentSong == null)
 | 
			
		||||
                return;
 | 
			
		||||
            var currentValue = musicPlayer.ToggleRepeatSong();
 | 
			
		||||
            await channel.SendMessageAsync(currentValue ?
 | 
			
		||||
                                        $"🎵🔂`Repeating track:`{currentSong.PrettyName}" :
 | 
			
		||||
                                        $"🎵🔂`Current track repeat stopped.`")
 | 
			
		||||
                                            .ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task RepeatPl(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            var currentValue = musicPlayer.ToggleRepeatPlaylist();
 | 
			
		||||
            await channel.SendMessageAsync($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ///
 | 
			
		||||
        //[LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Save(IMessage imsg, [Remainder] string name)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //[LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Load(IMessage imsg, [Remainder] string name)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //[LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Playlists(IMessage imsg, [Remainder] string num)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //[LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task DeletePlaylist(IMessage imsg, [Remainder] string pl)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Goto(IMessage imsg, int time)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            if (((IGuildUser)imsg.Author).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (time < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
 | 
			
		||||
            if (currentSong == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            //currentSong.PrintStatusMessage = false;
 | 
			
		||||
            var gotoSong = currentSong.Clone();
 | 
			
		||||
            gotoSong.SkipTo = time;
 | 
			
		||||
            musicPlayer.AddSong(gotoSong, 0);
 | 
			
		||||
            musicPlayer.Next();
 | 
			
		||||
 | 
			
		||||
            var minutes = (time / 60).ToString();
 | 
			
		||||
            var seconds = (time % 60).ToString();
 | 
			
		||||
 | 
			
		||||
            if (minutes.Length == 1)
 | 
			
		||||
                minutes = "0" + minutes;
 | 
			
		||||
            if (seconds.Length == 1)
 | 
			
		||||
                seconds = "0" + seconds;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task GetLink(IMessage imsg, int index = 0)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (index < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (index > 0)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                var selSong = musicPlayer.Playlist.DefaultIfEmpty(null).ElementAtOrDefault(index - 1);
 | 
			
		||||
                if (selSong == null)
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync("Could not select song, likely wrong index");
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync($"🎶`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var curSong = musicPlayer.CurrentSong;
 | 
			
		||||
                if (curSong == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                await channel.SendMessageAsync($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Autoplay(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (!musicPlayer.ToggleAutoplay())
 | 
			
		||||
                await channel.SendMessageAsync("🎶`Autoplay disabled.`").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync("🎶`Autoplay enabled.`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
 | 
			
		||||
        {
 | 
			
		||||
            if (voiceCh == null || voiceCh.Guild != textCh.Guild)
 | 
			
		||||
            {
 | 
			
		||||
                if (!silent)
 | 
			
		||||
                    await textCh.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.").ConfigureAwait(false);
 | 
			
		||||
                throw new ArgumentNullException(nameof(voiceCh));
 | 
			
		||||
            }
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
 | 
			
		||||
                throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
 | 
			
		||||
 | 
			
		||||
            var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server =>
 | 
			
		||||
            {
 | 
			
		||||
                //todo DB
 | 
			
		||||
                float vol = 100;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
 | 
			
		||||
                var mp = new MusicPlayer(voiceCh, vol);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                IMessage playingMessage = null;
 | 
			
		||||
                IMessage lastFinishedMessage = null;
 | 
			
		||||
                mp.OnCompleted += async (s, song) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (song.PrintStatusMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            if (lastFinishedMessage != null)
 | 
			
		||||
                                await lastFinishedMessage.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            if (playingMessage != null)
 | 
			
		||||
                                await playingMessage.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            lastFinishedMessage = await textCh.SendMessageAsync($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
 | 
			
		||||
                            if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
 | 
			
		||||
                            {
 | 
			
		||||
                                await QueueSong(queuer.Guild.GetCurrentUser(), textCh, voiceCh, (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception e)
 | 
			
		||||
                        {
 | 
			
		||||
                            Console.WriteLine(e);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mp.OnStarted += async (s, song) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (song.PrintStatusMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var sender = s as MusicPlayer;
 | 
			
		||||
                        if (sender == null)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                            var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`";
 | 
			
		||||
                            playingMessage = await textCh.SendMessageAsync(msgTxt).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                return mp;
 | 
			
		||||
            });
 | 
			
		||||
            Song resolvedSong;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                musicPlayer.ThrowIfQueueFull();
 | 
			
		||||
                resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                musicPlayer.AddSong(resolvedSong, queuer.Username);
 | 
			
		||||
            }
 | 
			
		||||
            catch (PlaylistFullException)
 | 
			
		||||
            {
 | 
			
		||||
                await textCh.SendMessageAsync($"🎵 `Queue is full at {musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}.` ");
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            if (!silent)
 | 
			
		||||
            {
 | 
			
		||||
                var queuedMessage = await textCh.SendMessageAsync($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
 | 
			
		||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 | 
			
		||||
                Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await queuedMessage.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                }).ConfigureAwait(false);
 | 
			
		||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,7 +26,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Hentai(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
 | 
			
		||||
@@ -45,7 +45,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Danbooru(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetDanbooruImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
@@ -59,7 +59,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Gelbooru(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetRule34ImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Rule34(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetGelbooruImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
@@ -87,7 +87,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task E621(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetE621ImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
@@ -101,7 +101,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Cp(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@@ -110,7 +110,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Boobs(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                JToken obj;
 | 
			
		||||
@@ -130,7 +130,7 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Butts(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Poke(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
//        [RequireContext(ContextType.Guild)]
 | 
			
		||||
//        public async Task Anime(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
//        {
 | 
			
		||||
//            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
//            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
//            if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
 | 
			
		||||
//            string result;
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
//        [RequireContext(ContextType.Guild)]
 | 
			
		||||
//        public async Task Manga(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
//        {
 | 
			
		||||
//            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
//            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
//            if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
 | 
			
		||||
//            string result;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Yomama(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    var response = await http.GetStringAsync("http://api.yomomma.info/").ConfigureAwait(false);
 | 
			
		||||
@@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Randjoke(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    var response = await http.GetStringAsync("http://tambal.azurewebsites.net/joke/random").ConfigureAwait(false);
 | 
			
		||||
@@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task ChuckNorris(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
                using (var http = new HttpClient())
 | 
			
		||||
                {
 | 
			
		||||
                    var response = await http.GetStringAsync("http://api.icndb.com/jokes/random/").ConfigureAwait(false);
 | 
			
		||||
@@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task WowJoke(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                if (!wowJokes.Any())
 | 
			
		||||
                {
 | 
			
		||||
@@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task MagicItem(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
                var rng = new Random();
 | 
			
		||||
                var item = magicItems[rng.Next(0, magicItems.Count)].ToString();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Lolban(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Memelist(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(await http.GetStringAsync("http://memegen.link/templates/"))
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Memegen(IMessage imsg, string meme, string topText, string botText)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var top = Uri.EscapeDataString(topText.Replace(' ', '-'));
 | 
			
		||||
            var bot = Uri.EscapeDataString(botText.Replace(' ', '-'));
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Osu(IMessage imsg, string usr, string mode)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(usr))
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -63,7 +63,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Osub(IMessage imsg, [Remainder] string map)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
 | 
			
		||||
                {
 | 
			
		||||
@@ -100,7 +100,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Osu5(IMessage imsg, string user, [Remainder] string mode)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync("💢 An osu! API key is required.").ConfigureAwait(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Pokemon(IMessage imsg, [Remainder] string pokemon = null)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                pokemon = pokemon?.Trim().ToUpperInvariant();
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(pokemon))
 | 
			
		||||
@@ -64,7 +64,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task PokemonAbility(IMessage imsg, [Remainder] string ability = null)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
                ability = ability?.Trim().ToUpperInvariant().Replace(" ", "");
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(ability))
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Weather(IMessage imsg, string city, string country)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            city = city.Replace(" ", "");
 | 
			
		||||
            country = city.Replace(" ", "");
 | 
			
		||||
            string response;
 | 
			
		||||
@@ -51,9 +51,9 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Youtube(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
 | 
			
		||||
            var result = (await _google.FindVideosByKeywordsAsync(query, 1)).FirstOrDefault();
 | 
			
		||||
            var result = (await _google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(result))
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("No results found for that query.");
 | 
			
		||||
@@ -66,7 +66,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Imdb(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (!(await ValidateQuery(imsg.Channel as ITextChannel, query).ConfigureAwait(false))) return;
 | 
			
		||||
            await imsg.Channel.TriggerTypingAsync().ConfigureAwait(false);
 | 
			
		||||
@@ -90,7 +90,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task RandomCat(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync(JObject.Parse(
 | 
			
		||||
@@ -103,7 +103,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task RandomDog(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("http://random.dog/" + await http.GetStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
@@ -114,7 +114,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task I(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -144,7 +144,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Ir(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -176,7 +176,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Lmgtfy(IMessage imsg, [Remainder] string ffs = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(ffs))
 | 
			
		||||
@@ -190,7 +190,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Google(IMessage imsg, [Remainder] string terms = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            terms = terms?.Trim();
 | 
			
		||||
@@ -204,7 +204,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Hearthstone(IMessage imsg, [Remainder] string name = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
        //    var arg = name;
 | 
			
		||||
        //    if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
        //    {
 | 
			
		||||
@@ -249,7 +249,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Ud(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var arg = query;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
@@ -283,7 +283,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Hashtag(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var arg = query;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
@@ -318,7 +318,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Quote(IMessage imsg)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
 | 
			
		||||
        //    await channel.SendMessageAsync(quote).ConfigureAwait(false);
 | 
			
		||||
@@ -328,7 +328,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Catfact(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            using (var http = new HttpClient())
 | 
			
		||||
            {
 | 
			
		||||
                var response = await http.GetStringAsync("http://catfacts-api.appspot.com/api/facts").ConfigureAwait(false);
 | 
			
		||||
@@ -342,7 +342,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Revav(IMessage imsg, [Remainder] string arg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var usrStr = arg?.Trim().ToUpperInvariant();
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(usrStr))
 | 
			
		||||
@@ -359,7 +359,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Revimg(IMessage imsg, [Remainder] string imageLink = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            imageLink = imageLink?.Trim() ?? "";
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(imageLink))
 | 
			
		||||
@@ -371,7 +371,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Safebooru(IMessage imsg, [Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetSafebooruImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
@@ -385,7 +385,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Wiki(IMessage imsg, [Remainder] string query = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            query = query?.Trim();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
@@ -406,7 +406,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //public async Task Clr(IMessage imsg, [Remainder] string color = null)
 | 
			
		||||
        //{
 | 
			
		||||
        //    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
        //    var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
        //    color = color?.Trim().Replace("#", "");
 | 
			
		||||
        //    if (string.IsNullOrWhiteSpace((string)color))
 | 
			
		||||
@@ -431,7 +431,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Videocall(IMessage imsg, [Remainder] string arg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -454,7 +454,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Avatar(IMessage imsg, [Remainder] string mention = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            var usr = imsg.MentionedUsers.FirstOrDefault();
 | 
			
		||||
            if (usr == null)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Translator
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Translate(IMessage imsg, string langs, [Remainder] string text = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Translator
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Translangs(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => str, columns: 4);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task WhoPlays(IMessage imsg, [Remainder] string game = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            game = game.Trim().ToUpperInvariant();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(game))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(roles))
 | 
			
		||||
                return;
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
            var arg = roles.Split(',').Select(r => r.Trim().ToUpperInvariant());
 | 
			
		||||
            string send = _l["`Here is a list of users in a specfic role:`"];
 | 
			
		||||
            foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@EVERYONE" && str != "EVERYONE"))
 | 
			
		||||
@@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Stats(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
            var channel = (ITextChannel)imsg.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync(await NadekoBot.Stats.Print());
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ namespace NadekoBot
 | 
			
		||||
        public static Localization Localizer { get; private set; }
 | 
			
		||||
        public static BotCredentials Credentials { get; private set; }
 | 
			
		||||
 | 
			
		||||
        private static GoogleApiService Youtube { get; set; }
 | 
			
		||||
        public static GoogleApiService Google { get; set; }
 | 
			
		||||
        public static StatsService Stats { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public async Task RunAsync(string[] args)
 | 
			
		||||
@@ -43,7 +43,7 @@ namespace NadekoBot
 | 
			
		||||
            Commands = new CommandService();
 | 
			
		||||
            Config = new BotConfiguration();
 | 
			
		||||
            Localizer = new Localization();
 | 
			
		||||
            Youtube = new GoogleApiService();
 | 
			
		||||
            Google = new GoogleApiService();
 | 
			
		||||
            Stats = new StatsService(Client);
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
@@ -53,7 +53,7 @@ namespace NadekoBot
 | 
			
		||||
            depMap.Add<IBotConfiguration>(Config);
 | 
			
		||||
            depMap.Add<DiscordSocketClient>(Client);
 | 
			
		||||
            depMap.Add<CommandService>(Commands);
 | 
			
		||||
            depMap.Add<IGoogleApiService>(Youtube);
 | 
			
		||||
            depMap.Add<IGoogleApiService>(Google);
 | 
			
		||||
 | 
			
		||||
            //connect
 | 
			
		||||
            await Client.LoginAsync(TokenType.Bot, Credentials.Token);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,10 @@ namespace NadekoBot.Services
 | 
			
		||||
{
 | 
			
		||||
    public interface IGoogleApiService
 | 
			
		||||
    {
 | 
			
		||||
        Task<IEnumerable<string>> FindVideosByKeywordsAsync(string keywords, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> FindPlaylistIdsByKeywordsAsync(string keywords, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> FindRelatedVideosAsync(string url, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> GetVideosByKeywordsAsync(string keywords, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> GetRelatedVideosAsync(string url, int count = 1);
 | 
			
		||||
        Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50);
 | 
			
		||||
 | 
			
		||||
        Task<string> ShortenUrl(string url);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,8 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
        public ulong[] OwnerIds { get; }
 | 
			
		||||
 | 
			
		||||
        public string LoLApiKey { get; }
 | 
			
		||||
        public string OsuApiKey { get; }
 | 
			
		||||
        public string SoundCloudClientId { get; }
 | 
			
		||||
 | 
			
		||||
        public BotCredentials()
 | 
			
		||||
        {
 | 
			
		||||
@@ -36,17 +38,22 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
                LoLApiKey = cm.LoLApiKey;
 | 
			
		||||
                GoogleApiKey = cm.GoogleApiKey;
 | 
			
		||||
                MashapeKey = cm.MashapeKey;
 | 
			
		||||
                OsuApiKey = cm.OsuApiKey;
 | 
			
		||||
                SoundCloudClientId = cm.SoundCloudClientId;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                _log.Fatal("credentials.json is missing. Failed to start.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class CredentialsModel {
 | 
			
		||||
        private class CredentialsModel
 | 
			
		||||
        {
 | 
			
		||||
            public string Token { get; set; }
 | 
			
		||||
            public ulong[] OwnerIds { get; set; }
 | 
			
		||||
            public string LoLApiKey { get; set; }
 | 
			
		||||
            public string GoogleApiKey { get; set; }
 | 
			
		||||
            public string MashapeKey { get; set; }
 | 
			
		||||
            public string OsuApiKey { get; set; }
 | 
			
		||||
            public string SoundCloudClientId { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool IsOwner(IUser u) => OwnerIds.Contains(u.Id);
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
            yt = new YouTubeService(bcs);
 | 
			
		||||
            sh = new UrlshortenerService(bcs);
 | 
			
		||||
        }
 | 
			
		||||
        public async Task<IEnumerable<string>> FindPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
 | 
			
		||||
        public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(keywords))
 | 
			
		||||
                throw new ArgumentNullException(nameof(keywords));
 | 
			
		||||
@@ -46,7 +46,7 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
            return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<IEnumerable<string>> FindRelatedVideosAsync(string id, int count = 1)
 | 
			
		||||
        public async Task<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(id))
 | 
			
		||||
                throw new ArgumentNullException(nameof(id));
 | 
			
		||||
@@ -66,7 +66,7 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
            return (await query.ExecuteAsync()).Items.Select(i => "http://www.youtube.com/watch?v=" + i.Id.VideoId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<IEnumerable<string>> FindVideosByKeywordsAsync(string keywords, int count = 1)
 | 
			
		||||
        public async Task<IEnumerable<string>> GetVideosByKeywordsAsync(string keywords, int count = 1)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(keywords))
 | 
			
		||||
                throw new ArgumentNullException(nameof(keywords));
 | 
			
		||||
@@ -89,5 +89,37 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
            var response = await sh.Url.Insert(new Url { LongUrl = url }).ExecuteAsync();
 | 
			
		||||
            return response.Id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(playlistId))
 | 
			
		||||
                throw new ArgumentNullException(nameof(playlistId));
 | 
			
		||||
 | 
			
		||||
            if (count <= 0)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(count));
 | 
			
		||||
 | 
			
		||||
            string nextPageToken = null;
 | 
			
		||||
 | 
			
		||||
            List<string> toReturn = new List<string>(count);
 | 
			
		||||
 | 
			
		||||
            do
 | 
			
		||||
            {
 | 
			
		||||
                var toGet = count > 50 ? 50 : count;
 | 
			
		||||
                count -= toGet;
 | 
			
		||||
 | 
			
		||||
                var query = yt.PlaylistItems.List("contentDetails");
 | 
			
		||||
                query.MaxResults = count;
 | 
			
		||||
                query.PlaylistId = playlistId;
 | 
			
		||||
                query.PageToken = nextPageToken;
 | 
			
		||||
 | 
			
		||||
                var data = await query.ExecuteAsync();
 | 
			
		||||
 | 
			
		||||
                toReturn.AddRange(data.Items.Select(i => i.ContentDetails.VideoId));
 | 
			
		||||
                nextPageToken = data.NextPageToken;
 | 
			
		||||
            }
 | 
			
		||||
            while (count > 0 && !string.IsNullOrWhiteSpace(nextPageToken));
 | 
			
		||||
 | 
			
		||||
            return toReturn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,8 @@ namespace NadekoBot.Extensions
 | 
			
		||||
            http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
 | 
			
		||||
 | 
			
		||||
        public static async Task<IMessage> SendMessageAsync(this IGuildUser user, string message, bool isTTS = false) =>
 | 
			
		||||
            await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,131 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 💩
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class PoopyBuffer
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        private readonly byte[] ringBuffer;
 | 
			
		||||
 | 
			
		||||
        public int WritePosition { get; private set; } = 0;
 | 
			
		||||
        public int ReadPosition { get; private set; } = 0;
 | 
			
		||||
 | 
			
		||||
        public int ContentLength => (WritePosition >= ReadPosition ?
 | 
			
		||||
                                     WritePosition - ReadPosition :
 | 
			
		||||
                                     (BufferSize - ReadPosition) + WritePosition);
 | 
			
		||||
 | 
			
		||||
        public int BufferSize { get; }
 | 
			
		||||
 | 
			
		||||
        private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1);
 | 
			
		||||
 | 
			
		||||
        public PoopyBuffer(int size)
 | 
			
		||||
        {
 | 
			
		||||
            if (size <= 0)
 | 
			
		||||
                throw new ArgumentException();
 | 
			
		||||
            BufferSize = size;
 | 
			
		||||
            ringBuffer = new byte[size];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task<int> ReadAsync(byte[] buffer, int count)
 | 
			
		||||
        {
 | 
			
		||||
            return Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                if (buffer.Length < count)
 | 
			
		||||
                    throw new ArgumentException();
 | 
			
		||||
                //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
 | 
			
		||||
                await readWriteLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    //read as much as you can if you're reading too much
 | 
			
		||||
                    if (count > ContentLength)
 | 
			
		||||
                        count = ContentLength;
 | 
			
		||||
                    //if nothing to read, return 0
 | 
			
		||||
                    if (WritePosition == ReadPosition)
 | 
			
		||||
                        return 0;
 | 
			
		||||
                    // if buffer is in the "normal" state, just read
 | 
			
		||||
                    if (WritePosition > ReadPosition)
 | 
			
		||||
                    {
 | 
			
		||||
                        Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
 | 
			
		||||
                        ReadPosition += count;
 | 
			
		||||
                        //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]");
 | 
			
		||||
                        return count;
 | 
			
		||||
                    }
 | 
			
		||||
                    //else ReadPos <Writepos
 | 
			
		||||
                    // buffer is in its inverted state
 | 
			
		||||
                    // A: if i can read as much as possible without hitting the buffer.length, read that
 | 
			
		||||
 | 
			
		||||
                    if (count + ReadPosition <= BufferSize)
 | 
			
		||||
                    {
 | 
			
		||||
                        Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
 | 
			
		||||
                        ReadPosition += count;
 | 
			
		||||
                        //Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]");
 | 
			
		||||
                        return count;
 | 
			
		||||
                    }
 | 
			
		||||
                    // B: if i can't read as much, read to the end,
 | 
			
		||||
                    var readNormaly = BufferSize - ReadPosition;
 | 
			
		||||
                    Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly);
 | 
			
		||||
 | 
			
		||||
                    //Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]");
 | 
			
		||||
                    //then read the remaining amount from the start
 | 
			
		||||
 | 
			
		||||
                    var readFromStart = count - readNormaly;
 | 
			
		||||
                    Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart);
 | 
			
		||||
                    //Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]");
 | 
			
		||||
                    ReadPosition = readFromStart;
 | 
			
		||||
                    return count;
 | 
			
		||||
                }
 | 
			
		||||
                finally { readWriteLock.Release(); }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken)
 | 
			
		||||
        {
 | 
			
		||||
            if (count > buffer.Length)
 | 
			
		||||
                throw new ArgumentException();
 | 
			
		||||
            while (ContentLength + count > BufferSize)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(20, cancelToken).ConfigureAwait(false);
 | 
			
		||||
                if (cancelToken.IsCancellationRequested)
 | 
			
		||||
                    return;
 | 
			
		||||
            }
 | 
			
		||||
            await Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                //the while above assures that i cannot write past readposition with my write, so i don't have to check
 | 
			
		||||
                // *unless its multithreaded or task is not awaited
 | 
			
		||||
                await readWriteLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    // if i can just write without hitting buffer.length, do it
 | 
			
		||||
                    if (WritePosition + count < BufferSize)
 | 
			
		||||
                    {
 | 
			
		||||
                        Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count);
 | 
			
		||||
                        WritePosition += count;
 | 
			
		||||
                        //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]");
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    // otherwise, i have to write to the end, then write the rest from the start
 | 
			
		||||
 | 
			
		||||
                    var wroteNormaly = BufferSize - WritePosition;
 | 
			
		||||
                    Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly);
 | 
			
		||||
 | 
			
		||||
                    //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]");
 | 
			
		||||
 | 
			
		||||
                    var wroteFromStart = count - wroteNormaly;
 | 
			
		||||
                    Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart);
 | 
			
		||||
 | 
			
		||||
                    //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}");
 | 
			
		||||
 | 
			
		||||
                    WritePosition = wroteFromStart;
 | 
			
		||||
                }
 | 
			
		||||
                finally { readWriteLock.Release(); }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,900 +0,0 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using Discord.Modules;
 | 
			
		||||
using NadekoBot.Classes;
 | 
			
		||||
using NadekoBot.DataModels;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Modules.Music.Classes;
 | 
			
		||||
using NadekoBot.Modules.Permissions.Classes;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Music
 | 
			
		||||
{
 | 
			
		||||
    internal class MusicModule : DiscordModule
 | 
			
		||||
    {
 | 
			
		||||
        public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
 | 
			
		||||
 | 
			
		||||
        public const string MusicDataPath = "data/musicdata";
 | 
			
		||||
 | 
			
		||||
        public MusicModule()
 | 
			
		||||
        {
 | 
			
		||||
            //it can fail if its currenctly opened or doesn't exist. Either way i don't care
 | 
			
		||||
            try { Directory.Delete(MusicDataPath, true); } catch { }
 | 
			
		||||
 | 
			
		||||
            Directory.CreateDirectory(MusicDataPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music;
 | 
			
		||||
 | 
			
		||||
        public override void Install(ModuleManager manager)
 | 
			
		||||
        {
 | 
			
		||||
            var client = NadekoBot.Client;
 | 
			
		||||
 | 
			
		||||
            manager.CreateCommands("", cgb =>
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                cgb.AddCheck(PermissionChecker.Instance);
 | 
			
		||||
 | 
			
		||||
                commands.ForEach(cmd => cmd.Init(cgb));
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "next")
 | 
			
		||||
                    .Alias(Prefix + "n")
 | 
			
		||||
                    .Alias(Prefix + "skip")
 | 
			
		||||
                    .Description($"Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `{Prefix}n`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
 | 
			
		||||
                        if (musicPlayer.PlaybackVoiceChannel == imsg.Author.VoiceChannel)
 | 
			
		||||
                            musicPlayer.Next();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "stop")
 | 
			
		||||
                    .Alias(Prefix + "s")
 | 
			
		||||
                    .Description($"Stops the music and clears the playlist. Stays in the channel. | `{Prefix}s`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                        {
 | 
			
		||||
                            musicPlayer.Autoplay = false;
 | 
			
		||||
                            musicPlayer.Stop();
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "destroy")
 | 
			
		||||
                    .Alias(Prefix + "d")
 | 
			
		||||
                    .Description("Completely stops the music and unbinds the bot from the channel. " +
 | 
			
		||||
                                 $"(may cause weird behaviour) | `{Prefix}d`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            musicPlayer.Destroy();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "pause")
 | 
			
		||||
                    .Alias(Prefix + "p")
 | 
			
		||||
                    .Description($"Pauses or Unpauses the song. | `{Prefix}p`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        musicPlayer.TogglePause();
 | 
			
		||||
                        if (musicPlayer.Paused)
 | 
			
		||||
                            await channel.SendMessageAsync("🎵`Music Player paused.`").ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await channel.SendMessageAsync("🎵`Music Player unpaused.`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "queue")
 | 
			
		||||
                    .Alias(Prefix + "q")
 | 
			
		||||
                    .Alias(Prefix + "yq")
 | 
			
		||||
                    .Description("Queue a song using keywords or a link. Bot will join your voice channel." +
 | 
			
		||||
                                 $"**You must be in a voice channel**. | `{Prefix}q Dream Of Venice`")
 | 
			
		||||
                    .Parameter("query", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, query).ConfigureAwait(false);
 | 
			
		||||
                        if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
 | 
			
		||||
                        {
 | 
			
		||||
                            await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                            await e.Message.Delete().ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "soundcloudqueue")
 | 
			
		||||
                    .Alias(Prefix + "sq")
 | 
			
		||||
                    .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." +
 | 
			
		||||
                                 $"**You must be in a voice channel**. | `{Prefix}sq Dream Of Venice`")
 | 
			
		||||
                    .Parameter("query", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, query, musicType: MusicType.Soundcloud).ConfigureAwait(false);
 | 
			
		||||
                        if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
 | 
			
		||||
                        {
 | 
			
		||||
                            await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                            await e.Message.Delete().ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "listqueue")
 | 
			
		||||
                    .Alias(Prefix + "lq")
 | 
			
		||||
                    .Description($"Lists 15 currently queued songs per page. Default page is 1. | `{Prefix}lq` or `{Prefix}lq 2`")
 | 
			
		||||
                    .Parameter("page", ParameterType.Optional)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("🎵 No active music player.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        int page;
 | 
			
		||||
                        if (!int.TryParse(page, out page) || page <= 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            page = 1;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
                        if (currentSong == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n";
 | 
			
		||||
                        if (musicPlayer.RepeatSong)
 | 
			
		||||
                            toSend += "🔂";
 | 
			
		||||
                        else if (musicPlayer.RepeatPlaylist)
 | 
			
		||||
                            toSend += "🔁";
 | 
			
		||||
                        toSend += $" **{musicPlayer.Playlist.Count}** `tracks currently queued. Showing page {page}` ";
 | 
			
		||||
                        if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
 | 
			
		||||
                            toSend += "**Song queue is full!**\n";
 | 
			
		||||
                        else
 | 
			
		||||
                            toSend += "\n";
 | 
			
		||||
                        const int itemsPerPage = 15;
 | 
			
		||||
                        int startAt = itemsPerPage * (page - 1);
 | 
			
		||||
                        var number = 1 + startAt;
 | 
			
		||||
                        await channel.SendMessageAsync(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "nowplaying")
 | 
			
		||||
                    .Alias(Prefix + "np")
 | 
			
		||||
                    .Description($"Shows the song currently playing. | `{Prefix}np`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
                        if (currentSong == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵`Now Playing` {currentSong.PrettyName} " +
 | 
			
		||||
                                                    $"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "volume")
 | 
			
		||||
                    .Alias(Prefix + "vol")
 | 
			
		||||
                    .Description($"Sets the music volume 0-100% | `{Prefix}vol 50`")
 | 
			
		||||
                    .Parameter("val", ParameterType.Required)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var arg = val;
 | 
			
		||||
                        int volume;
 | 
			
		||||
                        if (!int.TryParse(arg, out volume))
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("Volume number invalid.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        volume = musicPlayer.SetVolume(volume);
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵 `Volume set to {volume}%`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "defvol")
 | 
			
		||||
                    .Alias(Prefix + "dv")
 | 
			
		||||
                    .Description("Sets the default music volume when music playback is started (0-100)." +
 | 
			
		||||
                                 $" Persists through restarts. | `{Prefix}dv 80`")
 | 
			
		||||
                    .Parameter("val", ParameterType.Required)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var arg = val;
 | 
			
		||||
                        float volume;
 | 
			
		||||
                        if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("Volume number invalid.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var conf = SpecificConfigurations.Default.Of(e.Server.Id);
 | 
			
		||||
                        conf.DefaultMusicVolume = volume / 100;
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "mute")
 | 
			
		||||
                    .Alias(Prefix + "min")
 | 
			
		||||
                    .Description($"Sets the music volume to 0% | `{Prefix}min`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        musicPlayer.SetVolume(0);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "max")
 | 
			
		||||
                    .Description($"Sets the music volume to 100%. | `{Prefix}max`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        musicPlayer.SetVolume(100);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "half")
 | 
			
		||||
                    .Description($"Sets the music volume to 50%. | `{Prefix}half`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        musicPlayer.SetVolume(50);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "shuffle")
 | 
			
		||||
                    .Alias(Prefix + "sh")
 | 
			
		||||
                    .Description($"Shuffles the current playlist. | `{Prefix}sh`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (musicPlayer.Playlist.Count < 2)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        musicPlayer.Shuffle();
 | 
			
		||||
                        await channel.SendMessageAsync("🎵 `Songs shuffled.`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "playlist")
 | 
			
		||||
                    .Alias(Prefix + "pl")
 | 
			
		||||
                    .Description($"Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `{Prefix}pl playlist link or name`")
 | 
			
		||||
                    .Parameter("playlist", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var arg = playlist;
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel?.Server != e.Server)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var plId = await SearchHelper.GetPlaylistIdByKeyword(arg).ConfigureAwait(false);
 | 
			
		||||
                        if (plId == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("No search results for that query.");
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var ids = await SearchHelper.GetVideoIDs(plId, 500).ConfigureAwait(false);
 | 
			
		||||
                        if (ids == null || ids.Count == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync($"🎵 `Failed to find any songs.`").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var idArray = ids as string[] ?? ids.ToArray();
 | 
			
		||||
                        var count = idArray.Length;
 | 
			
		||||
                        var msg =
 | 
			
		||||
                            await channel.SendMessageAsync($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`").ConfigureAwait(false);
 | 
			
		||||
                        foreach (var id in idArray)
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, id, true).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (PlaylistFullException)
 | 
			
		||||
                            { break; }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
                        await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "soundcloudpl")
 | 
			
		||||
                    .Alias(Prefix + "scpl")
 | 
			
		||||
                    .Description($"Queue a soundcloud playlist using a link. | `{Prefix}scpl https://soundcloud.com/saratology/sets/symphony`")
 | 
			
		||||
                    .Parameter("pl", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var pl = pl?.Trim();
 | 
			
		||||
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(pl))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var scvids = JObject.Parse(await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Credentials.SoundCloudClientID}").ConfigureAwait(false))["tracks"].ToObject<SoundCloudVideo[]>();
 | 
			
		||||
                        await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        MusicPlayer mp;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out mp))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        foreach (var svideo in scvids.Skip(1))
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                mp.AddSong(new Song(new Classes.SongInfo
 | 
			
		||||
                                {
 | 
			
		||||
                                    Title = svideo.FullName,
 | 
			
		||||
                                    Provider = "SoundCloud",
 | 
			
		||||
                                    Uri = svideo.StreamLink,
 | 
			
		||||
                                    ProviderType = MusicType.Normal,
 | 
			
		||||
                                    Query = svideo.TrackLink,
 | 
			
		||||
                                }), imsg.Author.Username);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (PlaylistFullException) { break; }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "localplaylst")
 | 
			
		||||
                    .Alias(Prefix + "lopl")
 | 
			
		||||
                    .Description($"Queues all songs from a directory. **Bot Owner Only!** | `{Prefix}lopl C:/music/classical`")
 | 
			
		||||
                    .Parameter("directory", ParameterType.Unparsed)
 | 
			
		||||
                    .AddCheck(SimpleCheckers.OwnerOnly())
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var arg = directory;
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                            return;
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            var fileEnum = new DirectoryInfo(arg).GetFiles()
 | 
			
		||||
                                                .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
 | 
			
		||||
                            foreach (var file in fileEnum)
 | 
			
		||||
                            {
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
 | 
			
		||||
                                }
 | 
			
		||||
                                catch (PlaylistFullException)
 | 
			
		||||
                                {
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                                catch { }
 | 
			
		||||
                            }
 | 
			
		||||
                            await channel.SendMessageAsync("🎵 `Directory queue complete.`").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "radio").Alias(Prefix + "ra")
 | 
			
		||||
                    .Description($"Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `{Prefix}ra radio link here`")
 | 
			
		||||
                    .Parameter("radio_link", ParameterType.Required)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (imsg.Author.VoiceChannel?.Server != e.Server)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false);
 | 
			
		||||
                        if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
 | 
			
		||||
                        {
 | 
			
		||||
                            await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                            await e.Message.Delete().ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "local")
 | 
			
		||||
                    .Alias(Prefix + "lo")
 | 
			
		||||
                    .Description($"Queues a local file by specifying a full path. **Bot Owner Only!** | `{Prefix}lo C:/music/mysong.mp3`")
 | 
			
		||||
                    .Parameter("path", ParameterType.Unparsed)
 | 
			
		||||
                    .AddCheck(SimpleCheckers.OwnerOnly())
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var arg = path;
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(arg))
 | 
			
		||||
                            return;
 | 
			
		||||
                        await QueueSong(imsg.Author, e.Channel, imsg.Author.VoiceChannel, path, musicType: MusicType.Local).ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "move")
 | 
			
		||||
                    .Alias(Prefix + "mv")
 | 
			
		||||
                    .Description($"Moves the bot to your voice channel. (works only if music is already playing) | `{Prefix}mv`")
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        var voiceChannel = imsg.Author.VoiceChannel;
 | 
			
		||||
                        if (voiceChannel == null || voiceChannel.Server != e.Server || !MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        musicPlayer.MoveToVoiceChannel(voiceChannel);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "remove")
 | 
			
		||||
                    .Alias(Prefix + "rm")
 | 
			
		||||
                    .Description($"Remove a song by its # in the queue, or 'all' to remove whole queue. | `{Prefix}rm 5`")
 | 
			
		||||
                    .Parameter("num", ParameterType.Required)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var arg = num;
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (arg?.ToLower() == "all")
 | 
			
		||||
                        {
 | 
			
		||||
                            musicPlayer.ClearQueue();
 | 
			
		||||
                            await channel.SendMessageAsync($"🎵`Queue cleared!`").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        int num;
 | 
			
		||||
                        if (!int.TryParse(arg, out num))
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (num <= 0 || num > musicPlayer.Playlist.Count)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var song = (musicPlayer.Playlist as List<Song>)?[num - 1];
 | 
			
		||||
                        musicPlayer.RemoveSongAt(num - 1);
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                //var msRegex = new Regex(@"(?<n1>\d+)>(?<n2>\d+)", RegexOptions.Compiled);
 | 
			
		||||
                cgb.CreateCommand(Prefix + "movesong")
 | 
			
		||||
                    .Alias(Prefix + "ms")
 | 
			
		||||
                    .Description($"Moves a song from one position to another. | `{Prefix} ms` 5>3")
 | 
			
		||||
                    .Parameter("fromto")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var fromto = fromto.Trim();
 | 
			
		||||
                        var fromtoArr = fromto.Split('>');
 | 
			
		||||
 | 
			
		||||
                        int n1;
 | 
			
		||||
                        int n2;
 | 
			
		||||
 | 
			
		||||
                        var playlist = musicPlayer.Playlist as List<Song> ?? musicPlayer.Playlist.ToList();
 | 
			
		||||
 | 
			
		||||
                        if (fromtoArr.Length != 2 || !int.TryParse(fromtoArr[0], out n1) ||
 | 
			
		||||
                            !int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
 | 
			
		||||
                            n1 > playlist.Count || n2 > playlist.Count)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("`Invalid input.`").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var s = playlist[n1 - 1];
 | 
			
		||||
                        playlist.Insert(n2 - 1, s);
 | 
			
		||||
                        var nn1 = n2 < n1 ? n1 : n1 - 1;
 | 
			
		||||
                        playlist.RemoveAt(nn1);
 | 
			
		||||
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵`Moved` {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "setmaxqueue")
 | 
			
		||||
                    .Alias(Prefix + "smq")
 | 
			
		||||
                    .Description($"Sets a maximum queue size. Supply 0 or no argument to have no limit.  | `{Prefix}smq` 50 or `{Prefix}smq`")
 | 
			
		||||
                    .Parameter("size", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var sizeStr = size?.Trim();
 | 
			
		||||
                        uint size = 0;
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(sizeStr) || !uint.TryParse(sizeStr, out size))
 | 
			
		||||
                        {
 | 
			
		||||
                            size = 0;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        musicPlayer.MaxQueueSize = size;
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵 `Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}`");
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "cleanup")
 | 
			
		||||
                    .Description($"Cleans up hanging voice connections. **Bot Owner Only!** | `{Prefix}cleanup`")
 | 
			
		||||
                    .AddCheck(SimpleCheckers.OwnerOnly())
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        foreach (var kvp in MusicPlayers)
 | 
			
		||||
                        {
 | 
			
		||||
                            var songs = kvp.Value.Playlist;
 | 
			
		||||
                            var currentSong = kvp.Value.CurrentSong;
 | 
			
		||||
                            if (songs.Count == 0 && currentSong == null)
 | 
			
		||||
                            {
 | 
			
		||||
                                MusicPlayer throwaway;
 | 
			
		||||
                                MusicPlayers.TryRemove(kvp.Key, out throwaway);
 | 
			
		||||
                                throwaway.Destroy();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "reptcursong")
 | 
			
		||||
                    .Alias(Prefix + "rcs")
 | 
			
		||||
                    .Description($"Toggles repeat of current song. | `{Prefix}rcs`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
                        if (currentSong == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var currentValue = musicPlayer.ToggleRepeatSong();
 | 
			
		||||
                        await channel.SendMessageAsync(currentValue ?
 | 
			
		||||
                                                    $"🎵🔂`Repeating track:`{currentSong.PrettyName}" :
 | 
			
		||||
                                                    $"🎵🔂`Current track repeat stopped.`")
 | 
			
		||||
                                                        .ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "rpeatplaylst")
 | 
			
		||||
                    .Alias(Prefix + "rpl")
 | 
			
		||||
                    .Description($"Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `{Prefix}rpl`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        var currentValue = musicPlayer.ToggleRepeatPlaylist();
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "save")
 | 
			
		||||
                    .Description($"Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `{Prefix}save classical1`")
 | 
			
		||||
                    .Parameter("name", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var name = name?.Trim();
 | 
			
		||||
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(name) ||
 | 
			
		||||
                            name.Length > 20 ||
 | 
			
		||||
                            name.Contains("-"))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        //to avoid concurrency issues
 | 
			
		||||
                        var currentPlaylist = new List<Song>(musicPlayer.Playlist);
 | 
			
		||||
                        var curSong = musicPlayer.CurrentSong;
 | 
			
		||||
                        if (curSong != null)
 | 
			
		||||
                            currentPlaylist.Insert(0, curSong);
 | 
			
		||||
 | 
			
		||||
                        if (!currentPlaylist.Any())
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                        var songInfos = currentPlaylist.Select(s => new DataModels.SongInfo
 | 
			
		||||
                        {
 | 
			
		||||
                            Provider = s.SongInfo.Provider,
 | 
			
		||||
                            ProviderType = (int)s.SongInfo.ProviderType,
 | 
			
		||||
                            Title = s.SongInfo.Title,
 | 
			
		||||
                            Uri = s.SongInfo.Uri,
 | 
			
		||||
                            Query = s.SongInfo.Query,
 | 
			
		||||
                        }).ToList();
 | 
			
		||||
 | 
			
		||||
                        var playlist = new MusicPlaylist
 | 
			
		||||
                        {
 | 
			
		||||
                            CreatorId = (long)imsg.Author.Id,
 | 
			
		||||
                            CreatorName = imsg.Author.Username,
 | 
			
		||||
                            Name = name.ToLowerInvariant(),
 | 
			
		||||
                        };
 | 
			
		||||
                        DbHandler.Instance.SaveAll(songInfos);
 | 
			
		||||
                        DbHandler.Instance.Save(playlist);
 | 
			
		||||
                        DbHandler.Instance.Connection.InsertAll(songInfos.Select(s => new PlaylistSongInfo
 | 
			
		||||
                        {
 | 
			
		||||
                            PlaylistId = playlist.Id.Value,
 | 
			
		||||
                            SongInfoId = s.Id.Value
 | 
			
		||||
                        }), typeof(PlaylistSongInfo));
 | 
			
		||||
 | 
			
		||||
                        await channel.SendMessageAsync($"🎵 `Saved playlist as {name}-{playlist.Id}`").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "load")
 | 
			
		||||
                    .Description($"Loads a playlist under a certain name.  | `{Prefix}load classical-1`")
 | 
			
		||||
                    .Parameter("name", ParameterType.Unparsed)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var voiceCh = imsg.Author.VoiceChannel;
 | 
			
		||||
                        var textCh = e.Channel;
 | 
			
		||||
                        if (voiceCh == null || voiceCh.Server != textCh.Server)
 | 
			
		||||
                        {
 | 
			
		||||
                            await textCh.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        var name = name?.Trim().ToLowerInvariant();
 | 
			
		||||
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(name))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var parts = name.Split('-');
 | 
			
		||||
                        if (parts.Length != 2)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var playlistName = parts[0];
 | 
			
		||||
 | 
			
		||||
                        int playlistNumber;
 | 
			
		||||
                        if (!int.TryParse(parts[1], out playlistNumber))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var playlist = DbHandler.Instance.FindOne<MusicPlaylist>(
 | 
			
		||||
                            p => p.Id == playlistNumber);
 | 
			
		||||
 | 
			
		||||
                        if (playlist == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            await channel.SendMessageAsync("Can't find playlist under that name.").ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var psis = DbHandler.Instance.FindAll<PlaylistSongInfo>(psi =>
 | 
			
		||||
                            psi.PlaylistId == playlist.Id);
 | 
			
		||||
 | 
			
		||||
                        var songInfos = psis.Select(psi => DbHandler.Instance
 | 
			
		||||
                            .FindOne<DataModels.SongInfo>(si => si.Id == psi.SongInfoId));
 | 
			
		||||
 | 
			
		||||
                        await channel.SendMessageAsync($"`Attempting to load {songInfos.Count()} songs`").ConfigureAwait(false);
 | 
			
		||||
                        foreach (var si in songInfos)
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await QueueSong(imsg.Author, textCh, voiceCh, si.Query, true, (MusicType)si.ProviderType).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (PlaylistFullException)
 | 
			
		||||
                            {
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (Exception ex)
 | 
			
		||||
                            {
 | 
			
		||||
                                Console.WriteLine($"Failed QueueSong in load playlist. {ex}");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "playlists")
 | 
			
		||||
                    .Alias(Prefix + "pls")
 | 
			
		||||
                    .Description($"Lists all playlists. Paginated. 20 per page. Default page is 0. |`{Prefix}pls 1`")
 | 
			
		||||
                    .Parameter("num", ParameterType.Optional)
 | 
			
		||||
                    .Do(e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        int num = 0;
 | 
			
		||||
                        int.TryParse(num, out num);
 | 
			
		||||
                        if (num < 0)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var result = DbHandler.Instance.GetPlaylistData(num);
 | 
			
		||||
                        if (result.Count == 0)
 | 
			
		||||
                            channel.SendMessageAsync($"`No saved playlists found on page {num}`").ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            channel.SendMessageAsync($"```js\n--- List of saved playlists ---\n\n" + string.Join("\n", result.Select(r => $"'{r.Name}-{r.Id}' by {r.Creator} ({r.SongCnt} songs)")) + $"\n\n        --- Page {num} ---```").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "deleteplaylist")
 | 
			
		||||
                    .Alias(Prefix + "delpls")
 | 
			
		||||
                    .Description($"Deletes a saved playlist. Only if you made it or if you are the bot owner. | `{Prefix}delpls animu-5`")
 | 
			
		||||
                    .Parameter("pl", ParameterType.Required)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var pl = pl.Trim().Split('-')[1];
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(pl))
 | 
			
		||||
                            return;
 | 
			
		||||
                        var plnum = int.Parse(pl);
 | 
			
		||||
                        if (NadekoBot.IsOwner(imsg.Author.Id))
 | 
			
		||||
                            DbHandler.Instance.Delete<MusicPlaylist>(plnum);
 | 
			
		||||
                        else
 | 
			
		||||
                            DbHandler.Instance.DeleteWhere<MusicPlaylist>(mp => mp.Id == plnum && (long)imsg.Author.Id == mp.CreatorId);
 | 
			
		||||
                        await channel.SendMessageAsync("`Ok.` :ok:").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "goto")
 | 
			
		||||
                    .Description($"Goes to a specific time in seconds in a song. | `{Prefix}goto 30`")
 | 
			
		||||
                    .Parameter("time")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var skipToStr = time?.Trim();
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (imsg.Author.VoiceChannel != musicPlayer.PlaybackVoiceChannel)
 | 
			
		||||
                            return;
 | 
			
		||||
                        int skipTo;
 | 
			
		||||
                        if (!int.TryParse(skipToStr, out skipTo) || skipTo < 0)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
 | 
			
		||||
                        if (currentSong == null)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        //currentSong.PrintStatusMessage = false;
 | 
			
		||||
                        var gotoSong = currentSong.Clone();
 | 
			
		||||
                        gotoSong.SkipTo = skipTo;
 | 
			
		||||
                        musicPlayer.AddSong(gotoSong, 0);
 | 
			
		||||
                        musicPlayer.Next();
 | 
			
		||||
 | 
			
		||||
                        var minutes = (skipTo / 60).ToString();
 | 
			
		||||
                        var seconds = (skipTo % 60).ToString();
 | 
			
		||||
 | 
			
		||||
                        if (minutes.Length == 1)
 | 
			
		||||
                            minutes = "0" + minutes;
 | 
			
		||||
                        if (seconds.Length == 1)
 | 
			
		||||
                            seconds = "0" + seconds;
 | 
			
		||||
 | 
			
		||||
                        await channel.SendMessageAsync($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "getlink")
 | 
			
		||||
                    .Alias(Prefix + "gl")
 | 
			
		||||
                    .Description($"Shows a link to the song in the queue by index, or the currently playing song by default. | `{Prefix}gl`")
 | 
			
		||||
                    .Parameter("index", ParameterType.Optional)
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
                        int index;
 | 
			
		||||
                        string arg = index?.Trim();
 | 
			
		||||
                        if (!string.IsNullOrEmpty(arg) && int.TryParse(arg, out index))
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                            var selSong = musicPlayer.Playlist.DefaultIfEmpty(null).ElementAtOrDefault(index - 1);
 | 
			
		||||
                            if (selSong == null)
 | 
			
		||||
                            {
 | 
			
		||||
                                await channel.SendMessageAsync("Could not select song, likely wrong index");
 | 
			
		||||
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                await channel.SendMessageAsync($"🎶`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>").ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            var curSong = musicPlayer.CurrentSong;
 | 
			
		||||
                            if (curSong == null)
 | 
			
		||||
                                return;
 | 
			
		||||
                            await channel.SendMessageAsync($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                cgb.CreateCommand(Prefix + "autoplay")
 | 
			
		||||
                    .Alias(Prefix + "ap")
 | 
			
		||||
                    .Description($"Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `{Prefix}ap`")
 | 
			
		||||
                    .Do(async e =>
 | 
			
		||||
                    {
 | 
			
		||||
 | 
			
		||||
                        MusicPlayer musicPlayer;
 | 
			
		||||
                        if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        if (!musicPlayer.ToggleAutoplay())
 | 
			
		||||
                            await channel.SendMessageAsync("🎶`Autoplay disabled.`").ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await channel.SendMessageAsync("🎶`Autoplay enabled.`").ConfigureAwait(false);
 | 
			
		||||
                    });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task QueueSong(User queuer, Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
 | 
			
		||||
        {
 | 
			
		||||
            if (voiceCh == null || voiceCh.Server != textCh.Server)
 | 
			
		||||
            {
 | 
			
		||||
                if (!silent)
 | 
			
		||||
                    await textCh.SendMessageAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.").ConfigureAwait(false);
 | 
			
		||||
                throw new ArgumentNullException(nameof(voiceCh));
 | 
			
		||||
            }
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
 | 
			
		||||
                throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
 | 
			
		||||
 | 
			
		||||
            var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server =>
 | 
			
		||||
            {
 | 
			
		||||
                float vol = SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
 | 
			
		||||
                var mp = new MusicPlayer(voiceCh, vol);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                Message playingMessage = null;
 | 
			
		||||
                Message lastFinishedMessage = null;
 | 
			
		||||
                mp.OnCompleted += async (s, song) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (song.PrintStatusMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            if (lastFinishedMessage != null)
 | 
			
		||||
                                await lastFinishedMessage.Delete().ConfigureAwait(false);
 | 
			
		||||
                            if (playingMessage != null)
 | 
			
		||||
                                await playingMessage.Delete().ConfigureAwait(false);
 | 
			
		||||
                            lastFinishedMessage = await textCh.SendMessageAsync($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
 | 
			
		||||
                            if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
 | 
			
		||||
                            {
 | 
			
		||||
                                await QueueSong(queuer.Server.CurrentUser, textCh, voiceCh, (await SearchHelper.GetRelatedVideoIds(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception e)
 | 
			
		||||
                        {
 | 
			
		||||
                            Console.WriteLine(e);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mp.OnStarted += async (s, song) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (song.PrintStatusMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var sender = s as MusicPlayer;
 | 
			
		||||
                        if (sender == null)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                            var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`";
 | 
			
		||||
                            playingMessage = await textCh.SendMessageAsync(msgTxt).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                return mp;
 | 
			
		||||
            });
 | 
			
		||||
            Song resolvedSong;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                musicPlayer.ThrowIfQueueFull();
 | 
			
		||||
                resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                musicPlayer.AddSong(resolvedSong, queuer.Name);
 | 
			
		||||
            }
 | 
			
		||||
            catch (PlaylistFullException)
 | 
			
		||||
            {
 | 
			
		||||
                await textCh.SendMessageAsync($"🎵 `Queue is full at {musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}.` ");
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            if (!silent)
 | 
			
		||||
            {
 | 
			
		||||
                var queuedMessage = await textCh.SendMessageAsync($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
 | 
			
		||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 | 
			
		||||
                Task.Run(async () =>
 | 
			
		||||
                                {
 | 
			
		||||
                                    await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                                    try
 | 
			
		||||
                                    {
 | 
			
		||||
                                        await queuedMessage.Delete().ConfigureAwait(false);
 | 
			
		||||
                                    }
 | 
			
		||||
                                    catch { }
 | 
			
		||||
                                }).ConfigureAwait(false);
 | 
			
		||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,9 +5,11 @@
 | 
			
		||||
  "copyright": "Kwoth",
 | 
			
		||||
  "buildOptions": {
 | 
			
		||||
    "emitEntryPoint": true,
 | 
			
		||||
    "allowUnsafe": true,
 | 
			
		||||
    "compile": {
 | 
			
		||||
      "exclude": [ "_Models", "Classes", "_Modules" ]
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
    "define": []
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "Microsoft.NETCore.App": {
 | 
			
		||||
@@ -24,12 +26,16 @@
 | 
			
		||||
    "Google.Apis.YouTube.v3": "1.15.0.582",
 | 
			
		||||
    "Google.Apis.Urlshortener.v1": "1.15.0.138",
 | 
			
		||||
    "System.Diagnostics.Contracts": "4.0.1",
 | 
			
		||||
    "NLog": "4.4.0-betaV15"
 | 
			
		||||
    "NLog": "4.4.0-betaV15",
 | 
			
		||||
    "VideoLibrary": "1.3.4"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  "frameworks": {
 | 
			
		||||
    "netcoreapp1.0": {
 | 
			
		||||
      "imports": "dnxcore50"
 | 
			
		||||
      "imports": [
 | 
			
		||||
        "dnxcore50",
 | 
			
		||||
        "portable-net45+win8+wpa81"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -680,6 +680,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Collections.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Collections.Concurrent/4.0.12": {
 | 
			
		||||
@@ -884,6 +887,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Diagnostics.Debug.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Diagnostics.DiagnosticSource/4.0.0": {
 | 
			
		||||
@@ -994,6 +1000,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.0/System.Diagnostics.Tools.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Diagnostics.TraceSource/4.0.0": {
 | 
			
		||||
@@ -1032,6 +1041,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.Diagnostics.Tracing.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Dynamic.Runtime/4.0.11": {
 | 
			
		||||
@@ -1069,6 +1081,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Globalization.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Globalization.Calendars/4.0.1": {
 | 
			
		||||
@@ -1118,6 +1133,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.IO.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.IO.Compression/4.1.0": {
 | 
			
		||||
@@ -1141,6 +1159,9 @@
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.IO.Compression.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wpa81/_._": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtimeTargets": {
 | 
			
		||||
          "runtimes/unix/lib/netstandard1.3/System.IO.Compression.dll": {
 | 
			
		||||
            "assetType": "runtime",
 | 
			
		||||
@@ -1400,6 +1421,9 @@
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Net.Http.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wpa81/_._": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtimeTargets": {
 | 
			
		||||
          "runtimes/unix/lib/netstandard1.6/System.Net.Http.dll": {
 | 
			
		||||
            "assetType": "runtime",
 | 
			
		||||
@@ -1453,6 +1477,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Net.Primitives.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Net.Requests/4.0.11": {
 | 
			
		||||
@@ -1475,6 +1502,9 @@
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Net.Requests.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtimeTargets": {
 | 
			
		||||
          "runtimes/unix/lib/netstandard1.3/System.Net.Requests.dll": {
 | 
			
		||||
            "assetType": "runtime",
 | 
			
		||||
@@ -1650,6 +1680,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.Reflection.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Reflection.DispatchProxy/4.0.1": {
 | 
			
		||||
@@ -1728,6 +1761,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.0/System.Reflection.Extensions.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Reflection.Metadata/1.3.0": {
 | 
			
		||||
@@ -1765,6 +1801,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.0/System.Reflection.Primitives.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Reflection.TypeExtensions/4.1.0": {
 | 
			
		||||
@@ -1807,6 +1846,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.0/System.Resources.ResourceManager.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Resources.ResourceWriter/4.0.0-beta-22816": {
 | 
			
		||||
@@ -1830,6 +1872,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.Runtime.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp80+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Runtime.Extensions/4.1.0": {
 | 
			
		||||
@@ -1841,6 +1886,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.Runtime.Extensions.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Runtime.Handles/4.0.1": {
 | 
			
		||||
@@ -1866,6 +1914,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.5/System.Runtime.InteropServices.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Runtime.InteropServices.RuntimeInformation/4.0.0": {
 | 
			
		||||
@@ -2218,6 +2269,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Text.Encoding.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Text.Encoding.CodePages/4.0.1": {
 | 
			
		||||
@@ -2256,6 +2310,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Text.Encoding.Extensions.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Text.RegularExpressions/4.1.0": {
 | 
			
		||||
@@ -2319,6 +2376,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "ref/netstandard1.3/System.Threading.Tasks.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win8+wp8+wpa81/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "System.Threading.Tasks.Dataflow/4.6.0": {
 | 
			
		||||
@@ -2522,6 +2582,15 @@
 | 
			
		||||
          "lib/netstandard1.3/_._": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "VideoLibrary/1.3.4": {
 | 
			
		||||
        "type": "package",
 | 
			
		||||
        "compile": {
 | 
			
		||||
          "lib/portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10/libvideo.dll": {}
 | 
			
		||||
        },
 | 
			
		||||
        "runtime": {
 | 
			
		||||
          "lib/portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10/libvideo.dll": {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "Discord.Net/1.0.0-dev": {
 | 
			
		||||
        "type": "project",
 | 
			
		||||
        "framework": ".NETStandard,Version=v1.3",
 | 
			
		||||
@@ -7871,6 +7940,16 @@
 | 
			
		||||
        "ref/xamarinwatchos10/_._"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "VideoLibrary/1.3.4": {
 | 
			
		||||
      "sha512": "HZ2RAE9xx/sjJGnwm8etawoJXYluaYGas4bAFpE14S62NFodNKzUf7Cm9TQ+JFJxAdY+1g1FEKk1b6FPSv9aMg==",
 | 
			
		||||
      "type": "package",
 | 
			
		||||
      "path": "VideoLibrary/1.3.4",
 | 
			
		||||
      "files": [
 | 
			
		||||
        "VideoLibrary.1.3.4.nupkg.sha512",
 | 
			
		||||
        "VideoLibrary.nuspec",
 | 
			
		||||
        "lib/portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10/libvideo.dll"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "Discord.Net/1.0.0-dev": {
 | 
			
		||||
      "type": "project",
 | 
			
		||||
      "path": "../../discord.net/src/Discord.Net/project.json",
 | 
			
		||||
@@ -7895,7 +7974,8 @@
 | 
			
		||||
      "NLog >= 4.4.0-betaV15",
 | 
			
		||||
      "Newtonsoft.Json >= 9.0.1",
 | 
			
		||||
      "System.Diagnostics.Contracts >= 4.0.1",
 | 
			
		||||
      "System.Resources.ResourceWriter >= 4.0.0-beta-22816"
 | 
			
		||||
      "System.Resources.ResourceWriter >= 4.0.0-beta-22816",
 | 
			
		||||
      "VideoLibrary >= 1.3.4"
 | 
			
		||||
    ],
 | 
			
		||||
    ".NETCoreApp,Version=v1.0": []
 | 
			
		||||
  },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user