Merge pull request #4 from mattburchett/revert-3-1.9
Revert "1.9 2017/11/30"
This commit is contained in:
		| @@ -1,7 +1,7 @@ | |||||||
|  |  | ||||||
| Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||||
| # Visual Studio 15 | # Visual Studio 15 | ||||||
| VisualStudioVersion = 15.0.26730.3 | VisualStudioVersion = 15.0.26430.12 | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}" | ||||||
| EndProject | EndProject | ||||||
| @@ -33,7 +33,4 @@ Global | |||||||
| 	GlobalSection(NestedProjects) = preSolution | 	GlobalSection(NestedProjects) = preSolution | ||||||
| 		{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2} | 		{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2} | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution |  | ||||||
| 		SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4} |  | ||||||
| 	EndGlobalSection |  | ||||||
| EndGlobal | EndGlobal | ||||||
|   | |||||||
| @@ -1,3 +1,3 @@ | |||||||
| { | { | ||||||
|   "sdk": { "version": "2.0.0" } |   "sdk": { "version": "1.0.1" } | ||||||
| } | } | ||||||
| @@ -2,11 +2,12 @@ | |||||||
| using System.Runtime.CompilerServices; | using System.Runtime.CompilerServices; | ||||||
| using Discord.Commands; | using Discord.Commands; | ||||||
| using NadekoBot.Services.Impl; | using NadekoBot.Services.Impl; | ||||||
|  |  | ||||||
| namespace NadekoBot.Common.Attributes | namespace NadekoBot.Common.Attributes | ||||||
| { | { | ||||||
|     public class Aliases : AliasAttribute |     public class Aliases : AliasAttribute | ||||||
|     { |     { | ||||||
|         public Aliases([CallerMemberName] string memberName = "") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Cmd.Split(' ').Skip(1).ToArray()) |         public Aliases([CallerMemberName] string memberName = "") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_cmd").Split(' ').Skip(1).ToArray()) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes | |||||||
| { | { | ||||||
|     public class Description : SummaryAttribute |     public class Description : SummaryAttribute | ||||||
|     { |     { | ||||||
|         public Description([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Desc) |         public Description([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_desc")) | ||||||
|         { |         { | ||||||
|  |  | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes | |||||||
| { | { | ||||||
|     public class NadekoCommand : CommandAttribute |     public class NadekoCommand : CommandAttribute | ||||||
|     { |     { | ||||||
|         public NadekoCommand([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Cmd) |         public NadekoCommand([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_cmd").Split(' ')[0]) | ||||||
|         { |         { | ||||||
|  |  | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes | |||||||
| { | { | ||||||
|     public class Usage : RemarksAttribute |     public class Usage : RemarksAttribute | ||||||
|     { |     { | ||||||
|         public Usage([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Usage) |         public Usage([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant()+"_usage")) | ||||||
|         { |         { | ||||||
|  |  | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,9 +0,0 @@ | |||||||
| namespace NadekoBot.Common |  | ||||||
| { |  | ||||||
|     public class CommandData |  | ||||||
|     { |  | ||||||
|         public string Cmd { get; set; } |  | ||||||
|         public string Usage { get; set; } |  | ||||||
|         public string Desc { get; set; } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										1949
									
								
								src/NadekoBot/Migrations/20170913022654_total-xp.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1949
									
								
								src/NadekoBot/Migrations/20170913022654_total-xp.Designer.cs
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,27 +0,0 @@ | |||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using Microsoft.EntityFrameworkCore.Migrations; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Migrations |  | ||||||
| { |  | ||||||
|     public partial class totalxp : Migration |  | ||||||
|     { |  | ||||||
|         protected override void Up(MigrationBuilder migrationBuilder) |  | ||||||
|         { |  | ||||||
|             migrationBuilder.AddColumn<int>( |  | ||||||
|                 name: "TotalXp", |  | ||||||
|                 table: "DiscordUser", |  | ||||||
|                 nullable: false, |  | ||||||
|                 defaultValue: 0); |  | ||||||
|  |  | ||||||
|             migrationBuilder.Sql(MigrationQueries.TotalXp); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override void Down(MigrationBuilder migrationBuilder) |  | ||||||
|         { |  | ||||||
|             migrationBuilder.DropColumn( |  | ||||||
|                 name: "TotalXp", |  | ||||||
|                 table: "DiscordUser"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,25 +0,0 @@ | |||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using Microsoft.EntityFrameworkCore.Migrations; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Migrations |  | ||||||
| { |  | ||||||
|     public partial class clubadmins : Migration |  | ||||||
|     { |  | ||||||
|         protected override void Up(MigrationBuilder migrationBuilder) |  | ||||||
|         { |  | ||||||
|             migrationBuilder.AddColumn<bool>( |  | ||||||
|                 name: "IsClubAdmin", |  | ||||||
|                 table: "DiscordUser", |  | ||||||
|                 nullable: false, |  | ||||||
|                 defaultValue: false); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override void Down(MigrationBuilder migrationBuilder) |  | ||||||
|         { |  | ||||||
|             migrationBuilder.DropColumn( |  | ||||||
|                 name: "IsClubAdmin", |  | ||||||
|                 table: "DiscordUser"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -34,9 +34,5 @@ INSERT INTO DiscordUser | |||||||
|     FROM DiscordUser_tmp; |     FROM DiscordUser_tmp; | ||||||
|  |  | ||||||
| DROP TABLE DiscordUser_tmp;"; | DROP TABLE DiscordUser_tmp;"; | ||||||
|         public static string TotalXp { get; } = |  | ||||||
| @"UPDATE DiscordUser |  | ||||||
| SET TotalXp = ifnull((SELECT SUM(Xp) FROM UserXpStats WHERE UserId = DiscordUser.UserId), 0)"; |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -462,18 +462,14 @@ namespace NadekoBot.Migrations | |||||||
|  |  | ||||||
|                     b.Property<string>("Discriminator"); |                     b.Property<string>("Discriminator"); | ||||||
|  |  | ||||||
|                     b.Property<bool>("IsClubAdmin"); |  | ||||||
|  |  | ||||||
|                     b.Property<DateTime>("LastLevelUp") |                     b.Property<DateTime>("LastLevelUp") | ||||||
|                         .ValueGeneratedOnAdd() |                         .ValueGeneratedOnAdd() | ||||||
|                         .HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 660, DateTimeKind.Local)); |                         .HasDefaultValue(new DateTime(2017, 9, 11, 22, 0, 31, 236, DateTimeKind.Local)); | ||||||
|  |  | ||||||
|                     b.Property<DateTime>("LastXpGain"); |                     b.Property<DateTime>("LastXpGain"); | ||||||
|  |  | ||||||
|                     b.Property<int>("NotifyOnLevelUp"); |                     b.Property<int>("NotifyOnLevelUp"); | ||||||
|  |  | ||||||
|                     b.Property<int>("TotalXp"); |  | ||||||
|  |  | ||||||
|                     b.Property<ulong>("UserId"); |                     b.Property<ulong>("UserId"); | ||||||
|  |  | ||||||
|                     b.Property<string>("Username"); |                     b.Property<string>("Username"); | ||||||
| @@ -1366,7 +1362,7 @@ namespace NadekoBot.Migrations | |||||||
|  |  | ||||||
|                     b.Property<DateTime>("LastLevelUp") |                     b.Property<DateTime>("LastLevelUp") | ||||||
|                         .ValueGeneratedOnAdd() |                         .ValueGeneratedOnAdd() | ||||||
|                         .HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 665, DateTimeKind.Local)); |                         .HasDefaultValue(new DateTime(2017, 9, 11, 22, 0, 31, 238, DateTimeKind.Local)); | ||||||
|  |  | ||||||
|                     b.Property<int>("NotifyOnLevelUp"); |                     b.Property<int>("NotifyOnLevelUp"); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,9 +30,8 @@ namespace NadekoBot.Modules.Administration | |||||||
|             private readonly IImagesService _images; |             private readonly IImagesService _images; | ||||||
|             private readonly MusicService _music; |             private readonly MusicService _music; | ||||||
|             private readonly IBotConfigProvider _bc; |             private readonly IBotConfigProvider _bc; | ||||||
|             private readonly NadekoBot _bot; |  | ||||||
|  |  | ||||||
|             public SelfCommands(DbService db, NadekoBot bot, DiscordSocketClient client, |             public SelfCommands(DbService db, DiscordSocketClient client, | ||||||
|                 MusicService music, IImagesService images, IBotConfigProvider bc) |                 MusicService music, IImagesService images, IBotConfigProvider bc) | ||||||
|             { |             { | ||||||
|                 _db = db; |                 _db = db; | ||||||
| @@ -40,7 +39,6 @@ namespace NadekoBot.Modules.Administration | |||||||
|                 _images = images; |                 _images = images; | ||||||
|                 _music = music; |                 _music = music; | ||||||
|                 _bc = bc; |                 _bc = bc; | ||||||
|                 _bot = bot; |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             [NadekoCommand, Usage, Description, Aliases] |             [NadekoCommand, Usage, Description, Aliases] | ||||||
| @@ -351,7 +349,7 @@ namespace NadekoBot.Modules.Administration | |||||||
|             [OwnerOnly] |             [OwnerOnly] | ||||||
|             public async Task SetGame([Remainder] string game = null) |             public async Task SetGame([Remainder] string game = null) | ||||||
|             { |             { | ||||||
|                 await _bot.SetGameAsync(game).ConfigureAwait(false); |                 await _client.SetGameAsync(game).ConfigureAwait(false); | ||||||
|  |  | ||||||
|                 await ReplyConfirmLocalized("set_game").ConfigureAwait(false); |                 await ReplyConfirmLocalized("set_game").ConfigureAwait(false); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ using NadekoBot.Modules.Music.Services; | |||||||
| using NadekoBot.Services; | using NadekoBot.Services; | ||||||
| using NadekoBot.Services.Database.Models; | using NadekoBot.Services.Database.Models; | ||||||
| using NLog; | using NLog; | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Modules.Administration.Services | namespace NadekoBot.Modules.Administration.Services | ||||||
| { | { | ||||||
| @@ -17,7 +16,6 @@ namespace NadekoBot.Modules.Administration.Services | |||||||
|         private readonly DiscordSocketClient _client; |         private readonly DiscordSocketClient _client; | ||||||
|         private readonly MusicService _music; |         private readonly MusicService _music; | ||||||
|         private readonly Logger _log; |         private readonly Logger _log; | ||||||
|         private readonly IDataCache _cache; |  | ||||||
|         private readonly Replacer _rep; |         private readonly Replacer _rep; | ||||||
|         private readonly DbService _db; |         private readonly DbService _db; | ||||||
|         private readonly IBotConfigProvider _bcp; |         private readonly IBotConfigProvider _bcp; | ||||||
| @@ -29,19 +27,13 @@ namespace NadekoBot.Modules.Administration.Services | |||||||
|             public int Index { get; set; } |             public int Index { get; set; } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp,  |         public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp, MusicService music, DbService db) | ||||||
|             MusicService music, DbService db, IDataCache cache, NadekoBot bot) |  | ||||||
|         { |         { | ||||||
|             _client = client; |             _client = client; | ||||||
|             _bcp = bcp; |             _bcp = bcp; | ||||||
|             _music = music; |             _music = music; | ||||||
|             _db = db; |             _db = db; | ||||||
|             _log = LogManager.GetCurrentClassLogger(); |             _log = LogManager.GetCurrentClassLogger(); | ||||||
|             _cache = cache; |  | ||||||
|  |  | ||||||
|             if (client.ShardId == 0) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|             _rep = new ReplacementBuilder() |             _rep = new ReplacementBuilder() | ||||||
|                 .WithClient(client) |                 .WithClient(client) | ||||||
|                 .WithStats(client) |                 .WithStats(client) | ||||||
| @@ -68,10 +60,7 @@ namespace NadekoBot.Modules.Administration.Services | |||||||
|  |  | ||||||
|                     status = _rep.Replace(status); |                     status = _rep.Replace(status); | ||||||
|  |  | ||||||
|                         try |                     try { await client.SetGameAsync(status).ConfigureAwait(false); } | ||||||
|                         { |  | ||||||
|                             await bot.SetGameAsync(status).ConfigureAwait(false); |  | ||||||
|                         } |  | ||||||
|                     catch (Exception ex) |                     catch (Exception ex) | ||||||
|                     { |                     { | ||||||
|                         _log.Warn(ex); |                         _log.Warn(ex); | ||||||
| @@ -84,5 +73,4 @@ namespace NadekoBot.Modules.Administration.Services | |||||||
|             }, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); |             }, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -58,7 +58,8 @@ namespace NadekoBot.Modules.CustomReactions | |||||||
|  |  | ||||||
|             if (channel == null) |             if (channel == null) | ||||||
|             { |             { | ||||||
|                 await _service.AddGcr(cr).ConfigureAwait(false); |                 Array.Resize(ref _service.GlobalReactions, _service.GlobalReactions.Length + 1); | ||||||
|  |                 _service.GlobalReactions[_service.GlobalReactions.Length - 1] = cr; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
| @@ -236,7 +237,8 @@ namespace NadekoBot.Modules.CustomReactions | |||||||
|                     if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) |                     if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) | ||||||
|                     { |                     { | ||||||
|                         uow.CustomReactions.Remove(toDelete); |                         uow.CustomReactions.Remove(toDelete); | ||||||
|                         await _service.DelGcr(toDelete.Id); |                         //todo 91 i can dramatically improve performance of this, if Ids are ordered. | ||||||
|  |                         _service.GlobalReactions = _service.GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray(); | ||||||
|                         success = true; |                         success = true; | ||||||
|                     } |                     } | ||||||
|                     else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) |                     else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ using NadekoBot.Modules.CustomReactions.Extensions; | |||||||
| using NadekoBot.Modules.Permissions.Common; | using NadekoBot.Modules.Permissions.Common; | ||||||
| using NadekoBot.Modules.Permissions.Services; | using NadekoBot.Modules.Permissions.Services; | ||||||
| using NadekoBot.Services.Impl; | using NadekoBot.Services.Impl; | ||||||
| using Newtonsoft.Json; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Modules.CustomReactions.Services | namespace NadekoBot.Modules.CustomReactions.Services | ||||||
| { | { | ||||||
| @@ -33,11 +32,9 @@ namespace NadekoBot.Modules.CustomReactions.Services | |||||||
|         private readonly CommandHandler _cmd; |         private readonly CommandHandler _cmd; | ||||||
|         private readonly IBotConfigProvider _bc; |         private readonly IBotConfigProvider _bc; | ||||||
|         private readonly NadekoStrings _strings; |         private readonly NadekoStrings _strings; | ||||||
|         private readonly IDataCache _cache; |  | ||||||
|  |  | ||||||
|         public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings, |         public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings, | ||||||
|             DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow,  |             DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow) | ||||||
|             IDataCache cache) |  | ||||||
|         { |         { | ||||||
|             _log = LogManager.GetCurrentClassLogger(); |             _log = LogManager.GetCurrentClassLogger(); | ||||||
|             _db = db; |             _db = db; | ||||||
| @@ -46,38 +43,12 @@ namespace NadekoBot.Modules.CustomReactions.Services | |||||||
|             _cmd = cmd; |             _cmd = cmd; | ||||||
|             _bc = bc; |             _bc = bc; | ||||||
|             _strings = strings; |             _strings = strings; | ||||||
|             _cache = cache; |  | ||||||
|  |  | ||||||
|             var sub = _cache.Redis.GetSubscriber(); |  | ||||||
|             sub.Subscribe("gcr.added", (ch, msg) => |  | ||||||
|             { |  | ||||||
|                 Array.Resize(ref GlobalReactions, GlobalReactions.Length + 1); |  | ||||||
|                 GlobalReactions[GlobalReactions.Length - 1] = JsonConvert.DeserializeObject<CustomReaction>(msg); |  | ||||||
|             }, StackExchange.Redis.CommandFlags.FireAndForget); |  | ||||||
|             sub.Subscribe("gcr.deleted", (ch, msg) => |  | ||||||
|             { |  | ||||||
|                 var id = int.Parse(msg); |  | ||||||
|                 GlobalReactions = GlobalReactions.Where(cr => cr?.Id != id).ToArray(); |  | ||||||
|             }, StackExchange.Redis.CommandFlags.FireAndForget); |  | ||||||
|              |              | ||||||
|             var items = uow.CustomReactions.GetAll(); |             var items = uow.CustomReactions.GetAll(); | ||||||
|  |  | ||||||
|             GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); |             GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); | ||||||
|             GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); |             GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public Task AddGcr(CustomReaction cr) |  | ||||||
|         { |  | ||||||
|             var sub = _cache.Redis.GetSubscriber(); |  | ||||||
|             return sub.PublishAsync("gcr.added", JsonConvert.SerializeObject(cr)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public Task DelGcr(int id) |  | ||||||
|         { |  | ||||||
|             var sub = _cache.Redis.GetSubscriber(); |  | ||||||
|             return sub.PublishAsync("gcr.deleted", id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void ClearStats() => ReactionStats.Clear(); |         public void ClearStats() => ReactionStats.Clear(); | ||||||
|  |  | ||||||
|         public CustomReaction TryGetCustomReaction(IUserMessage umsg) |         public CustomReaction TryGetCustomReaction(IUserMessage umsg) | ||||||
|   | |||||||
| @@ -331,7 +331,7 @@ namespace NadekoBot.Modules.Gambling | |||||||
|                 var embed = new EmbedBuilder().WithOkColor(); |                 var embed = new EmbedBuilder().WithOkColor(); | ||||||
|  |  | ||||||
|                 if (entry.Type == ShopEntryType.Role) |                 if (entry.Type == ShopEntryType.Role) | ||||||
|                     return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(Context.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE"))).WithIsInline(true)) |                     return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(entry.RoleName))).WithIsInline(true)) | ||||||
|                             .AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true)) |                             .AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true)) | ||||||
|                             .AddField(efb => efb.WithName(GetText("type")).WithValue(entry.Type.ToString()).WithIsInline(true)); |                             .AddField(efb => efb.WithName(GetText("type")).WithValue(entry.Type.ToString()).WithIsInline(true)); | ||||||
|                 else if (entry.Type == ShopEntryType.List) |                 else if (entry.Type == ShopEntryType.List) | ||||||
| @@ -349,7 +349,7 @@ namespace NadekoBot.Modules.Gambling | |||||||
|             { |             { | ||||||
|                 if (entry.Type == ShopEntryType.Role) |                 if (entry.Type == ShopEntryType.Role) | ||||||
|                 { |                 { | ||||||
|                     return GetText("shop_role", Format.Bold(Context.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE")); |                     return GetText("shop_role", Format.Bold(entry.RoleName)); | ||||||
|                 } |                 } | ||||||
|                 else if (entry.Type == ShopEntryType.List) |                 else if (entry.Type == ShopEntryType.List) | ||||||
|                 { |                 { | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ namespace NadekoBot.Modules.Games | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|         public async Task EightBall([Remainder] string question = null) |         public async Task _8Ball([Remainder] string question = null) | ||||||
|         { |         { | ||||||
|             if (string.IsNullOrWhiteSpace(question)) |             if (string.IsNullOrWhiteSpace(question)) | ||||||
|                 return; |                 return; | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ using System; | |||||||
| using System.Diagnostics; | using System.Diagnostics; | ||||||
| using System.IO; | using System.IO; | ||||||
| using System.Threading; | using System.Threading; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  |  | ||||||
| namespace NadekoBot.Modules.Music.Common | namespace NadekoBot.Modules.Music.Common | ||||||
| { | { | ||||||
| @@ -17,16 +18,27 @@ namespace NadekoBot.Modules.Music.Common | |||||||
|  |  | ||||||
|         public string SongUri { get; private set; } |         public string SongUri { get; private set; } | ||||||
|  |  | ||||||
|  |         //private volatile bool restart = false; | ||||||
|  |  | ||||||
|         public SongBuffer(string songUri, string skipTo, bool isLocal) |         public SongBuffer(string songUri, string skipTo, bool isLocal) | ||||||
|         { |         { | ||||||
|             _log = LogManager.GetCurrentClassLogger(); |             _log = LogManager.GetCurrentClassLogger(); | ||||||
|  |             //_log.Warn(songUri); | ||||||
|             this.SongUri = songUri; |             this.SongUri = songUri; | ||||||
|             this._isLocal = isLocal; |             this._isLocal = isLocal; | ||||||
|  |  | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 this.p = StartFFmpegProcess(SongUri, 0); |                 this.p = StartFFmpegProcess(SongUri, 0); | ||||||
|  |                 var t = Task.Run(() => | ||||||
|  |                 { | ||||||
|  |                     this.p.BeginErrorReadLine(); | ||||||
|  |                     this.p.ErrorDataReceived += P_ErrorDataReceived; | ||||||
|  |                     this.p.WaitForExit(); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|                 this._outStream = this.p.StandardOutput.BaseStream; |                 this._outStream = this.p.StandardOutput.BaseStream; | ||||||
|  |  | ||||||
|             } |             } | ||||||
|             catch (System.ComponentModel.Win32Exception) |             catch (System.ComponentModel.Win32Exception) | ||||||
|             { |             { | ||||||
| @@ -56,14 +68,113 @@ Check the guides for your platform on how to setup ffmpeg correctly: | |||||||
|                 Arguments = args, |                 Arguments = args, | ||||||
|                 UseShellExecute = false, |                 UseShellExecute = false, | ||||||
|                 RedirectStandardOutput = true, |                 RedirectStandardOutput = true, | ||||||
|                 RedirectStandardError = false, |                 RedirectStandardError = true, | ||||||
|                 CreateNoWindow = true, |                 CreateNoWindow = true, | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e) | ||||||
|  |         { | ||||||
|  |             if (string.IsNullOrWhiteSpace(e.Data)) | ||||||
|  |                 return; | ||||||
|  |             _log.Error(">>> " + e.Data); | ||||||
|  |             if (e.Data?.Contains("Error in the pull function") == true) | ||||||
|  |             { | ||||||
|  |                 _log.Error("Ignore this."); | ||||||
|  |                 //restart = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         private readonly object locker = new object(); |         private readonly object locker = new object(); | ||||||
|         private readonly bool _isLocal; |         private readonly bool _isLocal; | ||||||
|  |  | ||||||
|  |         public Task<bool> StartBuffering(CancellationToken cancelToken) | ||||||
|  |         { | ||||||
|  |             var toReturn = new TaskCompletionSource<bool>(); | ||||||
|  |             var _ = Task.Run(() => | ||||||
|  |             { | ||||||
|  |                 try | ||||||
|  |                 { | ||||||
|  |  | ||||||
|  |                     ////int maxLoopsPerSec = 25; | ||||||
|  |                     //var sw = Stopwatch.StartNew(); | ||||||
|  |                     ////var delay = 1000 / maxLoopsPerSec; | ||||||
|  |                     //int currentLoops = 0; | ||||||
|  |                     //int _bytesSent = 0; | ||||||
|  |                     //try | ||||||
|  |                     //{ | ||||||
|  |                     //    //do | ||||||
|  |                     //    //{ | ||||||
|  |                     //    //    if (restart) | ||||||
|  |                     //    //    { | ||||||
|  |                     //    //        var cur = _bytesSent / 3840 / (1000 / 20.0f); | ||||||
|  |                     //    //        _log.Info("Restarting"); | ||||||
|  |                     //    //        try { this.p.StandardOutput.Dispose(); } catch { } | ||||||
|  |                     //    //        try { this.p.Dispose(); } catch { } | ||||||
|  |                     //    //        this.p = StartFFmpegProcess(SongUri, cur); | ||||||
|  |                     //    //    } | ||||||
|  |                     //    //    restart = false; | ||||||
|  |                     //        ++currentLoops; | ||||||
|  |                     //        byte[] buffer = new byte[readSize]; | ||||||
|  |                     //        int bytesRead = 1; | ||||||
|  |                     //        while (!cancelToken.IsCancellationRequested && !this.p.HasExited) | ||||||
|  |                     //        { | ||||||
|  |                     //            bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, readSize, cancelToken).ConfigureAwait(false); | ||||||
|  |                     //            _bytesSent += bytesRead; | ||||||
|  |                     //            if (bytesRead == 0) | ||||||
|  |                     //                break; | ||||||
|  |                     //            bool written; | ||||||
|  |                     //            do | ||||||
|  |                     //            { | ||||||
|  |                     //                lock (locker) | ||||||
|  |                     //                    written = _outStream.Write(buffer, 0, bytesRead); | ||||||
|  |                     //                if (!written) | ||||||
|  |                     //                    await Task.Delay(2000, cancelToken); | ||||||
|  |                     //            } | ||||||
|  |                     //            while (!written && !cancelToken.IsCancellationRequested); | ||||||
|  |                     //            lock (locker) | ||||||
|  |                     //                if (_outStream.Length > 200_000 || bytesRead == 0) | ||||||
|  |                     //                    if (toReturn.TrySetResult(true)) | ||||||
|  |                     //                        _log.Info("Prebuffering finished in {0}", sw.Elapsed.TotalSeconds.ToString("F2")); | ||||||
|  |  | ||||||
|  |                     //            //_log.Info(_outStream.Length); | ||||||
|  |                     //            await Task.Delay(10); | ||||||
|  |                     //        } | ||||||
|  |                     //        //if (cancelToken.IsCancellationRequested) | ||||||
|  |                     //        //    _log.Info("Song canceled"); | ||||||
|  |                     //        //else if (p.HasExited) | ||||||
|  |                     //        //    _log.Info("Song buffered completely (FFmpeg exited)"); | ||||||
|  |                     //        //else if (bytesRead == 0) | ||||||
|  |                     //        //    _log.Info("Nothing read"); | ||||||
|  |                     //    //} | ||||||
|  |                     //    //while (restart && !cancelToken.IsCancellationRequested); | ||||||
|  |                     //return Task.CompletedTask; | ||||||
|  |                     toReturn.TrySetResult(true); | ||||||
|  |                 } | ||||||
|  |                 catch (System.ComponentModel.Win32Exception) | ||||||
|  |                 { | ||||||
|  |                     _log.Error(@"You have not properly installed or configured FFMPEG.  | ||||||
|  | Please install and configure FFMPEG to play music.  | ||||||
|  | Check the guides for your platform on how to setup ffmpeg correctly: | ||||||
|  |     Windows Guide: https://goo.gl/OjKk8F | ||||||
|  |     Linux Guide:  https://goo.gl/ShjCUo"); | ||||||
|  |                 } | ||||||
|  |                 catch (OperationCanceledException) { } | ||||||
|  |                 catch (InvalidOperationException) { } // when ffmpeg is disposed | ||||||
|  |                 catch (Exception ex) | ||||||
|  |                 { | ||||||
|  |                     _log.Info(ex); | ||||||
|  |                 } | ||||||
|  |                 finally | ||||||
|  |                 { | ||||||
|  |                     if (toReturn.TrySetResult(false)) | ||||||
|  |                         _log.Info("Prebuffering failed"); | ||||||
|  |                 } | ||||||
|  |             }, cancelToken); | ||||||
|  |  | ||||||
|  |             return toReturn.Task; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public int Read(byte[] b, int offset, int toRead) |         public int Read(byte[] b, int offset, int toRead) | ||||||
|         { |         { | ||||||
|             lock (locker) |             lock (locker) | ||||||
| @@ -93,3 +204,214 @@ Check the guides for your platform on how to setup ffmpeg correctly: | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //namespace NadekoBot.Services.Music | ||||||
|  | //{ | ||||||
|  | //    /// <summary> | ||||||
|  | //    /// Create a buffer for a song file. It will create multiples files to ensure, that radio don't fill up disk space. | ||||||
|  | //    /// It also help for large music by deleting files that are already seen. | ||||||
|  | //    /// </summary> | ||||||
|  | //    class SongBuffer : Stream | ||||||
|  | //    { | ||||||
|  | //        public SongBuffer(MusicPlayer musicPlayer, string basename, SongInfo songInfo, int skipTo, int maxFileSize) | ||||||
|  | //        { | ||||||
|  | //            MusicPlayer = musicPlayer; | ||||||
|  | //            Basename = basename; | ||||||
|  | //            SongInfo = songInfo; | ||||||
|  | //            SkipTo = skipTo; | ||||||
|  | //            MaxFileSize = maxFileSize; | ||||||
|  | //            CurrentFileStream = new FileStream(this.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); | ||||||
|  | //            _log = LogManager.GetCurrentClassLogger(); | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        MusicPlayer MusicPlayer { get; } | ||||||
|  |  | ||||||
|  | //        private string Basename { get; } | ||||||
|  |  | ||||||
|  | //        private SongInfo SongInfo { get; } | ||||||
|  |  | ||||||
|  | //        private int SkipTo { get; } | ||||||
|  |  | ||||||
|  | //        private int MaxFileSize { get; } = 2.MiB(); | ||||||
|  |  | ||||||
|  | //        private long FileNumber = -1; | ||||||
|  |  | ||||||
|  | //        private long NextFileToRead = 0; | ||||||
|  |  | ||||||
|  | //        public bool BufferingCompleted { get; private set; } = false; | ||||||
|  |  | ||||||
|  | //        private ulong CurrentBufferSize = 0; | ||||||
|  |  | ||||||
|  | //        private FileStream CurrentFileStream; | ||||||
|  | //        private Logger _log; | ||||||
|  |  | ||||||
|  | //        public Task BufferSong(CancellationToken cancelToken) => | ||||||
|  | //           Task.Run(async () => | ||||||
|  | //           { | ||||||
|  | //               Process p = null; | ||||||
|  | //               FileStream outStream = null; | ||||||
|  | //               try | ||||||
|  | //               { | ||||||
|  | //                   p = Process.Start(new ProcessStartInfo | ||||||
|  | //                   { | ||||||
|  | //                       FileName = "ffmpeg", | ||||||
|  | //                       Arguments = $"-ss {SkipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -vn -ac 2 pipe:1 -loglevel quiet", | ||||||
|  | //                       UseShellExecute = false, | ||||||
|  | //                       RedirectStandardOutput = true, | ||||||
|  | //                       RedirectStandardError = false, | ||||||
|  | //                       CreateNoWindow = true, | ||||||
|  | //                   }); | ||||||
|  |  | ||||||
|  | //                   byte[] buffer = new byte[81920]; | ||||||
|  | //                   int currentFileSize = 0; | ||||||
|  | //                   ulong prebufferSize = 100ul.MiB(); | ||||||
|  |  | ||||||
|  | //                   outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read); | ||||||
|  | //                   while (!p.HasExited) //Also fix low bandwidth | ||||||
|  | //                   { | ||||||
|  | //                       int bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false); | ||||||
|  | //                       if (currentFileSize >= MaxFileSize) | ||||||
|  | //                       { | ||||||
|  | //                           try | ||||||
|  | //                           { | ||||||
|  | //                               outStream.Dispose(); | ||||||
|  | //                           } | ||||||
|  | //                           catch { } | ||||||
|  | //                           outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read); | ||||||
|  | //                           currentFileSize = bytesRead; | ||||||
|  | //                       } | ||||||
|  | //                       else | ||||||
|  | //                       { | ||||||
|  | //                           currentFileSize += bytesRead; | ||||||
|  | //                       } | ||||||
|  | //                       CurrentBufferSize += Convert.ToUInt64(bytesRead); | ||||||
|  | //                       await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false); | ||||||
|  | //                       while (CurrentBufferSize > prebufferSize) | ||||||
|  | //                           await Task.Delay(100, cancelToken); | ||||||
|  | //                   } | ||||||
|  | //                   BufferingCompleted = true; | ||||||
|  | //               } | ||||||
|  | //               catch (System.ComponentModel.Win32Exception) | ||||||
|  | //               { | ||||||
|  | //                   var oldclr = Console.ForegroundColor; | ||||||
|  | //                   Console.ForegroundColor = ConsoleColor.Red; | ||||||
|  | //                   Console.WriteLine(@"You have not properly installed or configured FFMPEG.  | ||||||
|  | //Please install and configure FFMPEG to play music.  | ||||||
|  | //Check the guides for your platform on how to setup ffmpeg correctly: | ||||||
|  | //    Windows Guide: https://goo.gl/OjKk8F | ||||||
|  | //    Linux Guide:  https://goo.gl/ShjCUo"); | ||||||
|  | //                   Console.ForegroundColor = oldclr; | ||||||
|  | //               } | ||||||
|  | //               catch (Exception ex) | ||||||
|  | //               { | ||||||
|  | //                   Console.WriteLine($"Buffering stopped: {ex.Message}"); | ||||||
|  | //               } | ||||||
|  | //               finally | ||||||
|  | //               { | ||||||
|  | //                   if (outStream != null) | ||||||
|  | //                       outStream.Dispose(); | ||||||
|  | //                   if (p != null) | ||||||
|  | //                   { | ||||||
|  | //                       try | ||||||
|  | //                       { | ||||||
|  | //                           p.Kill(); | ||||||
|  | //                       } | ||||||
|  | //                       catch { } | ||||||
|  | //                       p.Dispose(); | ||||||
|  | //                   } | ||||||
|  | //               } | ||||||
|  | //           }); | ||||||
|  |  | ||||||
|  | //        /// <summary> | ||||||
|  | //        /// Return the next file to read, and delete the old one | ||||||
|  | //        /// </summary> | ||||||
|  | //        /// <returns>Name of the file to read</returns> | ||||||
|  | //        private string GetNextFile() | ||||||
|  | //        { | ||||||
|  | //            string filename = Basename + "-" + NextFileToRead; | ||||||
|  |  | ||||||
|  | //            if (NextFileToRead != 0) | ||||||
|  | //            { | ||||||
|  | //                try | ||||||
|  | //                { | ||||||
|  | //                    CurrentBufferSize -= Convert.ToUInt64(new FileInfo(Basename + "-" + (NextFileToRead - 1)).Length); | ||||||
|  | //                    File.Delete(Basename + "-" + (NextFileToRead - 1)); | ||||||
|  | //                } | ||||||
|  | //                catch { } | ||||||
|  | //            } | ||||||
|  | //            NextFileToRead++; | ||||||
|  | //            return filename; | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        private bool IsNextFileReady() | ||||||
|  | //        { | ||||||
|  | //            return NextFileToRead <= FileNumber; | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        private void CleanFiles() | ||||||
|  | //        { | ||||||
|  | //            for (long i = NextFileToRead - 1; i <= FileNumber; i++) | ||||||
|  | //            { | ||||||
|  | //                try | ||||||
|  | //                { | ||||||
|  | //                    File.Delete(Basename + "-" + i); | ||||||
|  | //                } | ||||||
|  | //                catch { } | ||||||
|  | //            } | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        //Stream part | ||||||
|  |  | ||||||
|  | //        public override bool CanRead => true; | ||||||
|  |  | ||||||
|  | //        public override bool CanSeek => false; | ||||||
|  |  | ||||||
|  | //        public override bool CanWrite => false; | ||||||
|  |  | ||||||
|  | //        public override long Length => (long)CurrentBufferSize; | ||||||
|  |  | ||||||
|  | //        public override long Position { get; set; } = 0; | ||||||
|  |  | ||||||
|  | //        public override void Flush() { } | ||||||
|  |  | ||||||
|  | //        public override int Read(byte[] buffer, int offset, int count) | ||||||
|  | //        { | ||||||
|  | //            int read = CurrentFileStream.Read(buffer, offset, count); | ||||||
|  | //            if (read < count) | ||||||
|  | //            { | ||||||
|  | //                if (!BufferingCompleted || IsNextFileReady()) | ||||||
|  | //                { | ||||||
|  | //                    CurrentFileStream.Dispose(); | ||||||
|  | //                    CurrentFileStream = new FileStream(GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); | ||||||
|  | //                    read += CurrentFileStream.Read(buffer, read + offset, count - read); | ||||||
|  | //                } | ||||||
|  | //                if (read < count) | ||||||
|  | //                    Array.Clear(buffer, read, count - read); | ||||||
|  | //            } | ||||||
|  | //            return read; | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        public override long Seek(long offset, SeekOrigin origin) | ||||||
|  | //        { | ||||||
|  | //            throw new NotImplementedException(); | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        public override void SetLength(long value) | ||||||
|  | //        { | ||||||
|  | //            throw new NotImplementedException(); | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        public override void Write(byte[] buffer, int offset, int count) | ||||||
|  | //        { | ||||||
|  | //            throw new NotImplementedException(); | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  | //        public new void Dispose() | ||||||
|  | //        { | ||||||
|  | //            CurrentFileStream.Dispose(); | ||||||
|  | //            MusicPlayer.SongCancelSource.Cancel(); | ||||||
|  | //            CleanFiles(); | ||||||
|  | //            base.Dispose(); | ||||||
|  | //        } | ||||||
|  | //    } | ||||||
|  | //} | ||||||
| @@ -16,13 +16,9 @@ using NadekoBot.Modules.NSFW.Exceptions; | |||||||
|  |  | ||||||
| namespace NadekoBot.Modules.NSFW | namespace NadekoBot.Modules.NSFW | ||||||
| { | { | ||||||
|     // thanks to halitalf for adding autoboob and autobutt features :D |  | ||||||
|     public class NSFW : NadekoTopLevelModule<SearchesService> |     public class NSFW : NadekoTopLevelModule<SearchesService> | ||||||
|     { |     { | ||||||
|         private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>(); |         private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>(); | ||||||
|         private static readonly ConcurrentDictionary<ulong, Timer> _autoBoobTimers = new ConcurrentDictionary<ulong, Timer>(); |  | ||||||
|         private static readonly ConcurrentDictionary<ulong, Timer> _autoButtTimers = new ConcurrentDictionary<ulong, Timer>(); |  | ||||||
|  |  | ||||||
|         private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>(); |         private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>(); | ||||||
|  |  | ||||||
|         private async Task InternalHentai(IMessageChannel channel, string tag, bool noError) |         private async Task InternalHentai(IMessageChannel channel, string tag, bool noError) | ||||||
| @@ -53,34 +49,10 @@ namespace NadekoBot.Modules.NSFW | |||||||
|                 .WithDescription($"[{GetText("tag")}: {tag}]({img})")) |                 .WithDescription($"[{GetText("tag")}: {tag}]({img})")) | ||||||
|                 .ConfigureAwait(false); |                 .ConfigureAwait(false); | ||||||
|         } |         } | ||||||
|         private async Task InternalBoobs(IMessageChannel Channel) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 JToken obj; |  | ||||||
|                 obj = JArray.Parse(await _service.Http.GetStringAsync($"http://api.oboobs.ru/boobs/{new NadekoRandom().Next(0, 10330)}").ConfigureAwait(false))[0]; |  | ||||||
|                 await Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}").ConfigureAwait(false); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 await Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private async Task InternalButts(IMessageChannel Channel) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 JToken obj; |  | ||||||
|                 obj = JArray.Parse(await _service.Http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}").ConfigureAwait(false))[0]; |  | ||||||
|                 await Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}").ConfigureAwait(false); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 await Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|  |         public Task Hentai([Remainder] string tag = null) => | ||||||
|  |             InternalHentai(Context.Channel, tag, false); | ||||||
| #if !GLOBAL_NADEKO | #if !GLOBAL_NADEKO | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|         [RequireUserPermission(ChannelPermission.ManageMessages)] |         [RequireUserPermission(ChannelPermission.ManageMessages)] | ||||||
| @@ -93,7 +65,7 @@ namespace NadekoBot.Modules.NSFW | |||||||
|                 if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return; |                 if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return; | ||||||
|  |  | ||||||
|                 t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer |                 t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer | ||||||
|                 await ReplyConfirmLocalized("stopped").ConfigureAwait(false); |                 await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -127,90 +99,8 @@ namespace NadekoBot.Modules.NSFW | |||||||
|                 interval, |                 interval, | ||||||
|                 string.Join(", ", tagsArr)).ConfigureAwait(false); |                 string.Join(", ", tagsArr)).ConfigureAwait(false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |  | ||||||
|         [RequireUserPermission(ChannelPermission.ManageMessages)] |  | ||||||
|         public async Task AutoBoobs(int interval = 0) |  | ||||||
|         { |  | ||||||
|             Timer t; |  | ||||||
|  |  | ||||||
|             if (interval == 0) |  | ||||||
|             { |  | ||||||
|                 if (!_autoBoobTimers.TryRemove(Context.Channel.Id, out t)) return; |  | ||||||
|  |  | ||||||
|                 t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer |  | ||||||
|                 await ReplyConfirmLocalized("stopped").ConfigureAwait(false); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (interval < 20) |  | ||||||
|                 return; |  | ||||||
|  |  | ||||||
|             t = new Timer(async (state) => |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     await InternalBoobs(Context.Channel).ConfigureAwait(false); |  | ||||||
|                 } |  | ||||||
|                 catch |  | ||||||
|                 { |  | ||||||
|                     // ignored |  | ||||||
|                 } |  | ||||||
|             }, null, interval * 1000, interval * 1000); |  | ||||||
|  |  | ||||||
|             _autoBoobTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => |  | ||||||
|             { |  | ||||||
|                 old.Change(Timeout.Infinite, Timeout.Infinite); |  | ||||||
|                 return t; |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             await ReplyConfirmLocalized("started", interval).ConfigureAwait(false); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |  | ||||||
|         [RequireUserPermission(ChannelPermission.ManageMessages)] |  | ||||||
|         public async Task AutoButts(int interval = 0) |  | ||||||
|         { |  | ||||||
|             Timer t; |  | ||||||
|  |  | ||||||
|             if (interval == 0) |  | ||||||
|             { |  | ||||||
|                 if (!_autoButtTimers.TryRemove(Context.Channel.Id, out t)) return; |  | ||||||
|  |  | ||||||
|                 t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer |  | ||||||
|                 await ReplyConfirmLocalized("stopped").ConfigureAwait(false); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (interval < 20) |  | ||||||
|                 return; |  | ||||||
|  |  | ||||||
|             t = new Timer(async (state) => |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     await InternalButts(Context.Channel).ConfigureAwait(false); |  | ||||||
|                 } |  | ||||||
|                 catch |  | ||||||
|                 { |  | ||||||
|                     // ignored |  | ||||||
|                 } |  | ||||||
|             }, null, interval * 1000, interval * 1000); |  | ||||||
|  |  | ||||||
|             _autoButtTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => |  | ||||||
|             { |  | ||||||
|                 old.Change(Timeout.Infinite, Timeout.Infinite); |  | ||||||
|                 return t; |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             await ReplyConfirmLocalized("started", interval).ConfigureAwait(false); |  | ||||||
|         } |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |  | ||||||
|         public Task Hentai([Remainder] string tag = null) => |  | ||||||
|             InternalHentai(Context.Channel, tag, false); |  | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|         public async Task HentaiBomb([Remainder] string tag = null) |         public async Task HentaiBomb([Remainder] string tag = null) | ||||||
|         { |         { | ||||||
| @@ -309,7 +199,7 @@ namespace NadekoBot.Modules.NSFW | |||||||
|                 tag = tag.Trim().ToLowerInvariant(); |                 tag = tag.Trim().ToLowerInvariant(); | ||||||
|                 var added = _service.ToggleBlacklistedTag(Context.Guild.Id, tag); |                 var added = _service.ToggleBlacklistedTag(Context.Guild.Id, tag); | ||||||
|  |  | ||||||
|                 if (added) |                 if(added) | ||||||
|                     await ReplyConfirmLocalized("blacklisted_tag_add", tag).ConfigureAwait(false); |                     await ReplyConfirmLocalized("blacklisted_tag_add", tag).ConfigureAwait(false); | ||||||
|                 else |                 else | ||||||
|                     await ReplyConfirmLocalized("blacklisted_tag_remove", tag).ConfigureAwait(false); |                     await ReplyConfirmLocalized("blacklisted_tag_remove", tag).ConfigureAwait(false); | ||||||
|   | |||||||
| @@ -135,11 +135,11 @@ namespace NadekoBot.Modules.Permissions.Services | |||||||
|                 { |                 { | ||||||
|                     var oldPrefixes = new[] { ".", ";", "!!", "!m", "!", "+", "-", "$", ">" }; |                     var oldPrefixes = new[] { ".", ";", "!!", "!m", "!", "+", "-", "$", ">" }; | ||||||
|                     uow._context.Database.ExecuteSqlCommand( |                     uow._context.Database.ExecuteSqlCommand( | ||||||
|     @"UPDATE Permissionv2 |     $@"UPDATE {nameof(Permissionv2)} | ||||||
| SET secondaryTargetName=trim(substr(secondaryTargetName, 3)) | SET secondaryTargetName=trim(substr(secondaryTargetName, 3)) | ||||||
| WHERE secondaryTargetName LIKE '!!%' OR secondaryTargetName LIKE '!m%'; | WHERE secondaryTargetName LIKE '!!%' OR secondaryTargetName LIKE '!m%'; | ||||||
|  |  | ||||||
| UPDATE Permissionv2 | UPDATE {nameof(Permissionv2)} | ||||||
| SET secondaryTargetName=substr(secondaryTargetName, 2) | SET secondaryTargetName=substr(secondaryTargetName, 2) | ||||||
| WHERE secondaryTargetName LIKE '.%' OR | WHERE secondaryTargetName LIKE '.%' OR | ||||||
| secondaryTargetName LIKE '~%' OR | secondaryTargetName LIKE '~%' OR | ||||||
|   | |||||||
| @@ -76,13 +76,11 @@ namespace NadekoBot.Modules.Searches.Common | |||||||
|                     if (images.Length == 0) |                     if (images.Length == 0) | ||||||
|                         return null; |                         return null; | ||||||
|                     var toReturn = images[_rng.Next(images.Length)]; |                     var toReturn = images[_rng.Next(images.Length)]; | ||||||
| #if !GLOBAL_NADEKO |  | ||||||
|                     foreach (var dledImg in images) |                     foreach (var dledImg in images) | ||||||
|                     { |                     { | ||||||
|                         if(dledImg != toReturn) |                         if(dledImg != toReturn) | ||||||
|                             _cache.Add(dledImg); |                             _cache.Add(dledImg); | ||||||
|                     } |                     } | ||||||
| #endif |  | ||||||
|                     return toReturn; |                     return toReturn; | ||||||
|                 }                     |                 }                     | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -11,14 +11,10 @@ namespace NadekoBot.Modules.Searches.Services | |||||||
|     public class AnimeSearchService : INService |     public class AnimeSearchService : INService | ||||||
|     { |     { | ||||||
|         private readonly Logger _log; |         private readonly Logger _log; | ||||||
|         private readonly IDataCache _cache; |  | ||||||
|         private readonly HttpClient _http; |  | ||||||
|  |  | ||||||
|         public AnimeSearchService(IDataCache cache) |         public AnimeSearchService() | ||||||
|         { |         { | ||||||
|             _log = LogManager.GetCurrentClassLogger(); |             _log = LogManager.GetCurrentClassLogger(); | ||||||
|             _cache = cache; |  | ||||||
|             _http = new HttpClient(); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public async Task<AnimeResult> GetAnimeData(string query) |         public async Task<AnimeResult> GetAnimeData(string query) | ||||||
| @@ -29,16 +25,11 @@ namespace NadekoBot.Modules.Searches.Services | |||||||
|             { |             { | ||||||
|  |  | ||||||
|                 var link = "https://aniapi.nadekobot.me/anime/" + Uri.EscapeDataString(query.Replace("/", " ")); |                 var link = "https://aniapi.nadekobot.me/anime/" + Uri.EscapeDataString(query.Replace("/", " ")); | ||||||
|                 link = link.ToLowerInvariant(); |                 using (var http = new HttpClient()) | ||||||
|                 var (ok, data) = await _cache.TryGetAnimeDataAsync(link).ConfigureAwait(false); |  | ||||||
|                 if (!ok) |  | ||||||
|                 { |                 { | ||||||
|                     data = await _http.GetStringAsync(link).ConfigureAwait(false); |                     var res = await http.GetStringAsync(link).ConfigureAwait(false); | ||||||
|                     await _cache.SetAnimeDataAsync(link, data).ConfigureAwait(false); |                     return JsonConvert.DeserializeObject<AnimeResult>(res); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|                 return JsonConvert.DeserializeObject<AnimeResult>(data); |  | ||||||
|             } |             } | ||||||
|             catch |             catch | ||||||
|             { |             { | ||||||
| @@ -54,16 +45,11 @@ namespace NadekoBot.Modules.Searches.Services | |||||||
|             { |             { | ||||||
|  |  | ||||||
|                 var link = "https://aniapi.nadekobot.me/manga/" + Uri.EscapeDataString(query.Replace("/", " ")); |                 var link = "https://aniapi.nadekobot.me/manga/" + Uri.EscapeDataString(query.Replace("/", " ")); | ||||||
|                 link = link.ToLowerInvariant(); |                 using (var http = new HttpClient()) | ||||||
|                 var (ok, data) = await _cache.TryGetAnimeDataAsync(link).ConfigureAwait(false); |  | ||||||
|                 if (!ok) |  | ||||||
|                 { |                 { | ||||||
|                     data = await _http.GetStringAsync(link).ConfigureAwait(false); |                     var res = await http.GetStringAsync(link).ConfigureAwait(false); | ||||||
|                     await _cache.SetAnimeDataAsync(link, data).ConfigureAwait(false); |                     return JsonConvert.DeserializeObject<MangaResult>(res); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|                 return JsonConvert.DeserializeObject<MangaResult>(data); |  | ||||||
|             } |             } | ||||||
|             catch |             catch | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -26,27 +26,6 @@ namespace NadekoBot.Modules.Xp | |||||||
|                 _client = client; |                 _client = client; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             [NadekoCommand, Usage, Description, Aliases] |  | ||||||
|             public async Task ClubAdmin([Remainder]IUser toAdmin) |  | ||||||
|             { |  | ||||||
|                 bool admin; |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     admin = _service.ToggleAdmin(Context.User, toAdmin); |  | ||||||
|                 } |  | ||||||
|                 catch (InvalidOperationException) |  | ||||||
|                 { |  | ||||||
|                     await ReplyErrorLocalized("club_admin_error").ConfigureAwait(false); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if(admin) |  | ||||||
|                     await ReplyConfirmLocalized("club_admin_add", Format.Bold(toAdmin.ToString())).ConfigureAwait(false); |  | ||||||
|                 else |  | ||||||
|                     await ReplyConfirmLocalized("club_admin_remove", Format.Bold(toAdmin.ToString())).ConfigureAwait(false); |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             [NadekoCommand, Usage, Description, Aliases] |             [NadekoCommand, Usage, Description, Aliases] | ||||||
|             public async Task ClubCreate([Remainder]string clubName) |             public async Task ClubCreate([Remainder]string clubName) | ||||||
|             { |             { | ||||||
| @@ -118,14 +97,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|                         .AddField("Level Req.", club.MinimumLevelReq.ToString(), true) |                         .AddField("Level Req.", club.MinimumLevelReq.ToString(), true) | ||||||
|                         .AddField("Members", string.Join("\n", club.Users |                         .AddField("Members", string.Join("\n", club.Users | ||||||
|                             .Skip(page * 10) |                             .Skip(page * 10) | ||||||
|                             .Take(10) |                             .Take(10)), false); | ||||||
|                             .OrderByDescending(x => x.IsClubAdmin) |  | ||||||
|                             .Select(x =>  |  | ||||||
|                             { |  | ||||||
|                                 if (x.IsClubAdmin) |  | ||||||
|                                     return x.ToString() + "⭐"; |  | ||||||
|                                 return x.ToString(); |  | ||||||
|                             })), false); |  | ||||||
|  |  | ||||||
|                     if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute)) |                     if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute)) | ||||||
|                         return embed.WithThumbnailUrl(club.ImageUrl); |                         return embed.WithThumbnailUrl(club.ImageUrl); | ||||||
| @@ -140,7 +112,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|                 if (--page < 0) |                 if (--page < 0) | ||||||
|                     return Task.CompletedTask; |                     return Task.CompletedTask; | ||||||
|  |  | ||||||
|                 var club = _service.GetClubWithBansAndApplications(Context.User.Id); |                 var club = _service.GetBansAndApplications(Context.User.Id); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return ReplyErrorLocalized("club_not_exists"); |                     return ReplyErrorLocalized("club_not_exists"); | ||||||
|  |  | ||||||
| @@ -159,8 +131,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|  |  | ||||||
|                         return new EmbedBuilder() |                         return new EmbedBuilder() | ||||||
|                             .WithTitle(GetText("club_bans_for", club.ToString())) |                             .WithTitle(GetText("club_bans_for", club.ToString())) | ||||||
|                             .WithDescription(toShow) |                             .WithDescription(toShow); | ||||||
|                             .WithOkColor(); |  | ||||||
|  |  | ||||||
|                     }, bans.Length / 10); |                     }, bans.Length / 10); | ||||||
|             } |             } | ||||||
| @@ -172,11 +143,11 @@ namespace NadekoBot.Modules.Xp | |||||||
|                 if (--page < 0) |                 if (--page < 0) | ||||||
|                     return Task.CompletedTask; |                     return Task.CompletedTask; | ||||||
|  |  | ||||||
|                 var club = _service.GetClubWithBansAndApplications(Context.User.Id); |                 var club = _service.GetBansAndApplications(Context.User.Id); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return ReplyErrorLocalized("club_not_exists"); |                     return ReplyErrorLocalized("club_not_exists"); | ||||||
|  |  | ||||||
|                 var apps = club |                 var bans = club | ||||||
|                     .Applicants |                     .Applicants | ||||||
|                     .Select(x => x.User) |                     .Select(x => x.User) | ||||||
|                     .ToArray(); |                     .ToArray(); | ||||||
| @@ -184,17 +155,16 @@ namespace NadekoBot.Modules.Xp | |||||||
|                 return Context.Channel.SendPaginatedConfirmAsync(_client, page, |                 return Context.Channel.SendPaginatedConfirmAsync(_client, page, | ||||||
|                     curPage => |                     curPage => | ||||||
|                     { |                     { | ||||||
|                         var toShow = string.Join("\n", apps |                         var toShow = string.Join("\n", bans | ||||||
|                             .Skip(page * 10) |                             .Skip(page * 10) | ||||||
|                             .Take(10) |                             .Take(10) | ||||||
|                             .Select(x => x.ToString())); |                             .Select(x => x.ToString())); | ||||||
|  |  | ||||||
|                         return new EmbedBuilder() |                         return new EmbedBuilder() | ||||||
|                             .WithTitle(GetText("club_apps_for", club.ToString())) |                             .WithTitle(GetText("club_apps_for", club.ToString())) | ||||||
|                             .WithDescription(toShow) |                             .WithDescription(toShow); | ||||||
|                             .WithOkColor(); |  | ||||||
|  |  | ||||||
|                     }, apps.Length / 10); |                     }, bans.Length / 10); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             [NadekoCommand, Usage, Description, Aliases] |             [NadekoCommand, Usage, Description, Aliases] | ||||||
| @@ -312,7 +282,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     await ReplyErrorLocalized("club_disband_error").ConfigureAwait(false); |                     await ReplyErrorLocalized("club_disaband_error").ConfigureAwait(false); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,11 +27,10 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             { |             { | ||||||
|                 var du = uow.DiscordUsers.GetOrCreate(user); |                 var du = uow.DiscordUsers.GetOrCreate(user); | ||||||
|                 uow._context.SaveChanges(); |                 uow._context.SaveChanges(); | ||||||
|                 var xp = new LevelStats(du.TotalXp); |                 var xp = new LevelStats(uow.Xp.GetTotalUserXp(user.Id)); | ||||||
|  |  | ||||||
|                 if (xp.Level >= 5 && du.Club == null) |                 if (xp.Level >= 5 && du.Club == null) | ||||||
|                 { |                 { | ||||||
|                     du.IsClubAdmin = true; |  | ||||||
|                     du.Club = new ClubInfo() |                     du.Club = new ClubInfo() | ||||||
|                     { |                     { | ||||||
|                         Name = clubName, |                         Name = clubName, | ||||||
| @@ -53,27 +52,6 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public bool ToggleAdmin(IUser owner, IUser toAdmin) |  | ||||||
|         { |  | ||||||
|             bool newState; |  | ||||||
|             using (var uow = _db.UnitOfWork) |  | ||||||
|             { |  | ||||||
|                 var club = uow.Clubs.GetByOwner(owner.Id); |  | ||||||
|                 var adminUser = uow.DiscordUsers.GetOrCreate(toAdmin); |  | ||||||
|  |  | ||||||
|                 if (club.OwnerId == adminUser.Id) |  | ||||||
|                     return true; |  | ||||||
|  |  | ||||||
|                 if (club == null || club.Owner.UserId != owner.Id ||  |  | ||||||
|                     !club.Users.Contains(adminUser)) |  | ||||||
|                     throw new InvalidOperationException(); |  | ||||||
|  |  | ||||||
|                 newState = adminUser.IsClubAdmin = !adminUser.IsClubAdmin; |  | ||||||
|                 uow.Complete(); |  | ||||||
|             } |  | ||||||
|             return newState; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public ClubInfo GetClubByMember(IUser user) |         public ClubInfo GetClubByMember(IUser user) | ||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
| @@ -129,7 +107,7 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                 uow._context.SaveChanges(); |                 uow._context.SaveChanges(); | ||||||
|  |  | ||||||
|                 if (du.Club != null |                 if (du.Club != null | ||||||
|                     || new LevelStats(du.TotalXp).Level < club.MinimumLevelReq |                     || new LevelStats(uow.Xp.GetTotalUserXp(user.Id)).Level < club.MinimumLevelReq | ||||||
|                     || club.Bans.Any(x => x.UserId == du.Id) |                     || club.Bans.Any(x => x.UserId == du.Id) | ||||||
|                     || club.Applicants.Any(x => x.UserId == du.Id)) |                     || club.Applicants.Any(x => x.UserId == du.Id)) | ||||||
|                 { |                 { | ||||||
| @@ -156,7 +134,11 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             discordUser = null; |             discordUser = null; | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 var club = uow.Clubs.GetByOwnerOrAdmin(clubOwnerUserId); |                 var club = uow.Clubs.GetByOwner(clubOwnerUserId, | ||||||
|  |                     set => set.Include(x => x.Applicants) | ||||||
|  |                         .ThenInclude(x => x.Club) | ||||||
|  |                         .Include(x => x.Applicants) | ||||||
|  |                         .ThenInclude(x => x.User)); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
| @@ -165,7 +147,6 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
|                 applicant.User.Club = club; |                 applicant.User.Club = club; | ||||||
|                 applicant.User.IsClubAdmin = false; |  | ||||||
|                 club.Applicants.Remove(applicant); |                 club.Applicants.Remove(applicant); | ||||||
|  |  | ||||||
|                 //remove that user's all other applications |                 //remove that user's all other applications | ||||||
| @@ -178,11 +159,15 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public ClubInfo GetClubWithBansAndApplications(ulong ownerUserId) |         public ClubInfo GetBansAndApplications(ulong ownerUserId) | ||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 return uow.Clubs.GetByOwnerOrAdmin(ownerUserId); |                 return uow.Clubs.GetByOwner(ownerUserId, | ||||||
|  |                     x => x.Include(y => y.Bans) | ||||||
|  |                           .ThenInclude(y => y.User) | ||||||
|  |                           .Include(y => y.Applicants) | ||||||
|  |                           .ThenInclude(y => y.User)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -195,7 +180,6 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
|                 du.Club = null; |                 du.Club = null; | ||||||
|                 du.IsClubAdmin = false; |  | ||||||
|                 uow.Complete(); |                 uow.Complete(); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
| @@ -237,7 +221,9 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId); |                 club = uow.Clubs.GetByOwner(ownerUserId, | ||||||
|  |                     set => set.Include(x => x.Applicants) | ||||||
|  |                         .ThenInclude(x => x.User)); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
| @@ -270,7 +256,9 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId); |                 club = uow.Clubs.GetByOwner(ownerUserId, | ||||||
|  |                     set => set.Include(x => x.Bans) | ||||||
|  |                         .ThenInclude(x => x.User)); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
| @@ -289,7 +277,7 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId); |                 club = uow.Clubs.GetByOwner(ownerUserId); | ||||||
|                 if (club == null) |                 if (club == null) | ||||||
|                     return false; |                     return false; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,7 +36,6 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|         private readonly IImagesService _images; |         private readonly IImagesService _images; | ||||||
|         private readonly Logger _log; |         private readonly Logger _log; | ||||||
|         private readonly NadekoStrings _strings; |         private readonly NadekoStrings _strings; | ||||||
|         private readonly IDataCache _cache; |  | ||||||
|         private readonly FontCollection _fonts = new FontCollection(); |         private readonly FontCollection _fonts = new FontCollection(); | ||||||
|         public const int XP_REQUIRED_LVL_1 = 36; |         public const int XP_REQUIRED_LVL_1 = 36; | ||||||
|  |  | ||||||
| @@ -55,6 +54,9 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|         private readonly ConcurrentQueue<UserCacheItem> _addMessageXp  |         private readonly ConcurrentQueue<UserCacheItem> _addMessageXp  | ||||||
|             = new ConcurrentQueue<UserCacheItem>(); |             = new ConcurrentQueue<UserCacheItem>(); | ||||||
|  |  | ||||||
|  |         private readonly ConcurrentDictionary<string, byte[]> _imageStreams  | ||||||
|  |             = new ConcurrentDictionary<string, byte[]>(); | ||||||
|  |  | ||||||
|         private readonly Timer updateXpTimer; |         private readonly Timer updateXpTimer; | ||||||
|         private readonly HttpClient http = new HttpClient(); |         private readonly HttpClient http = new HttpClient(); | ||||||
|         private FontFamily _usernameFontFamily; |         private FontFamily _usernameFontFamily; | ||||||
| @@ -67,7 +69,7 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|  |  | ||||||
|         public XpService(CommandHandler cmd, IBotConfigProvider bc, |         public XpService(CommandHandler cmd, IBotConfigProvider bc, | ||||||
|             IEnumerable<GuildConfig> allGuildConfigs, IImagesService images, |             IEnumerable<GuildConfig> allGuildConfigs, IImagesService images, | ||||||
|             DbService db, NadekoStrings strings, IDataCache cache) |             DbService db, NadekoStrings strings) | ||||||
|         { |         { | ||||||
|             _db = db; |             _db = db; | ||||||
|             _cmd = cmd; |             _cmd = cmd; | ||||||
| @@ -75,7 +77,6 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             _images = images; |             _images = images; | ||||||
|             _log = LogManager.GetCurrentClassLogger(); |             _log = LogManager.GetCurrentClassLogger(); | ||||||
|             _strings = strings; |             _strings = strings; | ||||||
|             _cache = cache; |  | ||||||
|  |  | ||||||
|             //load settings |             //load settings | ||||||
|             allGuildConfigs = allGuildConfigs.Where(x => x.XpSettings != null); |             allGuildConfigs = allGuildConfigs.Where(x => x.XpSettings != null); | ||||||
| @@ -144,13 +145,12 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|  |  | ||||||
|                             du.LastXpGain = DateTime.UtcNow; |                             du.LastXpGain = DateTime.UtcNow; | ||||||
|  |  | ||||||
|                             var globalXp = du.TotalXp; |                             var globalXp = uow.Xp.GetTotalUserXp(item.Key.User.Id); | ||||||
|                             var oldGlobalLevelData = new LevelStats(globalXp); |                             var oldGlobalLevelData = new LevelStats(globalXp); | ||||||
|                             var newGlobalLevelData = new LevelStats(globalXp + xp); |                             var newGlobalLevelData = new LevelStats(globalXp + xp); | ||||||
|  |  | ||||||
|                             var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); |                             var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); | ||||||
|                             usr.Xp += xp; |                             usr.Xp += xp; | ||||||
|                             du.TotalXp += xp; |  | ||||||
|                             if (du.Club != null) |                             if (du.Club != null) | ||||||
|                                 du.Club.Xp += xp; |                                 du.Club.Xp += xp; | ||||||
|                             var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); |                             var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); | ||||||
| @@ -308,11 +308,11 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public DiscordUser[] GetUserXps(int page) |         public (ulong UserId, int TotalXp)[] GetUserXps(int page) | ||||||
|         { |         { | ||||||
|             using (var uow = _db.UnitOfWork) |             using (var uow = _db.UnitOfWork) | ||||||
|             { |             { | ||||||
|                 return uow.DiscordUsers.GetUsersXpLeaderboardFor(page); |                 return uow.Xp.GetUsersFor(page); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -403,6 +403,17 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             return _rewardedUsers.Add(userId); |             return _rewardedUsers.Add(userId); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public LevelStats GetGlobalUserStats(ulong userId) | ||||||
|  |         { | ||||||
|  |             int totalXp; | ||||||
|  |             using (var uow = _db.UnitOfWork) | ||||||
|  |             { | ||||||
|  |                 totalXp = uow.Xp.GetTotalUserXp(userId); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return new LevelStats(totalXp); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public FullUserStats GetUserStats(IGuildUser user) |         public FullUserStats GetUserStats(IGuildUser user) | ||||||
|         { |         { | ||||||
|             DiscordUser du; |             DiscordUser du; | ||||||
| @@ -414,8 +425,8 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             { |             { | ||||||
|                 du = uow.DiscordUsers.GetOrCreate(user); |                 du = uow.DiscordUsers.GetOrCreate(user); | ||||||
|                 stats = uow.Xp.GetOrCreateUser(user.GuildId, user.Id); |                 stats = uow.Xp.GetOrCreateUser(user.GuildId, user.Id); | ||||||
|                 totalXp = du.TotalXp; |                 totalXp = uow.Xp.GetTotalUserXp(user.Id); | ||||||
|                 globalRank = uow.DiscordUsers.GetUserGlobalRanking(user.Id); |                 globalRank = uow.Xp.GetUserGlobalRanking(user.Id); | ||||||
|                 guildRank = uow.Xp.GetUserGuildRanking(user.Id, user.GuildId); |                 guildRank = uow.Xp.GetUserGuildRanking(user.Id, user.GuildId); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -539,7 +550,7 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public Task<MemoryStream> GenerateImageAsync(IGuildUser user) |         public Task<Image<Rgba32>> GenerateImageAsync(IGuildUser user) | ||||||
|         { |         { | ||||||
|             return GenerateImageAsync(GetUserStats(user)); |             return GenerateImageAsync(GetUserStats(user)); | ||||||
|         } |         } | ||||||
| @@ -555,10 +566,9 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|             _timeFont = _fonts.Find("Whitney-Bold").CreateFont(20); |             _timeFont = _fonts.Find("Whitney-Bold").CreateFont(20); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public Task<MemoryStream> GenerateImageAsync(FullUserStats stats) => Task.Run(async () => |         public Task<Image<Rgba32>> GenerateImageAsync(FullUserStats stats) => Task.Run(async () => | ||||||
|         { |  | ||||||
|             using (var img = Image.Load(_images.XpCard.ToArray())) |  | ||||||
|         { |         { | ||||||
|  |             var img = Image.Load(_images.XpCard.ToArray()); | ||||||
|  |  | ||||||
|             var username = stats.User.ToString(); |             var username = stats.User.ToString(); | ||||||
|             var usernameFont = _usernameFontFamily |             var usernameFont = _usernameFontFamily | ||||||
| @@ -655,19 +665,20 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                 { |                 { | ||||||
|                     var avatarUrl = stats.User.RealAvatarUrl(); |                     var avatarUrl = stats.User.RealAvatarUrl(); | ||||||
|  |  | ||||||
|                         var (succ, data) = await _cache.TryGetImageDataAsync(avatarUrl); |                     byte[] s; | ||||||
|                         if (!succ) |                     if (!_imageStreams.TryGetValue(avatarUrl, out s)) | ||||||
|                     { |                     { | ||||||
|                         using (var temp = await http.GetStreamAsync(avatarUrl)) |                         using (var temp = await http.GetStreamAsync(avatarUrl)) | ||||||
|                             using (var tempDraw = Image.Load(temp).Resize(69, 70)) |  | ||||||
|                         { |                         { | ||||||
|  |                             var tempDraw = Image.Load(temp); | ||||||
|  |                             tempDraw = tempDraw.Resize(69, 70); | ||||||
|                             ApplyRoundedCorners(tempDraw, 35); |                             ApplyRoundedCorners(tempDraw, 35); | ||||||
|                                 data = tempDraw.ToStream().ToArray(); |                             s = tempDraw.ToStream().ToArray(); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                             await _cache.SetImageDataAsync(avatarUrl, data); |                         _imageStreams.AddOrUpdate(avatarUrl, s, (k, v) => s); | ||||||
|                     } |                     } | ||||||
|                         var toDraw = Image.Load(data); |                     var toDraw = Image.Load(s); | ||||||
|  |  | ||||||
|  |  | ||||||
|                     img.DrawImage(toDraw, |                     img.DrawImage(toDraw, | ||||||
| @@ -688,19 +699,20 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                 var imgUrl = stats.User.Club.ImageUrl; |                 var imgUrl = stats.User.Club.ImageUrl; | ||||||
|                 try |                 try | ||||||
|                 { |                 { | ||||||
|                         var (succ, data) = await _cache.TryGetImageDataAsync(imgUrl); |                     byte[] s; | ||||||
|                         if (!succ) |                     if (!_imageStreams.TryGetValue(imgUrl, out s)) | ||||||
|                     { |                     { | ||||||
|                         using (var temp = await http.GetStreamAsync(imgUrl)) |                         using (var temp = await http.GetStreamAsync(imgUrl)) | ||||||
|                             using (var tempDraw = Image.Load(temp).Resize(45, 45)) |  | ||||||
|                         { |                         { | ||||||
|  |                             var tempDraw = Image.Load(temp); | ||||||
|  |                             tempDraw = tempDraw.Resize(45, 45); | ||||||
|                             ApplyRoundedCorners(tempDraw, 22.5f); |                             ApplyRoundedCorners(tempDraw, 22.5f); | ||||||
|                                 data = tempDraw.ToStream().ToArray(); |                             s = tempDraw.ToStream().ToArray(); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                             await _cache.SetImageDataAsync(imgUrl, data); |                         _imageStreams.AddOrUpdate(imgUrl, s, (k, v) => s); | ||||||
|                     } |                     } | ||||||
|                         var toDraw = Image.Load(data); |                     var toDraw = Image.Load(s); | ||||||
|  |  | ||||||
|                     img.DrawImage(toDraw, |                     img.DrawImage(toDraw, | ||||||
|                         1, |                         1, | ||||||
| @@ -713,8 +725,11 @@ namespace NadekoBot.Modules.Xp.Services | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|                 return img.Resize(432, 211).ToStream(); |             var arr = img.ToStream().ToArray(); | ||||||
|             } |  | ||||||
|  |             //_log.Info("{0:F2} KB", arr.Length * 1.0f / 1.KB()); | ||||||
|  |  | ||||||
|  |             return img; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,12 +1,10 @@ | |||||||
| using Discord; | using Discord; | ||||||
| using Discord.Commands; | using Discord.Commands; | ||||||
| using Discord.WebSocket; | using Discord.WebSocket; | ||||||
| using NadekoBot.Common; |  | ||||||
| using NadekoBot.Common.Attributes; | using NadekoBot.Common.Attributes; | ||||||
| using NadekoBot.Extensions; | using NadekoBot.Extensions; | ||||||
| using NadekoBot.Modules.Xp.Common; | using NadekoBot.Modules.Xp.Common; | ||||||
| using NadekoBot.Modules.Xp.Services; | using NadekoBot.Modules.Xp.Services; | ||||||
| using NadekoBot.Services; |  | ||||||
| using NadekoBot.Services.Database.Models; | using NadekoBot.Services.Database.Models; | ||||||
| using System.Diagnostics; | using System.Diagnostics; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| @@ -17,55 +15,23 @@ namespace NadekoBot.Modules.Xp | |||||||
|     public partial class Xp : NadekoTopLevelModule<XpService> |     public partial class Xp : NadekoTopLevelModule<XpService> | ||||||
|     { |     { | ||||||
|         private readonly DiscordSocketClient _client; |         private readonly DiscordSocketClient _client; | ||||||
|         private readonly DbService _db; |  | ||||||
|  |  | ||||||
|         public Xp(DiscordSocketClient client,DbService db) |         public Xp(DiscordSocketClient client) | ||||||
|         { |         { | ||||||
|             _client = client; |             _client = client; | ||||||
|             _db = db; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //[NadekoCommand, Usage, Description, Aliases] |  | ||||||
|         //[RequireContext(ContextType.Guild)] |  | ||||||
|         //[OwnerOnly] |  | ||||||
|         //public async Task Populate() |  | ||||||
|         //{ |  | ||||||
|         //    var rng = new NadekoRandom(); |  | ||||||
|         //    using (var uow = _db.UnitOfWork) |  | ||||||
|         //    { |  | ||||||
|         //        for (var i = 0ul; i < 1000000; i++) |  | ||||||
|         //        { |  | ||||||
|         //            uow.DiscordUsers.Add(new DiscordUser() |  | ||||||
|         //            { |  | ||||||
|         //                AvatarId = i.ToString(), |  | ||||||
|         //                Discriminator = "1234", |  | ||||||
|         //                UserId = i, |  | ||||||
|         //                Username = i.ToString(), |  | ||||||
|         //                Club = null, |  | ||||||
|         //            }); |  | ||||||
|         //            var xp = uow.Xp.GetOrCreateUser(Context.Guild.Id, i); |  | ||||||
|         //            xp.Xp = rng.Next(100, 100000); |  | ||||||
|         //        } |  | ||||||
|         //        uow.Complete(); |  | ||||||
|         //    } |  | ||||||
|         //} |  | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|         [RequireContext(ContextType.Guild)] |         [RequireContext(ContextType.Guild)] | ||||||
|         //[Ratelimit(30)] |  | ||||||
|         public async Task Experience([Remainder]IUser user = null) |         public async Task Experience([Remainder]IUser user = null) | ||||||
|         { |         { | ||||||
|             user = user ?? Context.User; |             user = user ?? Context.User; | ||||||
|             var sw = Stopwatch.StartNew(); |  | ||||||
|             await Context.Channel.TriggerTypingAsync(); |             await Context.Channel.TriggerTypingAsync(); | ||||||
|             var img = await _service.GenerateImageAsync((IGuildUser)user); |             var img = await _service.GenerateImageAsync((IGuildUser)user); | ||||||
|             sw.Stop(); |              | ||||||
|             _log.Info("Generating finished in {0:F2}s", sw.Elapsed.TotalSeconds); |             await Context.Channel.SendFileAsync(img.ToStream(), $"{user.Id}_xp.png") | ||||||
|             sw.Restart(); |  | ||||||
|             await Context.Channel.SendFileAsync(img, $"{user.Id}_xp.png") |  | ||||||
|                 .ConfigureAwait(false); |                 .ConfigureAwait(false); | ||||||
|             sw.Stop(); |  | ||||||
|             _log.Info("Sending finished in {0:F2}s", sw.Elapsed.TotalSeconds); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
| @@ -74,7 +40,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|         { |         { | ||||||
|             page--; |             page--; | ||||||
|  |  | ||||||
|             if (page < 0 || page > 100) |             if (page < 0) | ||||||
|                 return Task.CompletedTask; |                 return Task.CompletedTask; | ||||||
|  |  | ||||||
|             var roles = _service.GetRoleRewards(Context.Guild.Id) |             var roles = _service.GetRoleRewards(Context.Guild.Id) | ||||||
| @@ -203,7 +169,7 @@ namespace NadekoBot.Modules.Xp | |||||||
|         [RequireContext(ContextType.Guild)] |         [RequireContext(ContextType.Guild)] | ||||||
|         public Task XpLeaderboard(int page = 1) |         public Task XpLeaderboard(int page = 1) | ||||||
|         { |         { | ||||||
|             if (--page < 0 || page > 100) |             if (--page < 0) | ||||||
|                 return Task.CompletedTask; |                 return Task.CompletedTask; | ||||||
|  |  | ||||||
|             return Context.Channel.SendPaginatedConfirmAsync(_client, page, async (curPage) => |             return Context.Channel.SendPaginatedConfirmAsync(_client, page, async (curPage) => | ||||||
| @@ -244,28 +210,32 @@ namespace NadekoBot.Modules.Xp | |||||||
|         [RequireContext(ContextType.Guild)] |         [RequireContext(ContextType.Guild)] | ||||||
|         public async Task XpGlobalLeaderboard(int page = 1) |         public async Task XpGlobalLeaderboard(int page = 1) | ||||||
|         { |         { | ||||||
|             if (--page < 0 || page > 100) |             if (--page < 0) | ||||||
|                 return; |                 return; | ||||||
|             var users = _service.GetUserXps(page); |  | ||||||
|  |             await Context.Channel.SendPaginatedConfirmAsync(_client, page, async (curPage) => | ||||||
|  |             { | ||||||
|  |                 var users = _service.GetUserXps(curPage); | ||||||
|  |  | ||||||
|                 var embed = new EmbedBuilder() |                 var embed = new EmbedBuilder() | ||||||
|                     .WithTitle(GetText("global_leaderboard")) |                     .WithTitle(GetText("global_leaderboard")) | ||||||
|                     .WithOkColor(); |                     .WithOkColor(); | ||||||
|  |  | ||||||
|                 if (!users.Any()) |                 if (!users.Any()) | ||||||
|                 embed.WithDescription("-"); |                     return embed.WithDescription("-"); | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     for (int i = 0; i < users.Length; i++) |                     for (int i = 0; i < users.Length; i++) | ||||||
|                     { |                     { | ||||||
|                     var user = users[i]; |                         var user = await Context.Guild.GetUserAsync(users[i].UserId).ConfigureAwait(false); | ||||||
|                         embed.AddField( |                         embed.AddField( | ||||||
|                         $"#{(i + 1 + page * 9)} {(user.ToString())}",  |                             $"#{(i + 1 + curPage * 9)} {(user?.ToString() ?? users[i].UserId.ToString())}",  | ||||||
|                             $"{GetText("level_x", LevelStats.FromXp(users[i].TotalXp).Level)} - {users[i].TotalXp}xp"); |                             $"{GetText("level_x", LevelStats.FromXp(users[i].TotalXp).Level)} - {users[i].TotalXp}xp"); | ||||||
|                     } |                     } | ||||||
|             } |  | ||||||
|  |  | ||||||
|             await Context.Channel.EmbedAsync(embed); |                     return embed; | ||||||
|  |                 } | ||||||
|  |             }, addPaginatedFooter: false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [NadekoCommand, Usage, Description, Aliases] |         [NadekoCommand, Usage, Description, Aliases] | ||||||
|   | |||||||
| @@ -20,8 +20,6 @@ using NadekoBot.Common.ShardCom; | |||||||
| using NadekoBot.Common.TypeReaders; | using NadekoBot.Common.TypeReaders; | ||||||
| using NadekoBot.Common.TypeReaders.Models; | using NadekoBot.Common.TypeReaders.Models; | ||||||
| using NadekoBot.Services.Database; | using NadekoBot.Services.Database; | ||||||
| using StackExchange.Redis; |  | ||||||
| using Newtonsoft.Json; |  | ||||||
|  |  | ||||||
| namespace NadekoBot | namespace NadekoBot | ||||||
| { | { | ||||||
| @@ -141,7 +139,6 @@ namespace NadekoBot | |||||||
|                     .AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this |                     .AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this | ||||||
|                     .AddManual<NadekoBot>(this) |                     .AddManual<NadekoBot>(this) | ||||||
|                     .AddManual<IUnitOfWork>(uow) |                     .AddManual<IUnitOfWork>(uow) | ||||||
|                     .AddManual<IDataCache>(new RedisCache()) |  | ||||||
|                     .LoadFrom(Assembly.GetEntryAssembly()) |                     .LoadFrom(Assembly.GetEntryAssembly()) | ||||||
|                     .Build(); |                     .Build(); | ||||||
|  |  | ||||||
| @@ -242,6 +239,13 @@ namespace NadekoBot | |||||||
| #if GLOBAL_NADEKO | #if GLOBAL_NADEKO | ||||||
|             isPublicNadeko = true; |             isPublicNadeko = true; | ||||||
| #endif | #endif | ||||||
|  |             //_log.Info(string.Join(", ", CommandService.Commands | ||||||
|  |             //    .Distinct(x => x.Name + x.Module.Name) | ||||||
|  |             //    .SelectMany(x => x.Aliases) | ||||||
|  |             //    .GroupBy(x => x) | ||||||
|  |             //    .Where(x => x.Count() > 1) | ||||||
|  |             //    .Select(x => x.Key + $"({x.Count()})"))); | ||||||
|  |  | ||||||
|             //unload modules which are not available on the public bot |             //unload modules which are not available on the public bot | ||||||
|  |  | ||||||
|             if(isPublicNadeko) |             if(isPublicNadeko) | ||||||
| @@ -252,7 +256,6 @@ namespace NadekoBot | |||||||
|                     .ForEach(x => CommandService.RemoveModuleAsync(x)); |                     .ForEach(x => CommandService.RemoveModuleAsync(x)); | ||||||
|  |  | ||||||
|             Ready.TrySetResult(true); |             Ready.TrySetResult(true); | ||||||
|             HandleStatusChanges(); |  | ||||||
|             _log.Info($"Shard {Client.ShardId} ready."); |             _log.Info($"Shard {Client.ShardId} ready."); | ||||||
|             //_log.Info(await stats.Print().ConfigureAwait(false)); |             //_log.Info(await stats.Print().ConfigureAwait(false)); | ||||||
|         } |         } | ||||||
| @@ -315,51 +318,5 @@ namespace NadekoBot | |||||||
|                 } |                 } | ||||||
|             })).Start(); |             })).Start(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void HandleStatusChanges() |  | ||||||
|         { |  | ||||||
|             var sub = Services.GetService<IDataCache>().Redis.GetSubscriber(); |  | ||||||
|             sub.Subscribe("status.game_set", async (ch, game) => |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     var obj = new { Name = default(string) }; |  | ||||||
|                     obj = JsonConvert.DeserializeAnonymousType(game, obj); |  | ||||||
|                     await Client.SetGameAsync(obj.Name).ConfigureAwait(false); |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     _log.Warn(ex); |  | ||||||
|                 } |  | ||||||
|             }, CommandFlags.FireAndForget); |  | ||||||
|  |  | ||||||
|             sub.Subscribe("status.stream_set", async (ch, streamData) => |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     var obj = new { Name = "", Url = "" }; |  | ||||||
|                     obj = JsonConvert.DeserializeAnonymousType(streamData, obj); |  | ||||||
|                     await Client.SetGameAsync(obj.Name, obj.Url, StreamType.Twitch).ConfigureAwait(false); |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     _log.Warn(ex); |  | ||||||
|                 } |  | ||||||
|             }, CommandFlags.FireAndForget); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public Task SetGameAsync(string game) |  | ||||||
|         { |  | ||||||
|             var obj = new { Name = game }; |  | ||||||
|             var sub = Services.GetService<IDataCache>().Redis.GetSubscriber(); |  | ||||||
|             return sub.PublishAsync("status.game_set", JsonConvert.SerializeObject(obj)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public Task SetStreamAsync(string name, string url) |  | ||||||
|         { |  | ||||||
|             var obj = new { Name = name, Url = url }; |  | ||||||
|             var sub = Services.GetService<IDataCache>().Redis.GetSubscriber(); |  | ||||||
|             return sub.PublishAsync("status.game_set", JsonConvert.SerializeObject(obj)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,18 +1,30 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |  | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <TargetFramework>netcoreapp2.0</TargetFramework> |     <Description>General purpose Discord bot written in C#.</Description> | ||||||
|     <RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion> |     <Copyright>Kwoth</Copyright> | ||||||
|     <OutputType>exe</OutputType> |     <Authors>Kwoth</Authors> | ||||||
|     <AssetTargetFallback>$(AssetTargetFallback);dnxcore50;portable-net45+win8+wpa81</AssetTargetFallback> |     <PublisherName>Kwoth</PublisherName> | ||||||
|  |     <TargetFramework>netcoreapp1.1</TargetFramework> | ||||||
|  |     <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||||
|  |     <AssemblyName>NadekoBot</AssemblyName> | ||||||
|  |     <OutputType>Exe</OutputType> | ||||||
|  |     <PackageId>NadekoBot</PackageId> | ||||||
|  |     <RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion> | ||||||
|  |     <PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net45+win8+wpa81</PackageTargetFallback> | ||||||
|  |     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> | ||||||
|  |     <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> | ||||||
|  |     <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> | ||||||
|  |     <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute> | ||||||
|  |     <GeneratePackageOnBuild>False</GeneratePackageOnBuild> | ||||||
|  |     <AssemblyVersion>1.0.0.0</AssemblyVersion> | ||||||
|  |     <FileVersion>1.0.0.0</FileVersion> | ||||||
|     <ApplicationIcon>nadeko_icon.ico</ApplicationIcon> |     <ApplicationIcon>nadeko_icon.ico</ApplicationIcon> | ||||||
|     <RuntimeIdentifiers>win7-x64<!--;ubuntu.14.04-x64;osx.10.10-x64 --></RuntimeIdentifiers> |     <RuntimeIdentifiers>win7-x64<!--;ubuntu.14.04-x64;osx.10.10-x64 --></RuntimeIdentifiers> | ||||||
|     <Configurations>Debug;Release;global_nadeko</Configurations> |  | ||||||
|     <LangVersion>latest</LangVersion> |  | ||||||
|     </PropertyGroup> |     </PropertyGroup> | ||||||
|  |  | ||||||
|   <PropertyGroup Condition=" '$(Version)' == '' "> |   <PropertyGroup Condition=" '$(Version)' == '' "> | ||||||
|     <VersionPrefix Condition=" '$(VersionPrefix)' == '' ">1.9.1</VersionPrefix> |     <VersionPrefix Condition=" '$(VersionPrefix)' == '' ">1.4.1</VersionPrefix> | ||||||
|     <Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version> |     <Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version> | ||||||
|     <Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version> |     <Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
| @@ -47,24 +59,27 @@ | |||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <PackageReference Include="AngleSharp" Version="0.9.9" /> |     <PackageReference Include="AngleSharp" Version="0.9.9" /> | ||||||
|     <PackageReference Include="Discord.Net" Version="2.0.0-alpha-build-00828" /> |     <PackageReference Include="Discord.Net" Version="2.0.0-alpha-build-00828" /> | ||||||
|     <PackageReference Include="CoreCLR-NCalc" Version="2.1.3" /> |     <PackageReference Include="libvideo" Version="1.0.1" /> | ||||||
|     <PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.29.1.138" /> |     <PackageReference Include="CoreCLR-NCalc" Version="2.1.2" /> | ||||||
|     <PackageReference Include="Google.Apis.YouTube.v3" Version="1.29.1.976" /> |     <PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" /> | ||||||
|     <PackageReference Include="Google.Apis.Customsearch.v1" Version="1.29.1.896" /> |     <PackageReference Include="Google.Apis.YouTube.v3" Version="1.20.0.701" /> | ||||||
|  |     <PackageReference Include="Google.Apis.Customsearch.v1" Version="1.20.0.466" /> | ||||||
|     <PackageReference Include="ImageSharp" Version="1.0.0-alpha9-00194" /> |     <PackageReference Include="ImageSharp" Version="1.0.0-alpha9-00194" /> | ||||||
|     <PackageReference Include="ImageSharp.Drawing" Version="1.0.0-alpha9-00189" /> |     <PackageReference Include="ImageSharp.Drawing" Version="1.0.0-alpha9-00189" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" /> |     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /> |     <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" /> |     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" /> |     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.1" /> | ||||||
|     <PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> |     <PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" /> | ||||||
|     <PackageReference Include="NLog" Version="5.0.0-beta10" /> |     <PackageReference Include="Newtonsoft.Json" Version="10.0.2" /> | ||||||
|     <PackageReference Include="StackExchange.Redis" Version="1.2.6" /> |     <PackageReference Include="NLog" Version="5.0.0-beta03" /> | ||||||
|     <PackageReference Include="System.ValueTuple" Version="4.4.0" /> |     <PackageReference Include="NYoutubeDL" Version="0.4.4" /> | ||||||
|  |     <PackageReference Include="System.ValueTuple" Version="4.4.0-preview1-25305-02" /> | ||||||
|  |     <PackageReference Include="System.Xml.XPath" Version="4.3.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|   <PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' "> |   <PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' "> | ||||||
| @@ -72,12 +87,22 @@ | |||||||
|     <NoWarn>$(NoWarn);CS1573;CS1591</NoWarn> |     <NoWarn>$(NoWarn);CS1573;CS1591</NoWarn> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | ||||||
|  |     <LangVersion>latest</LangVersion> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | ||||||
|     <AllowUnsafeBlocks>true</AllowUnsafeBlocks> |     <LangVersion>latest</LangVersion> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> |     <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" /> | ||||||
|     <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /> |     <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <Compile Update="Resources\CommandStrings.Designer.cs"> | ||||||
|  |       <SubType>Designer</SubType> | ||||||
|  |     </Compile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								src/NadekoBot/NadekoBot.nuspec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/NadekoBot/NadekoBot.nuspec
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | ||||||
|  |   <metadata> | ||||||
|  |     <id>NadekoBot</id> | ||||||
|  |     <version>1.4.0-2$suffix$</version> | ||||||
|  |     <title>NadekoBot</title> | ||||||
|  |     <authors>Kwoth</authors> | ||||||
|  |     <owners>Kwoth</owners> | ||||||
|  |     <description>General purpose discord chat bot written in C#.</description> | ||||||
|  |     <tags>nadeko;bot;nadekobot;discord bot</tags> | ||||||
|  |     <projectUrl>https://github.com/Kwoth/NadekoBot</projectUrl> | ||||||
|  |     <licenseUrl>https://choosealicense.com/licenses/unlicense/</licenseUrl> | ||||||
|  |     <requireLicenseAcceptance>false</requireLicenseAcceptance> | ||||||
|  |   </metadata> | ||||||
|  | </package> | ||||||
							
								
								
									
										7
									
								
								src/NadekoBot/NadekoBot.xproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/NadekoBot/NadekoBot.xproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Ccommands/@EntryIndexedValue">True</s:Boolean> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgambling_005Ccommands/@EntryIndexedValue">True</s:Boolean> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgames_005Ccommands/@EntryIndexedValue">True</s:Boolean> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cpermissions_005Ccommands/@EntryIndexedValue">True</s:Boolean> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Csearches_005Ccommands/@EntryIndexedValue">True</s:Boolean> | ||||||
|  | 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cutility_005Ccommands/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> | ||||||
							
								
								
									
										19
									
								
								src/NadekoBot/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/NadekoBot/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | using System.Reflection; | ||||||
|  | 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("")] | ||||||
|  | [assembly: AssemblyInformationalVersion("1.0")] | ||||||
|  |  | ||||||
|  | // 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")] | ||||||
| @@ -3589,7 +3589,7 @@ | |||||||
|     <value>`{0}xpex Role Excluded-Role` `{0}xpex Server`</value> |     <value>`{0}xpex Role Excluded-Role` `{0}xpex Server`</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="xpexclude_desc" xml:space="preserve"> |   <data name="xpexclude_desc" xml:space="preserve"> | ||||||
|     <value>Exclude a channel, role or current server from the xp system.</value> |     <value>Exclude a user or a role from the xp system, or whole current server.</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="xpnotify_cmd" xml:space="preserve"> |   <data name="xpnotify_cmd" xml:space="preserve"> | ||||||
|     <value>xpnotify xpn</value> |     <value>xpnotify xpn</value> | ||||||
| @@ -3780,31 +3780,4 @@ | |||||||
|   <data name="nsfwclearcache_desc" xml:space="preserve"> |   <data name="nsfwclearcache_desc" xml:space="preserve"> | ||||||
|     <value>Clears nsfw cache.</value> |     <value>Clears nsfw cache.</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="clubadmin_cmd" xml:space="preserve"> |  | ||||||
|     <value>clubadmin</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="clubadmin_usage" xml:space="preserve"> |  | ||||||
|     <value>`{0}clubadmin`</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="clubadmin_desc" xml:space="preserve"> |  | ||||||
|     <value>Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications.</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autoboobs_cmd" xml:space="preserve"> |  | ||||||
|     <value>autoboobs</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autoboobs_desc" xml:space="preserve"> |  | ||||||
|     <value>Posts a boobs every X seconds. 20 seconds minimum. Provide no arguments to disable.</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autoboobs_usage" xml:space="preserve"> |  | ||||||
|     <value>`{0}autoboobs 30` or `{0}autoboobs`</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autobutts_cmd" xml:space="preserve"> |  | ||||||
|     <value>autobutts</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autobutts_desc" xml:space="preserve"> |  | ||||||
|     <value>Posts a butts every X seconds. 20 seconds minimum. Provide no arguments to disable.</value> |  | ||||||
|   </data> |  | ||||||
|   <data name="autobutts_usage" xml:space="preserve"> |  | ||||||
|     <value>`{0}autobutts 30` or `{0}autobutts`</value> |  | ||||||
|   </data> |  | ||||||
| </root> | </root> | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| using Newtonsoft.Json; | using System.ComponentModel.DataAnnotations.Schema; | ||||||
| using System.ComponentModel.DataAnnotations.Schema; |  | ||||||
| using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||||
|  |  | ||||||
| namespace NadekoBot.Services.Database.Models | namespace NadekoBot.Services.Database.Models | ||||||
| @@ -7,9 +6,7 @@ namespace NadekoBot.Services.Database.Models | |||||||
|     public class CustomReaction : DbEntity |     public class CustomReaction : DbEntity | ||||||
|     { |     { | ||||||
|         public ulong? GuildId { get; set; } |         public ulong? GuildId { get; set; } | ||||||
|  |  | ||||||
|         [NotMapped] |         [NotMapped] | ||||||
|         [JsonIgnore] |  | ||||||
|         public Regex Regex { get; set; } |         public Regex Regex { get; set; } | ||||||
|         public string Response { get; set; } |         public string Response { get; set; } | ||||||
|         public string Trigger { get; set; } |         public string Trigger { get; set; } | ||||||
| @@ -19,7 +16,6 @@ namespace NadekoBot.Services.Database.Models | |||||||
|         public bool AutoDeleteTrigger { get; set; } |         public bool AutoDeleteTrigger { get; set; } | ||||||
|         public bool DmResponse { get; set; } |         public bool DmResponse { get; set; } | ||||||
|  |  | ||||||
|         [JsonIgnore] |  | ||||||
|         public bool IsGlobal => !GuildId.HasValue; |         public bool IsGlobal => !GuildId.HasValue; | ||||||
|  |  | ||||||
|         public bool ContainsAnywhere { get; set; } |         public bool ContainsAnywhere { get; set; } | ||||||
|   | |||||||
| @@ -10,9 +10,6 @@ namespace NadekoBot.Services.Database.Models | |||||||
|         public string AvatarId { get; set; } |         public string AvatarId { get; set; } | ||||||
|          |          | ||||||
|         public ClubInfo Club { get; set; } |         public ClubInfo Club { get; set; } | ||||||
|         public bool IsClubAdmin { get; set; } |  | ||||||
|  |  | ||||||
|         public int TotalXp { get; set; } |  | ||||||
|         public DateTime LastLevelUp { get; set; } = DateTime.UtcNow; |         public DateTime LastLevelUp { get; set; } = DateTime.UtcNow; | ||||||
|         public DateTime LastXpGain { get; set; } = DateTime.MinValue; |         public DateTime LastXpGain { get; set; } = DateTime.MinValue; | ||||||
|         public XpNotificationType NotifyOnLevelUp { get; set; } |         public XpNotificationType NotifyOnLevelUp { get; set; } | ||||||
|   | |||||||
| @@ -3,21 +3,23 @@ using System.Collections.Generic; | |||||||
| using System.Linq; | using System.Linq; | ||||||
| using NadekoBot.Services.Database.Models; | using NadekoBot.Services.Database.Models; | ||||||
| using NadekoBot.Extensions; | using NadekoBot.Extensions; | ||||||
|  | using Microsoft.EntityFrameworkCore.Infrastructure; | ||||||
| using System; | using System; | ||||||
| using Microsoft.EntityFrameworkCore.Design; |  | ||||||
| using Microsoft.Data.Sqlite; |  | ||||||
| using System.IO; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Services.Database | namespace NadekoBot.Services.Database | ||||||
| { | { | ||||||
|     public class NadekoContextFactory : IDesignTimeDbContextFactory<NadekoContext> |  | ||||||
|  |     public class NadekoContextFactory : IDbContextFactory<NadekoContext> | ||||||
|     { |     { | ||||||
|         public NadekoContext CreateDbContext(string[] args) |         /// <summary> | ||||||
|  |         /// :\ Used for migrations | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="options"></param> | ||||||
|  |         /// <returns></returns> | ||||||
|  |         public NadekoContext Create(DbContextFactoryOptions options) | ||||||
|         { |         { | ||||||
|             var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>(); |             var optionsBuilder = new DbContextOptionsBuilder(); | ||||||
|             var builder = new SqliteConnectionStringBuilder("Data Source=data/NadekoBot.db"); |             optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); | ||||||
|             builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); |  | ||||||
|             optionsBuilder.UseSqlite(builder.ToString()); |  | ||||||
|             var ctx = new NadekoContext(optionsBuilder.Options); |             var ctx = new NadekoContext(optionsBuilder.Options); | ||||||
|             ctx.Database.SetCommandTimeout(60); |             ctx.Database.SetCommandTimeout(60); | ||||||
|             return ctx; |             return ctx; | ||||||
| @@ -56,7 +58,12 @@ namespace NadekoBot.Services.Database | |||||||
|         public DbSet<ModulePrefix> ModulePrefixes { get; set; } |         public DbSet<ModulePrefix> ModulePrefixes { get; set; } | ||||||
|         public DbSet<RewardedUser> RewardedUsers { get; set; } |         public DbSet<RewardedUser> RewardedUsers { get; set; } | ||||||
|  |  | ||||||
|         public NadekoContext(DbContextOptions<NadekoContext> options) : base(options) |         public NadekoContext() : base() | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public NadekoContext(DbContextOptions options) : base(options) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -224,7 +231,7 @@ namespace NadekoBot.Services.Database | |||||||
|             musicPlaylistEntity |             musicPlaylistEntity | ||||||
|                 .HasMany(p => p.Songs) |                 .HasMany(p => p.Songs) | ||||||
|                 .WithOne() |                 .WithOne() | ||||||
|                 .OnDelete(DeleteBehavior.Cascade); |                 .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Cascade); | ||||||
|  |  | ||||||
|  |  | ||||||
|             #endregion |             #endregion | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ namespace NadekoBot.Services.Database.Repositories | |||||||
|         int GetNextDiscrim(string clubName); |         int GetNextDiscrim(string clubName); | ||||||
|         ClubInfo GetByName(string v, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); |         ClubInfo GetByName(string v, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); | ||||||
|         ClubInfo GetByOwner(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); |         ClubInfo GetByOwner(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); | ||||||
|         ClubInfo GetByOwnerOrAdmin(ulong userId); |  | ||||||
|         ClubInfo GetByMember(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); |         ClubInfo GetByMember(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null); | ||||||
|         ClubInfo[] GetClubLeaderboardPage(int page); |         ClubInfo[] GetClubLeaderboardPage(int page); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,7 +6,5 @@ namespace NadekoBot.Services.Database.Repositories | |||||||
|     public interface IDiscordUserRepository : IRepository<DiscordUser> |     public interface IDiscordUserRepository : IRepository<DiscordUser> | ||||||
|     { |     { | ||||||
|         DiscordUser GetOrCreate(IUser original); |         DiscordUser GetOrCreate(IUser original); | ||||||
|         int GetUserGlobalRanking(ulong id); |  | ||||||
|         DiscordUser[] GetUsersXpLeaderboardFor(int page); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,7 +5,10 @@ namespace NadekoBot.Services.Database.Repositories | |||||||
|     public interface IXpRepository : IRepository<UserXpStats> |     public interface IXpRepository : IRepository<UserXpStats> | ||||||
|     { |     { | ||||||
|         UserXpStats GetOrCreateUser(ulong guildId, ulong userId); |         UserXpStats GetOrCreateUser(ulong guildId, ulong userId); | ||||||
|         int GetUserGuildRanking(ulong userId, ulong guildId); |         int GetTotalUserXp(ulong userId); | ||||||
|         UserXpStats[] GetUsersFor(ulong guildId, int page); |         UserXpStats[] GetUsersFor(ulong guildId, int page); | ||||||
|  |         (ulong UserId, int TotalXp)[] GetUsersFor(int page); | ||||||
|  |         int GetUserGlobalRanking(ulong userId); | ||||||
|  |         int GetUserGuildRanking(ulong userId, ulong guildId); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,30 +24,6 @@ namespace NadekoBot.Services.Database.Repositories.Impl | |||||||
|             return func(_set).FirstOrDefault(x => x.Owner.UserId == userId); |             return func(_set).FirstOrDefault(x => x.Owner.UserId == userId); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public ClubInfo GetByOwnerOrAdmin(ulong userId) |  | ||||||
|         { |  | ||||||
|             return _set |  | ||||||
|                 .Include(x => x.Bans) |  | ||||||
|                     .ThenInclude(x => x.User) |  | ||||||
|                 .Include(x => x.Applicants) |  | ||||||
|                     .ThenInclude(x => x.User) |  | ||||||
|                 .Include(x => x.Owner) |  | ||||||
|                 .FirstOrDefault(x => x.Owner.UserId == userId) ?? |  | ||||||
|             _context.Set<DiscordUser>() |  | ||||||
|                 .Include(x => x.Club) |  | ||||||
|                     .ThenInclude(x => x.Users) |  | ||||||
|                 .Include(x => x.Club) |  | ||||||
|                     .ThenInclude(x => x.Bans) |  | ||||||
|                         .ThenInclude(x => x.User) |  | ||||||
|                 .Include(x => x.Club) |  | ||||||
|                     .ThenInclude(x => x.Applicants) |  | ||||||
|                         .ThenInclude(x => x.User) |  | ||||||
|                 .Include(x => x.Club) |  | ||||||
|                 .ThenInclude(x => x.Owner) |  | ||||||
|                 .FirstOrDefault(x => x.UserId == userId && x.IsClubAdmin) |  | ||||||
|                 ?.Club; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public ClubInfo GetByName(string name, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null) |         public ClubInfo GetByName(string name, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null) | ||||||
|         { |         { | ||||||
|             if (func == null) |             if (func == null) | ||||||
|   | |||||||
| @@ -37,23 +37,5 @@ namespace NadekoBot.Services.Database.Repositories.Impl | |||||||
|  |  | ||||||
|             return toReturn; |             return toReturn; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public int GetUserGlobalRanking(ulong id) |  | ||||||
|         { |  | ||||||
|             return _set.Count(x => x.TotalXp >  |  | ||||||
|                 _set.Where(y => y.UserId == id) |  | ||||||
|                     .DefaultIfEmpty() |  | ||||||
|                     .Sum(y => y.TotalXp)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public DiscordUser[] GetUsersXpLeaderboardFor(int page) |  | ||||||
|         { |  | ||||||
|             return _set |  | ||||||
|                 .OrderByDescending(x => x.TotalXp) |  | ||||||
|                 .Skip(page * 9) |  | ||||||
|                 .Take(9) |  | ||||||
|                 .AsEnumerable() |  | ||||||
|                 .ToArray(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,6 +29,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl | |||||||
|             return usr; |             return usr; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public int GetTotalUserXp(ulong userId) | ||||||
|  |         { | ||||||
|  |             return _set.Where(x => x.UserId == userId).Sum(x => x.Xp); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public UserXpStats[] GetUsersFor(ulong guildId, int page) |         public UserXpStats[] GetUsersFor(ulong guildId, int page) | ||||||
|         { |         { | ||||||
|             return _set.Where(x => x.GuildId == guildId) |             return _set.Where(x => x.GuildId == guildId) | ||||||
| @@ -38,6 +43,15 @@ namespace NadekoBot.Services.Database.Repositories.Impl | |||||||
|                 .ToArray(); |                 .ToArray(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public int GetUserGlobalRanking(ulong userId) | ||||||
|  |         { | ||||||
|  |             return _set | ||||||
|  |                 .GroupBy(x => x.UserId) | ||||||
|  |                 .Count(x => x.Sum(y => y.Xp) > _set | ||||||
|  |                     .Where(y => y.UserId == userId) | ||||||
|  |                     .Sum(y => y.Xp)) + 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public int GetUserGuildRanking(ulong userId, ulong guildId) |         public int GetUserGuildRanking(ulong userId, ulong guildId) | ||||||
|         { |         { | ||||||
|             return _set |             return _set | ||||||
| @@ -48,5 +62,16 @@ namespace NadekoBot.Services.Database.Repositories.Impl | |||||||
|                     .DefaultIfEmpty() |                     .DefaultIfEmpty() | ||||||
|                     .Sum())) + 1; |                     .Sum())) + 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public (ulong UserId, int TotalXp)[] GetUsersFor(int page) | ||||||
|  |         { | ||||||
|  |             return _set.GroupBy(x => x.UserId) | ||||||
|  |                 .OrderByDescending(x => x.Sum(y => y.Xp)) | ||||||
|  |                 .Skip(page * 9) | ||||||
|  |                 .Take(9) | ||||||
|  |                 .AsEnumerable() | ||||||
|  |                 .Select(x => (x.Key, x.Sum(y => y.Xp))) | ||||||
|  |                 .ToArray(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,28 +1,25 @@ | |||||||
| using Microsoft.Data.Sqlite; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using NadekoBot.Services.Database; | using NadekoBot.Services.Database; | ||||||
| using System; |  | ||||||
| using System.IO; |  | ||||||
| using System.Linq; | using System.Linq; | ||||||
|  |  | ||||||
| namespace NadekoBot.Services | namespace NadekoBot.Services | ||||||
| { | { | ||||||
|     public class DbService |     public class DbService | ||||||
|     { |     { | ||||||
|         private readonly DbContextOptions<NadekoContext> options; |         private readonly DbContextOptions options; | ||||||
|         private readonly DbContextOptions<NadekoContext> migrateOptions; |         private readonly DbContextOptions migrateOptions; | ||||||
|  |  | ||||||
|  |         private readonly string _connectionString; | ||||||
|  |  | ||||||
|         public DbService(IBotCredentials creds) |         public DbService(IBotCredentials creds) | ||||||
|         { |         { | ||||||
|             var builder = new SqliteConnectionStringBuilder(creds.Db.ConnectionString); |             _connectionString = creds.Db.ConnectionString; | ||||||
|             builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); |             var optionsBuilder = new DbContextOptionsBuilder(); | ||||||
|              |             optionsBuilder.UseSqlite(creds.Db.ConnectionString); | ||||||
|             var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>(); |  | ||||||
|             optionsBuilder.UseSqlite(builder.ToString()); |  | ||||||
|             options = optionsBuilder.Options; |             options = optionsBuilder.Options; | ||||||
|  |  | ||||||
|             optionsBuilder = new DbContextOptionsBuilder<NadekoContext>(); |             optionsBuilder = new DbContextOptionsBuilder(); | ||||||
|             optionsBuilder.UseSqlite(builder.ToString(), x => x.SuppressForeignKeyEnforcement()); |             optionsBuilder.UseSqlite(creds.Db.ConnectionString, x => x.SuppressForeignKeyEnforcement()); | ||||||
|             migrateOptions = optionsBuilder.Options; |             migrateOptions = optionsBuilder.Options; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,18 +0,0 @@ | |||||||
| using StackExchange.Redis; |  | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| using System.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Services |  | ||||||
| { |  | ||||||
|     public interface IDataCache |  | ||||||
|     { |  | ||||||
|         ConnectionMultiplexer Redis { get; } |  | ||||||
|         Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key); |  | ||||||
|         Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key); |  | ||||||
|         Task SetImageDataAsync(string key, byte[] data); |  | ||||||
|         Task SetAnimeDataAsync(string link, string data); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -90,13 +90,18 @@ namespace NadekoBot.Services.Impl | |||||||
|                 ulong.TryParse(data[nameof(ClientId)], out ulong clId); |                 ulong.TryParse(data[nameof(ClientId)], out ulong clId); | ||||||
|                 ClientId = clId; |                 ClientId = clId; | ||||||
|  |  | ||||||
|  |                 //var scId = data[nameof(SoundCloudClientId)]; | ||||||
|  |                 //SoundCloudClientId = scId; | ||||||
|  |                 //SoundCloudClientId = string.IsNullOrWhiteSpace(scId) | ||||||
|  |                 //    ?  | ||||||
|  |                 //    : scId; | ||||||
|                 CarbonKey = data[nameof(CarbonKey)]; |                 CarbonKey = data[nameof(CarbonKey)]; | ||||||
|                 var dbSection = data.GetSection("db"); |                 var dbSection = data.GetSection("db"); | ||||||
|                 Db = new DBConfig(string.IsNullOrWhiteSpace(dbSection["Type"])  |                 Db = new DBConfig(string.IsNullOrWhiteSpace(dbSection["Type"])  | ||||||
|                                 ? "sqlite"  |                                 ? "sqlite"  | ||||||
|                                 : dbSection["Type"],  |                                 : dbSection["Type"],  | ||||||
|                             string.IsNullOrWhiteSpace(dbSection["ConnectionString"])  |                             string.IsNullOrWhiteSpace(dbSection["ConnectionString"])  | ||||||
|                                 ? "Data Source=data/NadekoBot.db" |                                 ? "Filename=./data/NadekoBot.db" | ||||||
|                                 : dbSection["ConnectionString"]); |                                 : dbSection["ConnectionString"]); | ||||||
|             } |             } | ||||||
|             catch (Exception ex) |             catch (Exception ex) | ||||||
| @@ -120,7 +125,7 @@ namespace NadekoBot.Services.Impl | |||||||
|             public string SoundCloudClientId { get; set; } = ""; |             public string SoundCloudClientId { get; set; } = ""; | ||||||
|             public string CleverbotApiKey { get; } = ""; |             public string CleverbotApiKey { get; } = ""; | ||||||
|             public string CarbonKey { get; set; } = ""; |             public string CarbonKey { get; set; } = ""; | ||||||
|             public DBConfig Db { get; set; } = new DBConfig("sqlite", "Data Source=data/NadekoBot.db"); |             public DBConfig Db { get; set; } = new DBConfig("sqlite", "Filename=./data/NadekoBot.db"); | ||||||
|             public int TotalShards { get; set; } = 1; |             public int TotalShards { get; set; } = 1; | ||||||
|             public string PatreonAccessToken { get; set; } = ""; |             public string PatreonAccessToken { get; set; } = ""; | ||||||
|             public string PatreonCampaignId { get; set; } = "334038"; |             public string PatreonCampaignId { get; set; } = "334038"; | ||||||
|   | |||||||
| @@ -5,9 +5,6 @@ using System.Linq; | |||||||
| using Discord; | using Discord; | ||||||
| using NLog; | using NLog; | ||||||
| using NadekoBot.Services.Database.Models; | using NadekoBot.Services.Database.Models; | ||||||
| using NadekoBot.Common; |  | ||||||
| using Newtonsoft.Json; |  | ||||||
| using System.IO; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Services.Impl | namespace NadekoBot.Services.Impl | ||||||
| { | { | ||||||
| @@ -19,14 +16,6 @@ namespace NadekoBot.Services.Impl | |||||||
|         public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; } |         public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; } | ||||||
|         public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; |         public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; | ||||||
|  |  | ||||||
|         private static readonly Dictionary<string, CommandData> _commandData; |  | ||||||
|  |  | ||||||
|         static Localization() |  | ||||||
|         { |  | ||||||
|             _commandData = JsonConvert.DeserializeObject<Dictionary<string, CommandData>>( |  | ||||||
|                 File.ReadAllText("./data/command_strings.json")); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private Localization() { } |         private Localization() { } | ||||||
|         public Localization(IBotConfigProvider bcp, IEnumerable<GuildConfig> gcs, DbService db) |         public Localization(IBotConfigProvider bcp, IEnumerable<GuildConfig> gcs, DbService db) | ||||||
|         { |         { | ||||||
| @@ -128,19 +117,10 @@ namespace NadekoBot.Services.Impl | |||||||
|             return info ?? DefaultCultureInfo; |             return info ?? DefaultCultureInfo; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static CommandData LoadCommand(string key) |         public static string LoadCommandString(string key) | ||||||
|         { |         { | ||||||
|             _commandData.TryGetValue(key, out var toReturn); |             string toReturn = Resources.CommandStrings.ResourceManager.GetString(key); | ||||||
|  |             return string.IsNullOrWhiteSpace(toReturn) ? key : toReturn; | ||||||
|             if (toReturn == null) |  | ||||||
|                 return new CommandData |  | ||||||
|                 { |  | ||||||
|                     Cmd = key, |  | ||||||
|                     Desc = key, |  | ||||||
|                     Usage = key, |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|             return toReturn; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,40 +0,0 @@ | |||||||
| using StackExchange.Redis; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| namespace NadekoBot.Services.Impl |  | ||||||
| { |  | ||||||
|     public class RedisCache : IDataCache |  | ||||||
|     { |  | ||||||
|         public ConnectionMultiplexer Redis { get; } |  | ||||||
|         private readonly IDatabase _db; |  | ||||||
|  |  | ||||||
|         public RedisCache() |  | ||||||
|         { |  | ||||||
|             Redis = ConnectionMultiplexer.Connect("127.0.0.1"); |  | ||||||
|             Redis.PreserveAsyncOrder = false; |  | ||||||
|             _db = Redis.GetDatabase(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key) |  | ||||||
|         { |  | ||||||
|             byte[] x = await _db.StringGetAsync("image_" + key); |  | ||||||
|             return (x != null, x); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public Task SetImageDataAsync(string key, byte[] data) |  | ||||||
|         { |  | ||||||
|             return _db.StringSetAsync("image_" + key, data); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key) |  | ||||||
|         { |  | ||||||
|             string x = await _db.StringGetAsync("anime_" + key); |  | ||||||
|             return (x != null, x); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public Task SetAnimeDataAsync(string key, string data) |  | ||||||
|         { |  | ||||||
|             return _db.StringSetAsync("anime_" + key, data); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -20,7 +20,7 @@ namespace NadekoBot.Services.Impl | |||||||
|         private readonly IBotCredentials _creds; |         private readonly IBotCredentials _creds; | ||||||
|         private readonly DateTime _started; |         private readonly DateTime _started; | ||||||
|  |  | ||||||
|         public const string BotVersion = "1.9.0"; |         public const string BotVersion = "1.8.4"; | ||||||
|  |  | ||||||
|         public string Author => "Kwoth#2560"; |         public string Author => "Kwoth#2560"; | ||||||
|         public string Library => "Discord.Net"; |         public string Library => "Discord.Net"; | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ namespace NadekoBot.Services | |||||||
|             var logConfig = new LoggingConfiguration(); |             var logConfig = new LoggingConfiguration(); | ||||||
|             var consoleTarget = new ColoredConsoleTarget() |             var consoleTarget = new ColoredConsoleTarget() | ||||||
|             { |             { | ||||||
|                 Layout = @"${date:format=HH\:mm\:ss} ${logger:shortName=True} | ${message}" |                 Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}" | ||||||
|             }; |             }; | ||||||
|             logConfig.AddTarget("Console", consoleTarget); |             logConfig.AddTarget("Console", consoleTarget); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
|   "customreactions_stats_not_found": "No stats for that trigger found, no action taken.", |   "customreactions_stats_not_found": "No stats for that trigger found, no action taken.", | ||||||
|   "customreactions_trigger": "Trigger", |   "customreactions_trigger": "Trigger", | ||||||
|   "customreactions_redacted_too_long": "Redecated because it's too long.", |   "customreactions_redacted_too_long": "Redecated because it's too long.", | ||||||
|  |   "nsfw_autohentai_stopped": "Autohentai stopped.", | ||||||
|   "nsfw_not_found": "No results found.", |   "nsfw_not_found": "No results found.", | ||||||
|   "nsfw_blacklisted_tag_list": "List of blacklisted tags:", |   "nsfw_blacklisted_tag_list": "List of blacklisted tags:", | ||||||
|   "nsfw_blacklisted_tag": "One or more tags you've used are blacklisted", |   "nsfw_blacklisted_tag": "One or more tags you've used are blacklisted", | ||||||
| @@ -867,10 +868,5 @@ | |||||||
|   "xp_club_icon_set": "New club icon set.", |   "xp_club_icon_set": "New club icon set.", | ||||||
|   "xp_club_bans_for": "Bans for {0} club", |   "xp_club_bans_for": "Bans for {0} club", | ||||||
|   "xp_club_apps_for": "Applicants for {0} club", |   "xp_club_apps_for": "Applicants for {0} club", | ||||||
|   "xp_club_leaderboard": "Club leaderboard - page {0}", |   "xp_club_leaderboard": "Club leaderboard - page {0}" | ||||||
|   "xp_club_admin_add": "{0} is now a club admin.", |  | ||||||
|   "xp_club_admin_remove": "{0} is no longer club admin.", |  | ||||||
|   "xp_club_admin_error": "Error. You are either not the owner of the club, or that user is not in your club.", |  | ||||||
|   "nsfw_started": "Started. Reposting every {0}s.", |  | ||||||
|   "nsfw_stopped": "Stopped reposting." |  | ||||||
| } | } | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|   "CarbonKey": "", |   "CarbonKey": "", | ||||||
|   "Db": { |   "Db": { | ||||||
|     "Type": "sqlite", |     "Type": "sqlite", | ||||||
|     "ConnectionString": "Data Source=data/NadekoBot.db" |     "ConnectionString": "Filename=./data/NadekoBot.db" | ||||||
|   }, |   }, | ||||||
|   "TotalShards": 1, |   "TotalShards": 1, | ||||||
|   "PatreonAccessToken": "", |   "PatreonAccessToken": "", | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user