More cleanup
This commit is contained in:
parent
028606b080
commit
b3243eb0e9
@ -13,15 +13,11 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
[Group]
|
[Group]
|
||||||
public class ResetPermissionsCommands : NadekoSubmodule
|
public class ResetPermissionsCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly PermissionService _service;
|
private readonly ResetPermissionsService _service;
|
||||||
private readonly DbService _db;
|
|
||||||
private readonly GlobalPermissionService _globalPerms;
|
|
||||||
|
|
||||||
public ResetPermissionsCommands(PermissionService service, GlobalPermissionService globalPerms, DbService db)
|
public ResetPermissionsCommands(ResetPermissionsService service)
|
||||||
{
|
{
|
||||||
_service = service;
|
_service = service;
|
||||||
_db = db;
|
|
||||||
_globalPerms = globalPerms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -29,14 +25,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
[RequireUserPermission(GuildPermission.Administrator)]
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
public async Task ResetPermissions()
|
public async Task ResetPermissions()
|
||||||
{
|
{
|
||||||
//todo 50 move to service
|
await _service.ResetPermissions(Context.Guild.Id).ConfigureAwait(false);
|
||||||
using (var uow = _db.UnitOfWork)
|
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
|
||||||
config.Permissions = Permissionv2.GetDefaultPermlist;
|
|
||||||
await uow.CompleteAsync();
|
|
||||||
_service.UpdateCache(config);
|
|
||||||
}
|
|
||||||
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,17 +33,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ResetGlobalPermissions()
|
public async Task ResetGlobalPermissions()
|
||||||
{
|
{
|
||||||
//todo 50 move to service
|
await _service.ResetGlobalPermissions().ConfigureAwait(false);
|
||||||
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 ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,16 +54,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return $"[{elem.InnerHtml}]({elem.Href})";
|
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")
|
var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li.clearfix")
|
||||||
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))
|
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))
|
||||||
.ToList();
|
.ToList();
|
||||||
@ -113,7 +103,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string MalInfoToEmoji(string info) {
|
private static string MalInfoToEmoji(string info)
|
||||||
|
{
|
||||||
info = info.Trim().ToLowerInvariant();
|
info = info.Trim().ToLowerInvariant();
|
||||||
switch (info)
|
switch (info)
|
||||||
{
|
{
|
||||||
@ -156,7 +147,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithImageUrl(animeData.image_url_lge)
|
.WithImageUrl(animeData.image_url_lge)
|
||||||
.AddField(efb => efb.WithName(GetText("episodes")).WithValue(animeData.total_episodes.ToString()).WithIsInline(true))
|
.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("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"));
|
.WithFooter(efb => efb.WithText(GetText("score") + " " + animeData.average_score + " / 100"));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -183,7 +174,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithImageUrl(mangaData.image_url_lge)
|
.WithImageUrl(mangaData.image_url_lge)
|
||||||
.AddField(efb => efb.WithName(GetText("chapters")).WithValue(mangaData.total_chapters.ToString()).WithIsInline(true))
|
.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("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"));
|
.WithFooter(efb => efb.WithText(GetText("score") + " " + mangaData.average_score + " / 100"));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
@ -11,7 +11,7 @@ namespace NadekoBot.Services.Administration
|
|||||||
{
|
{
|
||||||
public class GuildTimezoneService : INService
|
public class GuildTimezoneService : INService
|
||||||
{
|
{
|
||||||
//hack >.>
|
// todo 70 this is a hack >.<
|
||||||
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
|
public static ConcurrentDictionary<ulong, GuildTimezoneService> AllServices { get; } = new ConcurrentDictionary<ulong, GuildTimezoneService>();
|
||||||
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
|
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
@ -274,8 +274,6 @@ namespace NadekoBot.Services
|
|||||||
}
|
}
|
||||||
else if (result.Error != null)
|
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);
|
LogErroredExecution(result.Error, usrMsg, channel as ITextChannel, exec2, exec3, execTime);
|
||||||
if (guild != null)
|
if (guild != null)
|
||||||
await CommandErrored(result.Info, channel as ITextChannel, result.Error);
|
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) =>
|
public static bool IsAuthor(this IMessage msg, IDiscordClient client) =>
|
||||||
msg.Author?.Id == client.CurrentUser.Id;
|
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 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 string RealRemarks(this CommandInfo cmd, string prefix) => string.Format(cmd.Remarks, prefix);
|
||||||
|
|
||||||
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
public static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (lastPage != null)
|
if (lastPage != null)
|
||||||
return embed.WithFooter(efb => efb.WithText($"{curPage + 1} / {lastPage + 1}"));
|
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()));
|
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)
|
public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordSocketClient client, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
|
||||||
{
|
{
|
||||||
if (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");
|
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)
|
public static IMessage DeleteAfter(this IUserMessage msg, int seconds)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
@ -184,29 +103,9 @@ namespace NadekoBot.Extensions
|
|||||||
return module;
|
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 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
|
public static void AddRange<T>(this HashSet<T> target, IEnumerable<T> elements) where T : class
|
||||||
{
|
{
|
||||||
foreach (var item in elements)
|
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 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) =>
|
public static IEnumerable<IUser> Members(this IRole role) =>
|
||||||
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
||||||
|
|
||||||
|
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
|
||||||
|
JsonConvert.SerializeObject(any, formatting);
|
||||||
|
|
||||||
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
|
public static Stream ToStream(this ImageSharp.Image img)
|
||||||
=> 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)
|
var imageStream = new MemoryStream();
|
||||||
.WithTitle(title);
|
img.Save(imageStream);
|
||||||
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
imageStream.Position = 0;
|
||||||
eb.WithUrl(url);
|
return imageStream;
|
||||||
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);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// returns an IEnumerable with randomized element order
|
/// returns an IEnumerable with randomized element order
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -339,135 +170,32 @@ namespace NadekoBot.Extensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elems, Action<T> exec)
|
||||||
/// 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;
|
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)
|
var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
|
||||||
throw new ArgumentOutOfRangeException(nameof(maxLength), $"Argument {nameof(maxLength)} can't be negative.");
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
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;
|
return ms;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToJson<T>(this T any, Formatting formatting = Formatting.Indented) =>
|
public static IEnumerable<IRole> GetRoles(this IGuildUser user) =>
|
||||||
JsonConvert.SerializeObject(any, formatting);
|
user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r != null);
|
||||||
|
|
||||||
public static int KiB(this int value) => value * 1024;
|
public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
|
||||||
public static int KB(this int value) => value * 1000;
|
{
|
||||||
|
var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).GetOrCreateDMChannelAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
public static int MiB(this int value) => value.KiB() * 1024;
|
return await ownerPrivate.SendMessageAsync(message).ConfigureAwait(false);
|
||||||
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("@", "ම");
|
|
||||||
|
|
||||||
public static ImageSharp.Image Merge(this IEnumerable<ImageSharp.Image> images)
|
public static ImageSharp.Image Merge(this IEnumerable<ImageSharp.Image> images)
|
||||||
{
|
{
|
||||||
@ -484,25 +212,5 @@ namespace NadekoBot.Extensions
|
|||||||
|
|
||||||
return canvas;
|
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