NadekoBot/NadekoBot/Classes/Extensions.cs
2016-07-21 12:57:57 +02:00

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;
}
}
}