From 941162a739aaa8d95f2bbb7b60fa952300214b67 Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 21 Dec 2016 17:29:25 +0530 Subject: [PATCH 01/18] Music and Overwatch Fix - Fixed more like bypassed the issue with now playing and list queue when a playlist of more than 50 song is queued. - added embeds to list queue and song removed (thanks to private) - fixed the embeds for local files and separated the url for youtube and soundcloud to prevent issues with radio and local queues, - added slow of 2s/queue to youtube playlist queue to patch the google api errors and issue of missing few songs from playlist due to that. - pause, resume, playing and finishes messages now do not spam the chat, there will always be one of each message on apply. - moved the playing msg to fix the bot spamming playing message instead of finish msg and spams the chat. - overwatch now shows stats for users with no competitive plays. --- src/NadekoBot/Modules/Music/Classes/Song.cs | 9 +- src/NadekoBot/Modules/Music/Music.cs | 175 ++++++++++++++---- .../Searches/Commands/OverwatchCommands.cs | 18 +- src/NadekoBot/project.json | 2 +- 4 files changed, 161 insertions(+), 43 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 2623f680..bfe9ea31 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -47,14 +47,19 @@ namespace NadekoBot.Modules.Music.Classes var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); var str = $"{(int)time.TotalMinutes}m {time.Seconds}s / "; if (TotalLength == TimeSpan.Zero) - str += "**?**"; + str += "(?)"; else if (TotalLength == TimeSpan.MaxValue) str += "**∞**"; else str += $"{(int)TotalLength.TotalMinutes}m {TotalLength.Seconds}s"; return str; } - + public string PrettyMusicPlayTime() + { + var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); + var str = $"{(int)time.TotalMinutes}m {time.Seconds}s "; + return str; + } const int milliseconds = 20; const int samplesPerFrame = (48000 / 1000) * milliseconds; const int frameBytes = 3840; //16-bit, 2 channels diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 81e5c95d..9d0eee8f 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -168,28 +168,58 @@ namespace NadekoBot.Modules.Music var currentSong = musicPlayer.CurrentSong; if (currentSong == null) - return; - - if (currentSong.TotalLength == TimeSpan.Zero) { - await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + await channel.SendErrorAsync("🎡 No active music player.").ConfigureAwait(false); + return; } + //if (currentSong.TotalLength == TimeSpan.Zero) + //{ + //await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + //} + //var toSend = $"🎡 Currently Playing {currentSong.PrettyName} " + $"`{currentSong.PrettyCurrentTime()}`\n"; - var toSend = $"🎡 Currently Playing {currentSong.PrettyName}\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; + //var toSend = $"🎡 Currently Playing {currentSong.PrettyName}\n"; + + //I did that ^ because current song, bugs when a youtube playlist is queued with more than 50 song, it more like a bug with youtube page token I believe. + + const int itemsPerPage = 15; int startAt = itemsPerPage * (page - 1); var number = 1 + startAt; - await channel.SendConfirmAsync(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithDescription(string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` **[{v.SongInfo.Title}]({v.SongInfo.Query})** `{v.PrettyProvider} | {v.PrettyUser}`"))) + .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) + .WithColor(NadekoBot.OkColor); + if (musicPlayer.RepeatSong) + { + embed.WithTitle($"πŸ”‚ Repeating Song: {currentSong.SongInfo.Title}"); + } + else if (musicPlayer.RepeatPlaylist) + { + embed.WithTitle("πŸ” Repeating Playlist"); + } + if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) + { + embed.WithTitle("πŸ” Song queue is full!"); + } + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + + + //var toSend = $"test"; //this was for testing + //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.SendConfirmAsync(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -205,25 +235,43 @@ namespace NadekoBot.Modules.Music if (currentSong == null) return; var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); - - if (currentSong.TotalLength == TimeSpan.Zero) - { - await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); - } + var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) .WithTitle($"{currentSong.SongInfo.Title}") - .WithUrl($"{currentSong.SongInfo.Query}") - .WithDescription($"{currentSong.PrettyCurrentTime()}") + //.WithDescription($"{currentSong.PrettyCurrentTime()}") .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.PrettyUser}")) - .WithColor(NadekoBot.OkColor); + .WithColor(NadekoBot.OkColor); if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase)) { embed.WithThumbnail(tn => tn.Url = $"https://img.youtube.com/vi/{videoid}/0.jpg"); + embed.WithUrl($"{currentSong.SongInfo.Query}"); + if (musicPlayer.Playlist.Count < 50) + { + if (currentSong.TotalLength == TimeSpan.Zero) + { + await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + } + embed.WithDescription($"{currentSong.PrettyCurrentTime()}"); + } + else if (musicPlayer.Playlist.Count > 50) + { + embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); + } } else if (currentSong.SongInfo.Provider.Equals("SoundCloud", StringComparison.OrdinalIgnoreCase)) { embed.WithThumbnail(tn => tn.Url = $"{currentSong.SongInfo.AlbumArt}"); + embed.WithUrl($"{currentSong.SongInfo.Query}"); + if (currentSong.TotalLength == TimeSpan.Zero) + { + await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + } + embed.WithDescription($"{currentSong.PrettyCurrentTime()}"); + } + else if (currentSong.SongInfo.Provider.Equals("Local File", StringComparison.OrdinalIgnoreCase)) + { + embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); } await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } @@ -310,17 +358,22 @@ namespace NadekoBot.Modules.Music } 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)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, id, true).ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(false); //fixes google api error for few songs on playlist.// } catch (SongNotFoundException) { } catch { break; } + } + await msg.ModifyAsync(m => m.Content = "βœ… Playlist queue complete.").ConfigureAwait(false); } @@ -453,7 +506,13 @@ namespace NadekoBot.Modules.Music return; var song = (musicPlayer.Playlist as List)?[num - 1]; musicPlayer.RemoveSongAt(num - 1); - await channel.SendConfirmAsync($"🎡 Track {song.PrettyName} at position `#{num}` has been **removed**.").ConfigureAwait(false); + //await channel.SendConfirmAsync($"🎡 Track {song.PrettyName} at position `#{num}` has been **removed**.").ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName("Song Removed!").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(80)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.PrettyUser}`").WithIsInline(true)) + .WithColor(NadekoBot.ErrorColor); + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -646,9 +705,16 @@ namespace NadekoBot.Modules.Music playlists = uow.MusicPlaylists.GetPlaylistsOnPage(num); } - await channel.SendConfirmAsync($@"🎢 **Page {num} of saved playlists:** + //await channel.SendConfirmAsync($@"🎢 **Page {num} of saved playlists:** -" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); +//" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); + + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **{r.Author}**\t ({r.Songs.Count} songs)"))) + .WithColor(NadekoBot.OkColor); + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + } //todo only author or owner @@ -805,10 +871,14 @@ namespace NadekoBot.Modules.Music try { if (lastFinishedMessage != null) - await lastFinishedMessage.DeleteAsync().ConfigureAwait(false); - if (playingMessage != null) - await playingMessage.DeleteAsync().ConfigureAwait(false); - try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + { + await lastFinishedMessage.DeleteAsync().ConfigureAwait(false); + try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + } + else + { + try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + } 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); @@ -822,21 +892,50 @@ namespace NadekoBot.Modules.Music if (song.PrintStatusMessage) { var sender = s as MusicPlayer; + var msgTxt = $"🎡 Playing {song.PrettyName}\t `Vol: {(int)(sender.Volume * 100)}%`"; if (sender == null) return; - - var msgTxt = $"🎡 Playing {song.PrettyName}\t `Vol: {(int)(sender.Volume * 100)}%`"; - try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + if (playingMessage != null) + { + await playingMessage.DeleteAsync().ConfigureAwait(false); + try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + } + else + { + try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + } } }; + IUserMessage resumemsg = null; + IUserMessage pausemsg = null; mp.OnPauseChanged += async (paused) => { try { if (paused) - await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); + { + if (pausemsg != null) + { + await pausemsg.DeleteAsync().ConfigureAwait(false); + try { pausemsg = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); } catch { } + } + else + { + try { pausemsg = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); } catch { } + } + } else - await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); + { + if (resumemsg != null) + { + await resumemsg.DeleteAsync().ConfigureAwait(false); + try { resumemsg = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); } catch { } + } + else + { + try { resumemsg = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); } catch { } + } + } } catch { } }; @@ -862,7 +961,7 @@ namespace NadekoBot.Modules.Music { try { - var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title.TrimTo(55)}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); + var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); var t = Task.Run(async () => { try diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index ec3ddfb1..69697608 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -37,6 +37,7 @@ namespace NadekoBot.Modules.Searches var rankimg = $"{model.Competitive.rank_img}"; var rank = $"{model.Competitive.rank}"; + var competitiveplay = $"{model.Games.Competitive.played}"; if (string.IsNullOrWhiteSpace(rank)) { var embed = new EmbedBuilder() @@ -72,8 +73,21 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - return; - } + } + if (string.IsNullOrWhiteSpace(competitiveplay)) + { + var embed = new EmbedBuilder() + .WithAuthor(eau => eau.WithName($"{model.username}") + .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") + .WithIconUrl($"{model.avatar}")) + .WithThumbnail(th => th.WithUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png")) + .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"0 hour").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) + .WithColor(NadekoBot.OkColor); + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + } } catch { diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index cbf49aa2..4aeef449 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -26,7 +26,7 @@ "target": "project" }, "Google.Apis.Urlshortener.v1": "1.19.0.138", - "Google.Apis.YouTube.v3": "1.19.0.655", + "Google.Apis.YouTube.v3": "1.20.0.701", "ImageSharp": "1.0.0-alpha-000079", "Microsoft.EntityFrameworkCore": "1.1.0", "Microsoft.EntityFrameworkCore.Design": "1.1.0", From 02325d1f5d6f98092e8db5c4fae9a23b9241a29b Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 22 Dec 2016 05:22:52 +0530 Subject: [PATCH 02/18] More changes --- src/NadekoBot/Modules/Music/Classes/Song.cs | 25 ++-- src/NadekoBot/Modules/Music/Music.cs | 119 ++++++++++++++------ src/NadekoBot/Modules/Searches/Searches.cs | 2 +- 3 files changed, 97 insertions(+), 49 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index bfe9ea31..e80a16be 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -24,28 +24,29 @@ namespace NadekoBot.Modules.Music.Classes public string Query { get; set; } public string Title { get; set; } public string Uri { get; set; } - public string AlbumArt { get; set; } + public string AlbumArt { get; set; } } public class Song { - public StreamState State { get; set; } + public StreamState State { get; set; } public string PrettyName => $"**{SongInfo.Title.TrimTo(55)} `{(SongInfo.Provider ?? "-")} by {QueuerName}`**"; - //$"{SongInfo.Title.TrimTo(70)}"; + //$"{SongInfo.Title.TrimTo(70)}"; public SongInfo SongInfo { get; } public MusicPlayer MusicPlayer { get; set; } - - public string PrettyUser => + + public string PrettyUser => $"{QueuerName}"; public string QueuerName { get; set; } - - public string PrettyProvider => + + public string PrettyProvider => $"{(SongInfo.Provider ?? "No Provider")}"; public string PrettyCurrentTime() { var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); - var str = $"{(int)time.TotalMinutes}m {time.Seconds}s / "; + //var str = $"{(int)time.TotalMinutes}m {time.Seconds}s / "; + var str = $""; if (TotalLength == TimeSpan.Zero) str += "(?)"; else if (TotalLength == TimeSpan.MaxValue) @@ -57,7 +58,7 @@ namespace NadekoBot.Modules.Music.Classes public string PrettyMusicPlayTime() { var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); - var str = $"{(int)time.TotalMinutes}m {time.Seconds}s "; + var str = $"{(int)time.TotalMinutes}m {time.Seconds}s"; return str; } const int milliseconds = 20; @@ -108,8 +109,6 @@ namespace NadekoBot.Modules.Music.Classes SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo, frameBytes * 100); var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false); - bytesSent = 0; - try { var attempt = 0; @@ -325,7 +324,7 @@ namespace NadekoBot.Modules.Music.Classes Uri = svideo.StreamLink, ProviderType = musicType, Query = svideo.TrackLink, - AlbumArt = svideo.artwork_url, + AlbumArt = svideo.artwork_url, }) { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; } @@ -340,7 +339,7 @@ namespace NadekoBot.Modules.Music.Classes Uri = svideo.StreamLink, ProviderType = MusicType.Normal, Query = svideo.TrackLink, - AlbumArt = svideo.artwork_url, + AlbumArt = svideo.artwork_url, }) { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 9d0eee8f..6040c162 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -98,16 +98,30 @@ namespace NadekoBot.Modules.Music [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public Task Destroy(IUserMessage umsg) + public async Task Destroy(IUserMessage umsg) + //public Task Destroy(IUserMessage umsg) { var channel = (ITextChannel)umsg.Channel; + var msg = + await channel.SendMessageAsync($"πŸ”΄ Initiating Self-Destruct Sequence!").ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "βšͺ️ Self-Destruct Sequence Initiated T Minus 4").ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "πŸ”΄ Self-Destruct Sequence Initiated T Minus 3").ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "βšͺ️ Self-Destruct Sequence Initiated T Minus 2").ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "πŸ”΄ Self-Destruct Sequence Initiated T Minus 1").ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "🌸 Nice Try! I am Indestructible.").ConfigureAwait(false); + - MusicPlayer musicPlayer; + /*MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask; if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel) if(MusicPlayers.TryRemove(channel.Guild.Id, out musicPlayer)) musicPlayer.Destroy(); - return Task.CompletedTask; + return Task.CompletedTask;*/ } [NadekoCommand, Usage, Description, Aliases] @@ -173,27 +187,29 @@ namespace NadekoBot.Modules.Music return; } - //if (currentSong.TotalLength == TimeSpan.Zero) - //{ - //await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); - //} + if (currentSong.TotalLength == TimeSpan.Zero) + { + await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); + } + //var toSend = $"🎡 Currently Playing {currentSong.PrettyName} " + $"`{currentSong.PrettyCurrentTime()}`\n"; //var toSend = $"🎡 Currently Playing {currentSong.PrettyName}\n"; //I did that ^ because current song, bugs when a youtube playlist is queued with more than 50 song, it more like a bug with youtube page token I believe. - - const int itemsPerPage = 15; + + const int itemsPerPage = 10; int startAt = itemsPerPage * (page - 1); var number = 1 + startAt; + var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) - .WithDescription(string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` **[{v.SongInfo.Title}]({v.SongInfo.Query})** `{v.PrettyProvider} | {v.PrettyUser}`"))) + .WithDescription(string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(10).Select(v => $"`{number++}.` **[{v.SongInfo.Title.TrimTo(70)}]({v.SongInfo.Query})**\n\t\t*{v.PrettyCurrentTime()}* **|** *{v.PrettyProvider}* **|** *{v.QueuerName}*"))) .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) .WithColor(NadekoBot.OkColor); if (musicPlayer.RepeatSong) { - embed.WithTitle($"πŸ”‚ Repeating Song: {currentSong.SongInfo.Title}"); + embed.WithTitle($"πŸ”‚ Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); } else if (musicPlayer.RepeatPlaylist) { @@ -201,8 +217,8 @@ namespace NadekoBot.Modules.Music } if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) { - embed.WithTitle("πŸ” Song queue is full!"); - } + embed.WithTitle("🎡 Song queue is full!"); + } await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); @@ -240,24 +256,24 @@ namespace NadekoBot.Modules.Music .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) .WithTitle($"{currentSong.SongInfo.Title}") //.WithDescription($"{currentSong.PrettyCurrentTime()}") - .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.PrettyUser}")) + .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.QueuerName}")) .WithColor(NadekoBot.OkColor); if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase)) { embed.WithThumbnail(tn => tn.Url = $"https://img.youtube.com/vi/{videoid}/0.jpg"); embed.WithUrl($"{currentSong.SongInfo.Query}"); - if (musicPlayer.Playlist.Count < 50) - { + //if (musicPlayer.Playlist.Count < 50) + //{ if (currentSong.TotalLength == TimeSpan.Zero) { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } - embed.WithDescription($"{currentSong.PrettyCurrentTime()}"); - } - else if (musicPlayer.Playlist.Count > 50) - { - embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); - } + embed.WithDescription($"{currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); + //} + //else if (musicPlayer.Playlist.Count > 50) + //{ + //embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); + //} } else if (currentSong.SongInfo.Provider.Equals("SoundCloud", StringComparison.OrdinalIgnoreCase)) { @@ -267,7 +283,7 @@ namespace NadekoBot.Modules.Music { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } - embed.WithDescription($"{currentSong.PrettyCurrentTime()}"); + embed.WithDescription($"{currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); } else if (currentSong.SongInfo.Provider.Equals("Local File", StringComparison.OrdinalIgnoreCase)) { @@ -367,7 +383,7 @@ namespace NadekoBot.Modules.Music try { await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, id, true).ConfigureAwait(false); - await Task.Delay(2000).ConfigureAwait(false); //fixes google api error for few songs on playlist.// + //await Task.Delay(2000).ConfigureAwait(false); //fixes google api error for few songs on playlist.// } catch (SongNotFoundException) { } catch { break; } @@ -510,7 +526,7 @@ namespace NadekoBot.Modules.Music var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName("Song Removed!").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(80)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.PrettyUser}`").WithIsInline(true)) + .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(70)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.QueuerName.TrimTo(15)}`").WithIsInline(true)) .WithColor(NadekoBot.ErrorColor); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } @@ -711,7 +727,7 @@ namespace NadekoBot.Modules.Music var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) - .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **{r.Author}**\t ({r.Songs.Count} songs)"))) + .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **`{r.Author}`**\t ({r.Songs.Count} songs)"))) .WithColor(NadekoBot.OkColor); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); @@ -816,7 +832,7 @@ namespace NadekoBot.Modules.Music } else { - await channel.SendConfirmAsync($"🎢 Selected song **{selSong.SongInfo.Title}**: <{selSong.SongInfo.Query}>").ConfigureAwait(false); + await channel.SendMessageAsync($"🎢 Selected song **{selSong.SongInfo.Title}**: <{selSong.SongInfo.Query}>").ConfigureAwait(false); } } else @@ -824,7 +840,7 @@ namespace NadekoBot.Modules.Music var curSong = musicPlayer.CurrentSong; if (curSong == null) return; - await channel.SendConfirmAsync($"🎢 Current song **{curSong.SongInfo.Title}**: <{curSong.SongInfo.Query}>").ConfigureAwait(false); + await channel.SendMessageAsync($"🎢 Current song **{curSong.SongInfo.Title}**: <{curSong.SongInfo.Query}>").ConfigureAwait(false); } } @@ -873,11 +889,23 @@ namespace NadekoBot.Modules.Music if (lastFinishedMessage != null) { await lastFinishedMessage.DeleteAsync().ConfigureAwait(false); - try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + //try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithTitle($"{song.SongInfo.Title}") + .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) + .Build()) + .ConfigureAwait(false); } catch { } } else { - try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } + try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithTitle($"{song.SongInfo.Title}") + .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) + .Build()) + .ConfigureAwait(false); } catch { } + //try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } } if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube") { @@ -892,17 +920,31 @@ namespace NadekoBot.Modules.Music if (song.PrintStatusMessage) { var sender = s as MusicPlayer; - var msgTxt = $"🎡 Playing {song.PrettyName}\t `Vol: {(int)(sender.Volume * 100)}%`"; + //var msgTxt = $"🎡 Playing {song.PrettyName}\t `Vol: {(int)(sender.Volume * 100)}%`"; if (sender == null) return; if (playingMessage != null) { await playingMessage.DeleteAsync().ConfigureAwait(false); - try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithTitle($"{song.SongInfo.Title}") + .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") + .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) + .Build()) + .ConfigureAwait(false); } catch { } } else { - try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } + try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithTitle($"{song.SongInfo.Title}") + .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") + .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) + .Build()) + .ConfigureAwait(false); } catch { } } } }; @@ -961,8 +1003,15 @@ namespace NadekoBot.Modules.Music { try { - var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); - var t = Task.Run(async () => + //var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); + var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithAuthor(eab => eab.WithName("Queued Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithTitle($"{resolvedSong.SongInfo.Title}") + .WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}") + .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) + .Build()) + .ConfigureAwait(false); + var t = Task.Run(async () => { try { diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index a3f5eb0e..c7e5367a 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -221,7 +221,7 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(terms)) return; - await channel.SendConfirmAsync($"https://google.com/search?q={ WebUtility.UrlEncode(terms).Replace(' ', '+') }") + await channel.SendMessageAsync($"https://google.com/search?q={ WebUtility.UrlEncode(terms).Replace(' ', '+') }") .ConfigureAwait(false); } From d8811aad0acd22bf00d8160413333f1e5c0c46cb Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 22 Dec 2016 05:32:05 +0530 Subject: [PATCH 03/18] animated destroy command replaced with message --- src/NadekoBot/Modules/Music/Music.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 6040c162..b3b27bc5 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -102,20 +102,8 @@ namespace NadekoBot.Modules.Music //public Task Destroy(IUserMessage umsg) { var channel = (ITextChannel)umsg.Channel; - var msg = - await channel.SendMessageAsync($"πŸ”΄ Initiating Self-Destruct Sequence!").ConfigureAwait(false); - await Task.Delay(2000).ConfigureAwait(false); - await msg.ModifyAsync(m => m.Content = "βšͺ️ Self-Destruct Sequence Initiated T Minus 4").ConfigureAwait(false); - await Task.Delay(1000).ConfigureAwait(false); - await msg.ModifyAsync(m => m.Content = "πŸ”΄ Self-Destruct Sequence Initiated T Minus 3").ConfigureAwait(false); - await Task.Delay(1000).ConfigureAwait(false); - await msg.ModifyAsync(m => m.Content = "βšͺ️ Self-Destruct Sequence Initiated T Minus 2").ConfigureAwait(false); - await Task.Delay(1000).ConfigureAwait(false); - await msg.ModifyAsync(m => m.Content = "πŸ”΄ Self-Destruct Sequence Initiated T Minus 1").ConfigureAwait(false); - await Task.Delay(2000).ConfigureAwait(false); - await msg.ModifyAsync(m => m.Content = "🌸 Nice Try! I am Indestructible.").ConfigureAwait(false); - - + await channel.SendErrorAsync("Command is temporarily disabled.").ConfigureAwait(false); + /*MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask; if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel) From b5c50b22bae7ad013d93d818890158e48f57c9e7 Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 22 Dec 2016 05:36:59 +0530 Subject: [PATCH 04/18] Embed icon url changed (thanks to Kwoth) --- src/NadekoBot/Modules/Music/Music.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index b3b27bc5..0bd7144d 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -191,7 +191,7 @@ namespace NadekoBot.Modules.Music var number = 1 + startAt; var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithDescription(string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(10).Select(v => $"`{number++}.` **[{v.SongInfo.Title.TrimTo(70)}]({v.SongInfo.Query})**\n\t\t*{v.PrettyCurrentTime()}* **|** *{v.PrettyProvider}* **|** *{v.QueuerName}*"))) .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) .WithColor(NadekoBot.OkColor); @@ -241,7 +241,7 @@ namespace NadekoBot.Modules.Music var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{currentSong.SongInfo.Title}") //.WithDescription($"{currentSong.PrettyCurrentTime()}") .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.QueuerName}")) @@ -512,7 +512,7 @@ namespace NadekoBot.Modules.Music musicPlayer.RemoveSongAt(num - 1); //await channel.SendConfirmAsync($"🎡 Track {song.PrettyName} at position `#{num}` has been **removed**.").ConfigureAwait(false); var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Song Removed!").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Song Removed!").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(70)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.QueuerName.TrimTo(15)}`").WithIsInline(true)) .WithColor(NadekoBot.ErrorColor); @@ -569,7 +569,7 @@ namespace NadekoBot.Modules.Music var embed = new EmbedBuilder() .WithTitle($"{s.SongInfo.Title.TrimTo(70)}") .WithUrl($"{s.SongInfo.Query}") - .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true)) .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); @@ -714,7 +714,7 @@ namespace NadekoBot.Modules.Music //" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **`{r.Author}`**\t ({r.Songs.Count} songs)"))) .WithColor(NadekoBot.OkColor); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); @@ -879,7 +879,7 @@ namespace NadekoBot.Modules.Music await lastFinishedMessage.DeleteAsync().ConfigureAwait(false); //try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{song.SongInfo.Title}") .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) .Build()) @@ -888,7 +888,7 @@ namespace NadekoBot.Modules.Music else { try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{song.SongInfo.Title}") .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) .Build()) @@ -916,7 +916,7 @@ namespace NadekoBot.Modules.Music await playingMessage.DeleteAsync().ConfigureAwait(false); //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{song.SongInfo.Title}") .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) @@ -927,7 +927,7 @@ namespace NadekoBot.Modules.Music { //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{song.SongInfo.Title}") .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) @@ -993,7 +993,7 @@ namespace NadekoBot.Modules.Music { //var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Queued Song").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .WithAuthor(eab => eab.WithName("Queued Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithTitle($"{resolvedSong.SongInfo.Title}") .WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}") .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) From 727da69c819a625b83b8b678e221ac2fcc639f4b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 04:49:33 +0100 Subject: [PATCH 05/18] Some cleanup and many music improvements --- .../Modules/ClashOfClans/ClashOfClans.cs | 42 +- .../CustomReactions/CustomReactions.cs | 6 +- .../Games/Commands/Hangman/HangmanGame.cs | 2 +- .../Games/Commands/Trivia/TriviaGame.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 2 +- src/NadekoBot/Modules/Help/Help.cs | 2 +- .../Modules/Music/Classes/MusicControls.cs | 13 +- .../Modules/Music/Classes/MusicExtensions.cs | 15 + src/NadekoBot/Modules/Music/Classes/Song.cs | 315 ++------------- .../Modules/Music/Classes/SongHandler.cs | 212 ++++++++++ src/NadekoBot/Modules/Music/Music.cs | 361 +++++++----------- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 2 +- .../Modules/Searches/Commands/LoLCommands.cs | 2 +- .../Searches/Commands/OMDB/OmdbProvider.cs | 3 +- .../Searches/Commands/OverwatchCommands.cs | 6 +- .../Commands/PokemonSearchCommands.cs | 4 +- .../Modules/Searches/Commands/XkcdCommands.cs | 2 +- src/NadekoBot/Modules/Searches/Searches.cs | 12 +- .../Modules/Utility/Commands/InfoCommands.cs | 6 +- .../Utility/Commands/UnitConversion.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 2 +- src/NadekoBot/_Extensions/Extensions.cs | 14 + 22 files changed, 475 insertions(+), 552 deletions(-) create mode 100644 src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs create mode 100644 src/NadekoBot/Modules/Music/Classes/SongHandler.cs diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 81be7144..0546837a 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -11,6 +11,7 @@ using Discord.WebSocket; using NadekoBot.Services.Database.Models; using System.Linq; using NadekoBot.Extensions; +using System.Threading; namespace NadekoBot.Modules.ClashOfClans { @@ -19,6 +20,8 @@ namespace NadekoBot.Modules.ClashOfClans { public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); + private static Timer checkWarTimer { get; } + static ClashOfClans() { using (var uow = DbHandler.UnitOfWork()) @@ -32,13 +35,21 @@ namespace NadekoBot.Modules.ClashOfClans ?.GetTextChannel(cw.ChannelId); return cw; }) - .Where(cw => cw?.Channel != null) + .Where(cw => cw.Channel != null) .GroupBy(cw => cw.GuildId) .ToDictionary(g => g.Key, g => g.ToList())); } - } - public ClashOfClans() : base() - { + + checkWarTimer = new Timer(async _ => + { + foreach (var kvp in ClashWars) + { + foreach (var war in kvp.Value) + { + try { await CheckWar(TimeSpan.FromHours(2), war).ConfigureAwait(false); } catch { } + } + } + }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } private static async Task CheckWar(TimeSpan callExpire, ClashWar war) @@ -46,12 +57,21 @@ namespace NadekoBot.Modules.ClashOfClans var Bases = war.Bases; for (var i = 0; i < Bases.Count; i++) { - if (Bases[i].CallUser == null) continue; - if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) + var callUser = Bases[i].CallUser; + if (callUser == null) continue; + if ((!Bases[i].BaseDestroyed) && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) { - Bases[i] = null; - try { await war.Channel.SendErrorAsync($"β—πŸ”°**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); } catch { } - } + if (Bases[i].Stars != 3) + Bases[i].BaseDestroyed = true; + else + Bases[i] = null; + try + { + SaveWar(war); + await war.Channel.SendErrorAsync($"β—πŸ”°**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); + } + catch { } + } } } @@ -216,7 +236,7 @@ namespace NadekoBot.Modules.ClashOfClans { var channel = (ITextChannel)umsg.Channel; - var warsInfo = GetWarInfo(umsg,number); + var warsInfo = GetWarInfo(umsg, number); if (warsInfo == null) { await channel.SendErrorAsync("πŸ”° That war does not exist.").ConfigureAwait(false); @@ -359,4 +379,4 @@ namespace NadekoBot.Modules.ClashOfClans } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index d7c28f91..d68aeab6 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -115,7 +115,7 @@ namespace NadekoBot.Modules.CustomReactions reactions.Add(cr); } - await imsg.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await imsg.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle("New Custom Reaction") .WithDescription($"#{cr.Id}") .AddField(efb => efb.WithName("Trigger").WithValue(key)) @@ -225,7 +225,7 @@ namespace NadekoBot.Modules.CustomReactions await imsg.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false); else { - await imsg.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await imsg.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription($"#{id}") .AddField(efb => efb.WithName("Trigger").WithValue(found.Trigger)) .AddField(efb => efb.WithName("Response").WithValue(found.Response + "\n```css\n" + found.Response + "```")) @@ -304,7 +304,7 @@ namespace NadekoBot.Modules.CustomReactions await imsg.Channel.EmbedAsync(ReactionStats.OrderByDescending(x => x.Value) .Skip((page - 1)*9) .Take(9) - .Aggregate(new EmbedBuilder().WithColor(NadekoBot.OkColor).WithTitle($"Custom Reaction stats page #{page}"), + .Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction stats page #{page}"), (agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))) .Build()) .ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 575e8edf..6baa9404 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman if (Errors >= MaxErrors) await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.ErrorColor).Build()).ConfigureAwait(false); else - await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.OkColor).Build()).ConfigureAwait(false); + await GameChannel.EmbedAsync(embed.WithOkColor().Build()).ConfigureAwait(false); } private Task PotentialGuess(IMessage msg) diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 534c5040..7a2f15c5 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Games.Trivia Games.TriviaCommands.RunningTrivias.TryRemove(channel.Guild.Id, out throwaway); try { - await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle("Leaderboard") .WithDescription(GetLeaderboard()) .Build(), "Trivia game ended.").ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 592881d1..8272598a 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Games return; var rng = new NadekoRandom(); - await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false)) .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false)) .Build()); diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 2b824111..2f25f31a 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Help var embed = new EmbedBuilder() .AddField(fb => fb.WithIndex(1).WithName(str).WithValue($"{ string.Format(com.Summary, com.Module.Prefix)} { GetCommandRequirements(com)}").WithIsInline(true)) .AddField(fb => fb.WithIndex(2).WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Prefix)}").WithIsInline(false)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 8555d3a3..5d10a22a 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -41,9 +41,9 @@ namespace NadekoBot.Modules.Music.Classes public float Volume { get; private set; } - public event EventHandler OnCompleted = delegate { }; - public event EventHandler OnStarted = delegate { }; - public event Action OnPauseChanged = delegate { }; + public event Func OnCompleted = delegate { return Task.CompletedTask; }; + public event Func OnStarted = delegate { return Task.CompletedTask; }; + public event Func OnPauseChanged = delegate { return Task.CompletedTask; }; public IVoiceChannel PlaybackVoiceChannel { get; private set; } @@ -250,11 +250,11 @@ namespace NadekoBot.Modules.Music.Classes { var curSong = CurrentSong; var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && - s.TotalLength == TimeSpan.Zero); + s.TotalTime == TimeSpan.Zero); if (curSong != null) toUpdate = toUpdate.Append(curSong); var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3)) - .Distinct(); + .Distinct(); var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids); @@ -264,11 +264,12 @@ namespace NadekoBot.Modules.Music.Classes { if (s.SongInfo.Query.EndsWith(kvp.Key)) { - s.TotalLength = kvp.Value; + s.TotalTime = kvp.Value; return; } } }); + } public void Destroy() diff --git a/src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs b/src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs new file mode 100644 index 00000000..2840fd16 --- /dev/null +++ b/src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs @@ -0,0 +1,15 @@ +ο»Ώusing Discord; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Music.Classes +{ + public static class MusicExtensions + { + public static EmbedAuthorBuilder WithMusicIcon(this EmbedAuthorBuilder eab) => + eab.WithIconUrl("http://i.imgur.com/nhKS3PT.png"); + } +} diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index e80a16be..71daa7ec 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -18,60 +18,54 @@ namespace NadekoBot.Modules.Music.Classes { public string Provider { get; set; } public MusicType ProviderType { get; set; } - /// - /// Will be set only if the providertype is normal - /// public string Query { get; set; } public string Title { get; set; } public string Uri { get; set; } - public string AlbumArt { get; set; } + public string AlbumArt { get; set; } } + public class Song { - public StreamState State { get; set; } - public string PrettyName => - $"**{SongInfo.Title.TrimTo(55)} `{(SongInfo.Provider ?? "-")} by {QueuerName}`**"; - //$"{SongInfo.Title.TrimTo(70)}"; public SongInfo SongInfo { get; } public MusicPlayer MusicPlayer { get; set; } - - public string PrettyUser => - $"{QueuerName}"; public string QueuerName { get; set; } - - public string PrettyProvider => - $"{(SongInfo.Provider ?? "No Provider")}"; - public string PrettyCurrentTime() - { - var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); - //var str = $"{(int)time.TotalMinutes}m {time.Seconds}s / "; - var str = $""; - if (TotalLength == TimeSpan.Zero) - str += "(?)"; - else if (TotalLength == TimeSpan.MaxValue) - str += "**∞**"; - else - str += $"{(int)TotalLength.TotalMinutes}m {TotalLength.Seconds}s"; - return str; - } - public string PrettyMusicPlayTime() - { - var time = TimeSpan.FromSeconds(bytesSent / 3840 / 50); - var str = $"{(int)time.TotalMinutes}m {time.Seconds}s"; - return str; - } + public TimeSpan TotalTime { get; set; } = TimeSpan.Zero; + public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / 1000 / milliseconds); + const int milliseconds = 20; const int samplesPerFrame = (48000 / 1000) * milliseconds; const int frameBytes = 3840; //16-bit, 2 channels private ulong bytesSent { get; set; } = 0; - public bool PrintStatusMessage { get; set; } = true; + //pwetty + + public string PrettyProvider => + $"{(SongInfo.Provider ?? "No Provider")}"; + + public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime; + + public string PrettyName => $"**[{SongInfo.Title.TrimTo(70)}]({SongInfo.Query})**"; + + public string PrettyInfo => $"{PrettyTotalTime} | {PrettyProvider} | {QueuerName}"; + + public string PrettyFullName => $"{PrettyName}\n\t\t*{PrettyInfo}*"; + + public string PrettyCurrentTime => TotalTime.ToString(@"mm\:ss"); + + private string PrettyTotalTime { + get { + if (TotalTime == TimeSpan.Zero) + return "(?)"; + else if (TotalTime == TimeSpan.MaxValue) + return "**∞**"; + else + return TotalTime.ToString(@"mm\:ss"); + } + } private int skipTo = 0; - private Logger _log; - public int SkipTo { get { return skipTo; } set { @@ -80,7 +74,7 @@ namespace NadekoBot.Modules.Music.Classes } } - public TimeSpan TotalLength { get; set; } = TimeSpan.Zero; + private readonly Logger _log; public Song(SongInfo songInfo) { @@ -92,16 +86,9 @@ namespace NadekoBot.Modules.Music.Classes { var s = new Song(SongInfo); s.MusicPlayer = MusicPlayer; - s.State = StreamState.Queued; return s; } - public Song SetMusicPlayer(MusicPlayer mp) - { - this.MusicPlayer = mp; - return this; - } - public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); @@ -111,7 +98,7 @@ namespace NadekoBot.Modules.Music.Classes try { - var attempt = 0; + var attempt = 0; var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken, 1.MiB()); //Fast connection can do this easy var finished = false; @@ -132,7 +119,7 @@ namespace NadekoBot.Modules.Music.Classes _log.Warn("Slow connection buffering more to ensure no disruption, consider hosting in cloud"); continue; } - + if (inStream.BufferingCompleted && count == 1) { _log.Debug("Prebuffering canceled. Cannot get any data from the stream."); @@ -142,7 +129,7 @@ namespace NadekoBot.Modules.Music.Classes { continue; } - } + } else if (prebufferingTask.IsCanceled) { _log.Debug("Prebuffering canceled. Cannot get any data from the stream."); @@ -151,7 +138,7 @@ namespace NadekoBot.Modules.Music.Classes finished = true; } sw.Stop(); - _log.Debug("Prebuffering successfully completed in "+ sw.Elapsed); + _log.Debug("Prebuffering successfully completed in " + sw.Elapsed); var outStream = voiceClient.CreatePCMStream(960); @@ -163,7 +150,7 @@ namespace NadekoBot.Modules.Music.Classes //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); //await inStream.CopyToAsync(voiceClient.OutputStream); - if(read < frameBytes) + if (read < frameBytes) _log.Debug("read {0}", read); unchecked { @@ -210,7 +197,7 @@ namespace NadekoBot.Modules.Music.Classes finally { await bufferTask; - if(inStream != null) + if (inStream != null) inStream.Dispose(); } } @@ -224,35 +211,6 @@ namespace NadekoBot.Modules.Music.Classes _log.Debug("Buffering successfull"); } - /* - //stackoverflow ftw - private static byte[] AdjustVolume(byte[] audioSamples, float volume) - { - if (Math.Abs(volume - 1.0f) < 0.01f) - return audioSamples; - var array = new byte[audioSamples.Length]; - for (var i = 0; i < array.Length; i += 2) - { - - // convert byte pair to int - short buf1 = audioSamples[i + 1]; - short buf2 = audioSamples[i]; - - buf1 = (short)((buf1 & 0xff) << 8); - buf2 = (short)(buf2 & 0xff); - - var res = (short)(buf1 | buf2); - res = (short)(res * volume); - - // convert back - array[i] = (byte)res; - array[i + 1] = (byte)(res >> 8); - - } - return array; - } - */ - //aidiakapi ftw public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume) { @@ -278,202 +236,5 @@ namespace NadekoBot.Modules.Music.Classes return audioSamples; } - - public static async Task ResolveSong(string query, MusicType musicType = MusicType.Normal) - { - if (string.IsNullOrWhiteSpace(query)) - throw new ArgumentNullException(nameof(query)); - - if (musicType != MusicType.Local && IsRadioLink(query)) - { - musicType = MusicType.Radio; - query = await HandleStreamContainers(query).ConfigureAwait(false) ?? query; - } - - try - { - switch (musicType) - { - case MusicType.Local: - return new Song(new SongInfo - { - Uri = "\"" + Path.GetFullPath(query) + "\"", - Title = Path.GetFileNameWithoutExtension(query), - Provider = "Local File", - ProviderType = musicType, - Query = query, - }); - case MusicType.Radio: - return new Song(new SongInfo - { - Uri = query, - Title = $"{query}", - Provider = "Radio Stream", - ProviderType = musicType, - Query = query - }) - { TotalLength = TimeSpan.MaxValue }; - } - if (SoundCloud.Default.IsSoundCloudLink(query)) - { - var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false); - return new Song(new SongInfo - { - Title = svideo.FullName, - Provider = "SoundCloud", - Uri = svideo.StreamLink, - ProviderType = musicType, - Query = svideo.TrackLink, - AlbumArt = svideo.artwork_url, - }) - { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; - } - - if (musicType == MusicType.Soundcloud) - { - var svideo = await SoundCloud.Default.GetVideoByQueryAsync(query).ConfigureAwait(false); - return new Song(new SongInfo - { - Title = svideo.FullName, - Provider = "SoundCloud", - Uri = svideo.StreamLink, - ProviderType = MusicType.Normal, - Query = svideo.TrackLink, - AlbumArt = svideo.artwork_url, - }) - { TotalLength = TimeSpan.FromMilliseconds(svideo.Duration) }; - } - - 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.Run(async () => { try { return await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false); } catch { return Enumerable.Empty(); } }).ConfigureAwait(false); - var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio); - var video = videos - .Where(v => v.AudioBitrate < 256) - .OrderByDescending(v => v.AudioBitrate) - .FirstOrDefault(); - - if (video == null) // do something with this error - throw new Exception("Could not load any video elements based on the query."); - var m = Regex.Match(query, @"\?t=(?\d*)"); - int gotoTime = 0; - if (m.Captures.Count > 0) - int.TryParse(m.Groups["t"].ToString(), out gotoTime); - var song = new Song(new SongInfo - { - Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube" - Provider = "YouTube", - Uri = video.Uri, - Query = link, - ProviderType = musicType, - }); - song.SkipTo = gotoTime; - return song; - } - catch (Exception ex) - { - Console.WriteLine($"Failed resolving the link.{ex.Message}"); - return null; - } - } - - private static async Task HandleStreamContainers(string query) - { - string file = null; - try - { - using (var http = new HttpClient()) - { - file = await http.GetStringAsync(query).ConfigureAwait(false); - } - } - catch - { - return query; - } - if (query.Contains(".pls")) - { - //File1=http://armitunes.com:8000/ - //Regex.Match(query) - try - { - var m = Regex.Match(file, "File1=(?.*?)\\n"); - var res = m.Groups["url"]?.ToString(); - return res?.Trim(); - } - catch - { - Console.WriteLine($"Failed reading .pls:\n{file}"); - return null; - } - } - if (query.Contains(".m3u")) - { - /* -# This is a comment - C:\xxx4xx\xxxxxx3x\xx2xxxx\xx.mp3 - C:\xxx5xx\x6xxxxxx\x7xxxxx\xx.mp3 - */ - try - { - var m = Regex.Match(file, "(?^[^#].*)", RegexOptions.Multiline); - var res = m.Groups["url"]?.ToString(); - return res?.Trim(); - } - catch - { - Console.WriteLine($"Failed reading .m3u:\n{file}"); - return null; - } - - } - if (query.Contains(".asx")) - { - // - try - { - var m = Regex.Match(file, ".*?)\""); - var res = m.Groups["url"]?.ToString(); - return res?.Trim(); - } - catch - { - Console.WriteLine($"Failed reading .asx:\n{file}"); - return null; - } - } - if (query.Contains(".xspf")) - { - /* - - - - file:///mp3s/song_1.mp3 - */ - try - { - var m = Regex.Match(file, "(?.*?)"); - var res = m.Groups["url"]?.ToString(); - return res?.Trim(); - } - catch - { - Console.WriteLine($"Failed reading .xspf:\n{file}"); - return null; - } - } - - return query; - } - - private static bool IsRadioLink(string query) => - (query.StartsWith("http") || - query.StartsWith("ww")) - && - (query.Contains(".pls") || - query.Contains(".m3u") || - query.Contains(".asx") || - query.Contains(".xspf")); } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Music/Classes/SongHandler.cs b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs new file mode 100644 index 00000000..50166561 --- /dev/null +++ b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs @@ -0,0 +1,212 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using VideoLibrary; + +namespace NadekoBot.Modules.Music.Classes +{ + public static class SongHandler + { + public static async Task ResolveSong(string query, MusicType musicType = MusicType.Normal) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + if (musicType != MusicType.Local && IsRadioLink(query)) + { + musicType = MusicType.Radio; + query = await HandleStreamContainers(query).ConfigureAwait(false) ?? query; + } + + try + { + switch (musicType) + { + case MusicType.Local: + return new Song(new SongInfo + { + Uri = "\"" + Path.GetFullPath(query) + "\"", + Title = Path.GetFileNameWithoutExtension(query), + Provider = "Local File", + ProviderType = musicType, + Query = query, + }); + case MusicType.Radio: + return new Song(new SongInfo + { + Uri = query, + Title = $"{query}", + Provider = "Radio Stream", + ProviderType = musicType, + Query = query + }) + { TotalTime = TimeSpan.MaxValue }; + } + if (SoundCloud.Default.IsSoundCloudLink(query)) + { + var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false); + return new Song(new SongInfo + { + Title = svideo.FullName, + Provider = "SoundCloud", + Uri = svideo.StreamLink, + ProviderType = musicType, + Query = svideo.TrackLink, + AlbumArt = svideo.artwork_url, + }) + { TotalTime = TimeSpan.FromMilliseconds(svideo.Duration) }; + } + + if (musicType == MusicType.Soundcloud) + { + var svideo = await SoundCloud.Default.GetVideoByQueryAsync(query).ConfigureAwait(false); + return new Song(new SongInfo + { + Title = svideo.FullName, + Provider = "SoundCloud", + Uri = svideo.StreamLink, + ProviderType = MusicType.Normal, + Query = svideo.TrackLink, + AlbumArt = svideo.artwork_url, + }) + { TotalTime = TimeSpan.FromMilliseconds(svideo.Duration) }; + } + + 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.Run(async () => { try { return await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false); } catch { return Enumerable.Empty(); } }).ConfigureAwait(false); + var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio); + var video = videos + .Where(v => v.AudioBitrate < 256) + .OrderByDescending(v => v.AudioBitrate) + .FirstOrDefault(); + + if (video == null) // do something with this error + throw new Exception("Could not load any video elements based on the query."); + var m = Regex.Match(query, @"\?t=(?\d*)"); + int gotoTime = 0; + if (m.Captures.Count > 0) + int.TryParse(m.Groups["t"].ToString(), out gotoTime); + var song = new Song(new SongInfo + { + Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube" + Provider = "YouTube", + Uri = video.Uri, + Query = link, + ProviderType = musicType, + }); + song.SkipTo = gotoTime; + return song; + } + catch (Exception ex) + { + Console.WriteLine($"Failed resolving the link.{ex.Message}"); + return null; + } + } + + private static async Task HandleStreamContainers(string query) + { + string file = null; + try + { + using (var http = new HttpClient()) + { + file = await http.GetStringAsync(query).ConfigureAwait(false); + } + } + catch + { + return query; + } + if (query.Contains(".pls")) + { + //File1=http://armitunes.com:8000/ + //Regex.Match(query) + try + { + var m = Regex.Match(file, "File1=(?.*?)\\n"); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Console.WriteLine($"Failed reading .pls:\n{file}"); + return null; + } + } + if (query.Contains(".m3u")) + { + /* +# This is a comment + C:\xxx4xx\xxxxxx3x\xx2xxxx\xx.mp3 + C:\xxx5xx\x6xxxxxx\x7xxxxx\xx.mp3 + */ + try + { + var m = Regex.Match(file, "(?^[^#].*)", RegexOptions.Multiline); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Console.WriteLine($"Failed reading .m3u:\n{file}"); + return null; + } + + } + if (query.Contains(".asx")) + { + // + try + { + var m = Regex.Match(file, ".*?)\""); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Console.WriteLine($"Failed reading .asx:\n{file}"); + return null; + } + } + if (query.Contains(".xspf")) + { + /* + + + + file:///mp3s/song_1.mp3 + */ + try + { + var m = Regex.Match(file, "(?.*?)"); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Console.WriteLine($"Failed reading .xspf:\n{file}"); + return null; + } + } + + return query; + } + + private static bool IsRadioLink(string query) => + (query.StartsWith("http") || + query.StartsWith("ww")) + && + (query.Contains(".pls") || + query.Contains(".m3u") || + query.Contains(".asx") || + query.Contains(".xspf")); + } +} diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 0bd7144d..64eb905c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -29,13 +29,13 @@ namespace NadekoBot.Modules.Music { //it can fail if its currenctly opened or doesn't exist. Either way i don't care try { Directory.Delete(MusicDataPath, true); } catch { } - - NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated; + + NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated; Directory.CreateDirectory(MusicDataPath); } - - private Task Client_UserVoiceStateUpdated(IUser iusr, IVoiceState oldState, IVoiceState newState) + + private Task Client_UserVoiceStateUpdated(IUser iusr, IVoiceState oldState, IVoiceState newState) { var usr = iusr as IGuildUser; if (usr == null || @@ -98,12 +98,12 @@ namespace NadekoBot.Modules.Music [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Destroy(IUserMessage umsg) + public async Task Destroy(IUserMessage umsg) //public Task Destroy(IUserMessage umsg) { var channel = (ITextChannel)umsg.Channel; - await channel.SendErrorAsync("Command is temporarily disabled.").ConfigureAwait(false); - + await channel.SendErrorAsync("This command is temporarily disabled.").ConfigureAwait(false); + /*MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask; if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel) @@ -175,55 +175,35 @@ namespace NadekoBot.Modules.Music return; } - if (currentSong.TotalLength == TimeSpan.Zero) - { - await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); - } - + try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } - //var toSend = $"🎡 Currently Playing {currentSong.PrettyName} " + $"`{currentSong.PrettyCurrentTime()}`\n"; - //var toSend = $"🎡 Currently Playing {currentSong.PrettyName}\n"; - - //I did that ^ because current song, bugs when a youtube playlist is queued with more than 50 song, it more like a bug with youtube page token I believe. - - const int itemsPerPage = 10; + const int itemsPerPage = 10; int startAt = itemsPerPage * (page - 1); - var number = 1 + startAt; + var number = 0 + startAt; - var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithDescription(string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(10).Select(v => $"`{number++}.` **[{v.SongInfo.Title.TrimTo(70)}]({v.SongInfo.Query})**\n\t\t*{v.PrettyCurrentTime()}* **|** *{v.PrettyProvider}* **|** *{v.QueuerName}*"))) - .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) - .WithColor(NadekoBot.OkColor); - if (musicPlayer.RepeatSong) - { - embed.WithTitle($"πŸ”‚ Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); - } - else if (musicPlayer.RepeatPlaylist) - { - embed.WithTitle("πŸ” Repeating Playlist"); - } - if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) - { - embed.WithTitle("🎡 Song queue is full!"); - } - await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - - - //var toSend = $"test"; //this was for testing - //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.SendConfirmAsync(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName($"Player Queue: Page {page}") + .WithMusicIcon()) + .WithDescription(string.Join("\n", musicPlayer.Playlist + .Skip(startAt) + .Take(10) + .Select(v => $"`{++number}.` {v.PrettyFullName}"))) + .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) + .WithOkColor(); + + if (musicPlayer.RepeatSong) + { + embed.WithTitle($"πŸ”‚ Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}"); + } + else if (musicPlayer.RepeatPlaylist) + { + embed.WithTitle("πŸ” Repeating Playlist"); + } + if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) + { + embed.WithTitle("🎡 Song queue is full!"); + } + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -231,53 +211,23 @@ namespace NadekoBot.Modules.Music public async Task NowPlaying(IUserMessage umsg) { var channel = (ITextChannel)umsg.Channel; - + MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return; var currentSong = musicPlayer.CurrentSong; if (currentSong == null) return; - var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); - - var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{currentSong.SongInfo.Title}") - //.WithDescription($"{currentSong.PrettyCurrentTime()}") - .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.QueuerName}")) - .WithColor(NadekoBot.OkColor); - if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase)) - { - embed.WithThumbnail(tn => tn.Url = $"https://img.youtube.com/vi/{videoid}/0.jpg"); - embed.WithUrl($"{currentSong.SongInfo.Query}"); - //if (musicPlayer.Playlist.Count < 50) - //{ - if (currentSong.TotalLength == TimeSpan.Zero) - { - await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); - } - embed.WithDescription($"{currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); - //} - //else if (musicPlayer.Playlist.Count > 50) - //{ - //embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); - //} - } - else if (currentSong.SongInfo.Provider.Equals("SoundCloud", StringComparison.OrdinalIgnoreCase)) - { - embed.WithThumbnail(tn => tn.Url = $"{currentSong.SongInfo.AlbumArt}"); - embed.WithUrl($"{currentSong.SongInfo.Query}"); - if (currentSong.TotalLength == TimeSpan.Zero) - { - await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); - } - embed.WithDescription($"{currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); - } - else if (currentSong.SongInfo.Provider.Equals("Local File", StringComparison.OrdinalIgnoreCase)) - { - embed.WithDescription($"{currentSong.PrettyMusicPlayTime()}"); - } - await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); + + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName("Now Playing") + .WithMusicIcon()) + .WithDescription(currentSong.PrettyName) + .WithFooter(ef => ef.WithText(currentSong.PrettyCurrentTime + "/" + currentSong.PrettyInfo)) + .WithOkColor(); + + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -365,19 +315,18 @@ namespace NadekoBot.Modules.Music var msg = await channel.SendMessageAsync($"🎡 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false); - + foreach (var id in idArray) { try { await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, id, true).ConfigureAwait(false); - //await Task.Delay(2000).ConfigureAwait(false); //fixes google api error for few songs on playlist.// } catch (SongNotFoundException) { } catch { break; } - + } - + await msg.ModifyAsync(m => m.Content = "βœ… Playlist queue complete.").ConfigureAwait(false); } @@ -511,12 +460,12 @@ namespace NadekoBot.Modules.Music var song = (musicPlayer.Playlist as List)?[num - 1]; musicPlayer.RemoveSongAt(num - 1); //await channel.SendConfirmAsync($"🎡 Track {song.PrettyName} at position `#{num}` has been **removed**.").ConfigureAwait(false); - var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Song Removed!").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(70)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.QueuerName.TrimTo(15)}`").WithIsInline(true)) - .WithColor(NadekoBot.ErrorColor); - await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName("Song Removed!").WithMusicIcon()) + .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(70)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.QueuerName.TrimTo(15)}`").WithIsInline(true)) + .WithColor(NadekoBot.ErrorColor); + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -565,19 +514,15 @@ namespace NadekoBot.Modules.Music playlist.Insert(n2 - 1, s); var nn1 = n2 < n1 ? n1 : n1 - 1; playlist.RemoveAt(nn1); - - var embed = new EmbedBuilder() - .WithTitle($"{s.SongInfo.Title.TrimTo(70)}") - .WithUrl($"{s.SongInfo.Query}") - .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true)) - .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + + var embed = new EmbedBuilder() + .WithTitle($"{s.SongInfo.Title.TrimTo(70)}") + .WithUrl($"{s.SongInfo.Query}") + .WithAuthor(eab => eab.WithName("Song Moved").WithMusicIcon()) + .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true)) + .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true)) + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - - //await channel.SendConfirmAsync($"🎡Moved {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false); - - } [NadekoCommand, Usage, Description, Aliases] @@ -606,9 +551,15 @@ namespace NadekoBot.Modules.Music if (currentSong == null) return; var currentValue = musicPlayer.ToggleRepeatSong(); - await channel.SendConfirmAsync(currentValue ? - $"πŸ”‚ Repeating track: {currentSong.PrettyName}" : - $"πŸ”‚ Current track repeat stopped.") + + if (currentValue) + await channel.EmbedAsync(new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithMusicIcon().WithName("πŸ”‚ Repeating track")) + .WithDescription(currentSong.PrettyFullName) + .Build()).ConfigureAwait(false); + else + await channel.SendConfirmAsync($"πŸ”‚ Current track repeat stopped.") .ConfigureAwait(false); } @@ -635,7 +586,8 @@ namespace NadekoBot.Modules.Music var curSong = musicPlayer.CurrentSong; var songs = musicPlayer.Playlist.Append(curSong) - .Select(s=> new PlaylistSong() { + .Select(s => new PlaylistSong() + { Provider = s.SongInfo.Provider, ProviderType = s.SongInfo.ProviderType, Title = s.SongInfo.Title, @@ -711,14 +663,14 @@ namespace NadekoBot.Modules.Music //await channel.SendConfirmAsync($@"🎢 **Page {num} of saved playlists:** -//" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); + //" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); - var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **`{r.Author}`**\t ({r.Songs.Count} songs)"))) - .WithColor(NadekoBot.OkColor); + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithMusicIcon()) + .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **`{r.Author}`**\t ({r.Songs.Count} songs)"))) + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - + } //todo only author or owner @@ -866,116 +818,63 @@ namespace NadekoBot.Modules.Music vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume; } var mp = new MusicPlayer(voiceCh, vol); - IUserMessage playingMessage = null; - IUserMessage lastFinishedMessage = null; + + IUserMessage finishedMessage = null; mp.OnCompleted += async (s, song) => - { - if (song.PrintStatusMessage) - { - try - { - if (lastFinishedMessage != null) - { - await lastFinishedMessage.DeleteAsync().ConfigureAwait(false); - //try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } - try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{song.SongInfo.Title}") - .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) - .Build()) - .ConfigureAwait(false); } catch { } - } - else - { - try { lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Finished Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{song.SongInfo.Title}") - .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) - .Build()) - .ConfigureAwait(false); } catch { } - //try { lastFinishedMessage = await textCh.SendConfirmAsync($"🎡 Finished {song.PrettyName}").ConfigureAwait(false); } catch { } - } - 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 { } - } - }; - mp.OnStarted += async (s, song) => - { - if (song.PrintStatusMessage) - { - var sender = s as MusicPlayer; - //var msgTxt = $"🎡 Playing {song.PrettyName}\t `Vol: {(int)(sender.Volume * 100)}%`"; - if (sender == null) - return; - if (playingMessage != null) - { - await playingMessage.DeleteAsync().ConfigureAwait(false); - //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } - try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{song.SongInfo.Title}") - .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") - .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) - .Build()) - .ConfigureAwait(false); } catch { } - } - else - { - //try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { } - try { playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Playing Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{song.SongInfo.Title}") - .WithDescription($"Volume: {(int)(sender.Volume * 100)}%") - .WithFooter(ef => ef.WithText($"{song.PrettyProvider} | {song.QueuerName}")) - .Build()) - .ConfigureAwait(false); } catch { } - } - } - }; - IUserMessage resumemsg = null; - IUserMessage pausemsg = null; - mp.OnPauseChanged += async (paused) => { try { - if (paused) - { - if (pausemsg != null) - { - await pausemsg.DeleteAsync().ConfigureAwait(false); - try { pausemsg = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); } catch { } - } - else - { - try { pausemsg = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); } catch { } - } - } - else - { - if (resumemsg != null) - { - await resumemsg.DeleteAsync().ConfigureAwait(false); - try { resumemsg = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); } catch { } - } - else - { - try { resumemsg = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); } catch { } - } - } + if (finishedMessage != null) + finishedMessage.DeleteAfter(0); + finishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) + .WithDescription(song.PrettyName) + .WithFooter(ef => ef.WithText(song.PrettyInfo)) + .Build()) + .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 { } }; + IUserMessage playingMessage = null; + mp.OnStarted += async (player, song) => + { + if (playingMessage != null) + playingMessage.DeleteAfter(0); + + playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) + .WithDescription(song.PrettyName) + .WithFooter(ef => ef.WithText(song.PrettyInfo)) + .Build()) + .ConfigureAwait(false); + }; + + mp.OnPauseChanged += async (paused) => + { + IUserMessage pauseMessage = null; + if (paused) + { + pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); + } + else + { + pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); + } + if (pauseMessage != null) + pauseMessage.DeleteAfter(15); + }; return mp; }); Song resolvedSong; try { musicPlayer.ThrowIfQueueFull(); - resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false); + resolvedSong = await SongHandler.ResolveSong(query, musicType).ConfigureAwait(false); if (resolvedSong == null) throw new SongNotFoundException(); @@ -992,19 +891,19 @@ namespace NadekoBot.Modules.Music try { //var queuedMessage = await textCh.SendConfirmAsync($"🎡 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); - var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .WithAuthor(eab => eab.WithName("Queued Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) - .WithTitle($"{resolvedSong.SongInfo.Title}") - .WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}") - .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) + var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithAuthor(eab => eab.WithName("Queued Song").WithMusicIcon()) + .WithTitle($"{resolvedSong.SongInfo.Title}") + .WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}") + .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) .Build()) .ConfigureAwait(false); - var t = Task.Run(async () => + var t = Task.Run(async () => { try { await Task.Delay(10000).ConfigureAwait(false); - + await queuedMessage.DeleteAsync().ConfigureAwait(false); } catch { } @@ -1014,4 +913,4 @@ namespace NadekoBot.Modules.Music } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 31dbf2cb..0861bc1d 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -316,7 +316,7 @@ namespace NadekoBot.Modules.Pokemon var targetType = StringToPokemonType(typeTargeted); if (targetType == null) { - await channel.EmbedAsync(PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"), (eb, pt) => eb.AddField(efb => efb.WithName(pt.Name).WithValue(pt.Icon).WithIsInline(true))).WithColor(NadekoBot.OkColor).Build()).ConfigureAwait(false); + await channel.EmbedAsync(PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"), (eb, pt) => eb.AddField(efb => efb.WithName(pt.Name).WithValue(pt.Icon).WithIsInline(true))).WithOkColor().Build()).ConfigureAwait(false); return; } if (targetType == GetPokeType(user.Id)) diff --git a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs index e50f2060..25c18267 100644 --- a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Searches $"limit={showCount}") .ConfigureAwait(false))["data"] as JArray; var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList(); - var eb = new EmbedBuilder().WithColor(NadekoBot.OkColor).WithTitle(Format.Underline($"{dataList.Count} most banned champions")); + var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline($"{dataList.Count} most banned champions")); for (var i = 0; i < dataList.Count; i++) { var champ = dataList[i]; diff --git a/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs b/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs index 02373bb3..b73973a2 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs @@ -1,5 +1,6 @@ ο»Ώusing Discord; using Discord.API; +using NadekoBot.Extensions; using Newtonsoft.Json; using System; using System.Net.Http; @@ -35,7 +36,7 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB public string Poster { get; set; } public Embed GetEmbed() => - new EmbedBuilder().WithColor(NadekoBot.OkColor) + new EmbedBuilder().WithOkColor() .WithTitle(Title) .WithUrl($"http://www.imdb.com/title/{ImdbId}/") .WithDescription(Plot) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 69697608..75da203a 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } else @@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } if (string.IsNullOrWhiteSpace(competitiveplay)) @@ -85,7 +85,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"0 hour").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs index 60b9c27e..36ead93d 100644 --- a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs @@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Searches if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant()) { var p = kvp.Value; - await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle(kvp.Key.ToTitleCase()) .WithDescription(p.BaseStats.ToString()) .AddField(efb => efb.WithName("Types").WithValue(string.Join(",\n", p.Types)).WithIsInline(true)) @@ -81,7 +81,7 @@ namespace NadekoBot.Modules.Searches { if (kvp.Key.ToUpperInvariant() == ability) { - await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle(kvp.Value.Name) .WithDescription(kvp.Value.Desc) .AddField(efb => efb.WithName("Rating").WithValue(kvp.Value.Rating.ToString()).WithIsInline(true)) diff --git a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs index f5700698..49478c2c 100644 --- a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs @@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Searches var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false); var comic = JsonConvert.DeserializeObject(res); - var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) + var embed = new EmbedBuilder().WithOkColor() .WithImage(eib => eib.WithUrl(comic.ImageLink)) .WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico")) .AddField(efb => efb.WithName("Comic#").WithValue(comic.Num.ToString()).WithIsInline(true)) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index c7e5367a..b51eaa03 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("πŸ”† **Feels like**").WithValue($"{obj["feelscentigrade"]}Β°C ({obj["feelsfahrenheit"]}Β°F)").WithIsInline(true)) .AddField(fb => fb.WithName("πŸŒ„ **Sunrise**").WithValue($"{obj["sunrise"]}").WithIsInline(true)) .AddField(fb => fb.WithName("πŸŒ‡ **Sunset**").WithValue($"{obj["sunset"]}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } @@ -202,7 +202,7 @@ namespace NadekoBot.Modules.Searches await msg.Channel.SendErrorAsync("Failed to shorten that url.").ConfigureAwait(false); } - await msg.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await msg.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .AddField(efb => efb.WithName("Original Url") .WithValue($"<{arg}>")) .AddField(efb => efb.WithName("Short Url") @@ -255,7 +255,7 @@ namespace NadekoBot.Modules.Searches var desc = item["text"].ToString(); var types = String.Join(",\n", item["types"].ToObject()); var img = item["editions"][0]["image_url"].ToString(); - var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) + var embed = new EmbedBuilder().WithOkColor() .WithTitle(item["name"].ToString()) .WithDescription(desc) .WithImage(eib => eib.WithUrl(img)) @@ -364,7 +364,7 @@ namespace NadekoBot.Modules.Searches .WithUrl("http://www.yodaspeak.co.uk/") .WithAuthor(au => au.WithName("Yoda").WithIconUrl("http://www.yodaspeak.co.uk/yoda-small1.gif")) .WithDescription(res) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } catch @@ -405,7 +405,7 @@ namespace NadekoBot.Modules.Searches var word = item["word"].ToString(); var def = item["definition"].ToString(); var link = item["permalink"].ToString(); - var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) + var embed = new EmbedBuilder().WithOkColor() .WithUrl(link) .WithAuthor(eab => eab.WithIconUrl("http://i.imgur.com/nwERwQE.jpg").WithName(word)) .WithDescription(def); @@ -452,7 +452,7 @@ namespace NadekoBot.Modules.Searches var hashtag = item["hashtag"].ToString(); var link = item["uri"].ToString(); var desc = item["text"].ToString(); - await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithUrl(link) .WithIconUrl("http://res.cloudinary.com/urbandictionary/image/upload/a_exif,c_fit,h_200,w_200/v1394975045/b8oszuu3tbq7ebyo7vo1.jpg") .WithName(query)) diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 740b18e0..e5ecdb10 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue(guild.Roles.Count().ToString()).WithIsInline(true)) .WithImage(tn => tn.WithUrl(guild.IconUrl)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); if (guild.Emojis.Count() > 0) { embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(", ", guild.Emojis))).WithIsInline(true)); @@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } @@ -92,7 +92,7 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Current Game**").WithValue($"{(user.Game?.Name == null ? "-" : user.Game.Name)}").WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.Roles.Count()})** - {string.Join(", ", user.Roles.Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithThumbnail(tn => tn.WithUrl(user.AvatarUrl)) - .WithColor(NadekoBot.OkColor); + .WithOkColor(); await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 3468a15f..78874828 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Utility { var res = Units.GroupBy(x => x.UnitType) .Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__") - .WithColor(NadekoBot.OkColor), + .WithOkColor(), (embed, g) => embed.AddField(efb => efb.WithName(g.Key.ToTitleCase()) .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1e6fce9c..40670c27 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Utility return; } - await channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithColor(NadekoBot.OkColor), + await channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithOkColor(), (embed, g) => embed.AddField(efb => efb.WithName(g.Name) .WithValue($"```css\nID: {g.Id}\nMembers: {g.GetUsers().Count}\nOwnerID: {g.OwnerId} ```") .WithIsInline(false))) diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index a94681bb..5cbe62ab 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -25,6 +25,20 @@ namespace NadekoBot.Extensions http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); } + public static EmbedBuilder WithOkColor(this EmbedBuilder eb) => + eb.WithColor(NadekoBot.OkColor); + + public static IMessage DeleteAfter(this IUserMessage msg, int seconds) + { + Task.Run(async () => + { + await Task.Delay(seconds * 1000); + try { await msg.DeleteAsync().ConfigureAwait(false); } + catch { } + }); + return msg; + } + public static async Task SendMessageToOwnerAsync(this IGuild guild, string message) { var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).CreateDMChannelAsync() From 0b1d47fc4ed2e5462b6a2075e7e3ecf1bb86418f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 05:32:34 +0100 Subject: [PATCH 06/18] More music stuff, more fixes --- .../Commands/SelfAssignedRolesCommand.cs | 16 +--- .../Commands/ServerGreetCommands.cs | 12 +-- .../Games/Commands/Hangman/HangmanGame.cs | 2 +- .../Games/Commands/PlantAndPickCommands.cs | 6 +- .../Modules/Games/Commands/PollCommands.cs | 3 +- .../Modules/Music/Classes/MusicControls.cs | 6 +- src/NadekoBot/Modules/Music/Classes/Song.cs | 4 +- src/NadekoBot/Modules/Music/Music.cs | 86 +++++++++---------- src/NadekoBot/Modules/NSFW/NSFW.cs | 2 +- src/NadekoBot/_Extensions/Extensions.cs | 3 + 10 files changed, 60 insertions(+), 80 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index dfd8b0a7..e4e66155 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -195,12 +195,8 @@ namespace NadekoBot.Modules.Administration if (conf.AutoDeleteSelfAssignedRoleMessages) { - var t = Task.Run(async () => - { - await Task.Delay(3000).ConfigureAwait(false); - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } // if 502 or something, i don't want bot crashing - try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { } - }); + msg.DeleteAfter(3); + umsg.DeleteAfter(3); } } @@ -242,12 +238,8 @@ namespace NadekoBot.Modules.Administration if (autoDeleteSelfAssignedRoleMessages) { - var t = Task.Run(async () => - { - await Task.Delay(3000).ConfigureAwait(false); - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } // if 502 or something, i don't want bot crashing - try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { } - }); + msg.DeleteAfter(3); + umsg.DeleteAfter(3); } } } diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 1a42e613..beffdd57 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -52,11 +52,7 @@ namespace NadekoBot.Modules.Administration var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); if (conf.AutoDeleteByeMessagesTimer > 0) { - var t = Task.Run(async () => - { - await Task.Delay(conf.AutoDeleteByeMessagesTimer * 1000).ConfigureAwait(false); // 5 minutes - try { await toDelete.DeleteAsync().ConfigureAwait(false); } catch { } - }); + toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); } } catch (Exception ex) { _log.Warn(ex); } @@ -91,11 +87,7 @@ namespace NadekoBot.Modules.Administration var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); if (conf.AutoDeleteGreetMessagesTimer > 0) { - var t = Task.Run(async () => - { - await Task.Delay(conf.AutoDeleteGreetMessagesTimer * 1000).ConfigureAwait(false); // 5 minutes - try { await toDelete.DeleteAsync().ConfigureAwait(false); } catch { } - }); + toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); } } catch (Exception ex) { _log.Warn(ex); } diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 6baa9404..be814333 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman .AddField(efb => efb.WithName("It was").WithValue(Term.Word)) .WithImage(eib => eib.WithUrl(Term.ImageUrl)); if (Errors >= MaxErrors) - await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.ErrorColor).Build()).ConfigureAwait(false); + await GameChannel.EmbedAsync(embed.WithErrorColor().Build()).ConfigureAwait(false); else await GameChannel.EmbedAsync(embed.WithOkColor().Build()).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 61a9a10d..b85825e3 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -119,11 +119,7 @@ namespace NadekoBot.Modules.Games await CurrencyHandler.AddCurrencyAsync((IGuildUser)imsg.Author, "Picked flower(s).", msgs.Count, false).ConfigureAwait(false); var msg = await channel.SendConfirmAsync($"**{imsg.Author}** picked {msgs.Count}{Gambling.Gambling.CurrencySign}!").ConfigureAwait(false); - var t = Task.Run(async () => - { - await Task.Delay(10000).ConfigureAwait(false); - try { await msg.DeleteAsync().ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } - }); + msg.DeleteAfter(10); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 840abdf1..23441b6e 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -172,8 +172,7 @@ namespace NadekoBot.Modules.Games else { var toDelete = await ch.SendConfirmAsync($"{msg.Author.Mention} cast their vote.").ConfigureAwait(false); - await Task.Delay(5000); - await toDelete.DeleteAsync().ConfigureAwait(false); + toDelete.DeleteAfter(5); } } } diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 5d10a22a..ae31b20e 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -41,9 +41,9 @@ namespace NadekoBot.Modules.Music.Classes public float Volume { get; private set; } - public event Func OnCompleted = delegate { return Task.CompletedTask; }; - public event Func OnStarted = delegate { return Task.CompletedTask; }; - public event Func OnPauseChanged = delegate { return Task.CompletedTask; }; + public event Action OnCompleted = delegate { }; + public event Action OnStarted = delegate { }; + public event Action OnPauseChanged = delegate { }; public IVoiceChannel PlaybackVoiceChannel { get; private set; } diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 71daa7ec..407f0dc8 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Music.Classes public string QueuerName { get; set; } public TimeSpan TotalTime { get; set; } = TimeSpan.Zero; - public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / 1000 / milliseconds); + public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / (1000 / milliseconds)); const int milliseconds = 20; const int samplesPerFrame = (48000 / 1000) * milliseconds; @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Music.Classes public string PrettyFullName => $"{PrettyName}\n\t\t*{PrettyInfo}*"; - public string PrettyCurrentTime => TotalTime.ToString(@"mm\:ss"); + public string PrettyCurrentTime => CurrentTime.ToString(@"mm\:ss"); private string PrettyTotalTime { get { diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 64eb905c..afc42496 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -15,6 +15,7 @@ using Newtonsoft.Json.Linq; using System.Collections.Generic; using NadekoBot.Services.Database.Models; using System.Text.RegularExpressions; +using System.Threading; namespace NadekoBot.Modules.Music { @@ -99,7 +100,6 @@ namespace NadekoBot.Modules.Music [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Destroy(IUserMessage umsg) - //public Task Destroy(IUserMessage umsg) { var channel = (ITextChannel)umsg.Channel; await channel.SendErrorAsync("This command is temporarily disabled.").ConfigureAwait(false); @@ -135,8 +135,7 @@ namespace NadekoBot.Modules.Music await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, query).ConfigureAwait(false); if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages) { - await Task.Delay(10000).ConfigureAwait(false); - await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false); + umsg.DeleteAfter(10); } } @@ -149,8 +148,7 @@ namespace NadekoBot.Modules.Music await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, query, musicType: MusicType.Soundcloud).ConfigureAwait(false); if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages) { - await Task.Delay(10000).ConfigureAwait(false); - await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false); + umsg.DeleteAfter(10); } } @@ -182,7 +180,7 @@ namespace NadekoBot.Modules.Music var number = 0 + startAt; var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Player Queue: Page {page}") + .WithAuthor(eab => eab.WithName($"Player Queue - Page {page}") .WithMusicIcon()) .WithDescription(string.Join("\n", musicPlayer.Playlist .Skip(startAt) @@ -315,17 +313,21 @@ namespace NadekoBot.Modules.Music var msg = await channel.SendMessageAsync($"🎡 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false); + var cancelSource = new CancellationTokenSource(); - foreach (var id in idArray) + var tasks = Task.WhenAll(idArray.Select(async id => { + if (cancelSource.Token.IsCancellationRequested) + return; try { await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, id, true).ConfigureAwait(false); } catch (SongNotFoundException) { } - catch { break; } + catch { try { cancelSource.Cancel(); } catch { } } + })); - } + await Task.WhenAny(tasks, Task.Delay(Timeout.Infinite, cancelSource.Token)); await msg.ModifyAsync(m => m.Content = "βœ… Playlist queue complete.").ConfigureAwait(false); } @@ -411,8 +413,7 @@ namespace NadekoBot.Modules.Music await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false); if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages) { - await Task.Delay(10000).ConfigureAwait(false); - await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false); + umsg.DeleteAfter(10); } } @@ -459,12 +460,13 @@ namespace NadekoBot.Modules.Music return; var song = (musicPlayer.Playlist as List)?[num - 1]; musicPlayer.RemoveSongAt(num - 1); - //await channel.SendConfirmAsync($"🎡 Track {song.PrettyName} at position `#{num}` has been **removed**.").ConfigureAwait(false); + var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName("Song Removed!").WithMusicIcon()) .AddField(fb => fb.WithName("**Song Position**").WithValue($"#{num}").WithIsInline(true)) .AddField(fb => fb.WithName("**Song Name**").WithValue($"**[{song.SongInfo.Title.TrimTo(70)}]({song.SongInfo.Query})** `{song.PrettyProvider} | {song.QueuerName.TrimTo(15)}`").WithIsInline(true)) - .WithColor(NadekoBot.ErrorColor); + .WithErrorColor(); + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } @@ -661,10 +663,6 @@ namespace NadekoBot.Modules.Music playlists = uow.MusicPlaylists.GetPlaylistsOnPage(num); } - //await channel.SendConfirmAsync($@"🎢 **Page {num} of saved playlists:** - - //" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by __{r.Author}__ ({r.Songs.Count} songs)"))).ConfigureAwait(false); - var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithMusicIcon()) .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}**\t by **`{r.Author}`**\t ({r.Songs.Count} songs)"))) @@ -843,30 +841,38 @@ namespace NadekoBot.Modules.Music IUserMessage playingMessage = null; mp.OnStarted += async (player, song) => { - if (playingMessage != null) - playingMessage.DeleteAfter(0); + try + { + if (playingMessage != null) + playingMessage.DeleteAfter(0); - playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) - .WithDescription(song.PrettyName) - .WithFooter(ef => ef.WithText(song.PrettyInfo)) - .Build()) - .ConfigureAwait(false); + playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) + .WithDescription(song.PrettyName) + .WithFooter(ef => ef.WithText(song.PrettyInfo)) + .Build()) + .ConfigureAwait(false); + } + catch { } }; mp.OnPauseChanged += async (paused) => { - IUserMessage pauseMessage = null; - if (paused) + try { - pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); + IUserMessage pauseMessage = null; + if (paused) + { + pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **paused**.").ConfigureAwait(false); + } + else + { + pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); + } + if (pauseMessage != null) + pauseMessage.DeleteAfter(15); } - else - { - pauseMessage = await textCh.SendConfirmAsync("🎡 Music playback **resumed**.").ConfigureAwait(false); - } - if (pauseMessage != null) - pauseMessage.DeleteAfter(15); + catch { } }; return mp; }); @@ -898,16 +904,8 @@ namespace NadekoBot.Modules.Music .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) .Build()) .ConfigureAwait(false); - var t = Task.Run(async () => - { - try - { - await Task.Delay(10000).ConfigureAwait(false); - - await queuedMessage.DeleteAsync().ConfigureAwait(false); - } - catch { } - }).ConfigureAwait(false); + if (queuedMessage != null) + queuedMessage.DeleteAfter(10); } catch { } // if queued message sending fails, don't attempt to delete it } diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 0fba9e0e..62603807 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -247,7 +247,7 @@ namespace NadekoBot.Modules.NSFW if (matches.Count == 0) return null; - return matches[rng.Next(0, matches.Count)].Groups["ll"].Value; + return "http:" + matches[rng.Next(0, matches.Count)].Groups["ll"].Value; } } diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 5cbe62ab..2e9c4b68 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -28,6 +28,9 @@ namespace NadekoBot.Extensions public static EmbedBuilder WithOkColor(this EmbedBuilder eb) => eb.WithColor(NadekoBot.OkColor); + public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) => + eb.WithColor(NadekoBot.ErrorColor); + public static IMessage DeleteAfter(this IUserMessage msg, int seconds) { Task.Run(async () => From 22c827867382e74ade2d53e7f47b83ba84a404ef Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 06:12:04 +0100 Subject: [PATCH 07/18] Moved some changes and fixes over from b2 branch --- .../Gambling/Commands/DiceRollCommand.cs | 130 +++++------------- .../Modules/Gambling/Commands/DrawCommand.cs | 2 +- .../Gambling/Commands/FlipCoinCommand.cs | 15 +- .../Games/Commands/Hangman/HangmanGame.cs | 6 +- .../Games/Commands/PlantAndPickCommands.cs | 2 - .../Modules/Music/Classes/MusicControls.cs | 1 + .../Modules/Searches/Commands/JokeCommands.cs | 1 + .../Searches/Commands/OverwatchCommands.cs | 50 +++---- .../Modules/Utility/Commands/CalcCommand.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 23 +++- .../Services/Impl/GoogleApiService.cs | 3 +- 11 files changed, 93 insertions(+), 142 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 22d58035..7b2c8118 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -46,54 +46,52 @@ namespace NadekoBot.Modules.Gambling await channel.SendFileAsync(imageStream, "dice.png", $"{umsg.Author.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false); } - //todo merge into internallDndRoll and internalRoll - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [Priority(1)] - public async Task Roll(IUserMessage umsg, string arg) + + public enum RollOrderType { - var channel = (ITextChannel)umsg.Channel; - if (channel == null) - return; - - var ordered = true; - var rng = new NadekoRandom(); - Match match; - if ((match = dndRegex.Match(arg)).Length != 0) - { - int n1; - int n2; - if (int.TryParse(match.Groups["n1"].ToString(), out n1) && - int.TryParse(match.Groups["n2"].ToString(), out n2) && - n1 <= 50 && n2 <= 100000 && n1 > 0 && n2 > 0) - { - var add = 0; - var sub = 0; - int.TryParse(match.Groups["add"].Value, out add); - int.TryParse(match.Groups["sub"].Value, out sub); - - var arr = new int[n1]; - for (int i = 0; i < n1; i++) - { - arr[i] = rng.Next(1, n2 + 1) + add - sub; - } - var elemCnt = 0; - await channel.SendConfirmAsync($"{umsg.Author.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}` +`{add}` -`{sub}`.\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false); - } - } + Ordered, + Unordered } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [Priority(0)] public async Task Roll(IUserMessage umsg, int num) + { + await InternalRoll(umsg, num, true).ConfigureAwait(false); + } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task Rolluo(IUserMessage umsg, int num) + { + await InternalRoll(umsg, num, false).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task Roll(IUserMessage umsg, string arg) + { + await InternallDndRoll(umsg, arg, true).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task Rolluo(IUserMessage umsg, string arg) + { + await InternallDndRoll(umsg, arg, false).ConfigureAwait(false); + } + + private async Task InternalRoll(IUserMessage umsg, int num, bool ordered) { var channel = (ITextChannel)umsg.Channel; if (channel == null) return; - var ordered = true; - if (num < 1 || num > 30) { await channel.SendErrorAsync("Invalid number specified. You can roll up to 1-30 dice at a time.").ConfigureAwait(false); @@ -137,15 +135,12 @@ namespace NadekoBot.Modules.Gambling await channel.SendFileAsync(ms, "dice.png", $"{umsg.Author.Mention} rolled {values.Count} {(values.Count == 1 ? "die" : "dice")}. Total: **{values.Sum()}** Average: **{(values.Sum() / (1.0f * values.Count)).ToString("N2")}**").ConfigureAwait(false); } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - public async Task Rolluo(IUserMessage umsg, string arg) + private async Task InternallDndRoll(IUserMessage umsg, string arg, bool ordered) { var channel = (ITextChannel)umsg.Channel; if (channel == null) return; - var ordered = false; var rng = new NadekoRandom(); Match match; if ((match = dndRegex.Match(arg)).Length != 0) @@ -172,59 +167,6 @@ namespace NadekoBot.Modules.Gambling } } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - public async Task Rolluo(IUserMessage umsg, int num) - { - var channel = (ITextChannel)umsg.Channel; - if (channel == null) - return; - - var ordered = false; - - if (num < 1 || num > 30) - { - await channel.SendErrorAsync("Invalid number specified. You can roll up to 1-30 dice at a time.").ConfigureAwait(false); - return; - } - - var rng = new NadekoRandom(); - - var dice = new List(num); - var values = new List(num); - for (var i = 0; i < num; i++) - { - var randomNumber = rng.Next(1, 7); - var toInsert = dice.Count; - if (ordered) - { - if (randomNumber == 6 || dice.Count == 0) - toInsert = 0; - else if (randomNumber != 1) - for (var j = 0; j < dice.Count; j++) - { - if (values[j] < randomNumber) - { - toInsert = j; - break; - } - } - } - else - { - toInsert = dice.Count; - } - dice.Insert(toInsert, GetDice(randomNumber)); - values.Insert(toInsert, randomNumber); - } - - var bitmap = dice.Merge(); - var ms = new MemoryStream(); - bitmap.SaveAsPng(ms); - ms.Position = 0; - await channel.SendFileAsync(ms, "dice.png", $"{umsg.Author.Mention} rolled {values.Count} {(values.Count == 1 ? "die" : "dice")}. Total: **{values.Sum()}** Average: **{(values.Sum() / (1.0f * values.Count)).ToString("N2")}**").ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task NRoll(IUserMessage umsg, [Remainder] string range) @@ -241,7 +183,7 @@ namespace NadekoBot.Modules.Gambling .Select(int.Parse) .ToArray(); if (arr[0] > arr[1]) - throw new ArgumentException("First argument should be bigger than the second one."); + throw new ArgumentException("Second argument must be larger than the first one."); rolled = new NadekoRandom().Next(arr[0], arr[1] + 1); } else diff --git a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs index 58785882..0f76ce41 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Gambling MemoryStream bitmapStream = new MemoryStream(); images.Merge().SaveAsPng(bitmapStream); bitmapStream.Position = 0; - //todo CARD NAMES? + var toSend = $"{msg.Author.Mention}"; if (cardObjects.Count == 5) toSend += $" drew `{Cards.GetHandValue(cardObjects)}`"; diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 867db68e..110905cc 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -63,20 +63,11 @@ namespace NadekoBot.Modules.Gambling .ConfigureAwait(false); return; } - // todo update this - long userFlowers; - using (var uow = DbHandler.UnitOfWork()) + var removed = await CurrencyHandler.RemoveCurrencyAsync(guildUser, "Betflip Gamble", amount, false).ConfigureAwait(false); + if (!removed) { - userFlowers = uow.Currency.GetOrCreate(umsg.Author.Id).Amount; + await channel.SendErrorAsync($"{guildUser.Mention} You don't have enough {Gambling.CurrencyPluralName}.").ConfigureAwait(false); } - - if (userFlowers < amount) - { - await channel.SendErrorAsync($"{umsg.Author.Mention} You don't have enough {Gambling.CurrencyPluralName}. You only have {userFlowers}{Gambling.CurrencySign}.").ConfigureAwait(false); - return; - } - - await CurrencyHandler.RemoveCurrencyAsync(guildUser, "Betflip Gamble", amount, false).ConfigureAwait(false); //heads = true //tails = false diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index be814333..048f51f3 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -143,10 +143,8 @@ namespace NadekoBot.Modules.Games.Commands.Hangman if (!(char.IsLetter(msg.Content[0]) || char.IsDigit(msg.Content[0])))// and a letter or a digit return Task.CompletedTask; - var guess = char.ToUpperInvariant(msg.Content[0]); - // todo hmmmm - // how do i want to limit the users on guessing? - // one guess every 5 seconds if wrong? + var guess = char.ToUpperInvariant(msg.Content[0]); + Task.Run(async () => { try diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index b85825e3..200b7ba5 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -17,8 +17,6 @@ using System.Threading.Tasks; namespace NadekoBot.Modules.Games { - //todo make currency generation change and cooldown modifyable - //only by bot owner through commands public partial class Games { /// diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index ae31b20e..b70c4d0e 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -130,6 +130,7 @@ namespace NadekoBot.Modules.Music.Classes { Console.WriteLine("Music thread almost crashed."); Console.WriteLine(ex); + await Task.Delay(3000).ConfigureAwait(false); } finally { diff --git a/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs b/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs index b5327810..3852786e 100644 --- a/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs @@ -49,6 +49,7 @@ namespace NadekoBot.Modules.Searches using (var http = new HttpClient()) { var response = await http.GetStringAsync("http://api.yomomma.info/").ConfigureAwait(false); + System.Console.WriteLine(response); await msg.Channel.SendConfirmAsync(JObject.Parse(response)["joke"].ToString() + " πŸ˜†").ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 75da203a..3500ab83 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -31,13 +31,15 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(query)) return; var battletag = Regex.Replace(query, "#", "-", RegexOptions.IgnoreCase); + + await channel.TriggerTypingAsync().ConfigureAwait(false); try { var model = await GetProfile(region, battletag); var rankimg = $"{model.Competitive.rank_img}"; var rank = $"{model.Competitive.rank}"; - var competitiveplay = $"{model.Games.Competitive.played}"; + var competitiveplay = $"{model.Games.Competitive.played}"; if (string.IsNullOrWhiteSpace(rank)) { var embed = new EmbedBuilder() @@ -73,10 +75,10 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - } - if (string.IsNullOrWhiteSpace(competitiveplay)) - { - var embed = new EmbedBuilder() + } + if (string.IsNullOrWhiteSpace(competitiveplay)) + { + var embed = new EmbedBuilder() .WithAuthor(eau => eau.WithName($"{model.username}") .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") .WithIconUrl($"{model.avatar}")) @@ -87,30 +89,30 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithOkColor(); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); - } + } } catch { await channel.SendErrorAsync("Found no user! Please check the **Region** and **BattleTag** before trying again."); } } - public async Task GetProfile(string region, string battletag) - { - try - { - using (var http = new HttpClient()) - { - var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); - var model = JsonConvert.DeserializeObject(Url); - return model.data; - } - } - catch - { - return null; - } - } - - } + public async Task GetProfile(string region, string battletag) + { + try + { + using (var http = new HttpClient()) + { + var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); + var model = JsonConvert.DeserializeObject(Url); + return model.data; + } + } + catch + { + return null; + } + } + + } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs index 31a91f6f..120fc4fc 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs @@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Utility "Equals", "GetHashCode", "GetType"}); - await msg.Channel.SendConfirmAsync(string.Join(", ",selection)); + await msg.Channel.SendConfirmAsync("Available functions in calc", string.Join(", ", selection)); } } diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 40670c27..9f35de60 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -132,13 +132,30 @@ namespace NadekoBot.Modules.Utility if (page < 1 || page > 100) return; + if (target != null) { - await channel.SendConfirmAsync($"βš” **Page #{page} of roles for {target.Username}**", $"```css\nβ€’ " + string.Join("\nβ€’ ", target.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage)).SanitizeMentions() + "\n```"); + var roles = target.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage); + if (!roles.Any()) + { + await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false); + } + else + { + await channel.SendConfirmAsync($"βš” **Page #{page} of roles for {target.Username}**", $"```css\nβ€’ " + string.Join("\nβ€’ ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false); + } } else { - await channel.SendConfirmAsync($"βš” **Page #{page} of all roles on this server:**", $"```css\nβ€’ " + string.Join("\nβ€’ ", guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage)).SanitizeMentions() + "\n```"); + var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage); + if (!roles.Any()) + { + await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false); + } + else + { + await channel.SendConfirmAsync($"βš” **Page #{page} of all roles on this server:**", $"```css\nβ€’ " + string.Join("\nβ€’ ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false); + } } } @@ -271,4 +288,4 @@ namespace NadekoBot.Modules.Utility .ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 6a18c686..6e5727f7 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -167,7 +167,8 @@ namespace NadekoBot.Services.Impl remaining -= toGet; var q = yt.Videos.List("contentDetails"); - q.Id = string.Join(",", videoIds); + q.Id = string.Join(",", videoIdsList.Take(toGet)); + videoIdsList = videoIdsList.Skip(toGet).ToList(); var items = (await q.ExecuteAsync().ConfigureAwait(false)).Items; foreach (var i in items) { From 7de4ade5e5c1df7b09e1864c03a796d3cd8baf01 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 06:15:59 +0100 Subject: [PATCH 08/18] .whpl fixed --- src/NadekoBot/Modules/Utility/Utility.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 9f35de60..e4e2fe31 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -35,16 +35,16 @@ namespace NadekoBot.Modules.Utility game = game.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(game)) return; - var arr = (await (umsg.Channel as IGuildChannel).Guild.GetUsersAsync()) + var usrs = (await (umsg.Channel as IGuildChannel).Guild.GetUsersAsync()) .Where(u => u.Game?.Name?.ToUpperInvariant() == game) .Select(u => u.Username) .ToList(); int i = 0; - if (!arr.Any()) + if (!usrs.Any()) await channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); else - await channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) + await channel.SendConfirmAsync($"List of users playing {game} game. Total {usrs.Count}.", "```css\n" + string.Join("\n", usrs.Take(30).GroupBy(item => (i++) / 2) .Select(ig => string.Concat(ig.Select(el => $"β€’ {el,-27}")))) + "\n```") .ConfigureAwait(false); } From a4b1df029bec751e31fd4c4598dbd200938df95c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 06:17:32 +0100 Subject: [PATCH 09/18] Updated commandlist --- docs/Commands List.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Commands List.md b/docs/Commands List.md index 47a7afc3..3537e8b7 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -120,6 +120,8 @@ Command and aliases | Description | Usage `.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1` `.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1` `.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5` +`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. | `.crstatsclear` or `.crstatsclear rng` +`.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3` ###### [Back to TOC](#table-of-contents) @@ -157,6 +159,8 @@ Command and aliases | Description | Usage `>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` +`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` +`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` `>pick` | Picks the currency planted in this channel. | `>pick` `>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant` `>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` @@ -322,6 +326,7 @@ Command and aliases | Description | Usage `~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko` `~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712` `~osu5` | Displays a user's top 5 plays. | `~osu5 Name` +`~overwatch` `~ow` | Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` | `~ow us Battletag#1337` or `~overwatch eu Battletag#2016` `~placelist` | Shows the list of available tags for the `~place` command. | `~placelist` `~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400` `~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon` From 935d43f04f3c6f4698d2461aafdcd5ff5c37c0ae Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 06:32:39 +0100 Subject: [PATCH 10/18] .aar fixed --- .../Commands/AutoAssignRoleCommands.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index e834e80b..d0a64082 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -6,6 +6,7 @@ using NadekoBot.Services; using NadekoBot.Services.Database.Models; using NLog; using System; +using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; @@ -17,9 +18,13 @@ namespace NadekoBot.Modules.Administration public class AutoAssignRoleCommands { private static Logger _log { get; } + //guildid/roleid + private static ConcurrentDictionary AutoAssignedRoles { get; } static AutoAssignRoleCommands() { + AutoAssignedRoles = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0) + .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId)); _log = LogManager.GetCurrentClassLogger(); NadekoBot.Client.UserJoined += (user) => { @@ -27,15 +32,16 @@ namespace NadekoBot.Modules.Administration { try { - GuildConfig conf = NadekoBot.AllGuildConfigs.FirstOrDefault(gc => gc.GuildId == user.Guild.Id); + ulong roleId = 0; + AutoAssignedRoles.TryGetValue(user.Guild.Id, out roleId); - if (conf.AutoAssignRoleId == 0) + if (roleId == 0) return; - var role = user.Guild.Roles.FirstOrDefault(r => r.Id == conf.AutoAssignRoleId); + var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId); if (role != null) - await user.AddRolesAsync(role); + await user.AddRolesAsync(role).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } }); @@ -55,9 +61,16 @@ namespace NadekoBot.Modules.Administration { conf = uow.GuildConfigs.For(channel.Guild.Id, set => set); if (role == null) + { conf.AutoAssignRoleId = 0; + ulong throwaway; + AutoAssignedRoles.TryRemove(channel.Guild.Id, out throwaway); + } else + { conf.AutoAssignRoleId = role.Id; + AutoAssignedRoles.AddOrUpdate(channel.Guild.Id, role.Id, (key, val) => role.Id); + } await uow.CompleteAsync().ConfigureAwait(false); } From e6e4f17eee3e3fdbb4bae6b9a4772fdb54dfcb8a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 06:41:37 +0100 Subject: [PATCH 11/18] .announce fix? --- src/NadekoBot/Modules/Administration/Administration.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 196aaea5..673d4ae6 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -615,7 +615,9 @@ namespace NadekoBot.Modules.Administration g.GetDefaultChannelAsync() )).ConfigureAwait(false); - await Task.WhenAll(channels.Select(c => c.SendConfirmAsync($"πŸ†• Message from {umsg.Author} `[Bot Owner]`:", message))) + if (channels == null) + return; + await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"πŸ†• Message from {umsg.Author} `[Bot Owner]`:", message))) .ConfigureAwait(false); await umsg.Channel.SendConfirmAsync("πŸ†—").ConfigureAwait(false); From 58f25400835f707f4f79f7d3657e7808a05a44ab Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 07:29:24 +0100 Subject: [PATCH 12/18] Weather fixed --- .../Searches/Commands/Models/WeatherModels.cs | 67 +++++++++++++++++++ src/NadekoBot/Modules/Searches/Searches.cs | 33 ++++----- .../Resources/CommandStrings.Designer.cs | 8 +-- src/NadekoBot/Resources/CommandStrings.resx | 6 +- src/NadekoBot/_Extensions/Extensions.cs | 2 + 5 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs diff --git a/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs b/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs new file mode 100644 index 00000000..417b4d46 --- /dev/null +++ b/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs @@ -0,0 +1,67 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Searches.Commands.Models +{ + public class Coord + { + public double lon { get; set; } + public double lat { get; set; } + } + + public class Weather + { + public int id { get; set; } + public string main { get; set; } + public string description { get; set; } + public string icon { get; set; } + } + + public class Main + { + public double temp { get; set; } + public int pressure { get; set; } + public int humidity { get; set; } + public double temp_min { get; set; } + public double temp_max { get; set; } + } + + public class Wind + { + public double speed { get; set; } + public int deg { get; set; } + } + + public class Clouds + { + public int all { get; set; } + } + + public class Sys + { + public int type { get; set; } + public int id { get; set; } + public double message { get; set; } + public string country { get; set; } + public double sunrise { get; set; } + public double sunset { get; set; } + } + + public class WeatherData + { + public Coord coord { get; set; } + public List weather { get; set; } + public Main main { get; set; } + public int visibility { get; set; } + public Wind wind { get; set; } + public Clouds clouds { get; set; } + public int dt { get; set; } + public Sys sys { get; set; } + public int id { get; set; } + public string name { get; set; } + public int cod { get; set; } + } +} diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index b51eaa03..6c05e4c5 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -17,6 +17,7 @@ using ImageSharp; using NadekoBot.Extensions; using System.IO; using NadekoBot.Modules.Searches.Commands.OMDB; +using NadekoBot.Modules.Searches.Commands.Models; namespace NadekoBot.Modules.Searches { @@ -25,28 +26,30 @@ namespace NadekoBot.Modules.Searches { [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Weather(IUserMessage umsg, string city, string country) + public async Task Weather(IUserMessage umsg, [Remainder] string query) { var channel = (ITextChannel)umsg.Channel; - city = city.Replace(" ", ""); - country = city.Replace(" ", ""); + if (string.IsNullOrWhiteSpace(query)) + return; + string response; using (var http = new HttpClient()) - response = await http.GetStringAsync($"http://api.ninetales.us/nadekobot/weather/?city={city}&country={country}").ConfigureAwait(false); + response = await http.GetStringAsync($"http://api.openweathermap.org/data/2.5/weather?q={query}&appid=42cd627dd60debf25a5739e50a217d74&units=metric").ConfigureAwait(false); - var obj = JObject.Parse(response)["weather"]; + var data = JsonConvert.DeserializeObject(response); var embed = new EmbedBuilder() - .AddField(fb => fb.WithName("🌍 **Location**").WithValue($"{obj["target"]}").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸ“ **Lat,Long**").WithValue($"{obj["latitude"]}, {obj["longitude"]}").WithIsInline(true)) - .AddField(fb => fb.WithName("☁ **Condition**").WithValue($"{obj["condition"]}").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸ˜“ **Humidity**").WithValue($"{obj["humidity"]}%").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸ’¨ **Wind Speed**").WithValue($"{obj["windspeedk"]}km/h ({obj["windspeedm"]}mph)").WithIsInline(true)) - .AddField(fb => fb.WithName("🌑 **Temperature**").WithValue($"{obj["centigrade"]}Β°C ({obj["fahrenheit"]}Β°F)").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸ”† **Feels like**").WithValue($"{obj["feelscentigrade"]}Β°C ({obj["feelsfahrenheit"]}Β°F)").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸŒ„ **Sunrise**").WithValue($"{obj["sunrise"]}").WithIsInline(true)) - .AddField(fb => fb.WithName("πŸŒ‡ **Sunset**").WithValue($"{obj["sunset"]}").WithIsInline(true)) - .WithOkColor(); + .AddField(fb => fb.WithName("🌍 **Location**").WithValue(data.name + ", " + data.sys.country).WithIsInline(true)) + .AddField(fb => fb.WithName("πŸ“ **Lat,Long**").WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true)) + .AddField(fb => fb.WithName("☁ **Condition**").WithValue(String.Join(", ", data.weather.Select(w=>w.main))).WithIsInline(true)) + .AddField(fb => fb.WithName("πŸ˜“ **Humidity**").WithValue($"{data.main.humidity}%").WithIsInline(true)) + .AddField(fb => fb.WithName("πŸ’¨ **Wind Speed**").WithValue(data.wind.speed + " km/h").WithIsInline(true)) + .AddField(fb => fb.WithName("🌑 **Temperature**").WithValue(data.main.temp + "Β°C").WithIsInline(true)) + .AddField(fb => fb.WithName("πŸ”† **Min - Max**").WithValue($"{data.main.temp_min}Β°C - {data.main.temp_max}Β°C").WithIsInline(true)) + .AddField(fb => fb.WithName("πŸŒ„ **Sunrise (utc)**").WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName("πŸŒ‡ **Sunset (utc)**").WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true)) + .WithOkColor() + .WithFooter(efb => efb.WithText("Powered by http://openweathermap.org")); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 2728e701..6ad23be8 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -4648,8 +4648,8 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("osub_usage", resourceCulture); } } - - /// + + /// /// Looks up a localized string similar to overwatch ow. /// public static string overwatch_cmd { @@ -7818,7 +7818,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations.. + /// Looks up a localized string similar to Shows weather data for a specified city. You can also specify a country after a comma.. /// public static string weather_desc { get { @@ -7827,7 +7827,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}we Moscow RF`. + /// Looks up a localized string similar to `{0}we Moscow, RU`. /// public static string weather_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3e6df293..51bf4cf4 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1876,10 +1876,10 @@ weather we - Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. + Shows weather data for a specified city. You can also specify a country after a comma. - `{0}we Moscow RF` + `{0}we Moscow, RU` youtube yt @@ -2781,7 +2781,7 @@ `{0}crstats` or `{0}crstats 3` - + overwatch ow diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 2e9c4b68..4c98b5dd 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -82,6 +82,8 @@ namespace NadekoBot.Extensions public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds; + public static DateTime ToUnixTimestamp(this double number) => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(number); + public static async Task SendMessageAsync(this IGuildUser user, string message, bool isTTS = false) => await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false); From 34a9a3dd5f9c782ca98f59332effeaf465395eff Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 08:12:51 +0100 Subject: [PATCH 13/18] Fixed pause --- src/NadekoBot/Modules/Music/Classes/Song.cs | 8 +++++ .../Modules/Music/Classes/SongBuffer.cs | 29 ++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 407f0dc8..4ed163fa 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -170,10 +170,15 @@ namespace NadekoBot.Modules.Music.Classes if (slowconnection) { _log.Warn("Slow connection has disrupted music, waiting a bit for buffer"); + await Task.Delay(1000, cancelToken).ConfigureAwait(false); + nextTime = Environment.TickCount + milliseconds; } else + { await Task.Delay(100, cancelToken).ConfigureAwait(false); + nextTime = Environment.TickCount + milliseconds; + } } else attempt = 0; @@ -182,7 +187,10 @@ namespace NadekoBot.Modules.Music.Classes attempt = 0; while (this.MusicPlayer.Paused) + { await Task.Delay(200, cancelToken).ConfigureAwait(false); + nextTime = Environment.TickCount + milliseconds; + } buffer = AdjustVolume(buffer, MusicPlayer.Volume); diff --git a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs index 0b8e7849..9fd23294 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs @@ -25,21 +25,21 @@ namespace NadekoBot.Modules.Music.Classes _log = LogManager.GetCurrentClassLogger(); } - MusicPlayer MusicPlayer; + MusicPlayer MusicPlayer { get; } - private string Basename; + private string Basename { get; } - private SongInfo SongInfo; + private SongInfo SongInfo { get; } - private int SkipTo; + private int SkipTo { get; } - private int MaxFileSize = 2.MiB(); + private int MaxFileSize { get; } = 2.MiB(); private long FileNumber = -1; private long NextFileToRead = 0; - public bool BufferingCompleted { get; private set;} = false; + public bool BufferingCompleted { get; private set; } = false; private ulong CurrentBufferSize = 0; @@ -76,7 +76,8 @@ namespace NadekoBot.Modules.Music.Classes try { outStream.Dispose(); - }catch { } + } + catch { } outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read); currentFileSize = bytesRead; } @@ -108,8 +109,8 @@ Check the guides for your platform on how to setup ffmpeg correctly: } finally { - if(outStream != null) - outStream.Dispose(); + if (outStream != null) + outStream.Dispose(); Console.WriteLine($"Buffering done."); if (p != null) { @@ -130,7 +131,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: private string GetNextFile() { string filename = Basename + "-" + NextFileToRead; - + if (NextFileToRead != 0) { try @@ -151,7 +152,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: private void CleanFiles() { - for (long i = NextFileToRead - 1 ; i <= FileNumber; i++) + for (long i = NextFileToRead - 1; i <= FileNumber; i++) { try { @@ -169,7 +170,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: public override bool CanWrite => false; - public override long Length => (long) CurrentBufferSize; + public override long Length => (long)CurrentBufferSize; public override long Position { get; set; } = 0; @@ -178,7 +179,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: public override int Read(byte[] buffer, int offset, int count) { int read = CurrentFileStream.Read(buffer, offset, count); - if(read < count) + if (read < count) { if (!BufferingCompleted || IsNextFileReady()) { @@ -215,4 +216,4 @@ Check the guides for your platform on how to setup ffmpeg correctly: base.Dispose(); } } -} +} \ No newline at end of file From b9a87a62b9f5d35639b6470ee2b35836c75d2ef5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 08:52:02 +0100 Subject: [PATCH 14/18] fixed special characters in memegen --- src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs index 3c48eab0..541eac15 100644 --- a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs @@ -39,8 +39,8 @@ namespace NadekoBot.Modules.Searches { var channel = (ITextChannel)umsg.Channel; - var top = Uri.EscapeDataString(topText.Replace(' ', '-')); - var bot = Uri.EscapeDataString(botText.Replace(' ', '-')); + var top = topText.Replace(' ', '-'); + var bot = botText.Replace(' ', '-'); await channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg") .ConfigureAwait(false); } From c5376f999e62ce9644143629777528455ec163f7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 11:39:19 +0100 Subject: [PATCH 15/18] Acrophobia added, closes #605 --- .../Modules/Games/Commands/Acropobia.cs | 266 ++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 27 ++ src/NadekoBot/Resources/CommandStrings.resx | 9 + 3 files changed, 302 insertions(+) create mode 100644 src/NadekoBot/Modules/Games/Commands/Acropobia.cs diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs new file mode 100644 index 00000000..728845b4 --- /dev/null +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -0,0 +1,266 @@ +ο»Ώusing Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Games +{ + public partial class Games + { + [Group] + public class Acropobia + { + //channelId, game + public static ConcurrentDictionary AcrophobiaGames { get; } = new ConcurrentDictionary(); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Acro(IUserMessage imsg, int time = 45) + { + var channel = (ITextChannel)imsg.Channel; + + var game = new AcrophobiaGame(channel, time); + if (AcrophobiaGames.TryAdd(channel.Id, game)) + { + try + { + await game.Run(); + } + finally + { + game.EnsureStopped(); + AcrophobiaGames.TryRemove(channel.Id, out game); + } + } + else + { + await channel.SendErrorAsync("Acrophobia game is already running in this channel.").ConfigureAwait(false); + } + } + } + + public enum AcroPhase + { + Submitting, + Idle, // used to wait for some other actions while transitioning through phases + Voting + } + + public class AcrophobiaGame + { + private readonly ITextChannel channel; + private readonly int time; + private readonly NadekoRandom rng; + private readonly ImmutableArray startingLetters; + private readonly CancellationTokenSource source; + private AcroPhase phase { get; set; } = AcroPhase.Submitting; + + private readonly ConcurrentDictionary submissions = new ConcurrentDictionary(); + public IReadOnlyDictionary Submissions => submissions; + + private int spamCount = 0; + + //text, votes + private readonly ConcurrentDictionary votes = new ConcurrentDictionary(); + + public AcrophobiaGame(ITextChannel channel, int time) + { + this.channel = channel; + this.time = time; + this.source = new CancellationTokenSource(); + + this.rng = new NadekoRandom(); + var wordCount = rng.Next(3, 6); + + var lettersArr = new char[wordCount]; + + for (int i = 0; i < wordCount; i++) + { + var randChar = (char)rng.Next(65, 91); + lettersArr[i] = randChar == 'X' ? (char)rng.Next(65, 88) : randChar; + } + startingLetters = lettersArr.ToImmutableArray(); + } + + private EmbedBuilder GetEmbed() + { + var i = 0; + return phase == AcroPhase.Submitting + + ? new EmbedBuilder().WithOkColor() + .WithTitle("Acrophobia") + .WithDescription($"Game started. Create a sentence with the following acronym: **{string.Join(".", startingLetters)}.**\n") + .WithFooter(efb => efb.WithText("You have " + this.time + " seconds to make a submission.")) + + : new EmbedBuilder() + .WithOkColor() + .WithTitle("Acrophobia - Submissions Closed") + .WithDescription($@"Acronym was **{string.Join(".", startingLetters)}.** +-- +{this.submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")} +--") + .WithFooter(efb => efb.WithText("Vote by retyping one of the submissions")); + } + + public async Task Run() + { + NadekoBot.Client.MessageReceived += PotentialAcro; + var embed = GetEmbed(); + + //SUBMISSIONS PHASE + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + try + { + await Task.Delay(time * 1000, source.Token).ConfigureAwait(false); + phase = AcroPhase.Idle; + } + catch (OperationCanceledException) + { + return; + } + + var i = 0; + if (submissions.Count == 0) + { + await channel.SendErrorAsync("Acrophobia", "Game ended with no submissions."); + return; + } + else if (submissions.Count == 1) + { + await channel.SendConfirmAsync("Acrophobia", $"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!").ConfigureAwait(false); + return; + } + var submissionClosedEmbed = GetEmbed(); + + await channel.EmbedAsync(submissionClosedEmbed.Build()).ConfigureAwait(false); + + //VOTING PHASE + this.phase = AcroPhase.Voting; + try + { + //30 secondds for voting + await Task.Delay(30000, source.Token).ConfigureAwait(false); + this.phase = AcroPhase.Idle; + } + catch (OperationCanceledException) + { + return; + } + await End().ConfigureAwait(false); + } + + private Task PotentialAcro(IMessage arg) + { + var t = Task.Run(async () => + { + try + { + var msg = arg as IUserMessage; + if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id) + return; + + ++spamCount; + + var guildUser = (IGuildUser)msg.Author; + + var input = msg.Content.ToUpperInvariant().Trim(); + + if (phase == AcroPhase.Submitting) + { + if (spamCount > 10) + { + spamCount = 0; + try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); } + catch { } + } + //user didn't input something already + IGuildUser throwaway; + if (submissions.TryGetValue(input, out throwaway)) + return; + var inputWords = input.Split(' '); //get all words + + if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters + return; + + for (int i = 0; i < startingLetters.Length; i++) + { + var letter = startingLetters[i]; + + if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match + return; + } + + //try adding it to the list of answers + if (!submissions.TryAdd(input, guildUser)) + return; + + // all good. valid input. answer recorded + await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)"); + try + { + await msg.DeleteAsync(); + } + catch + { + await msg.DeleteAsync(); //try twice + } + } + else if (phase == AcroPhase.Voting) + { + if (spamCount > 10) + { + spamCount = 0; + try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); } + catch { } + } + + IGuildUser usr; + if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id) + { + votes.AddOrUpdate(input, 1, (key, old) => ++old); + await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); + await msg.DeleteAsync().ConfigureAwait(false); + } + + } + } + catch { } + }); + return Task.CompletedTask; + } + + public async Task End() + { + if (!votes.Any()) + { + await channel.SendErrorAsync("Acrophobia", "No votes cast. Game ended with no winner.").ConfigureAwait(false); + return; + } + var table = votes.OrderByDescending(v => v.Value); + var winner = table.First(); + var embed = new EmbedBuilder().WithOkColor() + .WithTitle("Acrophobia") + .WithDescription($"Winner is {submissions[winner.Key].Mention} with {winner.Value} points.\n") + .WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase())); + + await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); + } + + public void EnsureStopped() + { + NadekoBot.Client.MessageReceived -= PotentialAcro; + if (!source.IsCancellationRequested) + source.Cancel(); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 6ad23be8..dc386816 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -86,6 +86,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to acro. + /// + public static string acro_cmd { + get { + return ResourceManager.GetString("acro_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 45). + /// + public static string acro_desc { + get { + return ResourceManager.GetString("acro_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}acro` or `{0}acro 30`. + /// + public static string acro_usage { + get { + return ResourceManager.GetString("acro_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to addcustreact acr. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 51bf4cf4..410ccbf5 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2790,4 +2790,13 @@ `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` + + acro + + + Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 45) + + + `{0}acro` or `{0}acro 30` + \ No newline at end of file From e8d8134321d7a2e21972e29e3af9719e1f0814a8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 12:14:18 +0100 Subject: [PATCH 16/18] Acrophobia and weather fixes --- .../Modules/Games/Commands/Acropobia.cs | 27 +++++++++++++++++-- .../Searches/Commands/Models/WeatherModels.cs | 2 +- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 728845b4..2a16fdc7 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Acro(IUserMessage imsg, int time = 45) + public async Task Acro(IUserMessage imsg, int time = 60) { var channel = (ITextChannel)imsg.Channel; @@ -67,6 +67,8 @@ namespace NadekoBot.Modules.Games private readonly ConcurrentDictionary submissions = new ConcurrentDictionary(); public IReadOnlyDictionary Submissions => submissions; + private readonly ConcurrentHashSet usersWhoVoted = new ConcurrentHashSet(); + private int spamCount = 0; //text, votes @@ -136,7 +138,10 @@ namespace NadekoBot.Modules.Games } else if (submissions.Count == 1) { - await channel.SendConfirmAsync("Acrophobia", $"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!").ConfigureAwait(false); + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithDescription($"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!") + .WithFooter(efb => efb.WithText(submissions.First().Key.ToLowerInvariant().ToTitleCase())) + .Build()).ConfigureAwait(false); return; } var submissionClosedEmbed = GetEmbed(); @@ -226,9 +231,27 @@ namespace NadekoBot.Modules.Games IGuildUser usr; if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id) { + if (!usersWhoVoted.Add(guildUser.Id)) + return; votes.AddOrUpdate(input, 1, (key, old) => ++old); await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); await msg.DeleteAsync().ConfigureAwait(false); + return; + } + + int num; + if (int.TryParse(input, out num) && num >= 0 && num < submissions.Count) + { + var kvp = submissions.Skip(num).First(); + usr = kvp.Value; + if (usr.Id == guildUser.Id) + return; + if (!usersWhoVoted.Add(guildUser.Id)) + return; + votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old); + await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); + await msg.DeleteAsync().ConfigureAwait(false); + return; } } diff --git a/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs b/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs index 417b4d46..d3c5742f 100644 --- a/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs +++ b/src/NadekoBot/Modules/Searches/Commands/Models/WeatherModels.cs @@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Searches.Commands.Models public class Wind { public double speed { get; set; } - public int deg { get; set; } + public double deg { get; set; } } public class Clouds diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index dc386816..e7f12432 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -96,7 +96,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 45). + /// Looks up a localized string similar to Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60). /// public static string acro_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 410ccbf5..ec4a51f0 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2794,7 +2794,7 @@ acro - Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 45) + Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) `{0}acro` or `{0}acro 30` From 4d7fc8402b5a5ea8d4c6775784ea59bd09b02583 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 12:16:14 +0100 Subject: [PATCH 17/18] Fixed blacklist/unblacklist message, thanks ghost --- .../Modules/Permissions/Commands/BlacklistCommands.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs index 2d90a2e7..af856f9b 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs @@ -105,7 +105,10 @@ namespace NadekoBot.Modules.Permissions } - await channel.SendConfirmAsync($"Blacklisted a `{type}` with id `{id}`").ConfigureAwait(false); + if(action == AddRemove.Add) + await channel.SendConfirmAsync($"Blacklisted a `{type}` with id `{id}`").ConfigureAwait(false); + else + await channel.SendConfirmAsync($"Unblacklisted a `{type}` with id `{id}`").ConfigureAwait(false); } } } From 9b887b76882192b58f6c681abefad5e4e5478c6c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 22 Dec 2016 12:29:56 +0100 Subject: [PATCH 18/18] acrophobia finalized --- .../Modules/Games/Commands/Acropobia.cs | 29 +++++++++---------- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 2a16fdc7..795c0f63 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Games -- {this.submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")} --") - .WithFooter(efb => efb.WithText("Vote by retyping one of the submissions")); + .WithFooter(efb => efb.WithText("Vote by typing a number of the submission")); } public async Task Run() @@ -229,24 +229,23 @@ namespace NadekoBot.Modules.Games } IGuildUser usr; - if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id) - { - if (!usersWhoVoted.Add(guildUser.Id)) - return; - votes.AddOrUpdate(input, 1, (key, old) => ++old); - await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); - await msg.DeleteAsync().ConfigureAwait(false); - return; - } + //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id) + //{ + // if (!usersWhoVoted.Add(guildUser.Id)) + // return; + // votes.AddOrUpdate(input, 1, (key, old) => ++old); + // await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); + // await msg.DeleteAsync().ConfigureAwait(false); + // return; + //} int num; - if (int.TryParse(input, out num) && num >= 0 && num < submissions.Count) + if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count) { - var kvp = submissions.Skip(num).First(); + var kvp = submissions.Skip(num - 1).First(); usr = kvp.Value; - if (usr.Id == guildUser.Id) - return; - if (!usersWhoVoted.Add(guildUser.Id)) + //can't vote for yourself, can't vote multiple times + if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id)) return; votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old); await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index e7f12432..d4e2eeda 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -87,7 +87,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to acro. + /// Looks up a localized string similar to acrophobia acro. /// public static string acro_cmd { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index ec4a51f0..0b6c7881 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2791,7 +2791,7 @@ `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` - acro + acrophobia acro Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60)