Intial 1.0 commit
18
src/NadekoBot/Attributes/LocalizedCommand.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Attributes
|
||||
{
|
||||
public class LocalizedCommandAttribute : CommandAttribute
|
||||
{
|
||||
public LocalizedCommandAttribute([CallerMemberName] string memberName="") : base(Localization.LoadString(memberName.ToLowerInvariant() + "_text"))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
18
src/NadekoBot/Attributes/LocalizedDescription.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Attributes
|
||||
{
|
||||
public class LocalizedDescriptionAttribute : DescriptionAttribute
|
||||
{
|
||||
public LocalizedDescriptionAttribute([CallerMemberName] string memberName="") : base(Localization.LoadString(memberName.ToLowerInvariant()+"_description"))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
18
src/NadekoBot/Attributes/LocalizedSummary.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Attributes
|
||||
{
|
||||
public class LocalizedSummaryAttribute : SummaryAttribute
|
||||
{
|
||||
public LocalizedSummaryAttribute([CallerMemberName] string memberName="") : base(Localization.LoadString(memberName.ToLowerInvariant() + "_summary"))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
164
src/NadekoBot/Classes/DBHandler.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using NadekoBot.DataModels;
|
||||
using SQLite;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal class DbHandler
|
||||
{
|
||||
public static DbHandler Instance { get; } = new DbHandler();
|
||||
|
||||
private string FilePath { get; } = "data/nadekobot.sqlite";
|
||||
|
||||
public SQLiteConnection Connection { get; set; }
|
||||
|
||||
static DbHandler() { }
|
||||
public DbHandler()
|
||||
{
|
||||
Connection = new SQLiteConnection(FilePath);
|
||||
Connection.CreateTable<Stats>();
|
||||
Connection.CreateTable<Command>();
|
||||
Connection.CreateTable<Announcement>();
|
||||
Connection.CreateTable<Request>();
|
||||
Connection.CreateTable<TypingArticle>();
|
||||
Connection.CreateTable<CurrencyState>();
|
||||
Connection.CreateTable<CurrencyTransaction>();
|
||||
Connection.CreateTable<Donator>();
|
||||
Connection.CreateTable<UserPokeTypes>();
|
||||
Connection.CreateTable<UserQuote>();
|
||||
Connection.CreateTable<Reminder>();
|
||||
Connection.CreateTable<SongInfo>();
|
||||
Connection.CreateTable<PlaylistSongInfo>();
|
||||
Connection.CreateTable<MusicPlaylist>();
|
||||
Connection.CreateTable<Incident>();
|
||||
Connection.Execute(Queries.TransactionTriggerQuery);
|
||||
try
|
||||
{
|
||||
Connection.Execute(Queries.DeletePlaylistTriggerQuery);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
internal T FindOne<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
return Connection.Table<T>().Where(p).FirstOrDefault();
|
||||
|
||||
}
|
||||
|
||||
internal IList<T> FindAll<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
|
||||
return Connection.Table<T>().Where(p).ToList();
|
||||
|
||||
}
|
||||
|
||||
internal void DeleteWhere<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
var id = Connection.Table<T>().Where(p).FirstOrDefault()?.Id;
|
||||
if (id.HasValue)
|
||||
Connection.Delete<T>(id);
|
||||
}
|
||||
|
||||
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
|
||||
{
|
||||
return new HashSet<T>(Connection.Table<T>());
|
||||
}
|
||||
|
||||
internal CurrencyState GetStateByUserId(long id)
|
||||
{
|
||||
return Connection.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
|
||||
}
|
||||
|
||||
internal T Delete<T>(int id) where T : IDataModel, new()
|
||||
{
|
||||
var found = Connection.Find<T>(id);
|
||||
if (found != null)
|
||||
Connection.Delete<T>(found.Id);
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing object or creates a new one
|
||||
/// </summary>
|
||||
internal void Save<T>(T o) where T : IDataModel, new()
|
||||
{
|
||||
var found = Connection.Find<T>(o.Id);
|
||||
if (found == null)
|
||||
Connection.Insert(o, typeof(T));
|
||||
else
|
||||
Connection.Update(o, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing object or creates a new one
|
||||
/// </summary>
|
||||
internal void SaveAll<T>(IEnumerable<T> ocol) where T : IDataModel, new()
|
||||
{
|
||||
foreach (var o in ocol)
|
||||
Connection.InsertOrReplace(o);
|
||||
}
|
||||
|
||||
internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
|
||||
{
|
||||
var r = new Random();
|
||||
return Connection.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="num">Page number (0+)</param>
|
||||
/// <returns></returns>
|
||||
internal List<PlaylistData> GetPlaylistData(int num)
|
||||
{
|
||||
return Connection.Query<PlaylistData>(
|
||||
@"SELECT mp.Name as 'Name',mp.Id as 'Id', mp.CreatorName as 'Creator', Count(*) as 'SongCnt' FROM MusicPlaylist as mp
|
||||
INNER JOIN PlaylistSongInfo as psi
|
||||
ON mp.Id = psi.PlaylistId
|
||||
Group BY mp.Name
|
||||
Order By mp.DateAdded desc
|
||||
Limit 20 OFFSET ?", num * 20);
|
||||
|
||||
}
|
||||
|
||||
internal IEnumerable<CurrencyState> GetTopRichest(int n = 10)
|
||||
{
|
||||
return Connection.Table<CurrencyState>().OrderByDescending(cs => cs.Value).Take(n).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PlaylistData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string Creator { get; set; }
|
||||
public int SongCnt { get; set; }
|
||||
}
|
||||
|
||||
public static class Queries
|
||||
{
|
||||
public const string TransactionTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
|
||||
AFTER INSERT ON CurrencyTransaction
|
||||
BEGIN
|
||||
INSERT OR REPLACE INTO CurrencyState (Id, UserId, Value, DateAdded)
|
||||
VALUES (COALESCE((SELECT Id from CurrencyState where UserId = NEW.UserId),(SELECT COALESCE(MAX(Id),0)+1 from CurrencyState)),
|
||||
NEW.UserId,
|
||||
COALESCE((SELECT Value+New.Value FROM CurrencyState Where UserId = NEW.UserId),NEW.Value),
|
||||
NEW.DateAdded);
|
||||
END
|
||||
";
|
||||
public const string DeletePlaylistTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS music_playlist
|
||||
AFTER DELETE ON MusicPlaylist
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DELETE FROM PlaylistSongInfo WHERE PlaylistId = OLD.Id;
|
||||
END";
|
||||
}
|
378
src/NadekoBot/Classes/Extensions.cs
Normal file
@ -0,0 +1,378 @@
|
||||
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 IList<T> 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;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <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 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 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;
|
||||
}
|
||||
|
||||
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
|
||||
}
|
||||
}
|
53
src/NadekoBot/Classes/FlowersHandler.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal static class FlowersHandler
|
||||
{
|
||||
public static async Task AddFlowersAsync(Discord.User u, string reason, int amount, bool silent = false)
|
||||
{
|
||||
if (amount <= 0)
|
||||
return;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
|
||||
{
|
||||
Reason = reason,
|
||||
UserId = (long)u.Id,
|
||||
Value = amount,
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
if (silent)
|
||||
return;
|
||||
|
||||
var flows = amount + " " + NadekoBot.Config.CurrencySign;
|
||||
|
||||
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<bool> RemoveFlowers(Discord.User u, string reason, int amount, bool silent=false, string message="👎`Bot owner has taken {0}{1} from you.`")
|
||||
{
|
||||
if (amount <= 0)
|
||||
return false;
|
||||
var uid = (long)u.Id;
|
||||
var state = DbHandler.Instance.FindOne<DataModels.CurrencyState>(cs => cs.UserId == uid);
|
||||
|
||||
if (state.Value < amount)
|
||||
return false;
|
||||
|
||||
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
|
||||
{
|
||||
Reason = reason,
|
||||
UserId = (long)u.Id,
|
||||
Value = -amount,
|
||||
});
|
||||
|
||||
if (silent)
|
||||
return true;
|
||||
|
||||
await u.SendMessage(string.Format(message,amount,NadekoBot.Config.CurrencySign)).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
25
src/NadekoBot/Classes/IncidentsHandler.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using NadekoBot.DataModels;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal static class IncidentsHandler
|
||||
{
|
||||
public static void Add(ulong serverId, ulong channelId, string text)
|
||||
{
|
||||
var def = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"INCIDENT: {text}");
|
||||
Console.ForegroundColor = def;
|
||||
var incident = new Incident
|
||||
{
|
||||
ChannelId = (long)channelId,
|
||||
ServerId = (long)serverId,
|
||||
Text = text,
|
||||
Read = false
|
||||
};
|
||||
|
||||
DbHandler.Instance.Connection.Insert(incident, typeof(Incident));
|
||||
}
|
||||
}
|
||||
}
|
284
src/NadekoBot/Classes/NadekoStats.cs
Normal file
@ -0,0 +1,284 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Commands;
|
||||
using NadekoBot.Modules.Music;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
public class NadekoStats
|
||||
{
|
||||
public static NadekoStats Instance { get; } = new NadekoStats();
|
||||
|
||||
public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
|
||||
|
||||
private int commandsRan = 0;
|
||||
private string statsCache = "";
|
||||
private readonly Stopwatch statsStopwatch = new Stopwatch();
|
||||
|
||||
public int ServerCount { get; private set; } = 0;
|
||||
public int TextChannelsCount { get; private set; } = 0;
|
||||
public int VoiceChannelsCount { get; private set; } = 0;
|
||||
|
||||
private readonly Timer commandLogTimer = new Timer() { Interval = 10000 };
|
||||
private readonly Timer carbonStatusTimer = new Timer() { Interval = 3600000 };
|
||||
|
||||
private static ulong messageCounter = 0;
|
||||
public static ulong MessageCounter => messageCounter;
|
||||
|
||||
static NadekoStats() { }
|
||||
|
||||
private NadekoStats()
|
||||
{
|
||||
var commandService = NadekoBot.Client.GetService<CommandService>();
|
||||
|
||||
statsStopwatch.Start();
|
||||
|
||||
commandService.CommandExecuted += StatsCollector_RanCommand;
|
||||
commandService.CommandFinished += CommandService_CommandFinished;
|
||||
commandService.CommandErrored += CommandService_CommandFinished;
|
||||
|
||||
Task.Run(StartCollecting);
|
||||
|
||||
commandLogTimer.Start();
|
||||
|
||||
ServerCount = NadekoBot.Client.Servers.Count();
|
||||
var channels = NadekoBot.Client.Servers.SelectMany(s => s.AllChannels);
|
||||
var channelsArray = channels as Channel[] ?? channels.ToArray();
|
||||
TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
|
||||
VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
|
||||
|
||||
NadekoBot.Client.MessageReceived += (s, e) => messageCounter++;
|
||||
|
||||
NadekoBot.Client.JoinedServer += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerCount++;
|
||||
TextChannelsCount += e.Server.TextChannels.Count();
|
||||
VoiceChannelsCount += e.Server.VoiceChannels.Count();
|
||||
//await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.LeftServer += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerCount--;
|
||||
TextChannelsCount -= e.Server.TextChannels.Count();
|
||||
VoiceChannelsCount -= e.Server.VoiceChannels.Count();
|
||||
//await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.ChannelCreated += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel.IsPrivate)
|
||||
return;
|
||||
if (e.Channel.Type == ChannelType.Text)
|
||||
TextChannelsCount++;
|
||||
else if (e.Channel.Type == ChannelType.Voice)
|
||||
VoiceChannelsCount++;
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
NadekoBot.Client.ChannelDestroyed += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Channel.IsPrivate)
|
||||
return;
|
||||
if (e.Channel.Type == ChannelType.Text)
|
||||
TextChannelsCount--;
|
||||
else if (e.Channel.Type == ChannelType.Voice)
|
||||
VoiceChannelsCount--;
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false);
|
||||
carbonStatusTimer.Start();
|
||||
}
|
||||
|
||||
HttpClient carbonClient = new HttpClient();
|
||||
private async Task SendUpdateToCarbon()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(new Dictionary<string, string> {
|
||||
{ "servercount", NadekoBot.Client.Servers.Count().ToString() },
|
||||
{ "key", NadekoBot.Creds.CarbonKey }
|
||||
}))
|
||||
{
|
||||
content.Headers.Clear();
|
||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
var res = await carbonClient.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Failed sending status update to carbon.");
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan GetUptime() =>
|
||||
DateTime.Now - Process.GetCurrentProcess().StartTime;
|
||||
|
||||
public string GetUptimeString()
|
||||
{
|
||||
var time = GetUptime();
|
||||
return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
|
||||
}
|
||||
|
||||
public Task LoadStats() =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
var songs = MusicModule.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
|
||||
sb.AppendLine($"`Bot Version: {BotVersion}`");
|
||||
sb.AppendLine($"`Bot id: {NadekoBot.Client.CurrentUser.Id}`");
|
||||
sb.Append("`Owners' Ids:` ");
|
||||
sb.AppendLine("`" + String.Join(", ", NadekoBot.Creds.OwnerIds) + "`");
|
||||
sb.AppendLine($"`Uptime: {GetUptimeString()}`");
|
||||
sb.Append($"`Servers: {ServerCount}");
|
||||
sb.Append($" | TextChannels: {TextChannelsCount}");
|
||||
sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
|
||||
sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
|
||||
sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`");
|
||||
sb.Append($"`Greeted {ServerGreetCommand.Greeted} times.`");
|
||||
sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) +
|
||||
$"{MusicModule.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
|
||||
sb.AppendLine($"`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap(false)}`");
|
||||
statsCache = sb.ToString();
|
||||
});
|
||||
|
||||
public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString();
|
||||
|
||||
public async Task<string> GetStats()
|
||||
{
|
||||
if (statsStopwatch.Elapsed.Seconds < 4 &&
|
||||
!string.IsNullOrWhiteSpace(statsCache)) return statsCache;
|
||||
await LoadStats().ConfigureAwait(false);
|
||||
statsStopwatch.Restart();
|
||||
return statsCache;
|
||||
}
|
||||
|
||||
private async Task StartCollecting()
|
||||
{
|
||||
var statsSw = new Stopwatch();
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
|
||||
statsSw.Start();
|
||||
try
|
||||
{
|
||||
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false);
|
||||
var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
|
||||
.Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)))
|
||||
.ConfigureAwait(false);
|
||||
var connectedServers = NadekoBot.Client.Servers.Count();
|
||||
|
||||
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Stats
|
||||
{
|
||||
OnlineUsers = onlineUsers,
|
||||
RealOnlineUsers = realOnlineUsers,
|
||||
Uptime = GetUptime(),
|
||||
ConnectedServers = connectedServers,
|
||||
DateAdded = DateTime.Now
|
||||
});
|
||||
|
||||
statsSw.Stop();
|
||||
var clr = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
Console.WriteLine($"--------------\nCollecting stats finished in {statsSw.Elapsed.TotalSeconds}s\n-------------");
|
||||
Console.ForegroundColor = clr;
|
||||
statsSw.Reset();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("DB Exception in stats collecting.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<ulong, DateTime> commandTracker = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
private void CommandService_CommandFinished(object sender, CommandEventArgs e)
|
||||
{
|
||||
|
||||
DateTime dt;
|
||||
if (!commandTracker.TryGetValue(e.Message.Id, out dt))
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (e is CommandErrorEventArgs)
|
||||
{
|
||||
var er = e as CommandErrorEventArgs;
|
||||
if (er.ErrorType == CommandErrorType.Exception)
|
||||
{
|
||||
File.AppendAllText("errors.txt", $@"Command: {er.Command}
|
||||
{er.Exception}
|
||||
-------------------------------------
|
||||
");
|
||||
Console.WriteLine($">>COMMAND ERRORED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
|
||||
{
|
||||
commandTracker.TryAdd(e.Message.Id, DateTime.UtcNow);
|
||||
Console.WriteLine($">>COMMAND STARTED\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
|
||||
#if !NADEKO_RELEASE
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
commandsRan++;
|
||||
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Command
|
||||
{
|
||||
ServerId = (long)(e.Server?.Id ?? 0),
|
||||
ServerName = e.Server?.Name ?? "--Direct Message--",
|
||||
ChannelId = (long)e.Channel.Id,
|
||||
ChannelName = e.Channel.IsPrivate ? "--Direct Message" : e.Channel.Name,
|
||||
UserId = (long)e.User.Id,
|
||||
UserName = e.User.Name,
|
||||
CommandName = e.Command.Text,
|
||||
DateAdded = DateTime.Now
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Probably unimportant error in ran command DB write.");
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
204
src/NadekoBot/Classes/ObservableConcurrentDictionary.cs
Normal file
@ -0,0 +1,204 @@
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// File: ObservableConcurrentDictionary.cs
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a thread-safe dictionary for use with data binding.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam>
|
||||
/// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam>
|
||||
[DebuggerDisplay("Count={Count}")]
|
||||
public class ObservableConcurrentDictionary<TKey, TValue> :
|
||||
ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,
|
||||
INotifyCollectionChanged, INotifyPropertyChanged
|
||||
{
|
||||
private readonly SynchronizationContext _context;
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the ObservableConcurrentDictionary class.
|
||||
/// </summary>
|
||||
public ObservableConcurrentDictionary()
|
||||
{
|
||||
_context = AsyncOperationManager.SynchronizationContext;
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
/// <summary>Event raised when the collection changes.</summary>
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
/// <summary>Event raised when a property on the collection changes.</summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
|
||||
/// </summary>
|
||||
private void NotifyObserversOfChange()
|
||||
{
|
||||
var collectionHandler = CollectionChanged;
|
||||
var propertyHandler = PropertyChanged;
|
||||
if (collectionHandler != null || propertyHandler != null)
|
||||
{
|
||||
_context.Post(s =>
|
||||
{
|
||||
if (collectionHandler != null)
|
||||
{
|
||||
collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
if (propertyHandler != null)
|
||||
{
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Count"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Keys"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Values"));
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="item">The item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return TryAddWithNotification(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be added.</param>
|
||||
/// <param name="value">The value of the item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(TKey key, TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryAdd(key, value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be removed.</param>
|
||||
/// <param name="value">The value of the item removed.</param>
|
||||
/// <returns>Whether the removal was successful.</returns>
|
||||
private bool TryRemoveWithNotification(TKey key, out TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryRemove(key, out value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be updated.</param>
|
||||
/// <param name="value">The new value to set for the item.</param>
|
||||
/// <returns>Whether the update was successful.</returns>
|
||||
private void UpdateWithNotification(TKey key, TValue value)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
#region ICollection<KeyValuePair<TKey,TValue>> Members
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TryAddWithNotification(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear();
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
int ICollection<KeyValuePair<TKey, TValue>>.Count {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(item.Key, out temp);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<KeyValuePair<TKey,TValue>> Members
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDictionary<TKey,TValue> Members
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public ICollection<TKey> Keys {
|
||||
get { return _dictionary.Keys; }
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(key, out temp);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
return TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public ICollection<TValue> Values {
|
||||
get { return _dictionary.Values; }
|
||||
}
|
||||
|
||||
public TValue this[TKey key] {
|
||||
get { return _dictionary[key]; }
|
||||
set { UpdateWithNotification(key, value); }
|
||||
}
|
||||
|
||||
public bool TryRemove(TKey key, out TValue value)
|
||||
{
|
||||
return TryRemoveWithNotification(key, out value);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
3278
src/NadekoBot/Classes/SQLite.cs
Normal file
381
src/NadekoBot/Classes/SearchHelper.cs
Normal file
@ -0,0 +1,381 @@
|
||||
using NadekoBot.Classes.JSONModels;
|
||||
using NadekoBot.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Authentication;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
public enum RequestHttpMethod
|
||||
{
|
||||
Get,
|
||||
Post
|
||||
}
|
||||
|
||||
public static class SearchHelper
|
||||
{
|
||||
private static DateTime lastRefreshed = DateTime.MinValue;
|
||||
private static string token { get; set; } = "";
|
||||
|
||||
public static async Task<Stream> GetResponseStreamAsync(string url,
|
||||
IEnumerable<KeyValuePair<string, string>> headers = null, RequestHttpMethod method = RequestHttpMethod.Get)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
var cl = new HttpClient();
|
||||
cl.DefaultRequestHeaders.Clear();
|
||||
switch (method)
|
||||
{
|
||||
case RequestHttpMethod.Get:
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
cl.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
return await cl.GetStreamAsync(url).ConfigureAwait(false);
|
||||
case RequestHttpMethod.Post:
|
||||
FormUrlEncodedContent formContent = null;
|
||||
if (headers != null)
|
||||
{
|
||||
formContent = new FormUrlEncodedContent(headers);
|
||||
}
|
||||
var message = await cl.PostAsync(url, formContent).ConfigureAwait(false);
|
||||
return await message.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
default:
|
||||
throw new NotImplementedException("That type of request is unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> GetResponseStringAsync(string url,
|
||||
IEnumerable<KeyValuePair<string, string>> headers = null,
|
||||
RequestHttpMethod method = RequestHttpMethod.Get)
|
||||
{
|
||||
|
||||
using (var streamReader = new StreamReader(await GetResponseStreamAsync(url, headers, method).ConfigureAwait(false)))
|
||||
{
|
||||
return await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<AnimeResult> GetAnimeData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
await RefreshAnilistToken().ConfigureAwait(false);
|
||||
|
||||
var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
|
||||
var smallContent = "";
|
||||
var cl = new RestSharp.RestClient("http://anilist.co/api");
|
||||
var rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query));
|
||||
rq.AddParameter("access_token", token);
|
||||
smallContent = cl.Execute(rq).Content;
|
||||
var smallObj = JArray.Parse(smallContent)[0];
|
||||
|
||||
rq = new RestSharp.RestRequest("/anime/" + smallObj["id"]);
|
||||
rq.AddParameter("access_token", token);
|
||||
var content = cl.Execute(rq).Content;
|
||||
|
||||
return await Task.Run(() => JsonConvert.DeserializeObject<AnimeResult>(content)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<MangaResult> GetMangaData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
await RefreshAnilistToken().ConfigureAwait(false);
|
||||
|
||||
var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
|
||||
var smallContent = "";
|
||||
var cl = new RestSharp.RestClient("http://anilist.co/api");
|
||||
var rq = new RestSharp.RestRequest("/manga/search/" + Uri.EscapeUriString(query));
|
||||
rq.AddParameter("access_token", token);
|
||||
smallContent = cl.Execute(rq).Content;
|
||||
var smallObj = JArray.Parse(smallContent)[0];
|
||||
|
||||
rq = new RestSharp.RestRequest("/manga/" + smallObj["id"]);
|
||||
rq.AddParameter("access_token", token);
|
||||
var content = cl.Execute(rq).Content;
|
||||
|
||||
return await Task.Run(() => JsonConvert.DeserializeObject<MangaResult>(content)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task RefreshAnilistToken()
|
||||
{
|
||||
if (DateTime.Now - lastRefreshed > TimeSpan.FromMinutes(29))
|
||||
lastRefreshed = DateTime.Now;
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
var headers = new Dictionary<string, string> {
|
||||
{"grant_type", "client_credentials"},
|
||||
{"client_id", "kwoth-w0ki9"},
|
||||
{"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
|
||||
};
|
||||
var content = await GetResponseStringAsync(
|
||||
"http://anilist.co/api/auth/access_token",
|
||||
headers,
|
||||
RequestHttpMethod.Post).ConfigureAwait(false);
|
||||
|
||||
token = JObject.Parse(content)["access_token"].ToString();
|
||||
}
|
||||
|
||||
public static async Task<bool> ValidateQuery(Discord.Channel ch, string query)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(query.Trim())) return true;
|
||||
await ch.Send("Please specify search parameters.").ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task<string> FindYoutubeUrlByKeywords(string keywords)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(keywords))
|
||||
throw new ArgumentNullException(nameof(keywords), "Query not specified.");
|
||||
if (keywords.Length > 150)
|
||||
throw new ArgumentException("Query is too long.");
|
||||
|
||||
//maybe it is already a youtube url, in which case we will just extract the id and prepend it with youtube.com?v=
|
||||
var match = new Regex("(?:youtu\\.be\\/|v=)(?<id>[\\da-zA-Z\\-_]*)").Match(keywords);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
return $"https://www.youtube.com/watch?v={match.Groups["id"].Value}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
throw new InvalidCredentialException("Google API Key is missing.");
|
||||
|
||||
var response = await GetResponseStringAsync(
|
||||
$"https://www.googleapis.com/youtube/v3/search?" +
|
||||
$"part=snippet&maxResults=1" +
|
||||
$"&q={Uri.EscapeDataString(keywords)}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
|
||||
|
||||
if (data.items.Length > 0)
|
||||
{
|
||||
var toReturn = "http://www.youtube.com/watch?v=" + data.items[0].id.videoId.ToString();
|
||||
return toReturn;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<string>> GetRelatedVideoIds(string id, int count = 1)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
var match = new Regex("(?:youtu\\.be\\/|v=)(?<id>[\\da-zA-Z\\-_]*)").Match(id);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
id = match.Groups["id"].Value;
|
||||
}
|
||||
var response = await GetResponseStringAsync(
|
||||
$"https://www.googleapis.com/youtube/v3/search?" +
|
||||
$"part=snippet&maxResults={count}&type=video" +
|
||||
$"&relatedToVideoId={id}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
|
||||
|
||||
return data.items.Select(v => "http://www.youtube.com/watch?v=" + v.id.videoId);
|
||||
}
|
||||
|
||||
public static async Task<string> GetPlaylistIdByKeyword(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
var match = new Regex("(?:youtu\\.be\\/|list=)(?<id>[\\da-zA-Z\\-_]*)").Match(query);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
return match.Groups["id"].Value.ToString();
|
||||
}
|
||||
var link = "https://www.googleapis.com/youtube/v3/search?part=snippet" +
|
||||
"&maxResults=1&type=playlist" +
|
||||
$"&q={Uri.EscapeDataString(query)}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
|
||||
var response = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var data = JsonConvert.DeserializeObject<YoutubePlaylistSearch>(response);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
return data.items.Length > 0 ? data.items[0].id.playlistId.ToString() : null;
|
||||
}
|
||||
|
||||
public static async Task<IList<string>> GetVideoIDs(string playlist, int number = 50)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(playlist));
|
||||
}
|
||||
if (number < 1)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
string nextPageToken = null;
|
||||
|
||||
List<string> toReturn = new List<string>();
|
||||
|
||||
do
|
||||
{
|
||||
var toGet = number > 50 ? 50 : number;
|
||||
number -= toGet;
|
||||
var link =
|
||||
$"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails" +
|
||||
$"&maxResults={toGet}" +
|
||||
$"&playlistId={playlist}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
if (!string.IsNullOrWhiteSpace(nextPageToken))
|
||||
link += $"&pageToken={nextPageToken}";
|
||||
var response = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var data = await Task.Run(() => JsonConvert.DeserializeObject<PlaylistItemsSearch>(response)).ConfigureAwait(false);
|
||||
nextPageToken = data.nextPageToken;
|
||||
toReturn.AddRange(data.items.Select(i => i.contentDetails.videoId));
|
||||
} while (number > 0 && !string.IsNullOrWhiteSpace(nextPageToken));
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<string> GetDanbooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
|
||||
if (tag == "loli") //loli doesn't work for some reason atm
|
||||
tag = "flat_chest";
|
||||
|
||||
var link = $"http://danbooru.donmai.us/posts?" +
|
||||
$"page={rng.Next(0, 15)}";
|
||||
if (!string.IsNullOrWhiteSpace(tag))
|
||||
link += $"&tags={tag.Replace(" ", "_")}";
|
||||
|
||||
var webpage = await GetResponseStringAsync(link).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "data-large-file-url=\"(?<id>.*?)\"");
|
||||
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
return $"http://danbooru.donmai.us" +
|
||||
$"{matches[rng.Next(0, matches.Count)].Groups["id"].Value}";
|
||||
}
|
||||
|
||||
public static async Task<string> GetGelbooruImageLink(string tag)
|
||||
{
|
||||
var headers = new Dictionary<string, string>() {
|
||||
{"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
|
||||
{"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
|
||||
};
|
||||
var url =
|
||||
$"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url, headers).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var rng = new Random();
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
public static async Task<string> GetSafebooruImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
public static async Task<string> GetRule34ImageLink(string tag)
|
||||
{
|
||||
var rng = new Random();
|
||||
var url =
|
||||
$"http://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
|
||||
var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
|
||||
var matches = Regex.Matches(webpage, "file_url=\"(?<url>.*?)\"");
|
||||
if (matches.Count == 0)
|
||||
return null;
|
||||
var match = matches[rng.Next(0, matches.Count)];
|
||||
return "http:" + matches[rng.Next(0, matches.Count)].Groups["url"].Value;
|
||||
}
|
||||
|
||||
|
||||
internal static async Task<string> GetE621ImageLink(string tags)
|
||||
{
|
||||
try
|
||||
{
|
||||
var headers = new Dictionary<string, string>() {
|
||||
{"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
|
||||
{"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
|
||||
};
|
||||
var data = await GetResponseStreamAsync(
|
||||
"http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1",
|
||||
headers);
|
||||
var doc = XDocument.Load(data);
|
||||
return doc.Descendants("file_url").FirstOrDefault().Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error in e621 search: \n" + ex);
|
||||
return "Error, do you have too many tags?";
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> ShortenUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey)) return url;
|
||||
try
|
||||
{
|
||||
var httpWebRequest =
|
||||
(HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" +
|
||||
NadekoBot.Creds.GoogleAPIKey);
|
||||
httpWebRequest.ContentType = "application/json";
|
||||
httpWebRequest.Method = "POST";
|
||||
|
||||
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
|
||||
{
|
||||
var json = "{\"longUrl\":\"" + Uri.EscapeDataString(url) + "\"}";
|
||||
streamWriter.Write(json);
|
||||
}
|
||||
|
||||
var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse;
|
||||
var responseStream = httpResponse.GetResponseStream();
|
||||
using (var streamReader = new StreamReader(responseStream))
|
||||
{
|
||||
var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||
return Regex.Match(responseText, @"""id"": ?""(?<id>.+)""").Groups["id"].Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Shortening of this url failed: " + url);
|
||||
Console.WriteLine(ex.ToString());
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ShowInPrettyCode<T>(IEnumerable<T> items, Func<T, string> howToPrint, int cols = 3)
|
||||
{
|
||||
var i = 0;
|
||||
return "```xl\n" + string.Join("\n", items.GroupBy(item => (i++) / cols)
|
||||
.Select(ig => string.Concat(ig.Select(el => howToPrint(el)))))
|
||||
+ $"\n```";
|
||||
}
|
||||
}
|
||||
}
|
292
src/NadekoBot/Classes/ServerSpecificConfig.cs
Normal file
@ -0,0 +1,292 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal class SpecificConfigurations
|
||||
{
|
||||
public static SpecificConfigurations Default { get; } = new SpecificConfigurations();
|
||||
public static bool Instantiated { get; private set; }
|
||||
|
||||
private const string filePath = "data/ServerSpecificConfigs.json";
|
||||
|
||||
static SpecificConfigurations() { }
|
||||
|
||||
private SpecificConfigurations()
|
||||
{
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
configs = JsonConvert
|
||||
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
|
||||
File.ReadAllText(filePath), new JsonSerializerSettings()
|
||||
{
|
||||
Error = (s, e) =>
|
||||
{
|
||||
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
|
||||
{
|
||||
e.ErrorContext.Handled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Deserialization failing: {ex}");
|
||||
}
|
||||
}
|
||||
if (configs == null)
|
||||
configs = new ConcurrentDictionary<ulong, ServerSpecificConfig>();
|
||||
Instantiated = true;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, ServerSpecificConfig> configs;
|
||||
|
||||
public IEnumerable<ServerSpecificConfig> AllConfigs => configs.Values;
|
||||
|
||||
public ServerSpecificConfig Of(ulong id) =>
|
||||
configs.GetOrAdd(id, _ => new ServerSpecificConfig());
|
||||
|
||||
private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public async Task Save()
|
||||
{
|
||||
await saveLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
|
||||
}
|
||||
finally
|
||||
{
|
||||
saveLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ServerSpecificConfig : INotifyPropertyChanged
|
||||
{
|
||||
[JsonProperty("VoicePlusTextEnabled")]
|
||||
private bool voicePlusTextEnabled;
|
||||
[JsonIgnore]
|
||||
public bool VoicePlusTextEnabled {
|
||||
get { return voicePlusTextEnabled; }
|
||||
set {
|
||||
voicePlusTextEnabled = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[JsonProperty("SendPrivateMessageOnMention")]
|
||||
private bool sendPrivateMessageOnMention;
|
||||
[JsonIgnore]
|
||||
public bool SendPrivateMessageOnMention {
|
||||
get { return sendPrivateMessageOnMention; }
|
||||
set {
|
||||
sendPrivateMessageOnMention = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogChannel")]
|
||||
private ulong? logServerChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogServerChannel {
|
||||
get { return logServerChannel; }
|
||||
set {
|
||||
logServerChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> logserverIgnoreChannels;
|
||||
public ObservableCollection<ulong> LogserverIgnoreChannels {
|
||||
get { return logserverIgnoreChannels; }
|
||||
set {
|
||||
logserverIgnoreChannels = value;
|
||||
if (value != null)
|
||||
logserverIgnoreChannels.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogPresenceChannel")]
|
||||
private ulong? logPresenceChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogPresenceChannel {
|
||||
get { return logPresenceChannel; }
|
||||
set {
|
||||
logPresenceChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableConcurrentDictionary<ulong, ulong> voiceChannelLog;
|
||||
public ObservableConcurrentDictionary<ulong, ulong> VoiceChannelLog {
|
||||
get { return voiceChannelLog; }
|
||||
set {
|
||||
voiceChannelLog = value;
|
||||
if (value != null)
|
||||
voiceChannelLog.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> listOfSelfAssignableRoles;
|
||||
public ObservableCollection<ulong> ListOfSelfAssignableRoles {
|
||||
get { return listOfSelfAssignableRoles; }
|
||||
set {
|
||||
listOfSelfAssignableRoles = value;
|
||||
if (value != null)
|
||||
listOfSelfAssignableRoles.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private ulong autoAssignedRole = 0;
|
||||
public ulong AutoAssignedRole {
|
||||
get { return autoAssignedRole; }
|
||||
set {
|
||||
autoAssignedRole = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableConcurrentDictionary<ulong, int> generateCurrencyChannels;
|
||||
public ObservableConcurrentDictionary<ulong, int> GenerateCurrencyChannels {
|
||||
get { return generateCurrencyChannels; }
|
||||
set {
|
||||
generateCurrencyChannels = value;
|
||||
if (value != null)
|
||||
generateCurrencyChannels.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool autoDeleteMessagesOnCommand = false;
|
||||
public bool AutoDeleteMessagesOnCommand {
|
||||
get { return autoDeleteMessagesOnCommand; }
|
||||
set {
|
||||
autoDeleteMessagesOnCommand = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool exclusiveSelfAssignedRoles = false;
|
||||
public bool ExclusiveSelfAssignedRoles
|
||||
{
|
||||
get { return exclusiveSelfAssignedRoles; }
|
||||
set
|
||||
{
|
||||
exclusiveSelfAssignedRoles = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<StreamNotificationConfig> observingStreams;
|
||||
public ObservableCollection<StreamNotificationConfig> ObservingStreams {
|
||||
get { return observingStreams; }
|
||||
set {
|
||||
observingStreams = value;
|
||||
if (value != null)
|
||||
observingStreams.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private float defaultMusicVolume = 1f;
|
||||
public float DefaultMusicVolume {
|
||||
get { return defaultMusicVolume; }
|
||||
set {
|
||||
defaultMusicVolume = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ServerSpecificConfig()
|
||||
{
|
||||
ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
|
||||
ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
|
||||
GenerateCurrencyChannels = new ObservableConcurrentDictionary<ulong, int>();
|
||||
VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>();
|
||||
LogserverIgnoreChannels = new ObservableCollection<ulong>();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); };
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
public class StreamNotificationConfig : IEquatable<StreamNotificationConfig>
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public StreamType Type { get; set; }
|
||||
public ulong ServerId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public bool LastStatus { get; set; }
|
||||
|
||||
public enum StreamType
|
||||
{
|
||||
Twitch,
|
||||
Beam,
|
||||
Hitbox,
|
||||
YoutubeGaming
|
||||
}
|
||||
|
||||
public bool Equals(StreamNotificationConfig other) =>
|
||||
this.Username.ToLower().Trim() == other.Username.ToLower().Trim() &&
|
||||
this.Type == other.Type &&
|
||||
this.ServerId == other.ServerId;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)ServerId + Username.Length + (int)Type;
|
||||
}
|
||||
}
|
||||
}
|
46
src/NadekoBot/Localization.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public class Localization
|
||||
{
|
||||
public static string LoadString(string key) => GetOrAddResourceKey(key);
|
||||
|
||||
private static string GetOrAddResourceKey(string key)
|
||||
{
|
||||
return Resources.Strings.ResourceManager.GetString(key);
|
||||
//var resx = new List<DictionaryEntry>();
|
||||
//var fs = new StreamReader(File.OpenRead("./Strings.resx"));
|
||||
//Console.WriteLine(fs.ReadToEnd());
|
||||
//using (var reader = new ResourceReader(fs.BaseStream))
|
||||
//{
|
||||
// List<DictionaryEntry> existing = new List<DictionaryEntry>();
|
||||
// foreach (DictionaryEntry item in reader)
|
||||
// {
|
||||
// existing.Add(item);
|
||||
// }
|
||||
// var existingResource = resx.Where(r => r.Key.ToString() == key).FirstOrDefault();
|
||||
// if (existingResource.Key == null)
|
||||
// {
|
||||
// resx.Add(new DictionaryEntry() { Key = key, Value = key });
|
||||
// }
|
||||
// else
|
||||
// return existingResource.Value.ToString();
|
||||
//}
|
||||
//using (var writer = new ResourceWriter(new FileStream("./Strings.resx", FileMode.OpenOrCreate)))
|
||||
//{
|
||||
// resx.ForEach(r =>
|
||||
// {
|
||||
// writer.AddResource(r.Key.ToString(), r.Value.ToString());
|
||||
// });
|
||||
// writer.Generate();
|
||||
//}
|
||||
//return key;
|
||||
}
|
||||
}
|
||||
}
|
99
src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs
Normal file
@ -0,0 +1,99 @@
|
||||
//using Discord;
|
||||
//using Discord.Commands;
|
||||
//using NadekoBot.Classes;
|
||||
//using NadekoBot.Extensions;
|
||||
//using System;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
|
||||
//namespace NadekoBot.Modules.Utility.Commands
|
||||
//{
|
||||
// class InfoCommands : DiscordCommand
|
||||
// {
|
||||
// public InfoCommands(DiscordModule module) : base(module)
|
||||
// {
|
||||
// }
|
||||
|
||||
// internal override void Init(CommandGroupBuilder cgb)
|
||||
// {
|
||||
// cgb.CreateCommand(Module.Prefix + "serverinfo")
|
||||
// .Alias(Module.Prefix + "sinfo")
|
||||
// .Description($"Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. |`{Module.Prefix}sinfo Some Server`")
|
||||
// .Parameter("server", ParameterType.Optional)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var servText = e.GetArg("server")?.Trim();
|
||||
// var server = string.IsNullOrWhiteSpace(servText)
|
||||
// ? e.Server
|
||||
// : NadekoBot.Client.FindServers(servText).FirstOrDefault();
|
||||
// if (server == null)
|
||||
// return;
|
||||
// var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(server.Id >> 22);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine($"`Name:` **#{server.Name}**");
|
||||
// sb.AppendLine($"`Owner:` **{server.Owner}**");
|
||||
// sb.AppendLine($"`Id:` **{server.Id}**");
|
||||
// sb.AppendLine($"`Icon Url:` **{await server.IconUrl.ShortenUrl().ConfigureAwait(false)}**");
|
||||
// sb.AppendLine($"`TextChannels:` **{server.TextChannels.Count()}** `VoiceChannels:` **{server.VoiceChannels.Count()}**");
|
||||
// sb.AppendLine($"`Members:` **{server.UserCount}** `Online:` **{server.Users.Count(u => u.Status == UserStatus.Online)}** (may be incorrect)");
|
||||
// sb.AppendLine($"`Roles:` **{server.Roles.Count()}**");
|
||||
// sb.AppendLine($"`Created At:` **{createdAt}**");
|
||||
// if (server.CustomEmojis.Count() > 0)
|
||||
// sb.AppendLine($"`Custom Emojis:` **{string.Join(", ", server.CustomEmojis)}**");
|
||||
// if (server.Features.Count() > 0)
|
||||
// sb.AppendLine($"`Features:` **{string.Join(", ", server.Features)}**");
|
||||
// if (!string.IsNullOrWhiteSpace(server.SplashId))
|
||||
// sb.AppendLine($"`Region:` **{server.Region.Name}**");
|
||||
// await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Module.Prefix + "channelinfo")
|
||||
// .Alias(Module.Prefix + "cinfo")
|
||||
// .Description($"Shows info about the channel. If no channel is supplied, it defaults to current one. |`{Module.Prefix}cinfo #some-channel`")
|
||||
// .Parameter("channel", ParameterType.Optional)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var chText = e.GetArg("channel")?.Trim();
|
||||
// var ch = string.IsNullOrWhiteSpace(chText)
|
||||
// ? e.Channel
|
||||
// : e.Server.FindChannels(chText, Discord.ChannelType.Text).FirstOrDefault();
|
||||
// if (ch == null)
|
||||
// return;
|
||||
// var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(ch.Id >> 22);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine($"`Name:` **#{ch.Name}**");
|
||||
// sb.AppendLine($"`Id:` **{ch.Id}**");
|
||||
// sb.AppendLine($"`Created At:` **{createdAt}**");
|
||||
// sb.AppendLine($"`Topic:` **{ch.Topic}**");
|
||||
// sb.AppendLine($"`Users:` **{ch.Users.Count()}**");
|
||||
// await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Module.Prefix + "userinfo")
|
||||
// .Alias(Module.Prefix + "uinfo")
|
||||
// .Description($"Shows info about the user. If no user is supplied, it defaults a user running the command. |`{Module.Prefix}uinfo @SomeUser`")
|
||||
// .Parameter("user", ParameterType.Optional)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var userText = e.GetArg("user")?.Trim();
|
||||
// var user = string.IsNullOrWhiteSpace(userText)
|
||||
// ? e.User
|
||||
// : e.Server.FindUsers(userText).FirstOrDefault();
|
||||
// if (user == null)
|
||||
// return;
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine($"`Name#Discrim:` **#{user.Name}#{user.Discriminator}**");
|
||||
// if (!string.IsNullOrWhiteSpace(user.Nickname))
|
||||
// sb.AppendLine($"`Nickname:` **{user.Nickname}**");
|
||||
// sb.AppendLine($"`Id:` **{user.Id}**");
|
||||
// sb.AppendLine($"`Current Game:` **{(user.CurrentGame?.Name == null ? "-" : user.CurrentGame.Value.Name)}**");
|
||||
// if (user.LastOnlineAt != null)
|
||||
// sb.AppendLine($"`Last Online:` **{user.LastOnlineAt:HH:mm:ss}**");
|
||||
// sb.AppendLine($"`Joined At:` **{user.JoinedAt}**");
|
||||
// sb.AppendLine($"`Roles:` **({user.Roles.Count()}) - {string.Join(", ", user.Roles.Select(r => r.Name))}**");
|
||||
// sb.AppendLine($"`AvatarUrl:` **{await user.AvatarUrl.ShortenUrl().ConfigureAwait(false)}**");
|
||||
// await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//}
|
197
src/NadekoBot/Modules/Utility/Commands/Remind.cs
Normal file
@ -0,0 +1,197 @@
|
||||
//using Discord;
|
||||
//using Discord.Commands;
|
||||
//using NadekoBot.Classes;
|
||||
//using NadekoBot.DataModels;
|
||||
//using NadekoBot.Modules.Permissions.Classes;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text.RegularExpressions;
|
||||
//using System.Timers;
|
||||
|
||||
//namespace NadekoBot.Modules.Utility.Commands
|
||||
//{
|
||||
// class Remind : DiscordCommand
|
||||
// {
|
||||
|
||||
// Regex regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
||||
// RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
// List<Timer> reminders = new List<Timer>();
|
||||
|
||||
// IDictionary<string, Func<Reminder, string>> replacements = new Dictionary<string, Func<Reminder, string>>
|
||||
// {
|
||||
// { "%message%" , (r) => r.Message },
|
||||
// { "%user%", (r) => $"<@!{r.UserId}>" },
|
||||
// { "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
||||
// };
|
||||
|
||||
// public Remind(DiscordModule module) : base(module)
|
||||
// {
|
||||
// var remList = DbHandler.Instance.GetAllRows<Reminder>();
|
||||
|
||||
// reminders = remList.Select(StartNewReminder).ToList();
|
||||
// }
|
||||
|
||||
// private Timer StartNewReminder(Reminder r)
|
||||
// {
|
||||
// var now = DateTime.Now;
|
||||
// var twoMins = new TimeSpan(0, 2, 0);
|
||||
// TimeSpan time = (r.When - now) < twoMins
|
||||
// ? twoMins //if the time is less than 2 minutes,
|
||||
// : r.When - now; //it will send the message 2 minutes after start
|
||||
// //To account for high bot startup times
|
||||
// if (time.TotalMilliseconds > int.MaxValue)
|
||||
// return null;
|
||||
// var t = new Timer(time.TotalMilliseconds);
|
||||
// t.Elapsed += async (s, e) =>
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// Channel ch;
|
||||
// if (r.IsPrivate)
|
||||
// {
|
||||
// ch = NadekoBot.Client.PrivateChannels.FirstOrDefault(c => (long)c.Id == r.ChannelId);
|
||||
// if (ch == null)
|
||||
// ch = await NadekoBot.Client.CreatePrivateChannel((ulong)r.ChannelId).ConfigureAwait(false);
|
||||
// }
|
||||
// else
|
||||
// ch = NadekoBot.Client.GetServer((ulong)r.ServerId)?.GetChannel((ulong)r.ChannelId);
|
||||
|
||||
// if (ch == null)
|
||||
// return;
|
||||
|
||||
// await ch.SendMessage(
|
||||
// replacements.Aggregate(NadekoBot.Config.RemindMessageFormat,
|
||||
// (cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
||||
// ).ConfigureAwait(false); //it works trust me
|
||||
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Console.WriteLine($"Timer error! {ex}");
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// DbHandler.Instance.Delete<Reminder>(r.Id.Value);
|
||||
// t.Stop();
|
||||
// t.Dispose();
|
||||
// }
|
||||
// };
|
||||
// t.Start();
|
||||
// return t;
|
||||
// }
|
||||
|
||||
// internal override void Init(CommandGroupBuilder cgb)
|
||||
// {
|
||||
// cgb.CreateCommand(Module.Prefix + "remind")
|
||||
// .Description("Sends a message to you or a channel after certain amount of time. " +
|
||||
// "First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. " +
|
||||
// "Third argument is a (multiword)message. " +
|
||||
// $" | `{Prefix}remind me 1d5h Do something` or `{Prefix}remind #general Start now!`")
|
||||
// .Parameter("meorchannel", ParameterType.Required)
|
||||
// .Parameter("time", ParameterType.Required)
|
||||
// .Parameter("message", ParameterType.Unparsed)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var meorchStr = e.GetArg("meorchannel").ToUpperInvariant();
|
||||
// Channel ch;
|
||||
// bool isPrivate = false;
|
||||
// if (meorchStr == "ME")
|
||||
// {
|
||||
// isPrivate = true;
|
||||
// ch = await e.User.CreatePMChannel().ConfigureAwait(false);
|
||||
// }
|
||||
// else if (meorchStr == "HERE")
|
||||
// {
|
||||
// ch = e.Channel;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ch = e.Server.FindChannels(meorchStr).FirstOrDefault();
|
||||
// }
|
||||
|
||||
// if (ch == null)
|
||||
// {
|
||||
// await e.Channel.SendMessage($"{e.User.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var timeStr = e.GetArg("time");
|
||||
|
||||
// var m = regex.Match(timeStr);
|
||||
|
||||
// if (m.Length == 0)
|
||||
// {
|
||||
// await e.Channel.SendMessage("Not a valid time format blablabla").ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// string output = "";
|
||||
// var namesAndValues = new Dictionary<string, int>();
|
||||
|
||||
// foreach (var groupName in regex.GetGroupNames())
|
||||
// {
|
||||
// if (groupName == "0") continue;
|
||||
// int value = 0;
|
||||
// int.TryParse(m.Groups[groupName].Value, out value);
|
||||
|
||||
// if (string.IsNullOrEmpty(m.Groups[groupName].Value))
|
||||
// {
|
||||
// namesAndValues[groupName] = 0;
|
||||
// continue;
|
||||
// }
|
||||
// else if (value < 1 ||
|
||||
// (groupName == "months" && value > 1) ||
|
||||
// (groupName == "weeks" && value > 4) ||
|
||||
// (groupName == "days" && value >= 7) ||
|
||||
// (groupName == "hours" && value > 23) ||
|
||||
// (groupName == "minutes" && value > 59))
|
||||
// {
|
||||
// await e.Channel.SendMessage($"Invalid {groupName} value.").ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// namesAndValues[groupName] = value;
|
||||
// output += m.Groups[groupName].Value + " " + groupName + " ";
|
||||
// }
|
||||
// var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] +
|
||||
// 7 * namesAndValues["weeks"] +
|
||||
// namesAndValues["days"],
|
||||
// namesAndValues["hours"],
|
||||
// namesAndValues["minutes"],
|
||||
// 0);
|
||||
|
||||
// var rem = new Reminder
|
||||
// {
|
||||
// ChannelId = (long)ch.Id,
|
||||
// IsPrivate = isPrivate,
|
||||
// When = time,
|
||||
// Message = e.GetArg("message"),
|
||||
// UserId = (long)e.User.Id,
|
||||
// ServerId = (long)e.Server.Id
|
||||
// };
|
||||
// DbHandler.Instance.Connection.Insert(rem);
|
||||
|
||||
// reminders.Add(StartNewReminder(rem));
|
||||
|
||||
// await e.Channel.SendMessage($"⏰ I will remind \"{ch.Name}\" to \"{e.GetArg("message").ToString()}\" in {output}. ({time:d.M.yyyy.} at {time:HH:mm})").ConfigureAwait(false);
|
||||
// });
|
||||
// cgb.CreateCommand(Module.Prefix + "remindmsg")
|
||||
// .Description("Sets message for when the remind is triggered. " +
|
||||
// " Available placeholders are %user% - user who ran the command, %message% -" +
|
||||
// $" Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!** | `{Prefix}remindmsg do something else`")
|
||||
// .Parameter("msg", ParameterType.Unparsed)
|
||||
// .AddCheck(SimpleCheckers.OwnerOnly())
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var arg = e.GetArg("msg")?.Trim();
|
||||
// if (string.IsNullOrWhiteSpace(arg))
|
||||
// return;
|
||||
|
||||
// NadekoBot.Config.RemindMessageFormat = arg;
|
||||
// await e.Channel.SendMessage("`New remind message set.`");
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//}
|
175
src/NadekoBot/Modules/Utility/UtilityModule.cs
Normal file
@ -0,0 +1,175 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
|
||||
[Module(".", AppendSpace = false)]
|
||||
public class UtilityModule
|
||||
{
|
||||
[LocalizedCommand]
|
||||
[LocalizedDescription]
|
||||
[LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task WhoPlays(IMessage imsg, [Remainder] string game)
|
||||
{
|
||||
var chnl = (IGuildChannel)imsg.Channel;
|
||||
game = game.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
var arr = (await chnl.Guild.GetUsersAsync())
|
||||
.Where(u => u.Game?.Name.ToUpperInvariant() == game)
|
||||
.Select(u => u.Username)
|
||||
.ToList();
|
||||
|
||||
int i = 0;
|
||||
if (!arr.Any())
|
||||
await imsg.Channel.SendMessageAsync("`Noone is playing that game.`").ConfigureAwait(false);
|
||||
else
|
||||
await imsg.Channel.SendMessageAsync("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Concat(ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[LocalizedCommand]
|
||||
[LocalizedDescription]
|
||||
[LocalizedSummary]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task InRole(IMessage imsg, [Remainder] string roles) {
|
||||
if (string.IsNullOrWhiteSpace(roles))
|
||||
return;
|
||||
var channel = imsg.Channel as IGuildChannel;
|
||||
var arg = roles.Split(',').Select(r => r.Trim().ToUpperInvariant());
|
||||
string send = $"`Here is a list of users in a specfic role:`";
|
||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@EVERYONE" && str != "EVERYONE"))
|
||||
{
|
||||
var role = channel.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleStr).FirstOrDefault();
|
||||
if (role == null) continue;
|
||||
send += $"\n`{role.Name}`\n";
|
||||
send += string.Join(", ", (await channel.Guild.GetUsersAsync()).Where(u=>u.Roles.Contains(role)).Select(u => u.ToString()));
|
||||
}
|
||||
|
||||
//todo
|
||||
|
||||
|
||||
//while (send.Length > 2000)
|
||||
//{
|
||||
// if (!)
|
||||
// {
|
||||
// await e.Channel.SendMessage($"{e.User.Mention} you are not allowed to use this command on roles with a lot of users in them to prevent abuse.");
|
||||
// return;
|
||||
// }
|
||||
// var curstr = send.Substring(0, 2000);
|
||||
// await imsg.Channel.SendMessageAsync(curstr.Substring(0,
|
||||
// curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
// send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
// send.Substring(2000);
|
||||
//}
|
||||
//await e.Channel.Send(send).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
//public void Install()
|
||||
//{
|
||||
// manager.CreateCommands("", cgb =>
|
||||
// {
|
||||
// cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
// var client = manager.Client;
|
||||
|
||||
// commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
// cgb.CreateCommand(Prefix + "whoplays")
|
||||
// .Description()
|
||||
// .Parameter("game", ParameterType.Unparsed)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// cgb.CreateCommand(Prefix + "checkmyperms")
|
||||
// .Description($"Checks your userspecific permissions on this channel. | `{Prefix}checkmyperms`")
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var output = "```\n";
|
||||
// foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
||||
// {
|
||||
// output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n";
|
||||
// }
|
||||
// output += "```";
|
||||
// await e.User.SendMessage(output).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Prefix + "stats")
|
||||
// .Description($"Shows some basic stats for Nadeko. | `{Prefix}stats`")
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Prefix + "dysyd")
|
||||
// .Description($"Shows some basic stats for Nadeko. | `{Prefix}dysyd`")
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
|
||||
// .Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"`")
|
||||
// .Parameter("user", ParameterType.Unparsed)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var usr = e.User;
|
||||
// if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
// if (usr == null)
|
||||
// return;
|
||||
// await e.Channel.SendMessage($"Id of the user { usr.Name } is { usr.Id }").ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
// cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
|
||||
// .Description($"Shows current channel ID. | `{Prefix}cid`")
|
||||
// .Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
|
||||
|
||||
// cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
|
||||
// .Description($"Shows current server ID. | `{Prefix}sid`")
|
||||
// .Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
|
||||
|
||||
// cgb.CreateCommand(Prefix + "roles")
|
||||
// .Description("List all roles on this server or a single user if specified. | `{Prefix}roles`")
|
||||
// .Parameter("user", ParameterType.Unparsed)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
// {
|
||||
// var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
// if (usr == null) return;
|
||||
|
||||
// await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
|
||||
// return;
|
||||
// }
|
||||
// await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
|
||||
// });
|
||||
|
||||
|
||||
// cgb.CreateCommand(Prefix + "channeltopic")
|
||||
// .Alias(Prefix + "ct")
|
||||
// .Description($"Sends current channel's topic as a message. | `{Prefix}ct`")
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// var topic = e.Channel.Topic;
|
||||
// if (string.IsNullOrWhiteSpace(topic))
|
||||
// return;
|
||||
// await e.Channel.SendMessage(topic).ConfigureAwait(false);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
42
src/NadekoBot/NadekoBot.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
public class NadekoBot
|
||||
{
|
||||
public static CommandService Commands { get; private set; }
|
||||
public static DiscordSocketClient Client { get; private set; }
|
||||
|
||||
public async Task RunAsync(string[] args)
|
||||
{
|
||||
Client = new DiscordSocketClient(new Discord.DiscordSocketConfig
|
||||
{
|
||||
AudioMode = Discord.Audio.AudioMode.Incoming,
|
||||
LargeThreshold = 200,
|
||||
LogLevel = Discord.LogSeverity.Warning,
|
||||
MessageCacheSize = 10,
|
||||
});
|
||||
|
||||
Commands = new CommandService();
|
||||
|
||||
//Client.MessageReceived += Client_MessageReceived;
|
||||
|
||||
//await Commands.Load(new UtilityModule());
|
||||
await Commands.LoadAssembly(Assembly.GetEntryAssembly());
|
||||
|
||||
await Client.LoginAsync(Discord.TokenType.Bot, "MTE5Nzc3MDIxMzE5NTc3NjEw.CmxGHA.nk1KyvR6y05nntj-J0W_Zvu-2kk");
|
||||
await Client.ConnectAsync();
|
||||
|
||||
Console.WriteLine(Commands.Commands.Count());
|
||||
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
}
|
||||
}
|
19
src/NadekoBot/NadekoBot.xproj
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>45ec1473-c678-4857-a544-07dfe0d0b478</ProjectGuid>
|
||||
<RootNamespace>NadekoBot</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
7
src/NadekoBot/Program.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace NadekoBot
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args) => new NadekoBot().RunAsync(args).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
19
src/NadekoBot/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NadekoBot")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f8225ac4-3cbc-40b4-bcf3-1cacf276bf29")]
|
7568
src/NadekoBot/Resources/Strings.Designer.cs
generated
Normal file
2622
src/NadekoBot/Resources/Strings.resx
Normal file
BIN
src/NadekoBot/Resources/images/cards/10_of_clubs.jpg
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/10_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/10_of_hearts.jpg
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src/NadekoBot/Resources/images/cards/10_of_spades.jpg
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
src/NadekoBot/Resources/images/cards/2_of_clubs.jpg
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src/NadekoBot/Resources/images/cards/2_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/NadekoBot/Resources/images/cards/2_of_hearts.jpg
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/NadekoBot/Resources/images/cards/2_of_spades.jpg
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/3_of_clubs.jpg
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/3_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/3_of_hearts.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
src/NadekoBot/Resources/images/cards/3_of_spades.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/NadekoBot/Resources/images/cards/4_of_clubs.jpg
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/4_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/NadekoBot/Resources/images/cards/4_of_hearts.jpg
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/4_of_spades.jpg
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/5_of_clubs.jpg
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
src/NadekoBot/Resources/images/cards/5_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
src/NadekoBot/Resources/images/cards/5_of_hearts.jpg
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/5_of_spades.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/NadekoBot/Resources/images/cards/6_of_clubs.jpg
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
src/NadekoBot/Resources/images/cards/6_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/6_of_hearts.jpg
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/6_of_spades.jpg
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
src/NadekoBot/Resources/images/cards/7_of_clubs.jpg
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
src/NadekoBot/Resources/images/cards/7_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
src/NadekoBot/Resources/images/cards/7_of_hearts.jpg
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/7_of_spades.jpg
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
src/NadekoBot/Resources/images/cards/8_of_clubs.jpg
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/8_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/8_of_hearts.jpg
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/8_of_spades.jpg
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/9_of_clubs.jpg
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
src/NadekoBot/Resources/images/cards/9_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/9_of_hearts.jpg
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/9_of_spades.jpg
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
src/NadekoBot/Resources/images/cards/Thumbs.db
Normal file
BIN
src/NadekoBot/Resources/images/cards/ace_of_clubs.jpg
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/NadekoBot/Resources/images/cards/ace_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/NadekoBot/Resources/images/cards/ace_of_hearts.jpg
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/ace_of_spades.jpg
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
src/NadekoBot/Resources/images/cards/black_joker.jpg
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/jack_of_clubs.jpg
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/jack_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
src/NadekoBot/Resources/images/cards/jack_of_hearts.jpg
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/jack_of_spades.jpg
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
src/NadekoBot/Resources/images/cards/king_of_clubs.jpg
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
src/NadekoBot/Resources/images/cards/king_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/NadekoBot/Resources/images/cards/king_of_hearts.jpg
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/king_of_spades.jpg
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
src/NadekoBot/Resources/images/cards/queen_of_clubs.jpg
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/queen_of_diamonds.jpg
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/NadekoBot/Resources/images/cards/queen_of_hearts.jpg
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
src/NadekoBot/Resources/images/cards/queen_of_spades.jpg
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
src/NadekoBot/Resources/images/cards/red_joker.jpg
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
src/NadekoBot/Resources/images/coins/heads.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/NadekoBot/Resources/images/coins/tails.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/NadekoBot/Resources/images/dice/0.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
src/NadekoBot/Resources/images/dice/1.png
Normal file
After Width: | Height: | Size: 1006 B |
BIN
src/NadekoBot/Resources/images/dice/2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
src/NadekoBot/Resources/images/dice/3.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/NadekoBot/Resources/images/dice/4.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/NadekoBot/Resources/images/dice/5.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/NadekoBot/Resources/images/dice/6.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/NadekoBot/Resources/images/dice/7.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/NadekoBot/Resources/images/dice/8.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/NadekoBot/Resources/images/dice/9.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/NadekoBot/Resources/images/hidden.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
src/NadekoBot/Resources/images/rip.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src/NadekoBot/Resources/images/rose_overlay.png
Normal file
After Width: | Height: | Size: 18 KiB |
56
src/NadekoBot/Services/IBotConfiguration.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public interface IBotConfiguration
|
||||
{
|
||||
bool DontJoinServers { get; set; }
|
||||
bool ForwardMessages { get; set; }
|
||||
bool ForwardToAllOwners { get; set; }
|
||||
|
||||
bool RotatePlayingStatus { get; set; }
|
||||
List<string> PlayingStatuses { get; set; }
|
||||
|
||||
ulong BufferSize { get; set; }
|
||||
List<string> RaceAnimals { get; set; }
|
||||
string RemindMessageFormat { get; set; }
|
||||
|
||||
|
||||
HashSet<ulong> BlacklistedServers { get; set; }
|
||||
HashSet<ulong> BlacklistedChannels { get; set; }
|
||||
HashSet<ulong> BlacklistedUsers { get; set; }
|
||||
|
||||
List<string> EightBallResponses { get; set; }
|
||||
Currency Currency { get; set; }
|
||||
|
||||
ModulePrefixes ModulePrefixes { get; set; }
|
||||
}
|
||||
|
||||
public class Currency {
|
||||
public string Sign { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string PluralName { get; set; }
|
||||
}
|
||||
|
||||
public class ModulePrefixes
|
||||
{
|
||||
public string Administration { get; set; } = ".";
|
||||
public string Searches { get; set; } = "~";
|
||||
public string NSFW { get; set; } = "~";
|
||||
public string Conversations { get; set; } = "<@{0}>";
|
||||
public string ClashOfClans { get; set; } = ",";
|
||||
public string Help { get; set; } = "-";
|
||||
public string Music { get; set; } = "!!";
|
||||
public string Trello { get; set; } = "trello ";
|
||||
public string Games { get; set; } = ">";
|
||||
public string Gambling { get; set; } = "$";
|
||||
public string Permissions { get; set; } = ";";
|
||||
public string Programming { get; set; } = "%";
|
||||
public string Pokemon { get; set; } = ">";
|
||||
public string Utility { get; set; } = ".";
|
||||
}
|
||||
}
|
93
src/NadekoBot/Services/Impl/BotConfiguration.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services.Impl
|
||||
{
|
||||
public class BotConfiguration : IBotConfiguration
|
||||
{
|
||||
public HashSet<ulong> BlacklistedChannels { get; set; } = new HashSet<ulong>();
|
||||
|
||||
public HashSet<ulong> BlacklistedServers { get; set; } = new HashSet<ulong>();
|
||||
|
||||
public HashSet<ulong> BlacklistedUsers { get; set; } = new HashSet<ulong>();
|
||||
|
||||
public ulong BufferSize { get; set; } = 4000000;
|
||||
|
||||
public bool DontJoinServers { get; set; } = false;
|
||||
|
||||
public bool ForwardMessages { get; set; } = true;
|
||||
|
||||
public bool ForwardToAllOwners { get; set; } = true;
|
||||
|
||||
public ModulePrefixes ModulePrefixes { get; set; } = new ModulePrefixes
|
||||
{
|
||||
Administration = ".",
|
||||
ClashOfClans = ",",
|
||||
Conversations = "<@{0}>",
|
||||
Gambling = "$",
|
||||
Games = ">",
|
||||
Pokemon = ">",
|
||||
Help = "-",
|
||||
Music = "!!",
|
||||
NSFW = "~",
|
||||
Permissions = ";",
|
||||
Programming = "%",
|
||||
Searches = "~",
|
||||
Trello = "trello",
|
||||
Utility = "."
|
||||
};
|
||||
|
||||
public List<string> PlayingStatuses { get; set; } = new List<string>();
|
||||
|
||||
public string RemindMessageFormat { get; set; } = "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗";
|
||||
|
||||
public bool RotatePlayingStatus { get; set; } = false;
|
||||
|
||||
public Currency Currency { get; set; } = new Currency
|
||||
{
|
||||
Name = "Nadeko Flower",
|
||||
PluralName = "Nadeko Flowers",
|
||||
Sign = "🌸",
|
||||
};
|
||||
|
||||
public List<string> EightBallResponses { get; set; } = new List<string>
|
||||
{
|
||||
"Most definitely yes",
|
||||
"For sure",
|
||||
"As I see it, yes",
|
||||
"My sources say yes",
|
||||
"Yes",
|
||||
"Most likely",
|
||||
"Perhaps",
|
||||
"Maybe",
|
||||
"Not sure",
|
||||
"It is uncertain",
|
||||
"Ask me again later",
|
||||
"Don't count on it",
|
||||
"Probably not",
|
||||
"Very doubtful",
|
||||
"Most likely no",
|
||||
"Nope",
|
||||
"No",
|
||||
"My sources say no",
|
||||
"Dont even think about it",
|
||||
"Definitely no",
|
||||
"NO - It may cause disease contraction"
|
||||
};
|
||||
|
||||
public List<string> RaceAnimals { get; set; } = new List<string>
|
||||
{
|
||||
"🐼",
|
||||
"🐻",
|
||||
"🐧",
|
||||
"🐨",
|
||||
"🐬",
|
||||
"🐞",
|
||||
"🦀",
|
||||
"🦄"
|
||||
};
|
||||
}
|
||||
}
|
20
src/NadekoBot/_Models/DataModels/AnnouncementModel.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
internal class Announcement : IDataModel
|
||||
{
|
||||
public long ServerId { get; set; } = 0;
|
||||
public bool Greet { get; set; } = false;
|
||||
public bool GreetPM { get; set; } = false;
|
||||
[JsonProperty("greetChannel")]
|
||||
public long GreetChannelId { get; set; } = 0;
|
||||
public string GreetText { get; set; } = "Welcome %user%!";
|
||||
public bool Bye { get; set; } = false;
|
||||
public bool ByePM { get; set; } = false;
|
||||
[JsonProperty("byeChannel")]
|
||||
public long ByeChannelId { get; set; } = 0;
|
||||
public string ByeText { get; set; } = "%user% has left the server.";
|
||||
public bool DeleteGreetMessages { get; set; } = true;
|
||||
}
|
||||
}
|
11
src/NadekoBot/_Models/DataModels/CommandModel.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class Command : IDataModel {
|
||||
public long UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public long ServerId { get; set; }
|
||||
public string ServerName { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
public string ChannelName { get; set; }
|
||||
public string CommandName { get; set; }
|
||||
}
|
||||
}
|
7
src/NadekoBot/_Models/DataModels/CurrencyStateModel.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class CurrencyState : IDataModel {
|
||||
public long Value { get; set; }
|
||||
[SQLite.Unique]
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class CurrencyTransaction : IDataModel {
|
||||
public string Reason { get; set; }
|
||||
public int Value { get; set; }
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
}
|
7
src/NadekoBot/_Models/DataModels/Donator.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace NadekoBot.DataModels {
|
||||
internal class Donator : IDataModel {
|
||||
public long UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
}
|
14
src/NadekoBot/_Models/DataModels/IDataModel.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using SQLite;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
internal abstract class IDataModel
|
||||
{
|
||||
[PrimaryKey, AutoIncrement]
|
||||
public int? Id { get; set; }
|
||||
[Newtonsoft.Json.JsonProperty("createdAt")]
|
||||
public DateTime DateAdded { get; set; } = DateTime.Now;
|
||||
public IDataModel() { }
|
||||
}
|
||||
}
|