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() { } | ||||
|     } | ||||
| } | ||||