Some cleanup and many music improvements

This commit is contained in:
Kwoth 2016-12-22 04:49:33 +01:00
parent 8b681c13a6
commit 727da69c81
22 changed files with 475 additions and 552 deletions

View File

@ -11,6 +11,7 @@ using Discord.WebSocket;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using System.Linq; using System.Linq;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System.Threading;
namespace NadekoBot.Modules.ClashOfClans 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>>(); public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
private static Timer checkWarTimer { get; }
static ClashOfClans() static ClashOfClans()
{ {
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
@ -32,13 +35,21 @@ namespace NadekoBot.Modules.ClashOfClans
?.GetTextChannel(cw.ChannelId); ?.GetTextChannel(cw.ChannelId);
return cw; return cw;
}) })
.Where(cw => cw?.Channel != null) .Where(cw => cw.Channel != null)
.GroupBy(cw => cw.GuildId) .GroupBy(cw => cw.GuildId)
.ToDictionary(g => g.Key, g => g.ToList())); .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) private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
@ -46,12 +57,21 @@ namespace NadekoBot.Modules.ClashOfClans
var Bases = war.Bases; var Bases = war.Bases;
for (var i = 0; i < Bases.Count; i++) for (var i = 0; i < Bases.Count; i++)
{ {
if (Bases[i].CallUser == null) continue; var callUser = Bases[i].CallUser;
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) if (callUser == null) continue;
if ((!Bases[i].BaseDestroyed) && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
{ {
Bases[i] = null; if (Bases[i].Stars != 3)
try { await war.Channel.SendErrorAsync($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); } catch { } 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 channel = (ITextChannel)umsg.Channel;
var warsInfo = GetWarInfo(umsg,number); var warsInfo = GetWarInfo(umsg, number);
if (warsInfo == null) if (warsInfo == null)
{ {
await channel.SendErrorAsync("🔰 That war does not exist.").ConfigureAwait(false); await channel.SendErrorAsync("🔰 That war does not exist.").ConfigureAwait(false);
@ -359,4 +379,4 @@ namespace NadekoBot.Modules.ClashOfClans
} }
} }
} }
} }

View File

@ -115,7 +115,7 @@ namespace NadekoBot.Modules.CustomReactions
reactions.Add(cr); reactions.Add(cr);
} }
await imsg.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) await imsg.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle("New Custom Reaction") .WithTitle("New Custom Reaction")
.WithDescription($"#{cr.Id}") .WithDescription($"#{cr.Id}")
.AddField(efb => efb.WithName("Trigger").WithValue(key)) .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); await imsg.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false);
else else
{ {
await imsg.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) await imsg.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithDescription($"#{id}") .WithDescription($"#{id}")
.AddField(efb => efb.WithName("Trigger").WithValue(found.Trigger)) .AddField(efb => efb.WithName("Trigger").WithValue(found.Trigger))
.AddField(efb => efb.WithName("Response").WithValue(found.Response + "\n```css\n" + found.Response + "```")) .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) await imsg.Channel.EmbedAsync(ReactionStats.OrderByDescending(x => x.Value)
.Skip((page - 1)*9) .Skip((page - 1)*9)
.Take(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))) (agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true)))
.Build()) .Build())
.ConfigureAwait(false); .ConfigureAwait(false);

View File

@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
if (Errors >= MaxErrors) if (Errors >= MaxErrors)
await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.ErrorColor).Build()).ConfigureAwait(false); await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.ErrorColor).Build()).ConfigureAwait(false);
else else
await GameChannel.EmbedAsync(embed.WithColor(NadekoBot.OkColor).Build()).ConfigureAwait(false); await GameChannel.EmbedAsync(embed.WithOkColor().Build()).ConfigureAwait(false);
} }
private Task PotentialGuess(IMessage msg) private Task PotentialGuess(IMessage msg)

View File

@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Games.Trivia
Games.TriviaCommands.RunningTrivias.TryRemove(channel.Guild.Id, out throwaway); Games.TriviaCommands.RunningTrivias.TryRemove(channel.Guild.Id, out throwaway);
try try
{ {
await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle("Leaderboard") .WithTitle("Leaderboard")
.WithDescription(GetLeaderboard()) .WithDescription(GetLeaderboard())
.Build(), "Trivia game ended.").ConfigureAwait(false); .Build(), "Trivia game ended.").ConfigureAwait(false);

View File

@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Games
return; return;
var rng = new NadekoRandom(); 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("❓ Question").WithValue(question).WithIsInline(false))
.AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false)) .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false))
.Build()); .Build());

View File

@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Help
var embed = new EmbedBuilder() 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(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)) .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); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }

View File

@ -41,9 +41,9 @@ namespace NadekoBot.Modules.Music.Classes
public float Volume { get; private set; } public float Volume { get; private set; }
public event EventHandler<Song> OnCompleted = delegate { }; public event Func<MusicPlayer, Song, Task> OnCompleted = delegate { return Task.CompletedTask; };
public event EventHandler<Song> OnStarted = delegate { }; public event Func<MusicPlayer, Song, Task> OnStarted = delegate { return Task.CompletedTask; };
public event Action<bool> OnPauseChanged = delegate { }; public event Func<bool, Task> OnPauseChanged = delegate { return Task.CompletedTask; };
public IVoiceChannel PlaybackVoiceChannel { get; private set; } public IVoiceChannel PlaybackVoiceChannel { get; private set; }
@ -250,11 +250,11 @@ namespace NadekoBot.Modules.Music.Classes
{ {
var curSong = CurrentSong; var curSong = CurrentSong;
var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal &&
s.TotalLength == TimeSpan.Zero); s.TotalTime == TimeSpan.Zero);
if (curSong != null) if (curSong != null)
toUpdate = toUpdate.Append(curSong); toUpdate = toUpdate.Append(curSong);
var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3)) var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3))
.Distinct(); .Distinct();
var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids); var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids);
@ -264,11 +264,12 @@ namespace NadekoBot.Modules.Music.Classes
{ {
if (s.SongInfo.Query.EndsWith(kvp.Key)) if (s.SongInfo.Query.EndsWith(kvp.Key))
{ {
s.TotalLength = kvp.Value; s.TotalTime = kvp.Value;
return; return;
} }
} }
}); });
} }
public void Destroy() public void Destroy()

View 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");
}
}

View File

@ -18,60 +18,54 @@ namespace NadekoBot.Modules.Music.Classes
{ {
public string Provider { get; set; } public string Provider { get; set; }
public MusicType ProviderType { 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 Query { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Uri { get; set; } public string Uri { get; set; }
public string AlbumArt { get; set; } public string AlbumArt { get; set; }
} }
public class Song 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 SongInfo SongInfo { get; }
public MusicPlayer MusicPlayer { get; set; } public MusicPlayer MusicPlayer { get; set; }
public string PrettyUser =>
$"{QueuerName}";
public string QueuerName { get; set; } public string QueuerName { get; set; }
public string PrettyProvider =>
$"{(SongInfo.Provider ?? "No Provider")}";
public string PrettyCurrentTime() public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
{ public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / 1000 / milliseconds);
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 milliseconds = 20;
const int samplesPerFrame = (48000 / 1000) * milliseconds; const int samplesPerFrame = (48000 / 1000) * milliseconds;
const int frameBytes = 3840; //16-bit, 2 channels const int frameBytes = 3840; //16-bit, 2 channels
private ulong bytesSent { get; set; } = 0; 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 int skipTo = 0;
private Logger _log;
public int SkipTo { public int SkipTo {
get { return skipTo; } get { return skipTo; }
set { 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) public Song(SongInfo songInfo)
{ {
@ -92,16 +86,9 @@ namespace NadekoBot.Modules.Music.Classes
{ {
var s = new Song(SongInfo); var s = new Song(SongInfo);
s.MusicPlayer = MusicPlayer; s.MusicPlayer = MusicPlayer;
s.State = StreamState.Queued;
return s; return s;
} }
public Song SetMusicPlayer(MusicPlayer mp)
{
this.MusicPlayer = mp;
return this;
}
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
{ {
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
@ -111,7 +98,7 @@ namespace NadekoBot.Modules.Music.Classes
try try
{ {
var attempt = 0; var attempt = 0;
var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken, 1.MiB()); //Fast connection can do this easy var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken, 1.MiB()); //Fast connection can do this easy
var finished = false; 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"); _log.Warn("Slow connection buffering more to ensure no disruption, consider hosting in cloud");
continue; continue;
} }
if (inStream.BufferingCompleted && count == 1) if (inStream.BufferingCompleted && count == 1)
{ {
_log.Debug("Prebuffering canceled. Cannot get any data from the stream."); _log.Debug("Prebuffering canceled. Cannot get any data from the stream.");
@ -142,7 +129,7 @@ namespace NadekoBot.Modules.Music.Classes
{ {
continue; continue;
} }
} }
else if (prebufferingTask.IsCanceled) else if (prebufferingTask.IsCanceled)
{ {
_log.Debug("Prebuffering canceled. Cannot get any data from the stream."); _log.Debug("Prebuffering canceled. Cannot get any data from the stream.");
@ -151,7 +138,7 @@ namespace NadekoBot.Modules.Music.Classes
finished = true; finished = true;
} }
sw.Stop(); sw.Stop();
_log.Debug("Prebuffering successfully completed in "+ sw.Elapsed); _log.Debug("Prebuffering successfully completed in " + sw.Elapsed);
var outStream = voiceClient.CreatePCMStream(960); 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---------"); //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
//await inStream.CopyToAsync(voiceClient.OutputStream); //await inStream.CopyToAsync(voiceClient.OutputStream);
if(read < frameBytes) if (read < frameBytes)
_log.Debug("read {0}", read); _log.Debug("read {0}", read);
unchecked unchecked
{ {
@ -210,7 +197,7 @@ namespace NadekoBot.Modules.Music.Classes
finally finally
{ {
await bufferTask; await bufferTask;
if(inStream != null) if (inStream != null)
inStream.Dispose(); inStream.Dispose();
} }
} }
@ -224,35 +211,6 @@ namespace NadekoBot.Modules.Music.Classes
_log.Debug("Buffering successfull"); _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 //aidiakapi ftw
public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume) public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume)
{ {
@ -278,202 +236,5 @@ namespace NadekoBot.Modules.Music.Classes
return audioSamples; 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"));
} }
} }

View 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"));
}
}

View File

@ -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 //it can fail if its currenctly opened or doesn't exist. Either way i don't care
try { Directory.Delete(MusicDataPath, true); } catch { } try { Directory.Delete(MusicDataPath, true); } catch { }
NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated; NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
Directory.CreateDirectory(MusicDataPath); 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; var usr = iusr as IGuildUser;
if (usr == null || if (usr == null ||
@ -98,12 +98,12 @@ namespace NadekoBot.Modules.Music
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Destroy(IUserMessage umsg) public async Task Destroy(IUserMessage umsg)
//public Task Destroy(IUserMessage umsg) //public Task Destroy(IUserMessage umsg)
{ {
var channel = (ITextChannel)umsg.Channel; 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; /*MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask;
if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel) if (((IGuildUser)umsg.Author).VoiceChannel == musicPlayer.PlaybackVoiceChannel)
@ -175,55 +175,35 @@ namespace NadekoBot.Modules.Music
return; return;
} }
if (currentSong.TotalLength == TimeSpan.Zero) try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
{
await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false);
}
//var toSend = $"🎵 Currently Playing {currentSong.PrettyName} " + $"`{currentSong.PrettyCurrentTime()}`\n"; const int itemsPerPage = 10;
//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;
int startAt = itemsPerPage * (page - 1); int startAt = itemsPerPage * (page - 1);
var number = 1 + startAt; var number = 0 + startAt;
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithAuthor(eab => eab.WithName($"Track List: Page {page}").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithAuthor(eab => eab.WithName($"Player Queue: Page {page}")
.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}*"))) .WithMusicIcon())
.WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued.")) .WithDescription(string.Join("\n", musicPlayer.Playlist
.WithColor(NadekoBot.OkColor); .Skip(startAt)
if (musicPlayer.RepeatSong) .Take(10)
{ .Select(v => $"`{++number}.` {v.PrettyFullName}")))
embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyMusicPlayTime()} / {currentSong.PrettyCurrentTime()}"); .WithFooter(ef => ef.WithText($"{musicPlayer.Playlist.Count} tracks currently queued."))
} .WithOkColor();
else if (musicPlayer.RepeatPlaylist)
{ if (musicPlayer.RepeatSong)
embed.WithTitle("🔁 Repeating Playlist"); {
} embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}");
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) }
{ else if (musicPlayer.RepeatPlaylist)
embed.WithTitle("🎵 Song queue is full!"); {
} embed.WithTitle("🔁 Repeating Playlist");
await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); }
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
{
//var toSend = $"test"; //this was for testing embed.WithTitle("🎵 Song queue is full!");
//if (musicPlayer.RepeatSong) }
//toSend += "🔂"; await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
//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] [NadekoCommand, Usage, Description, Aliases]
@ -231,53 +211,23 @@ namespace NadekoBot.Modules.Music
public async Task NowPlaying(IUserMessage umsg) public async Task NowPlaying(IUserMessage umsg)
{ {
var channel = (ITextChannel)umsg.Channel; var channel = (ITextChannel)umsg.Channel;
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
return; return;
var currentSong = musicPlayer.CurrentSong; var currentSong = musicPlayer.CurrentSong;
if (currentSong == null) if (currentSong == null)
return; return;
var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithAuthor(eab => eab.WithName("Now Playing")
.WithTitle($"{currentSong.SongInfo.Title}") .WithMusicIcon())
//.WithDescription($"{currentSong.PrettyCurrentTime()}") .WithDescription(currentSong.PrettyName)
.WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.QueuerName}")) .WithFooter(ef => ef.WithText(currentSong.PrettyCurrentTime + "/" + currentSong.PrettyInfo))
.WithColor(NadekoBot.OkColor); .WithOkColor();
if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase))
{ await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
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);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -365,19 +315,18 @@ namespace NadekoBot.Modules.Music
var msg = var msg =
await channel.SendMessageAsync($"🎵 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false); await channel.SendMessageAsync($"🎵 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false);
foreach (var id in idArray) foreach (var id in idArray)
{ {
try try
{ {
await QueueSong(((IGuildUser)umsg.Author), channel, ((IGuildUser)umsg.Author).VoiceChannel, id, true).ConfigureAwait(false); 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 (SongNotFoundException) { }
catch { break; } catch { break; }
} }
await msg.ModifyAsync(m => m.Content = "✅ Playlist queue complete.").ConfigureAwait(false); 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<Song>)?[num - 1]; var song = (musicPlayer.Playlist as List<Song>)?[num - 1];
musicPlayer.RemoveSongAt(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() 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 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)) .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); .WithColor(NadekoBot.ErrorColor);
await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -565,19 +514,15 @@ namespace NadekoBot.Modules.Music
playlist.Insert(n2 - 1, s); playlist.Insert(n2 - 1, s);
var nn1 = n2 < n1 ? n1 : n1 - 1; var nn1 = n2 < n1 ? n1 : n1 - 1;
playlist.RemoveAt(nn1); playlist.RemoveAt(nn1);
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithTitle($"{s.SongInfo.Title.TrimTo(70)}") .WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
.WithUrl($"{s.SongInfo.Query}") .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("**From Position**").WithValue($"#{n1}").WithIsInline(true))
.AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").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.EmbedAsync(embed.Build()).ConfigureAwait(false);
//await channel.SendConfirmAsync($"🎵Moved {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -606,9 +551,15 @@ namespace NadekoBot.Modules.Music
if (currentSong == null) if (currentSong == null)
return; return;
var currentValue = musicPlayer.ToggleRepeatSong(); var currentValue = musicPlayer.ToggleRepeatSong();
await channel.SendConfirmAsync(currentValue ?
$"🔂 Repeating track: {currentSong.PrettyName}" : if (currentValue)
$"🔂 Current track repeat stopped.") 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); .ConfigureAwait(false);
} }
@ -635,7 +586,8 @@ namespace NadekoBot.Modules.Music
var curSong = musicPlayer.CurrentSong; var curSong = musicPlayer.CurrentSong;
var songs = musicPlayer.Playlist.Append(curSong) var songs = musicPlayer.Playlist.Append(curSong)
.Select(s=> new PlaylistSong() { .Select(s => new PlaylistSong()
{
Provider = s.SongInfo.Provider, Provider = s.SongInfo.Provider,
ProviderType = s.SongInfo.ProviderType, ProviderType = s.SongInfo.ProviderType,
Title = s.SongInfo.Title, Title = s.SongInfo.Title,
@ -711,14 +663,14 @@ namespace NadekoBot.Modules.Music
//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() 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)"))) .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); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
//todo only author or owner //todo only author or owner
@ -866,116 +818,63 @@ namespace NadekoBot.Modules.Music
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume; vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
} }
var mp = new MusicPlayer(voiceCh, vol); var mp = new MusicPlayer(voiceCh, vol);
IUserMessage playingMessage = null;
IUserMessage lastFinishedMessage = null; IUserMessage finishedMessage = null;
mp.OnCompleted += async (s, song) => 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 try
{ {
if (paused) if (finishedMessage != null)
{ finishedMessage.DeleteAfter(0);
if (pausemsg != null) finishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
{ .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon())
await pausemsg.DeleteAsync().ConfigureAwait(false); .WithDescription(song.PrettyName)
try { pausemsg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); } catch { } .WithFooter(ef => ef.WithText(song.PrettyInfo))
} .Build())
else .ConfigureAwait(false);
{
try { pausemsg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").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);
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 { } 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; return mp;
}); });
Song resolvedSong; Song resolvedSong;
try try
{ {
musicPlayer.ThrowIfQueueFull(); musicPlayer.ThrowIfQueueFull();
resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false); resolvedSong = await SongHandler.ResolveSong(query, musicType).ConfigureAwait(false);
if (resolvedSong == null) if (resolvedSong == null)
throw new SongNotFoundException(); throw new SongNotFoundException();
@ -992,19 +891,19 @@ namespace NadekoBot.Modules.Music
try try
{ {
//var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); //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) var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithAuthor(eab => eab.WithName("Queued Song").WithIconUrl("http://i.imgur.com/nhKS3PT.png")) .WithAuthor(eab => eab.WithName("Queued Song").WithMusicIcon())
.WithTitle($"{resolvedSong.SongInfo.Title}") .WithTitle($"{resolvedSong.SongInfo.Title}")
.WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}") .WithDescription($"Queue #{musicPlayer.Playlist.Count + 1}")
.WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}")) .WithFooter(ef => ef.WithText($"{resolvedSong.PrettyProvider}"))
.Build()) .Build())
.ConfigureAwait(false); .ConfigureAwait(false);
var t = Task.Run(async () => var t = Task.Run(async () =>
{ {
try try
{ {
await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
await queuedMessage.DeleteAsync().ConfigureAwait(false); await queuedMessage.DeleteAsync().ConfigureAwait(false);
} }
catch { } catch { }
@ -1014,4 +913,4 @@ namespace NadekoBot.Modules.Music
} }
} }
} }
} }

View File

@ -316,7 +316,7 @@ namespace NadekoBot.Modules.Pokemon
var targetType = StringToPokemonType(typeTargeted); var targetType = StringToPokemonType(typeTargeted);
if (targetType == null) 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; return;
} }
if (targetType == GetPokeType(user.Id)) if (targetType == GetPokeType(user.Id))

View File

@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Searches
$"limit={showCount}") $"limit={showCount}")
.ConfigureAwait(false))["data"] as JArray; .ConfigureAwait(false))["data"] as JArray;
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList(); 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++) for (var i = 0; i < dataList.Count; i++)
{ {
var champ = dataList[i]; var champ = dataList[i];

View File

@ -1,5 +1,6 @@
using Discord; using Discord;
using Discord.API; using Discord.API;
using NadekoBot.Extensions;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Net.Http; using System.Net.Http;
@ -35,7 +36,7 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB
public string Poster { get; set; } public string Poster { get; set; }
public Embed GetEmbed() => public Embed GetEmbed() =>
new EmbedBuilder().WithColor(NadekoBot.OkColor) new EmbedBuilder().WithOkColor()
.WithTitle(Title) .WithTitle(Title)
.WithUrl($"http://www.imdb.com/title/{ImdbId}/") .WithUrl($"http://www.imdb.com/title/{ImdbId}/")
.WithDescription(Plot) .WithDescription(Plot)

View File

@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Searches
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) .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("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").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); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
else else
@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Searches
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) .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("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").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); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
if (string.IsNullOrWhiteSpace(competitiveplay)) 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("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"0 hour").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)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))
.WithColor(NadekoBot.OkColor); .WithOkColor();
await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
} }

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Searches
if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant()) if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant())
{ {
var p = kvp.Value; var p = kvp.Value;
await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle(kvp.Key.ToTitleCase()) .WithTitle(kvp.Key.ToTitleCase())
.WithDescription(p.BaseStats.ToString()) .WithDescription(p.BaseStats.ToString())
.AddField(efb => efb.WithName("Types").WithValue(string.Join(",\n", p.Types)).WithIsInline(true)) .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) if (kvp.Key.ToUpperInvariant() == ability)
{ {
await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle(kvp.Value.Name) .WithTitle(kvp.Value.Name)
.WithDescription(kvp.Value.Desc) .WithDescription(kvp.Value.Desc)
.AddField(efb => efb.WithName("Rating").WithValue(kvp.Value.Rating.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName("Rating").WithValue(kvp.Value.Rating.ToString()).WithIsInline(true))

View File

@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Searches
var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false); var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false);
var comic = JsonConvert.DeserializeObject<XkcdComic>(res); var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) var embed = new EmbedBuilder().WithOkColor()
.WithImage(eib => eib.WithUrl(comic.ImageLink)) .WithImage(eib => eib.WithUrl(comic.ImageLink))
.WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico")) .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)) .AddField(efb => efb.WithName("Comic#").WithValue(comic.Num.ToString()).WithIsInline(true))

View File

@ -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("🔆 **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("🌄 **Sunrise**").WithValue($"{obj["sunrise"]}").WithIsInline(true))
.AddField(fb => fb.WithName("🌇 **Sunset**").WithValue($"{obj["sunset"]}").WithIsInline(true)) .AddField(fb => fb.WithName("🌇 **Sunset**").WithValue($"{obj["sunset"]}").WithIsInline(true))
.WithColor(NadekoBot.OkColor); .WithOkColor();
await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); 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.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") .AddField(efb => efb.WithName("Original Url")
.WithValue($"<{arg}>")) .WithValue($"<{arg}>"))
.AddField(efb => efb.WithName("Short Url") .AddField(efb => efb.WithName("Short Url")
@ -255,7 +255,7 @@ namespace NadekoBot.Modules.Searches
var desc = item["text"].ToString(); var desc = item["text"].ToString();
var types = String.Join(",\n", item["types"].ToObject<string[]>()); var types = String.Join(",\n", item["types"].ToObject<string[]>());
var img = item["editions"][0]["image_url"].ToString(); var img = item["editions"][0]["image_url"].ToString();
var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) var embed = new EmbedBuilder().WithOkColor()
.WithTitle(item["name"].ToString()) .WithTitle(item["name"].ToString())
.WithDescription(desc) .WithDescription(desc)
.WithImage(eib => eib.WithUrl(img)) .WithImage(eib => eib.WithUrl(img))
@ -364,7 +364,7 @@ namespace NadekoBot.Modules.Searches
.WithUrl("http://www.yodaspeak.co.uk/") .WithUrl("http://www.yodaspeak.co.uk/")
.WithAuthor(au => au.WithName("Yoda").WithIconUrl("http://www.yodaspeak.co.uk/yoda-small1.gif")) .WithAuthor(au => au.WithName("Yoda").WithIconUrl("http://www.yodaspeak.co.uk/yoda-small1.gif"))
.WithDescription(res) .WithDescription(res)
.WithColor(NadekoBot.OkColor); .WithOkColor();
await channel.EmbedAsync(embed.Build()).ConfigureAwait(false); await channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
catch catch
@ -405,7 +405,7 @@ namespace NadekoBot.Modules.Searches
var word = item["word"].ToString(); var word = item["word"].ToString();
var def = item["definition"].ToString(); var def = item["definition"].ToString();
var link = item["permalink"].ToString(); var link = item["permalink"].ToString();
var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) var embed = new EmbedBuilder().WithOkColor()
.WithUrl(link) .WithUrl(link)
.WithAuthor(eab => eab.WithIconUrl("http://i.imgur.com/nwERwQE.jpg").WithName(word)) .WithAuthor(eab => eab.WithIconUrl("http://i.imgur.com/nwERwQE.jpg").WithName(word))
.WithDescription(def); .WithDescription(def);
@ -452,7 +452,7 @@ namespace NadekoBot.Modules.Searches
var hashtag = item["hashtag"].ToString(); var hashtag = item["hashtag"].ToString();
var link = item["uri"].ToString(); var link = item["uri"].ToString();
var desc = item["text"].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) .WithAuthor(eab => eab.WithUrl(link)
.WithIconUrl("http://res.cloudinary.com/urbandictionary/image/upload/a_exif,c_fit,h_200,w_200/v1394975045/b8oszuu3tbq7ebyo7vo1.jpg") .WithIconUrl("http://res.cloudinary.com/urbandictionary/image/upload/a_exif,c_fit,h_200,w_200/v1394975045/b8oszuu3tbq7ebyo7vo1.jpg")
.WithName(query)) .WithName(query))

View File

@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Utility
.AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
.AddField(fb => fb.WithName("**Roles**").WithValue(guild.Roles.Count().ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue(guild.Roles.Count().ToString()).WithIsInline(true))
.WithImage(tn => tn.WithUrl(guild.IconUrl)) .WithImage(tn => tn.WithUrl(guild.IconUrl))
.WithColor(NadekoBot.OkColor); .WithOkColor();
if (guild.Emojis.Count() > 0) if (guild.Emojis.Count() > 0)
{ {
embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(", ", guild.Emojis))).WithIsInline(true)); 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("**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("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
.AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true))
.WithColor(NadekoBot.OkColor); .WithOkColor();
await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false); 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("**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)) .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)) .WithThumbnail(tn => tn.WithUrl(user.AvatarUrl))
.WithColor(NadekoBot.OkColor); .WithOkColor();
await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false); await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
} }
} }

View File

@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Utility
{ {
var res = Units.GroupBy(x => x.UnitType) var res = Units.GroupBy(x => x.UnitType)
.Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__") .Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__")
.WithColor(NadekoBot.OkColor), .WithOkColor(),
(embed, g) => embed.AddField(efb => (embed, g) => embed.AddField(efb =>
efb.WithName(g.Key.ToTitleCase()) efb.WithName(g.Key.ToTitleCase())
.WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault())

View File

@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Utility
return; 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) (embed, g) => embed.AddField(efb => efb.WithName(g.Name)
.WithValue($"```css\nID: {g.Id}\nMembers: {g.GetUsers().Count}\nOwnerID: {g.OwnerId} ```") .WithValue($"```css\nID: {g.Id}\nMembers: {g.GetUsers().Count}\nOwnerID: {g.OwnerId} ```")
.WithIsInline(false))) .WithIsInline(false)))

View File

@ -25,6 +25,20 @@ namespace NadekoBot.Extensions
http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); 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) public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
{ {
var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).CreateDMChannelAsync() var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).CreateDMChannelAsync()