Some cleanup and many music improvements
This commit is contained in:
		| @@ -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<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>(); | ||||
|  | ||||
|         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,11 +57,20 @@ 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) | ||||
|                 { | ||||
|                     if (Bases[i].Stars != 3) | ||||
|                         Bases[i].BaseDestroyed = true; | ||||
|                     else | ||||
|                         Bases[i] = null; | ||||
|                     try { await war.Channel.SendErrorAsync($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); } catch { } | ||||
|                     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); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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()); | ||||
|   | ||||
| @@ -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); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -41,9 +41,9 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|  | ||||
|         public float Volume { get; private set; } | ||||
|  | ||||
|         public event EventHandler<Song> OnCompleted = delegate { }; | ||||
|         public event EventHandler<Song> OnStarted = delegate { }; | ||||
|         public event Action<bool> OnPauseChanged = delegate { }; | ||||
|         public event Func<MusicPlayer, Song, Task> OnCompleted = delegate { return Task.CompletedTask; }; | ||||
|         public event Func<MusicPlayer, Song, Task> OnStarted = delegate { return Task.CompletedTask; }; | ||||
|         public event Func<bool, Task> OnPauseChanged = delegate { return Task.CompletedTask; }; | ||||
|  | ||||
|         public IVoiceChannel PlaybackVoiceChannel { get; private set; } | ||||
|  | ||||
| @@ -250,7 +250,7 @@ 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)) | ||||
| @@ -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() | ||||
|   | ||||
							
								
								
									
										15
									
								
								src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/NadekoBot/Modules/Music/Classes/MusicExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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"); | ||||
|     } | ||||
| } | ||||
| @@ -18,60 +18,54 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|     { | ||||
|         public string Provider { get; set; } | ||||
|         public MusicType ProviderType { get; set; } | ||||
|         /// <summary> | ||||
|         /// Will be set only if the providertype is normal | ||||
|         /// </summary> | ||||
|         public string Query { get; set; } | ||||
|         public string Title { get; set; } | ||||
|         public string Uri { 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 TimeSpan TotalTime { get; set; } = TimeSpan.Zero; | ||||
|         public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / 1000 / milliseconds); | ||||
|  | ||||
|         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; | ||||
| 		} | ||||
|         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()); | ||||
| @@ -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<Song> 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<YouTubeVideo>(); } }).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=(?<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<string> 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=(?<url>.*?)\\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, "(?<url>^[^#].*)", 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")) | ||||
|             { | ||||
|                 //<ref href="http://armitunes.com:8000"/> | ||||
|                 try | ||||
|                 { | ||||
|                     var m = Regex.Match(file, "<ref href=\"(?<url>.*?)\""); | ||||
|                     var res = m.Groups["url"]?.ToString(); | ||||
|                     return res?.Trim(); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     Console.WriteLine($"Failed reading .asx:\n{file}"); | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|             if (query.Contains(".xspf")) | ||||
|             { | ||||
|                 /* | ||||
|                 <?xml version="1.0" encoding="UTF-8"?> | ||||
|                     <playlist version="1" xmlns="http://xspf.org/ns/0/"> | ||||
|                         <trackList> | ||||
|                             <track><location>file:///mp3s/song_1.mp3</location></track> | ||||
|                 */ | ||||
|                 try | ||||
|                 { | ||||
|                     var m = Regex.Match(file, "<location>(?<url>.*?)</location>"); | ||||
|                     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")); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										212
									
								
								src/NadekoBot/Modules/Music/Classes/SongHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								src/NadekoBot/Modules/Music/Classes/SongHandler.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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<Song> 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<YouTubeVideo>(); } }).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=(?<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<string> 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=(?<url>.*?)\\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, "(?<url>^[^#].*)", 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")) | ||||
|             { | ||||
|                 //<ref href="http://armitunes.com:8000"/> | ||||
|                 try | ||||
|                 { | ||||
|                     var m = Regex.Match(file, "<ref href=\"(?<url>.*?)\""); | ||||
|                     var res = m.Groups["url"]?.ToString(); | ||||
|                     return res?.Trim(); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     Console.WriteLine($"Failed reading .asx:\n{file}"); | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|             if (query.Contains(".xspf")) | ||||
|             { | ||||
|                 /* | ||||
|                 <?xml version="1.0" encoding="UTF-8"?> | ||||
|                     <playlist version="1" xmlns="http://xspf.org/ns/0/"> | ||||
|                         <trackList> | ||||
|                             <track><location>file:///mp3s/song_1.mp3</location></track> | ||||
|                 */ | ||||
|                 try | ||||
|                 { | ||||
|                     var m = Regex.Match(file, "<location>(?<url>.*?)</location>"); | ||||
|                     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")); | ||||
|     } | ||||
| } | ||||
| @@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Music | ||||
|         //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; | ||||
| @@ -175,29 +175,25 @@ namespace NadekoBot.Modules.Music | ||||
|                 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"; | ||||
| 		 | ||||
| 		//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. | ||||
|             try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } | ||||
|  | ||||
|             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}*"))) | ||||
|                 .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.")) | ||||
| 			.WithColor(NadekoBot.OkColor); | ||||
|                 .WithOkColor(); | ||||
|  | ||||
|             if (musicPlayer.RepeatSong) | ||||
|             { | ||||
| 			embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); | ||||
|                 embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}"); | ||||
|             } | ||||
|             else if (musicPlayer.RepeatPlaylist) | ||||
|             { | ||||
| @@ -208,22 +204,6 @@ namespace NadekoBot.Modules.Music | ||||
|                 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] | ||||
| @@ -241,42 +221,12 @@ 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("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()}"); | ||||
| 		} | ||||
|                     .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); | ||||
|         } | ||||
|  | ||||
| @@ -371,7 +321,6 @@ 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.// | ||||
|                 } | ||||
|                 catch (SongNotFoundException) { } | ||||
|                 catch { break; } | ||||
| @@ -512,7 +461,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("http://i.imgur.com/nhKS3PT.png")) | ||||
|                 .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); | ||||
| @@ -569,15 +518,11 @@ 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("http://i.imgur.com/nhKS3PT.png")) | ||||
|             .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)) | ||||
| 		.WithColor(NadekoBot.OkColor); | ||||
|             .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,12 +663,12 @@ 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")) | ||||
|                 .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)"))) | ||||
| 				.WithColor(NadekoBot.OkColor); | ||||
|                 .WithOkColor(); | ||||
|             await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); | ||||
|  | ||||
|         } | ||||
| @@ -866,108 +818,55 @@ 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}")) | ||||
|                         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); } 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 { } | ||||
| 							} | ||||
|                                                   .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 { } | ||||
|                     } | ||||
|                 }; | ||||
|                 mp.OnStarted += async (s, song) => | ||||
|                 IUserMessage playingMessage = null; | ||||
|                 mp.OnStarted += async (player, 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}")) | ||||
|                         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); } 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 { } | ||||
| 						} | ||||
|                     } | ||||
|                                                 .ConfigureAwait(false); | ||||
|                 }; | ||||
| 				IUserMessage resumemsg = null; | ||||
| 				IUserMessage pausemsg = null; | ||||
|  | ||||
|                 mp.OnPauseChanged += async (paused) => | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                     IUserMessage pauseMessage = null; | ||||
|                     if (paused) | ||||
|                     { | ||||
| 							if (pausemsg != null) | ||||
| 							{ | ||||
| 								await pausemsg.DeleteAsync().ConfigureAwait(false); | ||||
| 								try { pausemsg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); } catch { } | ||||
|                         pauseMessage = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
| 								try { pausemsg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); } catch { } | ||||
|                         pauseMessage = await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); | ||||
|                     } | ||||
| 						} | ||||
|                         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 { } | ||||
| 							} | ||||
| 						} | ||||
|                     } | ||||
|                     catch { } | ||||
|                     if (pauseMessage != null) | ||||
|                         pauseMessage.DeleteAfter(15); | ||||
|                 }; | ||||
|                 return mp; | ||||
|             }); | ||||
| @@ -975,7 +874,7 @@ namespace NadekoBot.Modules.Music | ||||
|             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,8 +891,8 @@ 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")) | ||||
|                     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}")) | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -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]; | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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); | ||||
| 					} | ||||
|                 } | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Searches | ||||
|                     var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false); | ||||
|  | ||||
|                     var comic = JsonConvert.DeserializeObject<XkcdComic>(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)) | ||||
|   | ||||
| @@ -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<string[]>()); | ||||
|                     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)) | ||||
|   | ||||
| @@ -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); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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()) | ||||
|   | ||||
| @@ -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))) | ||||
|   | ||||
| @@ -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<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message) | ||||
|         { | ||||
|             var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).CreateDMChannelAsync() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user