Intial 1.0 commit

This commit is contained in:
Kwoth
2016-08-13 20:45:08 +02:00
parent 30ba68e073
commit f748bad188
648 changed files with 19608 additions and 55378 deletions

View 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"))
{
}
}
}

View 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"))
{
}
}
}

View 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"))
{
}
}
}

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

View 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```";
}
}
}

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

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

View 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);
// });
// }
// }
//}

View 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.`");
// });
// }
// }
//}

View 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);
// });
// });
// }
// }
//}

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

View 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
View File

@ -0,0 +1,7 @@
namespace NadekoBot
{
public class Program
{
public static void Main(string[] args) => new NadekoBot().RunAsync(args).GetAwaiter().GetResult();
}
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View 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; } = ".";
}
}

View 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>
{
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄"
};
}
}

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

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

View File

@ -0,0 +1,7 @@
namespace NadekoBot.DataModels {
internal class CurrencyState : IDataModel {
public long Value { get; set; }
[SQLite.Unique]
public long UserId { get; set; }
}
}

View File

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

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

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

Some files were not shown because too many files have changed in this diff Show More