More cleanup
This commit is contained in:
parent
028606b080
commit
b3243eb0e9
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
// }
|
||||
//}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
119
src/NadekoBot/_Extensions/IMessageChannelExtensions.cs
Normal file
119
src/NadekoBot/_Extensions/IMessageChannelExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
43
src/NadekoBot/_Extensions/IUserExtensions.cs
Normal file
43
src/NadekoBot/_Extensions/IUserExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
29
src/NadekoBot/_Extensions/NumberExtensions.cs
Normal file
29
src/NadekoBot/_Extensions/NumberExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
136
src/NadekoBot/_Extensions/StringExtensions.cs
Normal file
136
src/NadekoBot/_Extensions/StringExtensions.cs
Normal 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()));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user