More cleanup

This commit is contained in:
Master Kwoth 2017-07-15 15:08:34 +02:00
parent 028606b080
commit b3243eb0e9
11 changed files with 412 additions and 610 deletions

View File

@ -13,15 +13,11 @@ namespace NadekoBot.Modules.Permissions
[Group]
public class ResetPermissionsCommands : NadekoSubmodule
{
private readonly PermissionService _service;
private readonly DbService _db;
private readonly GlobalPermissionService _globalPerms;
private readonly ResetPermissionsService _service;
public ResetPermissionsCommands(PermissionService service, GlobalPermissionService globalPerms, DbService db)
public ResetPermissionsCommands(ResetPermissionsService service)
{
_service = service;
_db = db;
_globalPerms = globalPerms;
}
[NadekoCommand, Usage, Description, Aliases]
@ -29,14 +25,7 @@ namespace NadekoBot.Modules.Permissions
[RequireUserPermission(GuildPermission.Administrator)]
public async Task ResetPermissions()
{
//todo 50 move to service
using (var uow = _db.UnitOfWork)
{
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
config.Permissions = Permissionv2.GetDefaultPermlist;
await uow.CompleteAsync();
_service.UpdateCache(config);
}
await _service.ResetPermissions(Context.Guild.Id).ConfigureAwait(false);
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
}
@ -44,17 +33,7 @@ namespace NadekoBot.Modules.Permissions
[OwnerOnly]
public async Task ResetGlobalPermissions()
{
//todo 50 move to service
using (var uow = _db.UnitOfWork)
{
var gc = uow.BotConfig.GetOrCreate();
gc.BlockedCommands.Clear();
gc.BlockedModules.Clear();
_globalPerms.BlockedCommands.Clear();
_globalPerms.BlockedModules.Clear();
await uow.CompleteAsync();
}
await _service.ResetGlobalPermissions().ConfigureAwait(false);
await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
}
}

View File

@ -54,16 +54,6 @@ namespace NadekoBot.Modules.Searches
return $"[{elem.InnerHtml}]({elem.Href})";
}));
//var favManga = "No favorite manga yet.";
//if (favorites[1].QuerySelector("p") == null)
// favManga = string.Join("\n", favorites[1].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
// .Take(3)
// .Select(x =>
// {
// var elem = (IHtmlAnchorElement)x;
// return $"[{elem.InnerHtml}]({elem.Href})";
// }));
var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li.clearfix")
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))
.ToList();
@ -113,7 +103,8 @@ namespace NadekoBot.Modules.Searches
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
private static string MalInfoToEmoji(string info) {
private static string MalInfoToEmoji(string info)
{
info = info.Trim().ToLowerInvariant();
switch (info)
{
@ -156,7 +147,7 @@ namespace NadekoBot.Modules.Searches
.WithImageUrl(animeData.image_url_lge)
.AddField(efb => efb.WithName(GetText("episodes")).WithValue(animeData.total_episodes.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("status")).WithValue(animeData.AiringStatus.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", animeData.Genres)).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", animeData.Genres.Any() ? animeData.Genres : new[] { "none" })).WithIsInline(true))
.WithFooter(efb => efb.WithText(GetText("score") + " " + animeData.average_score + " / 100"));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
@ -183,7 +174,7 @@ namespace NadekoBot.Modules.Searches
.WithImageUrl(mangaData.image_url_lge)
.AddField(efb => efb.WithName(GetText("chapters")).WithValue(mangaData.total_chapters.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("status")).WithValue(mangaData.publishing_status.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", mangaData.Genres)).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", mangaData.Genres.Any() ? mangaData.Genres : new[] { "none" })).WithIsInline(true))
.WithFooter(efb => efb.WithText(GetText("score") + " " + mangaData.average_score + " / 100"));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);

View File

@ -11,7 +11,7 @@ namespace NadekoBot.Services.Administration
{
public class GuildTimezoneService : INService
{
//hack >.>
// todo 70 this is a hack >.<
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
private readonly DbService _db;

View File

@ -274,8 +274,6 @@ namespace NadekoBot.Services
}
else if (result.Error != null)
{
//todo 80 should have log levels and it should return some kind of result,
// instead of tuple with the type of thing that went wrong, like before
LogErroredExecution(result.Error, usrMsg, channel as ITextChannel, exec2, exec3, execTime);
if (guild != null)
await CommandErrored(result.Info, channel as ITextChannel, result.Error);

View File

@ -1,245 +0,0 @@
using NadekoBot.Extensions;
using System.Net;
using Discord;
using NadekoBot.Services.Database.Models;
using System;
namespace NadekoBot.Services.Music
{
//public class Song
//{
// public SongInfo SongInfo { get; }
// public MusicPlayer MusicPlayer { get; set; }
// private string _queuerName;
// public string QueuerName { get{
// return Format.Sanitize(_queuerName);
// } set { _queuerName = value; } }
// public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
// public TimeSpan CurrentTime => TimeSpan.FromSeconds(BytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));
// private const int _milliseconds = 20;
// private const int _samplesPerFrame = (48000 / 1000) * _milliseconds;
// private const int _frameBytes = 3840; //16-bit, 2 channels
// private ulong BytesSent { get; set; }
// //pwetty
// public string PrettyProvider =>
// $"{(SongInfo.Provider ?? "???")}";
// public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime;
// public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({SongUrl})**";
// public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}";
// public string PrettyFullName => $"{PrettyName}\n\t\t`{PrettyTotalTime} | {PrettyProvider} | {QueuerName}`";
// public string PrettyCurrentTime {
// get {
// var time = CurrentTime.ToString(@"mm\:ss");
// var hrs = (int)CurrentTime.TotalHours;
// if (hrs > 0)
// return hrs + ":" + time;
// else
// return time;
// }
// }
// public string PrettyTotalTime {
// get
// {
// if (TotalTime == TimeSpan.Zero)
// return "(?)";
// if (TotalTime == TimeSpan.MaxValue)
// return "∞";
// var time = TotalTime.ToString(@"mm\:ss");
// var hrs = (int)TotalTime.TotalHours;
// if (hrs > 0)
// return hrs + ":" + time;
// return time;
// }
// }
// public string Thumbnail {
// get {
// switch (SongInfo.ProviderType)
// {
// case MusicType.Radio:
// return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
// case MusicType.Normal:
// //todo 50 have videoid in songinfo from the start
// var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
// return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
// case MusicType.Local:
// return "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links
// case MusicType.Soundcloud:
// return SongInfo.AlbumArt;
// default:
// return "";
// }
// }
// }
// public string SongUrl {
// get {
// switch (SongInfo.ProviderType)
// {
// case MusicType.Normal:
// return SongInfo.Query;
// case MusicType.Soundcloud:
// return SongInfo.Query;
// case MusicType.Local:
// return $"https://google.com/search?q={ WebUtility.UrlEncode(SongInfo.Title).Replace(' ', '+') }";
// case MusicType.Radio:
// return $"https://google.com/search?q={SongInfo.Title}";
// default:
// return "";
// }
// }
// }
// private readonly Logger _log;
// public Song(SongInfo songInfo)
// {
// SongInfo = songInfo;
// _log = LogManager.GetCurrentClassLogger();
// }
// public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
// {
// BytesSent = (ulong) SkipTo * 3840 * 50;
// var filename = Path.Combine(MusicService.MusicDataPath, DateTime.UtcNow.UnixTimestamp().ToString());
// var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
// var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
// try
// {
// var attempt = 0;
// var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken, 1.MiB()); //Fast connection can do this easy
// var finished = false;
// var count = 0;
// var sw = new Stopwatch();
// var slowconnection = false;
// sw.Start();
// while (!finished)
// {
// var t = await Task.WhenAny(prebufferingTask, Task.Delay(2000, cancelToken));
// if (t != prebufferingTask)
// {
// count++;
// if (count == 10)
// {
// slowconnection = true;
// prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken, 20.MiB());
// _log.Warn("Slow connection buffering more to ensure no disruption, consider hosting in cloud");
// continue;
// }
// if (inStream.BufferingCompleted && count == 1)
// {
// _log.Debug("Prebuffering canceled. Cannot get any data from the stream.");
// return;
// }
// else
// {
// continue;
// }
// }
// else if (prebufferingTask.IsCanceled)
// {
// _log.Debug("Prebuffering canceled. Cannot get any data from the stream.");
// return;
// }
// finished = true;
// }
// sw.Stop();
// _log.Debug("Prebuffering successfully completed in " + sw.Elapsed);
// var outStream = voiceClient.CreatePCMStream(AudioApplication.Music);
// int nextTime = Environment.TickCount + _milliseconds;
// byte[] buffer = new byte[_frameBytes];
// while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason
// !(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime
// {
// var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
// //await inStream.CopyToAsync(voiceClient.OutputStream);
// if (read < _frameBytes)
// _log.Debug("read {0}", read);
// unchecked
// {
// BytesSent += (ulong)read;
// }
// if (read < _frameBytes)
// {
// if (read == 0)
// {
// if (inStream.BufferingCompleted)
// break;
// if (attempt++ == 20)
// {
// MusicPlayer.SongCancelSource.Cancel();
// break;
// }
// if (slowconnection)
// {
// _log.Warn("Slow connection has disrupted music, waiting a bit for buffer");
// await Task.Delay(1000, cancelToken).ConfigureAwait(false);
// nextTime = Environment.TickCount + _milliseconds;
// }
// else
// {
// await Task.Delay(100, cancelToken).ConfigureAwait(false);
// nextTime = Environment.TickCount + _milliseconds;
// }
// }
// else
// attempt = 0;
// }
// else
// attempt = 0;
// while (MusicPlayer.Paused)
// {
// await Task.Delay(200, cancelToken).ConfigureAwait(false);
// nextTime = Environment.TickCount + _milliseconds;
// }
// buffer = AdjustVolume(buffer, MusicPlayer.Volume);
// if (read != _frameBytes) continue;
// nextTime = unchecked(nextTime + _milliseconds);
// int delayMillis = unchecked(nextTime - Environment.TickCount);
// if (delayMillis > 0)
// await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false);
// await outStream.WriteAsync(buffer, 0, read).ConfigureAwait(false);
// }
// }
// finally
// {
// await bufferTask;
// inStream.Dispose();
// }
// }
// private async Task CheckPrebufferingAsync(SongBuffer inStream, CancellationToken cancelToken, long size)
// {
// while (!inStream.BufferingCompleted && inStream.Length < size)
// {
// await Task.Delay(100, cancelToken);
// }
// _log.Debug("Buffering successfull");
// }
//}
}

View File

@ -0,0 +1,44 @@
using NadekoBot.Services.Database.Models;
using System.Threading.Tasks;
namespace NadekoBot.Services.Permissions
{
public class ResetPermissionsService : INService
{
private readonly PermissionService _perms;
private readonly GlobalPermissionService _globalPerms;
private readonly DbService _db;
public ResetPermissionsService(PermissionService perms, GlobalPermissionService globalPerms, DbService db)
{
_perms = perms;
_globalPerms = globalPerms;
_db = db;
}
public async Task ResetPermissions(ulong guildId)
{
using (var uow = _db.UnitOfWork)
{
var config = uow.GuildConfigs.GcWithPermissionsv2For(guildId);
config.Permissions = Permissionv2.GetDefaultPermlist;
await uow.CompleteAsync().ConfigureAwait(false);
_perms.UpdateCache(config);
}
}
public async Task ResetGlobalPermissions()
{
using (var uow = _db.UnitOfWork)
{
var gc = uow.BotConfig.GetOrCreate();
gc.BlockedCommands.Clear();
gc.BlockedModules.Clear();
_globalPerms.BlockedCommands.Clear();
_globalPerms.BlockedModules.Clear();
await uow.CompleteAsync().ConfigureAwait(false);
}
}
}
}

View File

@ -48,86 +48,10 @@ namespace NadekoBot.Extensions
public static bool IsAuthor(this IMessage msg, IDiscordClient client) =>
msg.Author?.Id == client.CurrentUser.Id;
private static readonly IEmote arrow_left = new Emoji("⬅");
private static readonly IEmote arrow_right = new Emoji("➡");
public static string ToBase64(this string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(plainTextBytes);
}
public static string RealSummary(this CommandInfo cmd, string prefix) => string.Format(cmd.Summary, prefix);
public static string RealRemarks(this CommandInfo cmd, string prefix) => string.Format(cmd.Remarks, prefix);
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
{
var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
public static Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true) =>
channel.SendPaginatedConfirmAsync(client, currentPage, (x) => Task.FromResult(pageFunc(x)), lastPage, addPaginatedFooter);
/// <summary>
/// danny kamisama
/// </summary>
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func<int, Task<EmbedBuilder>> pageFunc, int? lastPage = null, bool addPaginatedFooter = true)
{
var embed = await pageFunc(currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
embed.AddPaginatedFooter(currentPage, lastPage);
var msg = await channel.EmbedAsync(embed) as IUserMessage;
if (lastPage == 0)
return;
await msg.AddReactionAsync(arrow_left).ConfigureAwait(false);
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
await Task.Delay(2000).ConfigureAwait(false);
Action<SocketReaction> changePage = async r =>
{
try
{
if (r.Emote.Name == arrow_left.Name)
{
if (currentPage == 0)
return;
var toSend = await pageFunc(--currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
toSend.AddPaginatedFooter(currentPage, lastPage);
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
}
else if (r.Emote.Name == arrow_right.Name)
{
if (lastPage == null || lastPage > currentPage)
{
var toSend = await pageFunc(++currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
toSend.AddPaginatedFooter(currentPage, lastPage);
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
}
}
}
catch (Exception)
{
//ignored
}
};
using (msg.OnReaction(client, changePage, changePage))
{
await Task.Delay(30000).ConfigureAwait(false);
}
await msg.RemoveAllReactionsAsync().ConfigureAwait(false);
}
private static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage)
public static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage)
{
if (lastPage != null)
return embed.WithFooter(efb => efb.WithText($"{curPage + 1} / {lastPage + 1}"));
@ -135,6 +59,12 @@ namespace NadekoBot.Extensions
return embed.WithFooter(efb => efb.WithText(curPage.ToString()));
}
public static EmbedBuilder WithOkColor(this EmbedBuilder eb) =>
eb.WithColor(NadekoBot.OkColor);
public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) =>
eb.WithColor(NadekoBot.ErrorColor);
public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordSocketClient client, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
{
if (reactionRemoved == null)
@ -153,17 +83,6 @@ namespace NadekoBot.Extensions
http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
}
public static string GetInitials(this string txt, string glue = "") =>
string.Join(glue, txt.Split(' ').Select(x => x.FirstOrDefault()));
public static DateTime ToUnixTimestamp(this double number) => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(number);
public static EmbedBuilder WithOkColor(this EmbedBuilder eb) =>
eb.WithColor(NadekoBot.OkColor);
public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) =>
eb.WithColor(NadekoBot.ErrorColor);
public static IMessage DeleteAfter(this IUserMessage msg, int seconds)
{
Task.Run(async () =>
@ -184,29 +103,9 @@ namespace NadekoBot.Extensions
return module;
}
public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
{
var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).GetOrCreateDMChannelAsync()
.ConfigureAwait(false);
return await ownerPrivate.SendMessageAsync(message).ConfigureAwait(false);
}
//public static async Task<IEnumerable<IGuildUser>> MentionedUsers(this IUserMessage msg) =>
public static IEnumerable<IRole> GetRoles(this IGuildUser user) =>
user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r != null);
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elems, Action<T> exec)
{
foreach (var elem in elems)
{
exec(elem);
}
return elems;
}
public static void AddRange<T>(this HashSet<T> target, IEnumerable<T> elements) where T : class
{
foreach (var item in elements)
@ -223,90 +122,22 @@ namespace NadekoBot.Extensions
}
}
public static bool IsInteger(this decimal number) => number == Math.Truncate(number);
public static string SanitizeMentions(this string str) =>
str.Replace("@everyone", "@everyοne").Replace("@here", "@һere");
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
//public static async Task<IUserMessage> SendMessageAsync(this IUser user, string message, bool isTTS = false) =>
// await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false);
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, string text)
=> await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text));
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, string title, string text, string url = null)
{
var eb = new EmbedBuilder().WithOkColor().WithDescription(text);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
return await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: eb);
}
public static async Task<IUserMessage> SendErrorAsync(this IUser user, string title, string error, string url = null)
{
var eb = new EmbedBuilder().WithErrorColor().WithDescription(error);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
return await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: eb);
}
public static async Task<IUserMessage> SendErrorAsync(this IUser user, string error)
=> await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error));
public static async Task<IUserMessage> SendFileAsync(this IUser user, string filePath, string caption = null, string text = null, bool isTTS = false) =>
await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(File.Open(filePath, FileMode.Open), caption ?? "x", text, isTTS).ConfigureAwait(false);
public static async Task<IUserMessage> SendFileAsync(this IUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) =>
await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false);
public static IEnumerable<IUser> Members(this IRole role) =>
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
=> ch.SendMessageAsync(msg, embed: embed);
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
JsonConvert.SerializeObject(any, formatting);
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, string title, string error, string url = null, string footer = null)
public static Stream ToStream(this ImageSharp.Image img)
{
var eb = new EmbedBuilder().WithErrorColor().WithDescription(error)
.WithTitle(title);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
eb.WithFooter(efb => efb.WithText(footer));
return ch.SendMessageAsync("", embed: eb);
var imageStream = new MemoryStream();
img.Save(imageStream);
imageStream.Position = 0;
return imageStream;
}
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, string error)
=> ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error));
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, string title, string text, string url = null, string footer = null)
{
var eb = new EmbedBuilder().WithOkColor().WithDescription(text)
.WithTitle(title);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
eb.WithFooter(efb => efb.WithText(footer));
return ch.SendMessageAsync("", embed: eb);
}
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, string text)
=> ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text));
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, string seed, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3)
{
var i = 0;
return ch.SendMessageAsync($@"{seed}```css
{string.Join("\n", items.GroupBy(item => (i++) / columns)
.Select(ig => string.Concat(ig.Select(el => howToPrint(el)))))}
```");
}
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3) =>
ch.SendTableAsync("", items, howToPrint, columns);
/// <summary>
/// returns an IEnumerable with randomized element order
/// </summary>
@ -339,135 +170,32 @@ namespace NadekoBot.Extensions
}
}
/// <summary>
/// Easy use of fast, efficient case-insensitive Contains check with StringComparison Member Types
/// CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase
/// </summary>
public static bool ContainsNoCase(this string str, string contains, StringComparison compare)
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elems, Action<T> exec)
{
return str.IndexOf(contains, compare) >= 0;
foreach (var elem in elems)
{
exec(elem);
}
return elems;
}
public static string TrimTo(this string str, int maxLength, bool hideDots = false)
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
{
if (maxLength < 0)
throw new ArgumentOutOfRangeException(nameof(maxLength), $"Argument {nameof(maxLength)} can't be negative.");
if (maxLength == 0)
return string.Empty;
if (maxLength <= 3)
return string.Concat(str.Select(c => '.'));
if (str.Length < maxLength)
return str;
return string.Concat(str.Take(maxLength - 3)) + (hideDots ? "" : "...");
}
public static string ToTitleCase(this string str)
{
var tokens = str.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < tokens.Length; i++)
{
var token = tokens[i];
tokens[i] = token.Substring(0, 1).ToUpper() + token.Substring(1);
}
return string.Join(" ", tokens);
}
/// <summary>
/// Removes trailing S or ES (if specified) on the given string if the num is 1
/// </summary>
/// <param name="str"></param>
/// <param name="num"></param>
/// <param name="es"></param>
/// <returns>String with the correct singular/plural form</returns>
public static string SnPl(this string str, int? num, bool es = false)
{
if (str == null)
throw new ArgumentNullException(nameof(str));
if (num == null)
throw new ArgumentNullException(nameof(num));
return num == 1 ? str.Remove(str.Length - 1, es ? 2 : 1) : str;
}
//http://www.dotnetperls.com/levenshtein
public static int LevenshteinDistance(this string s, string t)
{
var n = s.Length;
var m = t.Length;
var d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (var i = 0; i <= n; d[i, 0] = i++)
{
}
for (var j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (var i = 1; i <= n; i++)
{
//Step 4
for (var j = 1; j <= m; j++)
{
// Step 5
var cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
public static async Task<Stream> ToStream(this string str)
{
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
await sw.WriteAsync(str);
await sw.FlushAsync();
ms.Position = 0;
var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
JsonConvert.SerializeObject(any, formatting);
public static IEnumerable<IRole> GetRoles(this IGuildUser user) =>
user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r != null);
public static int KiB(this int value) => value * 1024;
public static int KB(this int value) => value * 1000;
public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
{
var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).GetOrCreateDMChannelAsync()
.ConfigureAwait(false);
public static int MiB(this int value) => value.KiB() * 1024;
public static int MB(this int value) => value.KB() * 1000;
public static int GiB(this int value) => value.MiB() * 1024;
public static int GB(this int value) => value.MB() * 1000;
public static ulong KiB(this ulong value) => value * 1024;
public static ulong KB(this ulong value) => value * 1000;
public static ulong MiB(this ulong value) => value.KiB() * 1024;
public static ulong MB(this ulong value) => value.KB() * 1000;
public static ulong GiB(this ulong value) => value.MiB() * 1024;
public static ulong GB(this ulong value) => value.MB() * 1000;
public static string Unmention(this string str) => str.Replace("@", "ම");
return await ownerPrivate.SendMessageAsync(message).ConfigureAwait(false);
}
public static ImageSharp.Image Merge(this IEnumerable<ImageSharp.Image> images)
{
@ -484,25 +212,5 @@ namespace NadekoBot.Extensions
return canvas;
}
public static Stream ToStream(this ImageSharp.Image img)
{
var imageStream = new MemoryStream();
img.Save(imageStream);
imageStream.Position = 0;
return imageStream;
}
private static readonly Regex filterRegex = new Regex(@"(?:discord(?:\.gg|.me|app\.com\/invite)\/(?<id>([\w]{16}|(?:[\w]+-?){3})))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static bool IsDiscordInvite(this string str)
=> filterRegex.IsMatch(str);
public static string RealAvatarUrl(this IUser usr)
{
return usr.AvatarId.StartsWith("a_")
? $"{DiscordConfig.CDNUrl}avatars/{usr.Id}/{usr.AvatarId}.gif"
: usr.GetAvatarUrl(ImageFormat.Auto);
}
}
}

View File

@ -0,0 +1,119 @@
using Discord;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Extensions
{
public static class IMessageChannelExtensions
{
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
=> ch.SendMessageAsync(msg, embed: embed);
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, string title, string error, string url = null, string footer = null)
{
var eb = new EmbedBuilder().WithErrorColor().WithDescription(error)
.WithTitle(title);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
eb.WithFooter(efb => efb.WithText(footer));
return ch.SendMessageAsync("", embed: eb);
}
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, string error)
=> ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error));
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, string title, string text, string url = null, string footer = null)
{
var eb = new EmbedBuilder().WithOkColor().WithDescription(text)
.WithTitle(title);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
eb.WithFooter(efb => efb.WithText(footer));
return ch.SendMessageAsync("", embed: eb);
}
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, string text)
=> ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text));
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, string seed, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3)
{
var i = 0;
return ch.SendMessageAsync($@"{seed}```css
{string.Join("\n", items.GroupBy(item => (i++) / columns)
.Select(ig => string.Concat(ig.Select(el => howToPrint(el)))))}
```");
}
public static Task<IUserMessage> SendTableAsync<T>(this IMessageChannel ch, IEnumerable<T> items, Func<T, string> howToPrint, int columns = 3) =>
ch.SendTableAsync("", items, howToPrint, columns);
private static readonly IEmote arrow_left = new Emoji("⬅");
private static readonly IEmote arrow_right = new Emoji("➡");
public static Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true) =>
channel.SendPaginatedConfirmAsync(client, currentPage, (x) => Task.FromResult(pageFunc(x)), lastPage, addPaginatedFooter);
/// <summary>
/// danny kamisama
/// </summary>
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func<int, Task<EmbedBuilder>> pageFunc, int? lastPage = null, bool addPaginatedFooter = true)
{
var embed = await pageFunc(currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
embed.AddPaginatedFooter(currentPage, lastPage);
var msg = await channel.EmbedAsync(embed) as IUserMessage;
if (lastPage == 0)
return;
await msg.AddReactionAsync(arrow_left).ConfigureAwait(false);
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
await Task.Delay(2000).ConfigureAwait(false);
Action<SocketReaction> changePage = async r =>
{
try
{
if (r.Emote.Name == arrow_left.Name)
{
if (currentPage == 0)
return;
var toSend = await pageFunc(--currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
toSend.AddPaginatedFooter(currentPage, lastPage);
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
}
else if (r.Emote.Name == arrow_right.Name)
{
if (lastPage == null || lastPage > currentPage)
{
var toSend = await pageFunc(++currentPage).ConfigureAwait(false);
if (addPaginatedFooter)
toSend.AddPaginatedFooter(currentPage, lastPage);
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
}
}
}
catch (Exception)
{
//ignored
}
};
using (msg.OnReaction(client, changePage, changePage))
{
await Task.Delay(30000).ConfigureAwait(false);
}
await msg.RemoveAllReactionsAsync().ConfigureAwait(false);
}
}
}

View File

@ -0,0 +1,43 @@
using Discord;
using System;
using System.IO;
using System.Threading.Tasks;
namespace NadekoBot.Extensions
{
public static class IUserExtensions
{
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, string text)
=> await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text));
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, string title, string text, string url = null)
{
var eb = new EmbedBuilder().WithOkColor().WithDescription(text);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
return await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: eb);
}
public static async Task<IUserMessage> SendErrorAsync(this IUser user, string title, string error, string url = null)
{
var eb = new EmbedBuilder().WithErrorColor().WithDescription(error);
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
eb.WithUrl(url);
return await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: eb);
}
public static async Task<IUserMessage> SendErrorAsync(this IUser user, string error)
=> await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error));
public static async Task<IUserMessage> SendFileAsync(this IUser user, string filePath, string caption = null, string text = null, bool isTTS = false) =>
await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(File.Open(filePath, FileMode.Open), caption ?? "x", text, isTTS).ConfigureAwait(false);
public static async Task<IUserMessage> SendFileAsync(this IUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) =>
await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false);
public static string RealAvatarUrl(this IUser usr) =>
usr.AvatarId.StartsWith("a_")
? $"{DiscordConfig.CDNUrl}avatars/{usr.Id}/{usr.AvatarId}.gif"
: usr.GetAvatarUrl(ImageFormat.Auto);
}
}

View File

@ -0,0 +1,29 @@
using System;
namespace NadekoBot.Extensions
{
public static class NumberExtensions
{
public static int KiB(this int value) => value * 1024;
public static int KB(this int value) => value * 1000;
public static int MiB(this int value) => value.KiB() * 1024;
public static int MB(this int value) => value.KB() * 1000;
public static int GiB(this int value) => value.MiB() * 1024;
public static int GB(this int value) => value.MB() * 1000;
public static ulong KiB(this ulong value) => value * 1024;
public static ulong KB(this ulong value) => value * 1000;
public static ulong MiB(this ulong value) => value.KiB() * 1024;
public static ulong MB(this ulong value) => value.KB() * 1000;
public static ulong GiB(this ulong value) => value.MiB() * 1024;
public static ulong GB(this ulong value) => value.MB() * 1000;
public static bool IsInteger(this decimal number) => number == Math.Truncate(number);
public static DateTime ToUnixTimestamp(this double number) => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(number);
}
}

View File

@ -0,0 +1,136 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace NadekoBot.Extensions
{
public static class StringExtensions
{
/// <summary>
/// Easy use of fast, efficient case-insensitive Contains check with StringComparison Member Types
/// CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase
/// </summary>
public static bool ContainsNoCase(this string str, string contains, StringComparison compare)
{
return str.IndexOf(contains, compare) >= 0;
}
public static string TrimTo(this string str, int maxLength, bool hideDots = false)
{
if (maxLength < 0)
throw new ArgumentOutOfRangeException(nameof(maxLength), $"Argument {nameof(maxLength)} can't be negative.");
if (maxLength == 0)
return string.Empty;
if (maxLength <= 3)
return string.Concat(str.Select(c => '.'));
if (str.Length < maxLength)
return str;
return string.Concat(str.Take(maxLength - 3)) + (hideDots ? "" : "...");
}
public static string ToTitleCase(this string str)
{
var tokens = str.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < tokens.Length; i++)
{
var token = tokens[i];
tokens[i] = token.Substring(0, 1).ToUpper() + token.Substring(1);
}
return string.Join(" ", tokens);
}
/// <summary>
/// Removes trailing S or ES (if specified) on the given string if the num is 1
/// </summary>
/// <param name="str"></param>
/// <param name="num"></param>
/// <param name="es"></param>
/// <returns>String with the correct singular/plural form</returns>
public static string SnPl(this string str, int? num, bool es = false)
{
if (str == null)
throw new ArgumentNullException(nameof(str));
if (num == null)
throw new ArgumentNullException(nameof(num));
return num == 1 ? str.Remove(str.Length - 1, es ? 2 : 1) : str;
}
//http://www.dotnetperls.com/levenshtein
public static int LevenshteinDistance(this string s, string t)
{
var n = s.Length;
var m = t.Length;
var d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (var i = 0; i <= n; d[i, 0] = i++)
{
}
for (var j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (var i = 1; i <= n; i++)
{
//Step 4
for (var j = 1; j <= m; j++)
{
// Step 5
var cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
public static async Task<Stream> ToStream(this string str)
{
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
await sw.WriteAsync(str);
await sw.FlushAsync();
ms.Position = 0;
return ms;
}
private static readonly Regex filterRegex = new Regex(@"(?:discord(?:\.gg|.me|app\.com\/invite)\/(?<id>([\w]{16}|(?:[\w]+-?){3})))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static bool IsDiscordInvite(this string str)
=> filterRegex.IsMatch(str);
public static string Unmention(this string str) => str.Replace("@", "ම");
public static string SanitizeMentions(this string str) =>
str.Replace("@everyone", "@everyοne").Replace("@here", "@һere");
public static string ToBase64(this string plainText)
{
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(plainTextBytes);
}
public static string GetInitials(this string txt, string glue = "") =>
string.Join(glue, txt.Split(' ').Select(x => x.FirstOrDefault()));
}
}