367 lines
12 KiB
C#
367 lines
12 KiB
C#
using Discord;
|
|
using Discord.Commands;
|
|
using NadekoBot.Classes;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace NadekoBot.Extensions
|
|
{
|
|
public static class Extensions
|
|
{
|
|
private static Random rng = new Random();
|
|
|
|
public static string Scramble(this string word)
|
|
{
|
|
|
|
var letters = word.ToArray();
|
|
var count = 0;
|
|
for (var i = 0; i < letters.Length; i++)
|
|
{
|
|
if (letters[i] == ' ')
|
|
continue;
|
|
|
|
count++;
|
|
if (count <= letters.Length / 5)
|
|
continue;
|
|
|
|
if (count % 3 == 0)
|
|
continue;
|
|
|
|
if (letters[i] != ' ')
|
|
letters[i] = '_';
|
|
}
|
|
return "`" + string.Join(" ", letters) + "`";
|
|
}
|
|
public static string TrimTo(this string str, int num, bool hideDots = false)
|
|
{
|
|
if (num < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(num), "TrimTo argument cannot be less than 0");
|
|
if (num == 0)
|
|
return string.Empty;
|
|
if (num <= 3)
|
|
return string.Concat(str.Select(c => '.'));
|
|
if (str.Length < num)
|
|
return str;
|
|
return string.Concat(str.Take(num - 3)) + (hideDots ? "" : "...");
|
|
}
|
|
/// <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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a message to the channel from which this command is called.
|
|
/// </summary>
|
|
/// <param name="e">EventArg</param>
|
|
/// <param name="message">Message to be sent</param>
|
|
/// <returns></returns>
|
|
public static async Task<Message> Send(this CommandEventArgs e, string message)
|
|
=> await e.Channel.SendMessage(message).ConfigureAwait(false);
|
|
|
|
/// <summary>
|
|
/// Sends a message to the channel from which MessageEventArg came.
|
|
/// </summary>
|
|
/// <param name="e">EventArg</param>
|
|
/// <param name="message">Message to be sent</param>
|
|
/// <returns></returns>
|
|
public static async Task Send(this MessageEventArgs e, string message)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(message))
|
|
return;
|
|
await e.Channel.SendMessage(message).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a message to this channel.
|
|
/// </summary>
|
|
/// <param name="c"></param>
|
|
/// <param name="message"></param>
|
|
/// <returns></returns>
|
|
public static async Task Send(this Channel c, string message)
|
|
{
|
|
await c.SendMessage(message).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a private message to this user.
|
|
/// </summary>
|
|
/// <param name="c"></param>
|
|
/// <param name="message"></param>
|
|
/// <returns></returns>
|
|
public static async Task Send(this User u, string message)
|
|
{
|
|
await u.SendMessage(message).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Replies to a user who invoked this command, message start with that user's mention.
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
/// <param name="message"></param>
|
|
/// <returns></returns>
|
|
public static async Task Reply(this CommandEventArgs e, string message)
|
|
{
|
|
await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Replies to a user who invoked this command, message start with that user's mention.
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
/// <param name="message"></param>
|
|
/// <returns></returns>
|
|
public static async Task Reply(this MessageEventArgs e, string message)
|
|
{
|
|
await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Randomizes element order in a list
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="list"></param>
|
|
public static void Shuffle<T>(this IList<T> list)
|
|
{
|
|
|
|
// Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
|
|
var provider = new RNGCryptoServiceProvider();
|
|
var n = list.Count;
|
|
while (n > 1)
|
|
{
|
|
var box = new byte[(n / Byte.MaxValue) + 1];
|
|
int boxSum;
|
|
do
|
|
{
|
|
provider.GetBytes(box);
|
|
boxSum = box.Sum(b => b);
|
|
}
|
|
while (!(boxSum < n * ((Byte.MaxValue * box.Length) / n)));
|
|
var k = (boxSum % n);
|
|
n--;
|
|
var value = list[k];
|
|
list[k] = list[n];
|
|
list[n] = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shortens a string URL
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="action"></param>
|
|
public static async Task<string> ShortenUrl(this string str)
|
|
{
|
|
try
|
|
{
|
|
var result = await SearchHelper.ShortenUrl(str).ConfigureAwait(false);
|
|
return result;
|
|
}
|
|
catch (WebException ex)
|
|
{
|
|
throw new InvalidOperationException("You must enable URL shortner in google developers console.", ex);
|
|
}
|
|
}
|
|
|
|
public static string GetOnPage<T>(this IEnumerable<T> source, int pageIndex, int itemsPerPage = 5)
|
|
{
|
|
var items = source.Skip(pageIndex * itemsPerPage).Take(itemsPerPage);
|
|
if (!items.Any())
|
|
{
|
|
return $"No items on page {pageIndex + 1}.";
|
|
}
|
|
var sb = new StringBuilder($"---page {pageIndex + 1} --\n");
|
|
var itemsDC = items as IEnumerable<KeyValuePair<string, IEnumerable<string>>>;
|
|
var itemsDS = items as IEnumerable<KeyValuePair<string, string>>;
|
|
if (itemsDC != null)
|
|
{
|
|
foreach (var item in itemsDC)
|
|
{
|
|
sb.Append($"{ Format.Code(item.Key)}\n");
|
|
int i = 1;
|
|
var last = item.Value.Last();
|
|
foreach (var value in item.Value)
|
|
{
|
|
if (last != value)
|
|
sb.AppendLine(" `├" + i++ + "─`" + Format.Bold(value));
|
|
else
|
|
sb.AppendLine(" `└" + i++ + "─`" + Format.Bold(value));
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (itemsDS != null)
|
|
{
|
|
foreach (var item in itemsDS)
|
|
{
|
|
sb.Append($"{ Format.Code(item.Key)}\n");
|
|
sb.AppendLine(" `└─`" + Format.Bold(item.Value));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in items)
|
|
{
|
|
sb.Append($"{ Format.Code(item.ToString())} \n");
|
|
}
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
/// <summary>
|
|
/// Gets the program runtime
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="action"></param>
|
|
public static string GetRuntime(this DiscordClient c) => ".Net Framework 4.5.2";
|
|
|
|
public static string Matrix(this string s)
|
|
=>
|
|
string.Concat(s.Select(c => c.ToString() + " ̵̢̬̜͉̞̭̖̰͋̉̎ͬ̔̇̌̀".TrimTo(rng.Next(0, 12), true)));
|
|
//.Replace("`", "");
|
|
|
|
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
|
{
|
|
foreach (var element in source)
|
|
{
|
|
action(element);
|
|
}
|
|
}
|
|
|
|
//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 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 Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null)
|
|
{
|
|
if (format == null)
|
|
format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
|
var stream = new MemoryStream();
|
|
img.Save(stream, format);
|
|
stream.Position = 0;
|
|
return stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges Images into 1 Image and returns a bitmap.
|
|
/// </summary>
|
|
/// <param name="images">The Images you want to merge.</param>
|
|
/// <returns>Merged bitmap</returns>
|
|
public static Bitmap Merge(this IEnumerable<Image> images, int reverseScaleFactor = 1)
|
|
{
|
|
var imageArray = images as Image[] ?? images.ToArray();
|
|
if (!imageArray.Any()) return null;
|
|
var width = imageArray.Sum(i => i.Width);
|
|
var height = imageArray.First().Height;
|
|
var bitmap = new Bitmap(width / reverseScaleFactor, height / reverseScaleFactor);
|
|
var r = new Random();
|
|
var offsetx = 0;
|
|
foreach (var img in imageArray)
|
|
{
|
|
var bm = new Bitmap(img);
|
|
for (var w = 0; w < img.Width; w++)
|
|
{
|
|
for (var h = 0; h < bitmap.Height; h++)
|
|
{
|
|
bitmap.SetPixel(w / reverseScaleFactor + offsetx, h, bm.GetPixel(w, h * reverseScaleFactor));
|
|
}
|
|
}
|
|
offsetx += img.Width / reverseScaleFactor;
|
|
}
|
|
return bitmap;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges Images into 1 Image and returns a bitmap asynchronously.
|
|
/// </summary>
|
|
/// <param name="images">The Images you want to merge.</param>
|
|
/// <param name="reverseScaleFactor"></param>
|
|
/// <returns>Merged bitmap</returns>
|
|
public static async Task<Bitmap> MergeAsync(this IEnumerable<Image> images, int reverseScaleFactor = 1) =>
|
|
await Task.Run(() => images.Merge(reverseScaleFactor)).ConfigureAwait(false);
|
|
|
|
public static string Unmention(this string str) => str.Replace("@", "ම");
|
|
|
|
public static Stream ToStream(this string str)
|
|
{
|
|
var sw = new StreamWriter(new MemoryStream());
|
|
sw.Write(str);
|
|
sw.Flush();
|
|
sw.BaseStream.Position = 0;
|
|
return sw.BaseStream;
|
|
}
|
|
|
|
}
|
|
}
|