Utility and nsfw work
This commit is contained in:
parent
d08bc60be5
commit
2df415341c
@ -1,46 +1,13 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Attributes
|
||||
{
|
||||
[System.AttributeUsage(AttributeTargets.Class)]
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
sealed class NadekoModuleAttribute : GroupAttribute
|
||||
{
|
||||
//modulename / prefix
|
||||
private static Dictionary<string, string> modulePrefixes = null;
|
||||
public static Dictionary<string, string> ModulePrefixes {
|
||||
get {
|
||||
if (modulePrefixes != null)
|
||||
return modulePrefixes;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
public NadekoModuleAttribute(string moduleName) : base("")
|
||||
{
|
||||
return (modulePrefixes = uow.BotConfig
|
||||
.GetOrCreate()
|
||||
.ModulePrefixes
|
||||
.ToDictionary(p => p.ModuleName, p => p.Prefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NadekoModuleAttribute(string moduleName, string defaultPrefix) : base(GetModulePrefix(moduleName, defaultPrefix), moduleName)
|
||||
{
|
||||
//AppendSpace = false;
|
||||
}
|
||||
|
||||
private static string GetModulePrefix(string moduleName, string defaultPrefix)
|
||||
{
|
||||
if (!ModulePrefixes.TryGetValue(moduleName, out string prefix))
|
||||
{
|
||||
NadekoBot.ModulePrefixes.TryAdd(moduleName, defaultPrefix);
|
||||
NLog.LogManager.GetCurrentClassLogger().Warn("Prefix not found for {0}. Will use default one: {1}", moduleName, defaultPrefix);
|
||||
}
|
||||
|
||||
|
||||
return prefix ?? defaultPrefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using System;
|
||||
using NadekoBot.Services.Impl;
|
||||
using Discord;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Attributes
|
||||
{
|
||||
public class OwnerOnlyAttribute : PreconditionAttribute
|
||||
{
|
||||
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) =>
|
||||
Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
|
||||
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand, IServiceProvider services)
|
||||
{
|
||||
var creds = (IBotCredentials)services.GetService(typeof(IBotCredentials));
|
||||
var client = (IDiscordClient)services.GetService(typeof(IDiscordClient));
|
||||
|
||||
return Task.FromResult((creds.IsOwner(context.User) || client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,4 @@
|
||||
using Discord.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static NadekoBot.Modules.Permissions.Permissions;
|
||||
|
||||
namespace NadekoBot.DataStructures
|
||||
{
|
||||
|
23
src/NadekoBot/DataStructures/PermissionCache.cs
Normal file
23
src/NadekoBot/DataStructures/PermissionCache.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.DataStructures
|
||||
{
|
||||
public class OldPermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public Permission RootPermission { get; set; }
|
||||
}
|
||||
|
||||
public class PermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public PermissionsCollection<Permissionv2> Permissions { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using Discord.Commands;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.TypeReaders
|
||||
{
|
||||
public class CommandTypeReader : TypeReader
|
||||
{
|
||||
private readonly CommandService _cmds;
|
||||
|
||||
public CommandTypeReader(CommandService cmds)
|
||||
{
|
||||
_cmds = cmds;
|
||||
}
|
||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var cmd = _cmds.Commands.FirstOrDefault(c =>
|
||||
c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
|
||||
if (cmd == null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
//public class CommandOrCrTypeReader : CommandTypeReader
|
||||
//{
|
||||
// public override async Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
// {
|
||||
// input = input.ToUpperInvariant();
|
||||
|
||||
// if (CustomReactions.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||
// {
|
||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||
// }
|
||||
// var guild = context.Guild;
|
||||
// if (guild != null)
|
||||
// {
|
||||
// CustomReaction[] crs;
|
||||
// if (CustomReactions.GuildReactions.TryGetValue(guild.Id, out crs))
|
||||
// {
|
||||
// if (crs.Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||
// {
|
||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// var cmd = await base.Read(context, input);
|
||||
// if (cmd.IsSuccess)
|
||||
// {
|
||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First()));
|
||||
// }
|
||||
// return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
|
||||
// }
|
||||
//}
|
||||
|
||||
public class CommandOrCrInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public CommandOrCrInfo(string input)
|
||||
{
|
||||
this.Name = input;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -6,10 +7,16 @@ namespace NadekoBot.TypeReaders
|
||||
{
|
||||
public class GuildTypeReader : TypeReader
|
||||
{
|
||||
private readonly DiscordShardedClient _client;
|
||||
|
||||
public GuildTypeReader(DiscordShardedClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.Trim().ToLowerInvariant();
|
||||
var guilds = NadekoBot.Client.Guilds;
|
||||
var guilds = _client.Guilds;
|
||||
var guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToLowerInvariant() == input) ?? //by id
|
||||
guilds.FirstOrDefault(g => g.Name.Trim().ToLowerInvariant() == input); //by name
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -7,10 +8,17 @@ namespace NadekoBot.TypeReaders
|
||||
{
|
||||
public class ModuleTypeReader : TypeReader
|
||||
{
|
||||
private readonly CommandService _cmds;
|
||||
|
||||
public ModuleTypeReader(CommandService cmds)
|
||||
{
|
||||
_cmds = cmds;
|
||||
}
|
||||
|
||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var module = NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
|
||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
|
||||
if (module == null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
||||
|
||||
@ -20,10 +28,17 @@ namespace NadekoBot.TypeReaders
|
||||
|
||||
public class ModuleOrCrTypeReader : TypeReader
|
||||
{
|
||||
private readonly CommandService _cmds;
|
||||
|
||||
public ModuleOrCrTypeReader(CommandService cmds)
|
||||
{
|
||||
_cmds = cmds;
|
||||
}
|
||||
|
||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToLowerInvariant();
|
||||
var module = NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToLowerInvariant() == input)?.Key;
|
||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToLowerInvariant() == input)?.Key;
|
||||
if (module == null && input != "actualcustomreactions")
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -2,10 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
|
@ -23,8 +23,6 @@ namespace NadekoBot.Modules.Music
|
||||
[DontAutoLoad]
|
||||
public class Music : NadekoTopLevelModule
|
||||
{
|
||||
public const string MusicDataPath = "data/musicdata";
|
||||
|
||||
private static MusicService music;
|
||||
|
||||
static Music()
|
||||
|
@ -11,15 +11,21 @@ using NadekoBot.Extensions;
|
||||
using System.Xml;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using NadekoBot.Services.Searches;
|
||||
|
||||
namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
[NadekoModule("NSFW", "~")]
|
||||
[NadekoModule("NSFW")]
|
||||
public class NSFW : NadekoTopLevelModule
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||
private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
||||
private readonly SearchesService _service;
|
||||
|
||||
public NSFW(SearchesService service)
|
||||
{
|
||||
_service = service;
|
||||
}
|
||||
|
||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||
{
|
||||
@ -142,11 +148,11 @@ namespace NadekoBot.Modules.NSFW
|
||||
#endif
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Yandere([Remainder] string tag = null)
|
||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Yandere);
|
||||
=> InternalDapiCommand(tag, DapiSearchType.Yandere);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Konachan([Remainder] string tag = null)
|
||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Konachan);
|
||||
=> InternalDapiCommand(tag, DapiSearchType.Konachan);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task E621([Remainder] string tag = null)
|
||||
@ -167,7 +173,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Rule34([Remainder] string tag = null)
|
||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Rule34);
|
||||
=> InternalDapiCommand(tag, DapiSearchType.Rule34);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Danbooru([Remainder] string tag = null)
|
||||
@ -210,7 +216,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Gelbooru([Remainder] string tag = null)
|
||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||
=> InternalDapiCommand(tag, DapiSearchType.Gelbooru);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Boobs()
|
||||
@ -270,23 +276,23 @@ namespace NadekoBot.Modules.NSFW
|
||||
}
|
||||
});
|
||||
|
||||
public static Task<string> GetRule34ImageLink(string tag) =>
|
||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34);
|
||||
public Task<string> GetRule34ImageLink(string tag) =>
|
||||
_service.DapiSearch(tag, DapiSearchType.Rule34);
|
||||
|
||||
public static Task<string> GetYandereImageLink(string tag) =>
|
||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Yandere);
|
||||
public Task<string> GetYandereImageLink(string tag) =>
|
||||
_service.DapiSearch(tag, DapiSearchType.Yandere);
|
||||
|
||||
public static Task<string> GetKonachanImageLink(string tag) =>
|
||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Konachan);
|
||||
public Task<string> GetKonachanImageLink(string tag) =>
|
||||
_service.DapiSearch(tag, DapiSearchType.Konachan);
|
||||
|
||||
public static Task<string> GetGelbooruImageLink(string tag) =>
|
||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||
public Task<string> GetGelbooruImageLink(string tag) =>
|
||||
_service.DapiSearch(tag, DapiSearchType.Gelbooru);
|
||||
|
||||
public async Task InternalDapiCommand(string tag, Searches.Searches.DapiSearchType type)
|
||||
public async Task InternalDapiCommand(string tag, DapiSearchType type)
|
||||
{
|
||||
tag = tag?.Trim() ?? "";
|
||||
|
||||
var url = await Searches.Searches.InternalDapiSearch(tag, type).ConfigureAwait(false);
|
||||
var url = await _service.DapiSearch(tag, type).ConfigureAwait(false);
|
||||
|
||||
if (url == null)
|
||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
@ -16,20 +17,23 @@ namespace NadekoBot.Modules
|
||||
public readonly string ModuleTypeName;
|
||||
public readonly string LowerModuleTypeName;
|
||||
|
||||
|
||||
//todo :thinking:
|
||||
public NadekoStrings _strings { get; set; }
|
||||
public ILocalization _localization { get; set; }
|
||||
|
||||
protected NadekoTopLevelModule(bool isTopLevelModule = true)
|
||||
{
|
||||
//if it's top level module
|
||||
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
||||
LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
|
||||
|
||||
if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out Prefix))
|
||||
Prefix = "?err?";
|
||||
Prefix = NadekoBot.Prefix;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
protected override void BeforeExecute()
|
||||
{
|
||||
_cultureInfo = NadekoBot.Localization.GetCultureInfo(Context.Guild?.Id);
|
||||
_cultureInfo =_localization.GetCultureInfo(Context.Guild?.Id);
|
||||
|
||||
_log.Info("Culture info is {0}", _cultureInfo);
|
||||
}
|
||||
@ -54,45 +58,11 @@ namespace NadekoBot.Modules
|
||||
// return Context.Channel.SendErrorAsync(title, text, url, footer);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
||||
/// </summary>
|
||||
private static readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
||||
|
||||
public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName)
|
||||
{
|
||||
var text = NadekoBot.Strings.GetString(lowerModuleTypeName + "_" + key, cultureInfo);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
||||
text = NadekoBot.Strings.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName,
|
||||
params object[] replacements)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(GetTextStatic(key, cultureInfo, lowerModuleTypeName), replacements);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this.";
|
||||
}
|
||||
}
|
||||
|
||||
protected string GetText(string key) =>
|
||||
GetTextStatic(key, _cultureInfo, LowerModuleTypeName);
|
||||
_strings.GetText(key, _cultureInfo, LowerModuleTypeName);
|
||||
|
||||
protected string GetText(string key, params object[] replacements) =>
|
||||
GetTextStatic(key, _cultureInfo, LowerModuleTypeName, replacements);
|
||||
_strings.GetText(key, _cultureInfo, LowerModuleTypeName, replacements);
|
||||
|
||||
public Task<IUserMessage> ErrorLocalized(string textKey, params object[] replacements)
|
||||
{
|
||||
|
@ -20,20 +20,6 @@ namespace NadekoBot.Modules.Permissions
|
||||
[NadekoModule("Permissions", ";")]
|
||||
public partial class Permissions : NadekoTopLevelModule
|
||||
{
|
||||
public class OldPermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public Permission RootPermission { get; set; }
|
||||
}
|
||||
|
||||
public class PermissionCache
|
||||
{
|
||||
public string PermRole { get; set; }
|
||||
public bool Verbose { get; set; } = true;
|
||||
public PermissionsCollection<Permissionv2> Permissions { get; set; }
|
||||
}
|
||||
|
||||
//guildid, root permission
|
||||
public static ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
|
||||
new ConcurrentDictionary<ulong, PermissionCache>();
|
||||
|
@ -762,14 +762,6 @@ namespace NadekoBot.Modules.Searches
|
||||
// }
|
||||
//}
|
||||
|
||||
public enum DapiSearchType
|
||||
{
|
||||
Safebooru,
|
||||
Gelbooru,
|
||||
Konachan,
|
||||
Rule34,
|
||||
Yandere
|
||||
}
|
||||
|
||||
public async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type)
|
||||
{
|
||||
@ -787,55 +779,6 @@ namespace NadekoBot.Modules.Searches
|
||||
.WithImageUrl(url)
|
||||
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<string> InternalDapiSearch(string tag, DapiSearchType type)
|
||||
{
|
||||
tag = tag?.Replace(" ", "_");
|
||||
var website = "";
|
||||
switch (type)
|
||||
{
|
||||
case DapiSearchType.Safebooru:
|
||||
website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Gelbooru:
|
||||
website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Rule34:
|
||||
website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Konachan:
|
||||
website = $"https://konachan.com/post.xml?s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Yandere:
|
||||
website = $"https://yande.re/post.xml?limit=100&tags={tag}";
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
var toReturn = await Task.Run(async () =>
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.AddFakeHeaders();
|
||||
var data = await http.GetStreamAsync(website).ConfigureAwait(false);
|
||||
var doc = new XmlDocument();
|
||||
doc.Load(data);
|
||||
|
||||
var node = doc.LastChild.ChildNodes[new NadekoRandom().Next(0, doc.LastChild.ChildNodes.Count)];
|
||||
|
||||
var url = node.Attributes["file_url"].Value;
|
||||
if (!url.StartsWith("http"))
|
||||
url = "https:" + url;
|
||||
return url;
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
return toReturn;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public async Task<bool> ValidateQuery(IMessageChannel ch, string query)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(query)) return true;
|
||||
|
@ -1,48 +1,32 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public partial class Utility
|
||||
{
|
||||
public class CommandAliasEqualityComparer : IEqualityComparer<CommandAlias>
|
||||
{
|
||||
public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger;
|
||||
|
||||
public int GetHashCode(CommandAlias obj) => obj.Trigger.GetHashCode();
|
||||
}
|
||||
|
||||
[Group]
|
||||
public class CommandMapCommands : NadekoSubmodule
|
||||
{
|
||||
//guildId, (trigger, mapping)
|
||||
public static ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
|
||||
private readonly UtilityService _service;
|
||||
private readonly DbHandler _db;
|
||||
private readonly DiscordShardedClient _client;
|
||||
|
||||
static CommandMapCommands()
|
||||
public CommandMapCommands(UtilityService service, DbHandler db, DiscordShardedClient client)
|
||||
{
|
||||
var eq = new CommandAliasEqualityComparer();
|
||||
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
|
||||
NadekoBot.AllGuildConfigs.ToDictionary(
|
||||
x => x.GuildId,
|
||||
x => new ConcurrentDictionary<string, string>(x.CommandAliases
|
||||
.Distinct(eq)
|
||||
.ToDictionary(ca => ca.Trigger, ca => ca.Mapping))));
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
AliasMaps.Clear();
|
||||
_service = service;
|
||||
_db = db;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -61,14 +45,14 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
ConcurrentDictionary<string, string> maps;
|
||||
string throwaway;
|
||||
if (!AliasMaps.TryGetValue(Context.Guild.Id, out maps) ||
|
||||
if (!_service.AliasMaps.TryGetValue(Context.Guild.Id, out maps) ||
|
||||
!maps.TryRemove(trigger, out throwaway))
|
||||
{
|
||||
await ReplyErrorLocalized("alias_remove_fail", Format.Code(trigger)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||
var toAdd = new CommandAlias()
|
||||
@ -83,9 +67,9 @@ namespace NadekoBot.Modules.Utility
|
||||
await ReplyConfirmLocalized("alias_removed", Format.Code(trigger)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
AliasMaps.AddOrUpdate(Context.Guild.Id, (_) =>
|
||||
_service.AliasMaps.AddOrUpdate(Context.Guild.Id, (_) =>
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||
config.CommandAliases.Add(new CommandAlias()
|
||||
@ -100,7 +84,7 @@ namespace NadekoBot.Modules.Utility
|
||||
});
|
||||
}, (_, map) =>
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||
var toAdd = new CommandAlias()
|
||||
@ -131,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
||||
return;
|
||||
|
||||
ConcurrentDictionary<string, string> maps;
|
||||
if (!AliasMaps.TryGetValue(Context.Guild.Id, out maps) || !maps.Any())
|
||||
if (!_service.AliasMaps.TryGetValue(Context.Guild.Id, out maps) || !maps.Any())
|
||||
{
|
||||
await ReplyErrorLocalized("aliases_none").ConfigureAwait(false);
|
||||
return;
|
||||
@ -139,7 +123,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
var arr = maps.ToArray();
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) =>
|
||||
await Context.Channel.SendPaginatedConfirmAsync(_client, page + 1, (curPage) =>
|
||||
{
|
||||
return new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("alias_list"))
|
||||
|
@ -15,60 +15,13 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class CrossServerTextChannel : NadekoSubmodule
|
||||
{
|
||||
static CrossServerTextChannel()
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||
}
|
||||
private readonly UtilityService _service;
|
||||
|
||||
public static void Unload()
|
||||
public CrossServerTextChannel(UtilityService service)
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||
_service = service;
|
||||
}
|
||||
|
||||
private static async Task Client_MessageReceived(Discord.WebSocket.SocketMessage imsg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (imsg.Author.IsBot)
|
||||
return;
|
||||
var msg = imsg as IUserMessage;
|
||||
if (msg == null)
|
||||
return;
|
||||
var channel = imsg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
if (msg.Author.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
foreach (var subscriber in Subscribers)
|
||||
{
|
||||
var set = subscriber.Value;
|
||||
if (!set.Contains(channel))
|
||||
continue;
|
||||
foreach (var chan in set.Except(new[] { channel }))
|
||||
{
|
||||
try
|
||||
{
|
||||
await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author,
|
||||
msg)).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) =>
|
||||
$"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
|
||||
|
||||
public static readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
|
||||
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
@ -76,7 +29,7 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
var token = new NadekoRandom().Next();
|
||||
var set = new ConcurrentHashSet<ITextChannel>();
|
||||
if (Subscribers.TryAdd(token, set))
|
||||
if (_service.Subscribers.TryAdd(token, set))
|
||||
{
|
||||
set.Add((ITextChannel) Context.Channel);
|
||||
await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString())
|
||||
@ -90,7 +43,7 @@ namespace NadekoBot.Modules.Utility
|
||||
public async Task Jcsc(int token)
|
||||
{
|
||||
ConcurrentHashSet<ITextChannel> set;
|
||||
if (!Subscribers.TryGetValue(token, out set))
|
||||
if (!_service.Subscribers.TryGetValue(token, out set))
|
||||
return;
|
||||
set.Add((ITextChannel) Context.Channel);
|
||||
await ReplyConfirmLocalized("csc_join").ConfigureAwait(false);
|
||||
@ -101,7 +54,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task Lcsc()
|
||||
{
|
||||
foreach (var subscriber in Subscribers)
|
||||
foreach (var subscriber in _service.Subscribers)
|
||||
{
|
||||
subscriber.Value.TryRemove((ITextChannel) Context.Channel);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -14,6 +16,17 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class InfoCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly IStatsService _stats;
|
||||
private readonly CommandHandler _ch;
|
||||
|
||||
public InfoCommands(DiscordShardedClient client, IStatsService stats, CommandHandler ch)
|
||||
{
|
||||
_client = client;
|
||||
_stats = stats;
|
||||
_ch = ch;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ServerInfo(string guildName = null)
|
||||
@ -24,7 +37,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (string.IsNullOrWhiteSpace(guildName))
|
||||
guild = channel.Guild;
|
||||
else
|
||||
guild = NadekoBot.Client.Guilds.FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant());
|
||||
guild = _client.Guilds.FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant());
|
||||
if (guild == null)
|
||||
return;
|
||||
var ownername = await guild.GetUserAsync(guild.OwnerId);
|
||||
@ -50,9 +63,9 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true))
|
||||
.WithImageUrl(guild.IconUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
if (guild.Emojis.Any())
|
||||
if (guild.Emotes.Any())
|
||||
{
|
||||
embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emojis.Count})").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||
embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emotes.Count})").WithValue(string.Join(" ", guild.Emotes.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||
}
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
@ -101,7 +114,6 @@ namespace NadekoBot.Modules.Utility
|
||||
embed.WithThumbnailUrl(user.RealAvatarUrl());
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@ -117,20 +129,21 @@ namespace NadekoBot.Modules.Utility
|
||||
int startCount = page * activityPerPage;
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage))
|
||||
foreach (var kvp in _ch.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page * activityPerPage).Take(activityPerPage))
|
||||
{
|
||||
str.AppendLine(GetText("activity_line",
|
||||
++startCount,
|
||||
Format.Bold(kvp.Key.ToString()),
|
||||
kvp.Value / NadekoBot.Stats.GetUptime().TotalSeconds, kvp.Value));
|
||||
kvp.Value / _stats.GetUptime().TotalSeconds, kvp.Value));
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
||||
.WithTitle(GetText("activity_page", page + 1))
|
||||
.WithOkColor()
|
||||
.WithFooter(efb => efb.WithText(GetText("activity_users_total",
|
||||
NadekoBot.CommandHandler.UserMessagesSent.Count)))
|
||||
_ch.UserMessagesSent.Count)))
|
||||
.WithDescription(str.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,17 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Net;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Modules.Utility.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
@ -22,140 +20,15 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class RepeatCommands : NadekoSubmodule
|
||||
{
|
||||
//guildid/RepeatRunners
|
||||
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
|
||||
private readonly UtilityService _service;
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DbHandler _db;
|
||||
|
||||
private static bool _ready;
|
||||
|
||||
public class RepeatRunner
|
||||
public RepeatCommands(UtilityService service, DiscordShardedClient client, DbHandler db)
|
||||
{
|
||||
private readonly Logger _log;
|
||||
|
||||
private CancellationTokenSource source { get; set; }
|
||||
private CancellationToken token { get; set; }
|
||||
public Repeater Repeater { get; }
|
||||
public SocketGuild Guild { get; }
|
||||
public ITextChannel Channel { get; private set; }
|
||||
private IUserMessage oldMsg = null;
|
||||
|
||||
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
Repeater = repeater;
|
||||
Channel = channel;
|
||||
|
||||
Guild = NadekoBot.Client.GetGuild(repeater.GuildId);
|
||||
if(Guild!=null)
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(Repeater.Interval, token).ConfigureAwait(false);
|
||||
|
||||
await Trigger().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Trigger()
|
||||
{
|
||||
var toSend = "🔄 " + Repeater.Message;
|
||||
//var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault();
|
||||
// if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel
|
||||
// continue;
|
||||
|
||||
if (oldMsg != null)
|
||||
try
|
||||
{
|
||||
await oldMsg.DeleteAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
try
|
||||
{
|
||||
if (Channel == null)
|
||||
Channel = Guild.GetTextChannel(Repeater.ChannelId);
|
||||
|
||||
if (Channel != null)
|
||||
oldMsg = await Channel.SendMessageAsync(toSend.SanitizeMentions()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
||||
{
|
||||
_log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id);
|
||||
return;
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
_log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
source.Cancel();
|
||||
var _ = Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
source.Cancel();
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
$"{Channel?.Mention ?? $"⚠<#{Repeater.ChannelId}>" } " +
|
||||
$"| {(int) Repeater.Interval.TotalHours}:{Repeater.Interval:mm} " +
|
||||
$"| {Repeater.Message.TrimTo(33)}";
|
||||
}
|
||||
|
||||
static RepeatCommands()
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
#if !GLOBAL_NADEKO
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
#else
|
||||
await Task.Delay(30000).ConfigureAwait(false);
|
||||
#endif
|
||||
//todo this is pretty terrible
|
||||
Repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
|
||||
.ToDictionary(gc => gc.GuildId,
|
||||
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters
|
||||
.Select(gr => new RepeatRunner(gr))
|
||||
.Where(x => x.Guild != null))));
|
||||
_ready = true;
|
||||
});
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
_ready = false;
|
||||
foreach (var kvp in Repeaters)
|
||||
{
|
||||
RepeatRunner r;
|
||||
while (kvp.Value.TryDequeue(out r))
|
||||
{
|
||||
r.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
Repeaters.Clear();
|
||||
_service = service;
|
||||
_client = client;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -163,11 +36,10 @@ namespace NadekoBot.Modules.Utility
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task RepeatInvoke(int index)
|
||||
{
|
||||
if (!_ready)
|
||||
if (!_service.RepeaterReady)
|
||||
return;
|
||||
index -= 1;
|
||||
ConcurrentQueue<RepeatRunner> rep;
|
||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var rep))
|
||||
{
|
||||
await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false);
|
||||
return;
|
||||
@ -193,14 +65,13 @@ namespace NadekoBot.Modules.Utility
|
||||
[Priority(0)]
|
||||
public async Task RepeatRemove(int index)
|
||||
{
|
||||
if (!_ready)
|
||||
if (!_service.RepeaterReady)
|
||||
return;
|
||||
if (index < 1)
|
||||
return;
|
||||
index -= 1;
|
||||
|
||||
ConcurrentQueue<RepeatRunner> rep;
|
||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var rep))
|
||||
return;
|
||||
|
||||
var repeaterList = rep.ToList();
|
||||
@ -215,7 +86,7 @@ namespace NadekoBot.Modules.Utility
|
||||
repeater.Stop();
|
||||
repeaterList.RemoveAt(index);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters));
|
||||
|
||||
@ -223,7 +94,7 @@ namespace NadekoBot.Modules.Utility
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
|
||||
if (_service.Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
|
||||
await Context.Channel.SendConfirmAsync(GetText("message_repeater"),
|
||||
GetText("repeater_stopped", index + 1) + $"\n\n{repeater}").ConfigureAwait(false);
|
||||
}
|
||||
@ -234,7 +105,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[Priority(1)]
|
||||
public async Task Repeat(int minutes, [Remainder] string message)
|
||||
{
|
||||
if (!_ready)
|
||||
if (!_service.RepeaterReady)
|
||||
return;
|
||||
if (minutes < 1 || minutes > 10080)
|
||||
return;
|
||||
@ -250,7 +121,7 @@ namespace NadekoBot.Modules.Utility
|
||||
Message = message
|
||||
};
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters));
|
||||
|
||||
@ -261,9 +132,9 @@ namespace NadekoBot.Modules.Utility
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var rep = new RepeatRunner(toAdd, (ITextChannel) Context.Channel);
|
||||
var rep = new RepeatRunner(_client, toAdd, (ITextChannel) Context.Channel);
|
||||
|
||||
Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] {rep}), (key, old) =>
|
||||
_service.Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] {rep}), (key, old) =>
|
||||
{
|
||||
old.Enqueue(rep);
|
||||
return old;
|
||||
@ -282,10 +153,9 @@ namespace NadekoBot.Modules.Utility
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task RepeatList()
|
||||
{
|
||||
if (!_ready)
|
||||
if (!_service.RepeaterReady)
|
||||
return;
|
||||
ConcurrentQueue<RepeatRunner> repRunners;
|
||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out repRunners))
|
||||
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var repRunners))
|
||||
{
|
||||
await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false);
|
||||
return;
|
||||
|
@ -22,16 +22,20 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class PatreonCommands : NadekoSubmodule
|
||||
{
|
||||
private static readonly PatreonThingy patreon;
|
||||
//todo rename patreon thingy and move it to be a service, or a part of utility service
|
||||
private readonly PatreonThingy patreon;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly BotConfig _config;
|
||||
private readonly DbHandler _db;
|
||||
private readonly CurrencyHandler _currency;
|
||||
|
||||
static PatreonCommands()
|
||||
public PatreonCommands(IBotCredentials creds, BotConfig config, DbHandler db, CurrencyHandler currency)
|
||||
{
|
||||
patreon = PatreonThingy.Instance;
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
patreon.Updater.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_creds = creds;
|
||||
_config = config;
|
||||
_db = db;
|
||||
_currency = currency;
|
||||
patreon = PatreonThingy.GetInstance(creds, db, currency);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -46,7 +50,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ClaimPatreonRewards()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken))
|
||||
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
|
||||
return;
|
||||
if (DateTime.UtcNow.Day < 5)
|
||||
{
|
||||
@ -65,11 +69,11 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("clpa_success", amount + _config.CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var rem = (patreon.Interval - (DateTime.UtcNow - patreon.LastUpdate));
|
||||
var helpcmd = Format.Code(NadekoBot.ModulePrefixes[typeof(Help.Help).Name] + "donate");
|
||||
var helpcmd = Format.Code(NadekoBot.Prefix + "donate");
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithDescription(GetText("clpa_fail"))
|
||||
.AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already")))
|
||||
@ -83,8 +87,10 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
public class PatreonThingy
|
||||
{
|
||||
public static PatreonThingy _instance = new PatreonThingy();
|
||||
public static PatreonThingy Instance => _instance;
|
||||
//todo quickly hacked while rewriting, fix this
|
||||
private static PatreonThingy _instance = null;
|
||||
public static PatreonThingy GetInstance(IBotCredentials creds, DbHandler db, CurrencyHandler cur)
|
||||
=> _instance ?? (_instance = new PatreonThingy(creds, db, cur));
|
||||
|
||||
private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1);
|
||||
|
||||
@ -96,10 +102,17 @@ namespace NadekoBot.Modules.Utility
|
||||
private readonly Logger _log;
|
||||
|
||||
public readonly TimeSpan Interval = TimeSpan.FromHours(1);
|
||||
private IBotCredentials _creds;
|
||||
private readonly DbHandler _db;
|
||||
private readonly CurrencyHandler _currency;
|
||||
|
||||
private PatreonThingy()
|
||||
static PatreonThingy() { }
|
||||
private PatreonThingy(IBotCredentials creds, DbHandler db, CurrencyHandler currency)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken))
|
||||
_creds = creds;
|
||||
_db = db;
|
||||
_currency = currency;
|
||||
if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken))
|
||||
return;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval);
|
||||
@ -116,7 +129,7 @@ namespace NadekoBot.Modules.Utility
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken);
|
||||
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken);
|
||||
var data = new PatreonData()
|
||||
{
|
||||
Links = new PatreonDataLinks()
|
||||
@ -170,7 +183,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
var amount = data.Reward.attributes.amount_cents;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var users = uow._context.Set<RewardedUser>();
|
||||
var usr = users.FirstOrDefault(x => x.PatreonUserId == data.User.id);
|
||||
@ -185,7 +198,7 @@ namespace NadekoBot.Modules.Utility
|
||||
AmountRewardedThisMonth = amount,
|
||||
});
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - new", amount, uow).ConfigureAwait(false);
|
||||
await _currency.AddCurrencyAsync(userId, "Patreon reward - new", amount, uow).ConfigureAwait(false);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
return amount;
|
||||
@ -197,7 +210,7 @@ namespace NadekoBot.Modules.Utility
|
||||
usr.AmountRewardedThisMonth = amount;
|
||||
usr.PatreonUserId = data.User.id;
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - recurring", amount, uow).ConfigureAwait(false);
|
||||
await _currency.AddCurrencyAsync(userId, "Patreon reward - recurring", amount, uow).ConfigureAwait(false);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
return amount;
|
||||
@ -211,7 +224,7 @@ namespace NadekoBot.Modules.Utility
|
||||
usr.AmountRewardedThisMonth = amount;
|
||||
usr.PatreonUserId = data.User.id;
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward - update", toAward, uow).ConfigureAwait(false);
|
||||
await _currency.AddCurrencyAsync(usr.UserId, "Patreon reward - update", toAward, uow).ConfigureAwait(false);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
return toAward;
|
||||
|
@ -17,6 +17,13 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class QuoteCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public QuoteCommands(DbHandler db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ListQuotes(int page = 1)
|
||||
@ -27,7 +34,7 @@ namespace NadekoBot.Modules.Utility
|
||||
return;
|
||||
|
||||
IEnumerable<Quote> quotes;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
quotes = uow.Quotes.GetGroup(Context.Guild.Id, page * 16, 16);
|
||||
}
|
||||
@ -50,7 +57,7 @@ namespace NadekoBot.Modules.Utility
|
||||
keyword = keyword.ToUpperInvariant();
|
||||
|
||||
Quote quote;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
quote =
|
||||
await uow.Quotes.GetRandomQuoteByKeywordAsync(Context.Guild.Id, keyword).ConfigureAwait(false);
|
||||
@ -87,7 +94,7 @@ namespace NadekoBot.Modules.Utility
|
||||
keyword = keyword.ToUpperInvariant();
|
||||
|
||||
Quote keywordquote;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
keywordquote =
|
||||
await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text)
|
||||
@ -108,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var qfromid = uow.Quotes.Get(id);
|
||||
CREmbed crembed;
|
||||
@ -146,7 +153,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
keyword = keyword.ToUpperInvariant();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.Quotes.Add(new Quote
|
||||
{
|
||||
@ -169,7 +176,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
var success = false;
|
||||
string response;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var q = uow.Quotes.Get(id);
|
||||
|
||||
@ -201,7 +208,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
keyword = keyword.ToUpperInvariant();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.Quotes.RemoveAllByKeyword(Context.Guild.Id, keyword.ToUpperInvariant());
|
||||
|
||||
|
@ -19,89 +19,13 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class RemindCommands : NadekoSubmodule
|
||||
{
|
||||
readonly Regex _regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
private readonly UtilityService _service;
|
||||
private readonly DbHandler _db;
|
||||
|
||||
private static string remindMessageFormat { get; }
|
||||
|
||||
private static readonly IDictionary<string, Func<Reminder, string>> _replacements = new Dictionary<string, Func<Reminder, string>>
|
||||
public RemindCommands(UtilityService service, DbHandler db)
|
||||
{
|
||||
{ "%message%" , (r) => r.Message },
|
||||
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
||||
{ "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
||||
};
|
||||
|
||||
private new static readonly Logger _log;
|
||||
private static readonly CancellationTokenSource cancelSource;
|
||||
private static readonly CancellationToken cancelAllToken;
|
||||
|
||||
static RemindCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
cancelSource = new CancellationTokenSource();
|
||||
cancelAllToken = cancelSource.Token;
|
||||
List<Reminder> reminders;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
reminders = uow.Reminders.GetAll().ToList();
|
||||
}
|
||||
remindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat;
|
||||
|
||||
foreach (var r in reminders)
|
||||
{
|
||||
Task.Run(() => StartReminder(r, cancelAllToken));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
if (!cancelSource.IsCancellationRequested)
|
||||
cancelSource.Cancel();
|
||||
}
|
||||
|
||||
private static async Task StartReminder(Reminder r, CancellationToken t)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
var time = r.When - now;
|
||||
|
||||
if (time.TotalMilliseconds > int.MaxValue)
|
||||
return;
|
||||
|
||||
await Task.Delay(time, t).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
IMessageChannel ch;
|
||||
if (r.IsPrivate)
|
||||
{
|
||||
var user = NadekoBot.Client.GetGuild(r.ServerId).GetUser(r.ChannelId);
|
||||
if(user == null)
|
||||
return;
|
||||
ch = await user.CreateDMChannelAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannel(r.ChannelId);
|
||||
}
|
||||
if (ch == null)
|
||||
return;
|
||||
|
||||
await ch.SendMessageAsync(
|
||||
_replacements.Aggregate(remindMessageFormat,
|
||||
(cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
||||
.SanitizeMentions()
|
||||
).ConfigureAwait(false); //it works trust me
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
finally
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
uow.Reminders.Remove(r);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
}
|
||||
_service = service;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public enum MeOrHere
|
||||
@ -139,7 +63,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
public async Task RemindInternal(ulong targetId, bool isPrivate, string timeStr, [Remainder] string message)
|
||||
{
|
||||
var m = _regex.Match(timeStr);
|
||||
var m = _service.Remind.Regex.Match(timeStr);
|
||||
|
||||
if (m.Length == 0)
|
||||
{
|
||||
@ -150,7 +74,7 @@ namespace NadekoBot.Modules.Utility
|
||||
string output = "";
|
||||
var namesAndValues = new Dictionary<string, int>();
|
||||
|
||||
foreach (var groupName in _regex.GetGroupNames())
|
||||
foreach (var groupName in _service.Remind.Regex.GetGroupNames())
|
||||
{
|
||||
if (groupName == "0") continue;
|
||||
int value;
|
||||
@ -191,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
||||
ServerId = Context.Guild.Id
|
||||
};
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.Reminders.Add(rem);
|
||||
await uow.CompleteAsync();
|
||||
@ -210,7 +134,7 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await StartReminder(rem, cancelAllToken);
|
||||
await _service.Remind.StartReminder(rem);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -220,7 +144,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim();
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
|
@ -2,17 +2,8 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Utility.Commands.Models;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
@ -22,108 +13,17 @@ namespace NadekoBot.Modules.Utility
|
||||
[Group]
|
||||
public class UnitConverterCommands : NadekoSubmodule
|
||||
{
|
||||
public static List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
||||
private new static readonly Logger _log;
|
||||
private static Timer _timer;
|
||||
private static readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0);
|
||||
private readonly UtilityService _service;
|
||||
|
||||
static UnitConverterCommands()
|
||||
public UnitConverterCommands(UtilityService service)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
try
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<MeasurementUnit>>(File.ReadAllText("data/units.json")).Select(u => new ConvertUnit()
|
||||
{
|
||||
Modifier = u.Modifier,
|
||||
UnitType = u.UnitType,
|
||||
InternalTrigger = string.Join("|", u.Triggers)
|
||||
}).ToArray();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
if (uow.ConverterUnits.Empty())
|
||||
{
|
||||
uow.ConverterUnits.AddRange(data);
|
||||
uow.Complete();
|
||||
_service = service;
|
||||
}
|
||||
}
|
||||
Units = data.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Could not load units: " + ex.Message);
|
||||
}
|
||||
|
||||
_timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval);
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
_timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
public static async Task UpdateCurrency()
|
||||
{
|
||||
try
|
||||
{
|
||||
var currencyRates = await UpdateCurrencyRates();
|
||||
var unitTypeString = "currency";
|
||||
var range = currencyRates.ConversionRates.Select(u => new ConvertUnit()
|
||||
{
|
||||
InternalTrigger = u.Key,
|
||||
Modifier = u.Value,
|
||||
UnitType = unitTypeString
|
||||
}).ToArray();
|
||||
var baseType = new ConvertUnit()
|
||||
{
|
||||
Triggers = new[] { currencyRates.Base },
|
||||
Modifier = decimal.One,
|
||||
UnitType = unitTypeString
|
||||
};
|
||||
var toRemove = Units.Where(u => u.UnitType == unitTypeString);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
uow.ConverterUnits.RemoveRange(toRemove.ToArray());
|
||||
uow.ConverterUnits.Add(baseType);
|
||||
uow.ConverterUnits.AddRange(range);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
Units.RemoveAll(u => u.UnitType == unitTypeString);
|
||||
Units.Add(baseType);
|
||||
Units.AddRange(range);
|
||||
_log.Info("Updated Currency");
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Failed updating currency. Ignore this.");
|
||||
}
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//[RequireContext(ContextType.Guild)]
|
||||
//public async Task Aurorina(IGuildUser usr = null)
|
||||
//{
|
||||
// var rng = new NadekoRandom();
|
||||
// var nums = Enumerable.Range(48, 10)
|
||||
// .Concat(Enumerable.Range(65, 26))
|
||||
// .Concat(Enumerable.Range(97, 26))
|
||||
// .Concat(new[] {45, 46, 95})
|
||||
// .ToArray();
|
||||
|
||||
// var token = String.Concat(new int[59]
|
||||
// .Select(x => (char) nums[rng.Next(0, nums.Length)]));
|
||||
// if (usr == null)
|
||||
// await Context.Channel.SendConfirmAsync(token).ConfigureAwait(false);
|
||||
// else
|
||||
// await Context.Channel.SendConfirmAsync($"Token of user {usr} is `{token}`").ConfigureAwait(false);
|
||||
//}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ConvertList()
|
||||
{
|
||||
var res = Units.GroupBy(x => x.UnitType)
|
||||
var res = _service.Converter.Units.GroupBy(x => x.UnitType)
|
||||
.Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist"))
|
||||
.WithColor(NadekoBot.OkColor),
|
||||
(embed, g) => embed.AddField(efb =>
|
||||
@ -135,8 +35,8 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Convert(string origin, string target, decimal value)
|
||||
{
|
||||
var originUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant()));
|
||||
var targetUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
|
||||
var originUnit = _service.Converter.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant()));
|
||||
var targetUnit = _service.Converter.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
|
||||
if (originUnit == null || targetUnit == null)
|
||||
{
|
||||
await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false);
|
||||
@ -189,14 +89,5 @@ namespace NadekoBot.Modules.Utility
|
||||
await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2)));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<Rates> UpdateCurrencyRates()
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var res = await http.GetStringAsync("http://api.fixer.io/latest").ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<Rates>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Modules.Utility.Commands.Models
|
||||
{
|
||||
public class MeasurementUnit
|
||||
{
|
||||
public List<string> Triggers { get; set; }
|
||||
public string UnitType { get; set; }
|
||||
public decimal Modifier { get; set; }
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Modules.Utility.Commands.Models
|
||||
{
|
||||
public class Rates
|
||||
{
|
||||
public string Base { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
[JsonProperty("rates")]
|
||||
public Dictionary<string, decimal> ConversionRates { get; set; }
|
||||
}
|
||||
}
|
114
src/NadekoBot/Modules/Utility/Models/RepeatRunner.cs
Normal file
114
src/NadekoBot/Modules/Utility/Models/RepeatRunner.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using Discord;
|
||||
using Discord.Net;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility.Models
|
||||
{
|
||||
public class RepeatRunner
|
||||
{
|
||||
private readonly Logger _log;
|
||||
|
||||
private CancellationTokenSource source { get; set; }
|
||||
private CancellationToken token { get; set; }
|
||||
public Repeater Repeater { get; }
|
||||
public SocketGuild Guild { get; }
|
||||
public ITextChannel Channel { get; private set; }
|
||||
private IUserMessage oldMsg = null;
|
||||
|
||||
public RepeatRunner(DiscordShardedClient client, Repeater repeater, ITextChannel channel = null)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
Repeater = repeater;
|
||||
Channel = channel;
|
||||
|
||||
//todo @.@ fix all of this
|
||||
Guild = client.GetGuild(repeater.GuildId);
|
||||
if (Guild != null)
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(Repeater.Interval, token).ConfigureAwait(false);
|
||||
|
||||
await Trigger().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Trigger()
|
||||
{
|
||||
var toSend = "🔄 " + Repeater.Message;
|
||||
//var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault();
|
||||
// if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel
|
||||
// continue;
|
||||
|
||||
if (oldMsg != null)
|
||||
try
|
||||
{
|
||||
await oldMsg.DeleteAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
try
|
||||
{
|
||||
if (Channel == null)
|
||||
Channel = Guild.GetTextChannel(Repeater.ChannelId);
|
||||
|
||||
if (Channel != null)
|
||||
oldMsg = await Channel.SendMessageAsync(toSend.SanitizeMentions()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
||||
{
|
||||
_log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id);
|
||||
return;
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
_log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
source.Cancel();
|
||||
var _ = Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
source.Cancel();
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
$"{Channel?.Mention ?? $"⚠<#{Repeater.ChannelId}>" } " +
|
||||
$"| {(int)Repeater.Interval.TotalHours}:{Repeater.Interval:mm} " +
|
||||
$"| {Repeater.Message.TrimTo(33)}";
|
||||
}
|
||||
}
|
@ -20,15 +20,23 @@ using System.Diagnostics;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
[NadekoModule("Utility", ".")]
|
||||
[NadekoModule("Utility")]
|
||||
public partial class Utility : NadekoTopLevelModule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly IStatsService _stats;
|
||||
private readonly UtilityService _service;
|
||||
//private readonly MusicService _music;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public static void Unload()
|
||||
public Utility(UtilityService service, DiscordShardedClient client, IStatsService stats, IBotCredentials creds)
|
||||
{
|
||||
_rotatingRoleColors.ForEach(x => x.Value?.Change(Timeout.Infinite, Timeout.Infinite));
|
||||
_rotatingRoleColors.Clear();
|
||||
_client = client;
|
||||
_stats = stats;
|
||||
_service = service;
|
||||
//_music = music;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -355,11 +363,11 @@ namespace NadekoBot.Modules.Utility
|
||||
if (page < 1)
|
||||
return;
|
||||
|
||||
var status = string.Join(", ", NadekoBot.Client.Shards.GroupBy(x => x.ConnectionState)
|
||||
var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState)
|
||||
.Select(x => $"{x.Count()} {x.Key}")
|
||||
.ToArray());
|
||||
|
||||
var allShardStrings = NadekoBot.Client.Shards
|
||||
var allShardStrings = _client.Shards
|
||||
.Select(x =>
|
||||
GetText("shard_stats_txt", x.ShardId.ToString(),
|
||||
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString())))
|
||||
@ -367,7 +375,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) =>
|
||||
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
|
||||
{
|
||||
|
||||
var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25));
|
||||
@ -386,7 +394,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ShardId(IGuild guild)
|
||||
{
|
||||
var shardId = NadekoBot.Client.GetShardIdFor(guild);
|
||||
var shardId = _client.GetShardIdFor(guild);
|
||||
|
||||
await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
@ -394,10 +402,8 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Stats()
|
||||
{
|
||||
var stats = NadekoBot.Stats;
|
||||
|
||||
var shardId = Context.Guild != null
|
||||
? NadekoBot.Client.GetShardIdFor(Context.Guild)
|
||||
? _client.GetShardIdFor(Context.Guild)
|
||||
: 0;
|
||||
|
||||
await Context.Channel.EmbedAsync(
|
||||
@ -405,21 +411,21 @@ namespace NadekoBot.Modules.Utility
|
||||
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
||||
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
|
||||
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
||||
.AddField(efb => efb.WithName(GetText("author")).WithValue(stats.Author).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("botid")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {NadekoBot.Client.Shards.Count}").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("owner_ids")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("author")).WithValue(_stats.Author).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {_client.Shards.Count}").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(_stats.CommandsRan.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("owner_ids")).WithValue(string.Join("\n", _creds.OwnerIds)).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
||||
GetText("presence_txt",
|
||||
NadekoBot.Client.Guilds.Count, stats.TextChannels, stats.VoiceChannels)).WithIsInline(true))
|
||||
_client.Guilds.Count, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true))
|
||||
#if !GLOBAL_NADEKO
|
||||
.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
||||
NadekoBot.MusicService.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
||||
NadekoBot.MusicService.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
||||
//.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
||||
// _music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
||||
// _music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@ -427,7 +433,7 @@ namespace NadekoBot.Modules.Utility
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Showemojis([Remainder] string emojis)
|
||||
{
|
||||
var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emoji)t.Value);
|
||||
var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emote)t.Value);
|
||||
|
||||
var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url)));
|
||||
|
||||
@ -446,7 +452,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (page < 0)
|
||||
return;
|
||||
|
||||
var guilds = await Task.Run(() => NadekoBot.Client.Guilds.OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
|
||||
var guilds = await Task.Run(() => _client.Guilds.OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
|
||||
|
||||
if (!guilds.Any())
|
||||
{
|
||||
|
319
src/NadekoBot/Modules/Utility/UtilityService.cs
Normal file
319
src/NadekoBot/Modules/Utility/UtilityService.cs
Normal file
@ -0,0 +1,319 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Utility.Models;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public class UtilityService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
|
||||
|
||||
//messagerepeater
|
||||
//guildid/RepeatRunners
|
||||
public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
|
||||
public bool RepeaterReady { get; private set; }
|
||||
|
||||
//remind
|
||||
public RemindService Remind { get; }
|
||||
|
||||
//unit conversion
|
||||
public ConverterService Converter { get; }
|
||||
|
||||
public UtilityService(IEnumerable<GuildConfig> guildConfigs, DiscordShardedClient client, BotConfig config, DbHandler db)
|
||||
{
|
||||
//commandmap
|
||||
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
|
||||
guildConfigs.ToDictionary(
|
||||
x => x.GuildId,
|
||||
x => new ConcurrentDictionary<string, string>(x.CommandAliases
|
||||
.Distinct(new CommandAliasEqualityComparer())
|
||||
.ToDictionary(ca => ca.Trigger, ca => ca.Mapping))));
|
||||
|
||||
//crossesrver
|
||||
_client = client;
|
||||
_client.MessageReceived += Client_MessageReceived;
|
||||
|
||||
//messagerepeater
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
#if !GLOBAL_NADEKO
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
#else
|
||||
await Task.Delay(30000).ConfigureAwait(false);
|
||||
#endif
|
||||
//todo this is pretty terrible :kms: no time
|
||||
Repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(guildConfigs
|
||||
.ToDictionary(gc => gc.GuildId,
|
||||
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters
|
||||
.Select(gr => new RepeatRunner(client, gr))
|
||||
.Where(x => x.Guild != null))));
|
||||
RepeaterReady = true;
|
||||
});
|
||||
|
||||
//reminder
|
||||
Remind = new RemindService(client, config, db);
|
||||
|
||||
//unit converter
|
||||
Converter = new ConverterService(db);
|
||||
}
|
||||
|
||||
private async Task Client_MessageReceived(Discord.WebSocket.SocketMessage imsg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (imsg.Author.IsBot)
|
||||
return;
|
||||
var msg = imsg as IUserMessage;
|
||||
if (msg == null)
|
||||
return;
|
||||
var channel = imsg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
if (msg.Author.Id == _client.CurrentUser.Id) return;
|
||||
foreach (var subscriber in Subscribers)
|
||||
{
|
||||
var set = subscriber.Value;
|
||||
if (!set.Contains(channel))
|
||||
continue;
|
||||
foreach (var chan in set.Except(new[] { channel }))
|
||||
{
|
||||
try
|
||||
{
|
||||
await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author,
|
||||
msg)).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) =>
|
||||
$"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
|
||||
|
||||
public readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
|
||||
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
||||
private DiscordShardedClient _client;
|
||||
}
|
||||
|
||||
public class ConverterService
|
||||
{
|
||||
public class MeasurementUnit
|
||||
{
|
||||
public List<string> Triggers { get; set; }
|
||||
public string UnitType { get; set; }
|
||||
public decimal Modifier { get; set; }
|
||||
}
|
||||
|
||||
public class Rates
|
||||
{
|
||||
public string Base { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
[JsonProperty("rates")]
|
||||
public Dictionary<string, decimal> ConversionRates { get; set; }
|
||||
}
|
||||
|
||||
public List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
||||
private readonly Logger _log;
|
||||
private Timer _timer;
|
||||
private readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0);
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public ConverterService(DbHandler db)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
try
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<MeasurementUnit>>(File.ReadAllText("data/units.json")).Select(u => new ConvertUnit()
|
||||
{
|
||||
Modifier = u.Modifier,
|
||||
UnitType = u.UnitType,
|
||||
InternalTrigger = string.Join("|", u.Triggers)
|
||||
}).ToArray();
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
if (uow.ConverterUnits.Empty())
|
||||
{
|
||||
uow.ConverterUnits.AddRange(data);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
Units = data.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Could not load units: " + ex.Message);
|
||||
}
|
||||
|
||||
_timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval);
|
||||
}
|
||||
|
||||
public static async Task<Rates> UpdateCurrencyRates()
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var res = await http.GetStringAsync("http://api.fixer.io/latest").ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<Rates>(res);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateCurrency()
|
||||
{
|
||||
try
|
||||
{
|
||||
var currencyRates = await UpdateCurrencyRates();
|
||||
var unitTypeString = "currency";
|
||||
var range = currencyRates.ConversionRates.Select(u => new ConvertUnit()
|
||||
{
|
||||
InternalTrigger = u.Key,
|
||||
Modifier = u.Value,
|
||||
UnitType = unitTypeString
|
||||
}).ToArray();
|
||||
var baseType = new ConvertUnit()
|
||||
{
|
||||
Triggers = new[] { currencyRates.Base },
|
||||
Modifier = decimal.One,
|
||||
UnitType = unitTypeString
|
||||
};
|
||||
var toRemove = Units.Where(u => u.UnitType == unitTypeString);
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.ConverterUnits.RemoveRange(toRemove.ToArray());
|
||||
uow.ConverterUnits.Add(baseType);
|
||||
uow.ConverterUnits.AddRange(range);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
Units.RemoveAll(u => u.UnitType == unitTypeString);
|
||||
Units.Add(baseType);
|
||||
Units.AddRange(range);
|
||||
_log.Info("Updated Currency");
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Failed updating currency. Ignore this.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class RemindService
|
||||
{
|
||||
public readonly Regex Regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
public string RemindMessageFormat { get; }
|
||||
|
||||
public readonly IDictionary<string, Func<Reminder, string>> _replacements = new Dictionary<string, Func<Reminder, string>>
|
||||
{
|
||||
{ "%message%" , (r) => r.Message },
|
||||
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
||||
{ "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
||||
};
|
||||
|
||||
private readonly Logger _log;
|
||||
private readonly CancellationTokenSource cancelSource;
|
||||
private readonly CancellationToken cancelAllToken;
|
||||
private readonly BotConfig _config;
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public RemindService(DiscordShardedClient client, BotConfig config, DbHandler db)
|
||||
{
|
||||
_config = config;
|
||||
_client = client;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
|
||||
cancelSource = new CancellationTokenSource();
|
||||
cancelAllToken = cancelSource.Token;
|
||||
List<Reminder> reminders;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
reminders = uow.Reminders.GetAll().ToList();
|
||||
}
|
||||
RemindMessageFormat = _config.RemindMessageFormat;
|
||||
|
||||
foreach (var r in reminders)
|
||||
{
|
||||
Task.Run(() => StartReminder(r));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartReminder(Reminder r)
|
||||
{
|
||||
var t = cancelAllToken;
|
||||
var now = DateTime.Now;
|
||||
|
||||
var time = r.When - now;
|
||||
|
||||
if (time.TotalMilliseconds > int.MaxValue)
|
||||
return;
|
||||
|
||||
await Task.Delay(time, t).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
IMessageChannel ch;
|
||||
if (r.IsPrivate)
|
||||
{
|
||||
var user = _client.GetGuild(r.ServerId).GetUser(r.ChannelId);
|
||||
if (user == null)
|
||||
return;
|
||||
ch = await user.CreateDMChannelAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = _client.GetGuild(r.ServerId)?.GetTextChannel(r.ChannelId);
|
||||
}
|
||||
if (ch == null)
|
||||
return;
|
||||
|
||||
await ch.SendMessageAsync(
|
||||
_replacements.Aggregate(RemindMessageFormat,
|
||||
(cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
||||
.SanitizeMentions()
|
||||
).ConfigureAwait(false); //it works trust me
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
finally
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.Reminders.Remove(r);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandAliasEqualityComparer : IEqualityComparer<CommandAlias>
|
||||
{
|
||||
public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger;
|
||||
|
||||
public int GetHashCode(CommandAlias obj) => obj.Trigger.GetHashCode();
|
||||
}
|
||||
}
|
@ -12,13 +12,12 @@ using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
using NadekoBot.TypeReaders;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using NadekoBot.Modules.Music;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Threading;
|
||||
using NadekoBot.Services.Music;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using NadekoBot.Services.Searches;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
@ -26,38 +25,34 @@ namespace NadekoBot
|
||||
{
|
||||
private Logger _log;
|
||||
|
||||
public static Color OkColor { get; }
|
||||
public static Color ErrorColor { get; }
|
||||
/* I don't know how to make this not be static
|
||||
* and keep the convenience of .WithOkColor
|
||||
* and .WithErrorColor extensions methods.
|
||||
* I don't want to pass botconfig every time I
|
||||
* want to send a confirm or error message, so
|
||||
* I'll keep this for now */
|
||||
public static Color OkColor { get; private set; }
|
||||
public static Color ErrorColor { get; private set; }
|
||||
|
||||
public static CommandService CommandService { get; private set; }
|
||||
public static CommandHandler CommandHandler { get; private set; }
|
||||
public static DiscordShardedClient Client { get; private set; }
|
||||
public static BotCredentials Credentials { get; }
|
||||
//todo placeholder, will be guild-based
|
||||
public static string Prefix { get; } = ".";
|
||||
|
||||
public static Localization Localization { get; private set; }
|
||||
public static NadekoStrings Strings { get; private set; }
|
||||
public ImmutableArray<GuildConfig> AllGuildConfigs { get; }
|
||||
public BotConfig BotConfig { get; }
|
||||
|
||||
public static GoogleApiService Google { get; private set; }
|
||||
public static StatsService Stats { get; private set; }
|
||||
public static IImagesService Images { get; private set; }
|
||||
public DiscordShardedClient Client { get; }
|
||||
public bool Ready { get; private set; }
|
||||
|
||||
public static ConcurrentDictionary<string, string> ModulePrefixes { get; private set; }
|
||||
public static bool Ready { get; private set; }
|
||||
public INServiceProvider Services { get; }
|
||||
|
||||
public static ImmutableArray<GuildConfig> AllGuildConfigs { get; }
|
||||
public static BotConfig BotConfig { get; }
|
||||
|
||||
//services
|
||||
//todo DI in the future
|
||||
public static GreetSettingsService GreetSettingsService { get; private set; }
|
||||
public static MusicService MusicService { get; private set; }
|
||||
|
||||
static NadekoBot()
|
||||
public NadekoBot()
|
||||
{
|
||||
SetupLogger();
|
||||
Credentials = new BotCredentials();
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
var credentials = new BotCredentials();
|
||||
var db = new DbHandler(credentials);
|
||||
using (var uow = db.UnitOfWork)
|
||||
{
|
||||
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray();
|
||||
BotConfig = uow.BotConfig.GetOrCreate();
|
||||
@ -65,70 +60,87 @@ namespace NadekoBot
|
||||
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
||||
}
|
||||
|
||||
Google = new GoogleApiService();
|
||||
GreetSettingsService = new GreetSettingsService();
|
||||
MusicService = new MusicService(Google);
|
||||
|
||||
//ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.PngFormat());
|
||||
//ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.JpegFormat());
|
||||
}
|
||||
|
||||
public async Task RunAsync(params string[] args)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
||||
|
||||
//create client
|
||||
Client = new DiscordShardedClient(new DiscordSocketConfig
|
||||
{
|
||||
MessageCacheSize = 10,
|
||||
LogLevel = LogSeverity.Warning,
|
||||
TotalShards = Credentials.TotalShards,
|
||||
TotalShards = credentials.TotalShards,
|
||||
ConnectionTimeout = int.MaxValue,
|
||||
#if !GLOBAL_NADEKO
|
||||
//AlwaysDownloadUsers = true,
|
||||
#endif
|
||||
AlwaysDownloadUsers = true,
|
||||
});
|
||||
|
||||
var google = new GoogleApiService(credentials);
|
||||
var strings = new NadekoStrings();
|
||||
|
||||
var greetSettingsService = new GreetSettingsService(AllGuildConfigs, db);
|
||||
|
||||
var localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), db);
|
||||
//var musicService = new MusicService(google, strings, localization);
|
||||
|
||||
var commandService = new CommandService(new CommandServiceConfig()
|
||||
{
|
||||
CaseSensitiveCommands = false,
|
||||
DefaultRunMode = RunMode.Sync,
|
||||
});
|
||||
|
||||
var commandHandler = new CommandHandler(Client, commandService, credentials, this);
|
||||
|
||||
var stats = new StatsService(Client, commandHandler, credentials);
|
||||
|
||||
var images = new ImagesService();
|
||||
|
||||
//module services
|
||||
var utilityService = new UtilityService(AllGuildConfigs, Client, BotConfig, db);
|
||||
var searchesService = new SearchesService();
|
||||
|
||||
//initialize Services
|
||||
Services = new NServiceProvider.ServiceProviderBuilder() //todo all Adds should be interfaces
|
||||
.Add<ILocalization>(localization)
|
||||
.Add<IStatsService>(stats)
|
||||
.Add<IImagesService>(images)
|
||||
.Add<IGoogleApiService>(google)
|
||||
.Add<IStatsService>(stats)
|
||||
.Add<IBotCredentials>(credentials)
|
||||
.Add<CommandService>(commandService)
|
||||
.Add<NadekoStrings>(strings)
|
||||
.Add<DiscordShardedClient>(Client)
|
||||
.Add<GreetSettingsService>(greetSettingsService)
|
||||
//.Add(musicService)
|
||||
.Add<CommandHandler>(commandHandler)
|
||||
.Add<DbHandler>(db)
|
||||
//modules
|
||||
.Add<UtilityService>(utilityService)
|
||||
.Add<SearchesService>(searchesService)
|
||||
.Build();
|
||||
|
||||
commandHandler.AddServices(Services);
|
||||
|
||||
//setup typereaders
|
||||
commandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
||||
commandService.AddTypeReader<CommandInfo>(new CommandTypeReader(commandService));
|
||||
//commandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader());
|
||||
commandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(commandService));
|
||||
commandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(commandService));
|
||||
commandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
||||
|
||||
#if GLOBAL_NADEKO
|
||||
Client.Log += Client_Log;
|
||||
#endif
|
||||
// initialize response strings
|
||||
Strings = new NadekoStrings();
|
||||
}
|
||||
|
||||
//initialize Services
|
||||
Localization = new Localization(NadekoBot.BotConfig.Locale, NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale));
|
||||
CommandService = new CommandService(new CommandServiceConfig() {
|
||||
CaseSensitiveCommands = false,
|
||||
DefaultRunMode = RunMode.Sync
|
||||
});
|
||||
CommandHandler = new CommandHandler(Client, CommandService);
|
||||
Stats = new StatsService(Client, CommandHandler);
|
||||
Images = await ImagesService.Create().ConfigureAwait(false);
|
||||
|
||||
////setup DI
|
||||
//var depMap = new DependencyMap();
|
||||
//depMap.Add<ILocalization>(Localizer);
|
||||
//depMap.Add<ShardedDiscordClient>(Client);
|
||||
//depMap.Add<CommandService>(CommandService);
|
||||
//depMap.Add<IGoogleApiService>(Google);
|
||||
|
||||
|
||||
//setup typereaders
|
||||
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
||||
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader());
|
||||
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader());
|
||||
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader());
|
||||
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader());
|
||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader());
|
||||
public async Task RunAsync(params string[] args)
|
||||
{
|
||||
var creds = Services.GetService<IBotCredentials>();
|
||||
var stats = Services.GetService<IStatsService>();
|
||||
var commandHandler = Services.GetService<CommandHandler>();
|
||||
var commandService = Services.GetService<CommandService>();
|
||||
|
||||
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
//connect
|
||||
await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false);
|
||||
await Client.LoginAsync(TokenType.Bot, creds.Token).ConfigureAwait(false);
|
||||
await Client.StartAsync().ConfigureAwait(false);
|
||||
//await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
|
||||
// wait for all shards to be ready
|
||||
int readyCount = 0;
|
||||
@ -138,25 +150,21 @@ namespace NadekoBot
|
||||
while (readyCount < Client.Shards.Count)
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
|
||||
Stats.Initialize();
|
||||
stats.Initialize();
|
||||
|
||||
sw.Stop();
|
||||
_log.Info("Connected in " + sw.Elapsed.TotalSeconds.ToString("F2"));
|
||||
|
||||
//load commands and prefixes
|
||||
|
||||
ModulePrefixes = new ConcurrentDictionary<string, string>(NadekoBot.BotConfig.ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix));
|
||||
|
||||
// start handling messages received in commandhandler
|
||||
await commandHandler.StartHandling().ConfigureAwait(false);
|
||||
|
||||
await CommandHandler.StartHandling().ConfigureAwait(false);
|
||||
|
||||
var _ = await Task.Run(() => CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly)).ConfigureAwait(false);
|
||||
var _ = await Task.Run(() => commandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly)).ConfigureAwait(false);
|
||||
#if !GLOBAL_NADEKO
|
||||
await CommandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
||||
//todo uncomment this
|
||||
//await commandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
||||
#endif
|
||||
Ready = true;
|
||||
_log.Info(await Stats.Print().ConfigureAwait(false));
|
||||
_log.Info(await stats.Print().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
private Task Client_Log(LogMessage arg)
|
||||
|
@ -27,7 +27,37 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="data\**\*;credentials.json;credentials_example.json;Modules\Music\Classes\PlaylistFullException.cs" />
|
||||
<Compile Remove="data\**\*;credentials.json;credentials_example.json" />
|
||||
<Compile Remove="Modules\Administration\**" />
|
||||
<Compile Remove="Modules\ClashOfClans\**" />
|
||||
<Compile Remove="Modules\CustomReactions\**" />
|
||||
<Compile Remove="Modules\Gambling\**" />
|
||||
<Compile Remove="Modules\Games\**" />
|
||||
<Compile Remove="Modules\Help\**" />
|
||||
<Compile Remove="Modules\Music\**" />
|
||||
<Compile Remove="Modules\Permissions\**" />
|
||||
<Compile Remove="Modules\Searches\**" />
|
||||
<Compile Remove="Services\Music\**" />
|
||||
<EmbeddedResource Remove="Modules\Administration\**" />
|
||||
<EmbeddedResource Remove="Modules\ClashOfClans\**" />
|
||||
<EmbeddedResource Remove="Modules\CustomReactions\**" />
|
||||
<EmbeddedResource Remove="Modules\Gambling\**" />
|
||||
<EmbeddedResource Remove="Modules\Games\**" />
|
||||
<EmbeddedResource Remove="Modules\Help\**" />
|
||||
<EmbeddedResource Remove="Modules\Music\**" />
|
||||
<EmbeddedResource Remove="Modules\Permissions\**" />
|
||||
<EmbeddedResource Remove="Modules\Searches\**" />
|
||||
<EmbeddedResource Remove="Services\Music\**" />
|
||||
<None Remove="Modules\Administration\**" />
|
||||
<None Remove="Modules\ClashOfClans\**" />
|
||||
<None Remove="Modules\CustomReactions\**" />
|
||||
<None Remove="Modules\Gambling\**" />
|
||||
<None Remove="Modules\Games\**" />
|
||||
<None Remove="Modules\Help\**" />
|
||||
<None Remove="Modules\Music\**" />
|
||||
<None Remove="Modules\Permissions\**" />
|
||||
<None Remove="Modules\Searches\**" />
|
||||
<None Remove="Services\Music\**" />
|
||||
<None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@ -44,7 +74,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
||||
<PackageReference Include="Discord.Net" Version="1.0.0-rc2-00014" />
|
||||
<PackageReference Include="Discord.Net" Version="1.0.0-rc3-00743" />
|
||||
<PackageReference Include="libvideo" Version="1.0.1" />
|
||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
||||
@ -58,10 +88,10 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.2-beta1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
<PackageReference Include="NLog" Version="5.0.0-beta03" />
|
||||
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
@ -6,18 +6,11 @@ using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using NLog;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
using Discord.Net;
|
||||
using NadekoBot.Extensions;
|
||||
using static NadekoBot.Modules.Permissions.Permissions;
|
||||
using NadekoBot.Modules.Help;
|
||||
using static NadekoBot.Modules.Administration.Administration;
|
||||
using NadekoBot.Modules.CustomReactions;
|
||||
using NadekoBot.Modules.Games;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using NadekoBot.DataStructures;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
@ -35,6 +28,9 @@ namespace NadekoBot.Services
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly CommandService _commandService;
|
||||
private readonly Logger _log;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly NadekoBot _bot;
|
||||
private INServiceProvider _services;
|
||||
|
||||
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels { get; set; } = new ImmutableArray<AsyncLazy<IDMChannel>>();
|
||||
|
||||
@ -46,10 +42,13 @@ namespace NadekoBot.Services
|
||||
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||
private readonly Timer _clearUsersOnShortCooldown;
|
||||
|
||||
public CommandHandler(DiscordShardedClient client, CommandService commandService)
|
||||
public CommandHandler(DiscordShardedClient client, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
|
||||
{
|
||||
_client = client;
|
||||
_commandService = commandService;
|
||||
_creds = credentials;
|
||||
_bot = bot;
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
_clearUsersOnShortCooldown = new Timer(_ =>
|
||||
@ -58,11 +57,16 @@ namespace NadekoBot.Services
|
||||
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
||||
}
|
||||
|
||||
public void AddServices(INServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText)
|
||||
{
|
||||
if (guildId != null)
|
||||
{
|
||||
var guild = NadekoBot.Client.GetGuild(guildId.Value);
|
||||
var guild = _client.GetGuild(guildId.Value);
|
||||
var channel = guild?.GetChannel(channelId) as SocketTextChannel;
|
||||
if (channel == null)
|
||||
{
|
||||
@ -87,28 +91,28 @@ namespace NadekoBot.Services
|
||||
{
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
_client.GetGuilds().SelectMany(g => g.Users);
|
||||
_client.Guilds.SelectMany(g => g.Users);
|
||||
|
||||
LoadOwnerChannels();
|
||||
|
||||
if (!ownerChannels.Any())
|
||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||
else
|
||||
_log.Info($"Created {ownerChannels.Length} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
|
||||
_log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels.");
|
||||
});
|
||||
|
||||
_client.MessageReceived += MessageReceivedHandler;
|
||||
_client.MessageUpdated += (oldmsg, newMsg, channel) =>
|
||||
{
|
||||
var ignore = Task.Run(async () =>
|
||||
var ignore = Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var usrMsg = newMsg as SocketUserMessage;
|
||||
var guild = (usrMsg?.Channel as ITextChannel)?.Guild;
|
||||
|
||||
if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
await WordFiltered(guild, usrMsg).ConfigureAwait(false);
|
||||
////todo invite filtering
|
||||
//if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
// await WordFiltered(guild, usrMsg).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -124,7 +128,7 @@ namespace NadekoBot.Services
|
||||
|
||||
private void LoadOwnerChannels()
|
||||
{
|
||||
var hs = new HashSet<ulong>(NadekoBot.Credentials.OwnerIds);
|
||||
var hs = new HashSet<ulong>(_creds.OwnerIds);
|
||||
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
||||
|
||||
foreach (var s in _client.Shards)
|
||||
@ -148,57 +152,59 @@ namespace NadekoBot.Services
|
||||
}
|
||||
}
|
||||
|
||||
ownerChannels = channels.OrderBy(x => NadekoBot.Credentials.OwnerIds.IndexOf(x.Key))
|
||||
ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key))
|
||||
.Select(x => x.Value)
|
||||
.ToImmutableArray();
|
||||
}
|
||||
private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild)
|
||||
{
|
||||
if (guild == null)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out Games.ChatterBotSession cbs);
|
||||
if (message == null || cbs == null)
|
||||
return false;
|
||||
////todo cleverbot
|
||||
//private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild)
|
||||
//{
|
||||
// if (guild == null)
|
||||
// return false;
|
||||
// try
|
||||
// {
|
||||
// var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out Games.ChatterBotSession cbs);
|
||||
// if (message == null || cbs == null)
|
||||
// return false;
|
||||
|
||||
PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||
if (!pc.Permissions.CheckPermissions(usrMsg,
|
||||
NadekoBot.ModulePrefixes[typeof(Games).Name] + "cleverbot",
|
||||
typeof(Games).Name,
|
||||
out int index))
|
||||
{
|
||||
//todo print in guild actually
|
||||
var returnMsg =
|
||||
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||
_log.Info(returnMsg);
|
||||
return true;
|
||||
}
|
||||
// PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||
// if (!pc.Permissions.CheckPermissions(usrMsg,
|
||||
// NadekoBot.Prefix + "cleverbot",
|
||||
// typeof(Games).Name,
|
||||
// out int index))
|
||||
// {
|
||||
// //todo print in guild actually
|
||||
// var returnMsg =
|
||||
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||
// _log.Info(returnMsg);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
|
||||
if (cleverbotExecuted)
|
||||
{
|
||||
_log.Info($@"CleverBot Executed
|
||||
Server: {guild.Name} [{guild.Id}]
|
||||
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||
Message: {usrMsg.Content}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) =>
|
||||
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||
// var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
|
||||
// if (cleverbotExecuted)
|
||||
// {
|
||||
// _log.Info($@"CleverBot Executed
|
||||
//Server: {guild.Name} [{guild.Id}]
|
||||
//Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||
//UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||
//Message: {usrMsg.Content}");
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
// return false;
|
||||
//}
|
||||
////todo blacklisting
|
||||
//private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) =>
|
||||
// (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||
// BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||
// BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||
|
||||
private const float _oneThousandth = 1.0f / 1000;
|
||||
private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total)
|
||||
|
||||
private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, params int[] execPoints)
|
||||
{
|
||||
_log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" +
|
||||
_log.Info("Command Executed after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
|
||||
"User: {0}\n\t" +
|
||||
"Server: {1}\n\t" +
|
||||
"Channel: {2}\n\t" +
|
||||
@ -206,18 +212,14 @@ namespace NadekoBot.Services
|
||||
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
|
||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||
usrMsg.Content, // {3}
|
||||
exec1 * _oneThousandth, // {4}
|
||||
exec2 * _oneThousandth, // {5}
|
||||
exec3 * _oneThousandth, // {6}
|
||||
total * _oneThousandth // {7}
|
||||
usrMsg.Content // {3}
|
||||
);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total)
|
||||
private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, params int[] execPoints)
|
||||
{
|
||||
_log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" +
|
||||
_log.Warn("Command Errored after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
|
||||
"User: {0}\n\t" +
|
||||
"Server: {1}\n\t" +
|
||||
"Channel: {2}\n\t" +
|
||||
@ -227,60 +229,57 @@ namespace NadekoBot.Services
|
||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||
usrMsg.Content,// {3}
|
||||
exec.Result.ErrorReason, // {4}
|
||||
exec1 * _oneThousandth, // {5}
|
||||
exec2 * _oneThousandth, // {6}
|
||||
exec3 * _oneThousandth, // {7}
|
||||
total * _oneThousandth // {8}
|
||||
exec.Result.ErrorReason // {4}
|
||||
);
|
||||
}
|
||||
////todo invite filtering
|
||||
//private async Task<bool> InviteFiltered(IGuild guild, IUserMessage usrMsg)
|
||||
//{
|
||||
// if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
|
||||
// Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
|
||||
// usrMsg.Content.IsDiscordInvite())
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
// return true;
|
||||
// }
|
||||
// catch (HttpException ex)
|
||||
// {
|
||||
// _log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
private async Task<bool> InviteFiltered(IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
|
||||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
|
||||
usrMsg.Content.IsDiscordInvite())
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> WordFiltered(IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
{
|
||||
foreach (var word in wordsInMessage)
|
||||
{
|
||||
if (filteredChannelWords.Contains(word) ||
|
||||
filteredServerWords.Contains(word))
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
////todo word filtering
|
||||
//private async Task<bool> WordFiltered(IGuild guild, IUserMessage usrMsg)
|
||||
//{
|
||||
// var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
// var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
// var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
// if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
// {
|
||||
// foreach (var word in wordsInMessage)
|
||||
// {
|
||||
// if (filteredChannelWords.Contains(word) ||
|
||||
// filteredServerWords.Contains(word))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
// }
|
||||
// catch (HttpException ex)
|
||||
// {
|
||||
// _log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
private Task MessageReceivedHandler(SocketMessage msg)
|
||||
{
|
||||
@ -288,7 +287,7 @@ namespace NadekoBot.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized
|
||||
if (msg.Author.IsBot || !_bot.Ready) //no bots, wait until bot connected and initialized
|
||||
return;
|
||||
|
||||
var usrMsg = msg as SocketUserMessage;
|
||||
@ -325,140 +324,144 @@ namespace NadekoBot.Services
|
||||
{
|
||||
var execTime = Environment.TickCount;
|
||||
|
||||
if (guild != null && guild.OwnerId != usrMsg.Author.Id)
|
||||
{
|
||||
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
////todo word and invite filtering
|
||||
//if (guild != null && guild.OwnerId != usrMsg.Author.Id)
|
||||
//{
|
||||
// if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
// return;
|
||||
|
||||
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
}
|
||||
// if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (IsBlacklisted(guild, usrMsg))
|
||||
return;
|
||||
////todo blacklisting
|
||||
//if (IsBlacklisted(guild, usrMsg))
|
||||
// return;
|
||||
|
||||
var exec1 = Environment.TickCount - execTime;
|
||||
|
||||
|
||||
var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
|
||||
if (cleverBotRan)
|
||||
return;
|
||||
//var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
|
||||
//if (cleverBotRan)
|
||||
// return;
|
||||
|
||||
var exec2 = Environment.TickCount - execTime;
|
||||
|
||||
// maybe this message is a custom reaction
|
||||
// todo log custom reaction executions. return struct with info
|
||||
var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
|
||||
if (cr != null) //if it was, don't execute the command
|
||||
{
|
||||
try
|
||||
{
|
||||
if (guild != null)
|
||||
{
|
||||
PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||
////todo custom reactions
|
||||
//// maybe this message is a custom reaction
|
||||
//// todo log custom reaction executions. return struct with info
|
||||
//var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
|
||||
//if (cr != null) //if it was, don't execute the command
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// if (guild != null)
|
||||
// {
|
||||
// PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||
|
||||
if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
|
||||
out int index))
|
||||
{
|
||||
//todo print in guild actually
|
||||
var returnMsg =
|
||||
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||
_log.Info(returnMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await cr.Send(usrMsg).ConfigureAwait(false);
|
||||
// if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
|
||||
// out int index))
|
||||
// {
|
||||
// //todo print in guild actually
|
||||
// var returnMsg =
|
||||
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||
// _log.Info(returnMsg);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// await cr.Send(usrMsg).ConfigureAwait(false);
|
||||
|
||||
if (cr.AutoDeleteTrigger)
|
||||
{
|
||||
try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Sending CREmbed failed");
|
||||
_log.Warn(ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// if (cr.AutoDeleteTrigger)
|
||||
// {
|
||||
// try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _log.Warn("Sending CREmbed failed");
|
||||
// _log.Warn(ex);
|
||||
// }
|
||||
// return;
|
||||
//}
|
||||
|
||||
var exec3 = Environment.TickCount - execTime;
|
||||
|
||||
string messageContent = usrMsg.Content;
|
||||
if (guild != null)
|
||||
{
|
||||
if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
|
||||
{
|
||||
////todo alias mapping
|
||||
// if (guild != null)
|
||||
// {
|
||||
// if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
|
||||
// {
|
||||
|
||||
var keys = maps.Keys
|
||||
.OrderByDescending(x => x.Length);
|
||||
// var keys = maps.Keys
|
||||
// .OrderByDescending(x => x.Length);
|
||||
|
||||
var lowerMessageContent = messageContent.ToLowerInvariant();
|
||||
foreach (var k in keys)
|
||||
{
|
||||
string newMessageContent;
|
||||
if (lowerMessageContent.StartsWith(k + " "))
|
||||
newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length);
|
||||
else if (lowerMessageContent == k)
|
||||
newMessageContent = maps[k];
|
||||
else
|
||||
continue;
|
||||
// var lowerMessageContent = messageContent.ToLowerInvariant();
|
||||
// foreach (var k in keys)
|
||||
// {
|
||||
// string newMessageContent;
|
||||
// if (lowerMessageContent.StartsWith(k + " "))
|
||||
// newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length);
|
||||
// else if (lowerMessageContent == k)
|
||||
// newMessageContent = maps[k];
|
||||
// else
|
||||
// continue;
|
||||
|
||||
_log.Info(@"--Mapping Command--
|
||||
GuildId: {0}
|
||||
Trigger: {1}
|
||||
Mapping: {2}", guild.Id, messageContent, newMessageContent);
|
||||
var oldMessageContent = messageContent;
|
||||
messageContent = newMessageContent;
|
||||
// _log.Info(@"--Mapping Command--
|
||||
//GuildId: {0}
|
||||
//Trigger: {1}
|
||||
//Mapping: {2}", guild.Id, messageContent, newMessageContent);
|
||||
// var oldMessageContent = messageContent;
|
||||
// messageContent = newMessageContent;
|
||||
|
||||
try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// execute the command and measure the time it took
|
||||
var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false);
|
||||
if (messageContent.StartsWith(NadekoBot.Prefix))
|
||||
{
|
||||
var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
|
||||
execTime = Environment.TickCount - execTime;
|
||||
|
||||
if (exec.Result.IsSuccess)
|
||||
{
|
||||
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
||||
await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false);
|
||||
await LogSuccessfulExecution(usrMsg, exec, channel, exec2, exec3, execTime).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
||||
{
|
||||
LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime);
|
||||
LogErroredExecution(usrMsg, exec, channel, exec2, exec3, execTime);
|
||||
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
|
||||
{
|
||||
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
|
||||
try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
if (usrMsg.Channel is IPrivateChannel)
|
||||
{
|
||||
// rofl, gotta do this to prevent dm help message being sent to
|
||||
// users who are voting on private polls (sending a number in a DM)
|
||||
if (int.TryParse(usrMsg.Content, out int vote)) return;
|
||||
|
||||
await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
|
||||
////todo help
|
||||
//await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
|
||||
|
||||
await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false);
|
||||
}
|
||||
////todo selfcommands
|
||||
//await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling);
|
||||
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), serviceProvider, multiMatchHandling);
|
||||
|
||||
|
||||
public async Task<ExecuteCommandResult> ExecuteCommand(CommandContext context, string input, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
public async Task<ExecuteCommandResult> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
{
|
||||
dependencyMap = dependencyMap ?? DependencyMap.Empty;
|
||||
|
||||
var searchResult = _commandService.Search(context, input);
|
||||
if (!searchResult.IsSuccess)
|
||||
return new ExecuteCommandResult(null, null, searchResult);
|
||||
@ -505,50 +508,55 @@ namespace NadekoBot.Services
|
||||
var module = cmd.Module.GetTopLevelModule();
|
||||
if (context.Guild != null)
|
||||
{
|
||||
PermissionCache pc = Permissions.GetCache(context.Guild.Id);
|
||||
if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out int index))
|
||||
{
|
||||
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)context.Guild)}** is preventing this action.";
|
||||
return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
|
||||
}
|
||||
|
||||
|
||||
if (module.Name == typeof(Permissions).Name)
|
||||
{
|
||||
var guildUser = (IGuildUser)context.User;
|
||||
if (!guildUser.GetRoles().Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && guildUser.Id != guildUser.Guild.OwnerId)
|
||||
{
|
||||
return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
|
||||
}
|
||||
}
|
||||
|
||||
//int price;
|
||||
//if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
|
||||
////todo perms
|
||||
//PermissionCache pc = Permissions.GetCache(context.Guild.Id);
|
||||
//if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out int index))
|
||||
//{
|
||||
// var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
|
||||
// if (!success)
|
||||
// var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)context.Guild)}** is preventing this action.";
|
||||
// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
|
||||
//}
|
||||
|
||||
|
||||
//if (module.Name == typeof(Permissions).Name)
|
||||
//{
|
||||
// var guildUser = (IGuildUser)context.User;
|
||||
// if (!guildUser.GetRoles().Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && guildUser.Id != guildUser.Guild.OwnerId)
|
||||
// {
|
||||
// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command."));
|
||||
// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
|
||||
// }
|
||||
//}
|
||||
|
||||
////////future
|
||||
//////int price;
|
||||
//////if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
|
||||
//////{
|
||||
////// var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
|
||||
////// if (!success)
|
||||
////// {
|
||||
////// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command."));
|
||||
////// }
|
||||
//////}
|
||||
}
|
||||
|
||||
if (cmd.Name != "resetglobalperms" &&
|
||||
(GlobalPermissionCommands.BlockedCommands.Contains(cmd.Aliases.First().ToLowerInvariant()) ||
|
||||
GlobalPermissionCommands.BlockedModules.Contains(module.Name.ToLowerInvariant())))
|
||||
{
|
||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner."));
|
||||
}
|
||||
////todo perms
|
||||
//if (cmd.Name != "resetglobalperms" &&
|
||||
// (GlobalPermissionCommands.BlockedCommands.Contains(cmd.Aliases.First().ToLowerInvariant()) ||
|
||||
// GlobalPermissionCommands.BlockedModules.Contains(module.Name.ToLowerInvariant())))
|
||||
//{
|
||||
// return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner."));
|
||||
//}
|
||||
|
||||
// Bot will ignore commands which are ran more often than what specified by
|
||||
// GlobalCommandsCooldown constant (miliseconds)
|
||||
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
|
||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."));
|
||||
|
||||
if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
|
||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "That command is on a cooldown for you."));
|
||||
////todo cmdcds
|
||||
//if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
|
||||
// return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "That command is on a cooldown for you."));
|
||||
|
||||
return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, dependencyMap));
|
||||
return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, serviceProvider));
|
||||
}
|
||||
|
||||
return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
|
||||
|
@ -2,25 +2,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Gambling;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Services.Database;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public static class CurrencyHandler
|
||||
public class CurrencyHandler
|
||||
{
|
||||
public static async Task<bool> RemoveCurrencyAsync(IUser author, string reason, long amount, bool sendMessage)
|
||||
private readonly BotConfig _config;
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public CurrencyHandler(BotConfig config, DbHandler db)
|
||||
{
|
||||
_config = config;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveCurrencyAsync(IUser author, string reason, long amount, bool sendMessage)
|
||||
{
|
||||
var success = await RemoveCurrencyAsync(author.Id, reason, amount);
|
||||
|
||||
if (success && sendMessage)
|
||||
try { await author.SendErrorAsync($"`You lost:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
|
||||
try { await author.SendErrorAsync($"`You lost:` {amount} {_config.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public static async Task<bool> RemoveCurrencyAsync(ulong authorId, string reason, long amount, IUnitOfWork uow = null)
|
||||
public async Task<bool> RemoveCurrencyAsync(ulong authorId, string reason, long amount, IUnitOfWork uow = null)
|
||||
{
|
||||
if (amount < 0)
|
||||
throw new ArgumentNullException(nameof(amount));
|
||||
@ -28,7 +36,7 @@ namespace NadekoBot.Services
|
||||
|
||||
if (uow == null)
|
||||
{
|
||||
using (uow = DbHandler.UnitOfWork())
|
||||
using (uow = _db.UnitOfWork)
|
||||
{
|
||||
var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
@ -39,7 +47,7 @@ namespace NadekoBot.Services
|
||||
return InternalRemoveCurrency(authorId, reason, amount, uow);
|
||||
}
|
||||
|
||||
private static bool InternalRemoveCurrency(ulong authorId, string reason, long amount, IUnitOfWork uow)
|
||||
private bool InternalRemoveCurrency(ulong authorId, string reason, long amount, IUnitOfWork uow)
|
||||
{
|
||||
var success = uow.Currency.TryUpdateState(authorId, -amount);
|
||||
if (!success)
|
||||
@ -53,15 +61,15 @@ namespace NadekoBot.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task AddCurrencyAsync(IUser author, string reason, long amount, bool sendMessage)
|
||||
public async Task AddCurrencyAsync(IUser author, string reason, long amount, bool sendMessage)
|
||||
{
|
||||
await AddCurrencyAsync(author.Id, reason, amount);
|
||||
|
||||
if (sendMessage)
|
||||
try { await author.SendConfirmAsync($"`You received:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
|
||||
try { await author.SendConfirmAsync($"`You received:` {amount} {_config.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
|
||||
}
|
||||
|
||||
public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount, IUnitOfWork uow = null)
|
||||
public async Task AddCurrencyAsync(ulong receiverId, string reason, long amount, IUnitOfWork uow = null)
|
||||
{
|
||||
if (amount < 0)
|
||||
throw new ArgumentNullException(nameof(amount));
|
||||
@ -74,7 +82,7 @@ namespace NadekoBot.Services
|
||||
};
|
||||
|
||||
if (uow == null)
|
||||
using (uow = DbHandler.UnitOfWork())
|
||||
using (uow = _db.UnitOfWork)
|
||||
{
|
||||
uow.Currency.TryUpdateState(receiverId, amount);
|
||||
uow.CurrencyTransactions.Add(transaction);
|
||||
|
@ -1,6 +1,4 @@
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
{
|
||||
public class PlaylistSong : DbEntity
|
||||
{
|
||||
@ -10,4 +8,12 @@ namespace NadekoBot.Services.Database.Models
|
||||
public string Uri { get; set; }
|
||||
public string Query { get; set; }
|
||||
}
|
||||
|
||||
public enum MusicType
|
||||
{
|
||||
Radio,
|
||||
Normal,
|
||||
Local,
|
||||
Soundcloud
|
||||
}
|
||||
}
|
||||
|
@ -7,19 +7,17 @@ namespace NadekoBot.Services
|
||||
{
|
||||
public class DbHandler
|
||||
{
|
||||
private static DbHandler _instance = null;
|
||||
public static DbHandler Instance = _instance ?? (_instance = new DbHandler());
|
||||
private readonly DbContextOptions options;
|
||||
|
||||
private string connectionString { get; }
|
||||
|
||||
static DbHandler() { }
|
||||
|
||||
private DbHandler()
|
||||
public DbHandler(IBotCredentials creds)
|
||||
{
|
||||
connectionString = NadekoBot.Credentials.Db.ConnectionString;
|
||||
connectionString = creds.Db.ConnectionString;
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlite(NadekoBot.Credentials.Db.ConnectionString);
|
||||
optionsBuilder.UseSqlite(creds.Db.ConnectionString);
|
||||
options = optionsBuilder.Options;
|
||||
//switch (NadekoBot.Credentials.Db.Type.ToUpperInvariant())
|
||||
//{
|
||||
@ -44,10 +42,7 @@ namespace NadekoBot.Services
|
||||
return context;
|
||||
}
|
||||
|
||||
private IUnitOfWork GetUnitOfWork() =>
|
||||
public IUnitOfWork UnitOfWork =>
|
||||
new UnitOfWork(GetDbContext());
|
||||
|
||||
public static IUnitOfWork UnitOfWork() =>
|
||||
DbHandler.Instance.GetUnitOfWork();
|
||||
}
|
||||
}
|
@ -15,13 +15,14 @@ namespace NadekoBot.Services.Discord
|
||||
public event Action<SocketReaction> OnReactionRemoved = delegate { };
|
||||
public event Action OnReactionsCleared = delegate { };
|
||||
|
||||
public ReactionEventWrapper(IUserMessage msg)
|
||||
public ReactionEventWrapper(DiscordShardedClient client, IUserMessage msg)
|
||||
{
|
||||
Message = msg ?? throw new ArgumentNullException(nameof(msg));
|
||||
_client = client;
|
||||
|
||||
NadekoBot.Client.ReactionAdded += Discord_ReactionAdded;
|
||||
NadekoBot.Client.ReactionRemoved += Discord_ReactionRemoved;
|
||||
NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared;
|
||||
_client.ReactionAdded += Discord_ReactionAdded;
|
||||
_client.ReactionRemoved += Discord_ReactionRemoved;
|
||||
_client.ReactionsCleared += Discord_ReactionsCleared;
|
||||
}
|
||||
|
||||
private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
|
||||
@ -62,15 +63,17 @@ namespace NadekoBot.Services.Discord
|
||||
|
||||
public void UnsubAll()
|
||||
{
|
||||
NadekoBot.Client.ReactionAdded -= Discord_ReactionAdded;
|
||||
NadekoBot.Client.ReactionRemoved -= Discord_ReactionRemoved;
|
||||
NadekoBot.Client.ReactionsCleared -= Discord_ReactionsCleared;
|
||||
_client.ReactionAdded -= Discord_ReactionAdded;
|
||||
_client.ReactionRemoved -= Discord_ReactionRemoved;
|
||||
_client.ReactionsCleared -= Discord_ReactionsCleared;
|
||||
OnReactionAdded = null;
|
||||
OnReactionRemoved = null;
|
||||
OnReactionsCleared = null;
|
||||
}
|
||||
|
||||
private bool disposing = false;
|
||||
private readonly DiscordShardedClient _client;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposing)
|
||||
|
@ -12,11 +12,14 @@ namespace NadekoBot.Services
|
||||
{
|
||||
public class GreetSettingsService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache { get; }
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public GreetSettingsService()
|
||||
public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache;
|
||||
|
||||
public GreetSettingsService(IEnumerable<GuildConfig> guildConfigs, DbHandler db)
|
||||
{
|
||||
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
||||
_db = db;
|
||||
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(guildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
||||
}
|
||||
|
||||
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||
@ -27,7 +30,7 @@ namespace NadekoBot.Services
|
||||
if (settings != null)
|
||||
return settings;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
settings = GreetSettings.Create(gc);
|
||||
@ -47,7 +50,7 @@ namespace NadekoBot.Services
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
conf.DmGreetMessageText = settings.DmGreetMessageText?.SanitizeMentions();
|
||||
@ -78,7 +81,7 @@ namespace NadekoBot.Services
|
||||
public async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
|
||||
{
|
||||
bool enabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
|
||||
@ -100,7 +103,7 @@ namespace NadekoBot.Services
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
|
||||
bool greetMsgEnabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
conf.ChannelGreetMessageText = message;
|
||||
@ -117,7 +120,7 @@ namespace NadekoBot.Services
|
||||
public async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
|
||||
{
|
||||
bool enabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
||||
@ -138,7 +141,7 @@ namespace NadekoBot.Services
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
|
||||
bool greetMsgEnabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId);
|
||||
conf.DmGreetMessageText = message;
|
||||
@ -155,7 +158,7 @@ namespace NadekoBot.Services
|
||||
public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
|
||||
{
|
||||
bool enabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
|
||||
@ -177,7 +180,7 @@ namespace NadekoBot.Services
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
|
||||
bool byeMsgEnabled;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
conf.ChannelByeMessageText = message;
|
||||
@ -196,7 +199,7 @@ namespace NadekoBot.Services
|
||||
if (timer < 0 || timer > 600)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
conf.AutoDeleteByeMessagesTimer = timer;
|
||||
|
@ -14,8 +14,10 @@ namespace NadekoBot.Services
|
||||
string MashapeKey { get; }
|
||||
string LoLApiKey { get; }
|
||||
string PatreonAccessToken { get; }
|
||||
string CarbonKey { get; }
|
||||
|
||||
DBConfig Db { get; }
|
||||
string SoundCloudClientId { get; set; }
|
||||
|
||||
bool IsOwner(IUser u);
|
||||
}
|
||||
|
@ -24,6 +24,6 @@ namespace NadekoBot.Services
|
||||
ImmutableArray<byte> WifeMatrix { get; }
|
||||
ImmutableArray<byte> RategirlDot { get; }
|
||||
|
||||
Task<TimeSpan> Reload();
|
||||
TimeSpan Reload();
|
||||
}
|
||||
}
|
||||
|
21
src/NadekoBot/Services/ILocalization.cs
Normal file
21
src/NadekoBot/Services/ILocalization.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using Discord;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public interface ILocalization
|
||||
{
|
||||
CultureInfo DefaultCultureInfo { get; }
|
||||
ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
||||
|
||||
CultureInfo GetCultureInfo(IGuild guild);
|
||||
CultureInfo GetCultureInfo(ulong? guildId);
|
||||
void RemoveGuildCulture(IGuild guild);
|
||||
void RemoveGuildCulture(ulong guildId);
|
||||
void ResetDefaultCulture();
|
||||
void SetDefaultCulture(CultureInfo ci);
|
||||
void SetGuildCulture(IGuild guild, CultureInfo ci);
|
||||
void SetGuildCulture(ulong guildId, CultureInfo ci);
|
||||
}
|
||||
}
|
@ -1,9 +1,22 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public interface IStatsService
|
||||
{
|
||||
string Author { get; }
|
||||
long CommandsRan { get; }
|
||||
string Heap { get; }
|
||||
string Library { get; }
|
||||
long MessageCounter { get; }
|
||||
double MessagesPerSecond { get; }
|
||||
long TextChannels { get; }
|
||||
long VoiceChannels { get; }
|
||||
|
||||
TimeSpan GetUptime();
|
||||
string GetUptimeString(string separator = ", ");
|
||||
void Initialize();
|
||||
Task<string> Print();
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,14 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
private Logger _log { get; }
|
||||
|
||||
public GoogleApiService()
|
||||
public GoogleApiService(IBotCredentials creds)
|
||||
{
|
||||
_creds = creds;
|
||||
|
||||
var bcs = new BaseClientService.Initializer
|
||||
{
|
||||
ApplicationName = "Nadeko Bot",
|
||||
ApiKey = NadekoBot.Credentials.GoogleApiKey,
|
||||
ApiKey = _creds.GoogleApiKey,
|
||||
};
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
@ -59,6 +61,7 @@ namespace NadekoBot.Services.Impl
|
||||
}
|
||||
|
||||
private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?<id>[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled);
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public async Task<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1)
|
||||
{
|
||||
@ -110,7 +113,7 @@ namespace NadekoBot.Services.Impl
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.GoogleApiKey))
|
||||
if (string.IsNullOrWhiteSpace(_creds.GoogleApiKey))
|
||||
return url;
|
||||
|
||||
try
|
||||
|
@ -44,19 +44,13 @@ namespace NadekoBot.Services.Impl
|
||||
public ImmutableArray<byte> WifeMatrix { get; private set; }
|
||||
public ImmutableArray<byte> RategirlDot { get; private set; }
|
||||
|
||||
private ImagesService()
|
||||
public ImagesService()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.Reload();
|
||||
}
|
||||
|
||||
public static async Task<IImagesService> Create()
|
||||
{
|
||||
var srvc = new ImagesService();
|
||||
await srvc.Reload().ConfigureAwait(false);
|
||||
return srvc;
|
||||
}
|
||||
|
||||
public Task<TimeSpan> Reload() => Task.Run(() =>
|
||||
public TimeSpan Reload()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -101,6 +95,6 @@ namespace NadekoBot.Services.Impl
|
||||
_log.Error(ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -12,17 +12,19 @@ using NLog;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public class Localization
|
||||
public class Localization : ILocalization
|
||||
{
|
||||
private readonly Logger _log;
|
||||
private readonly DbHandler _db;
|
||||
|
||||
public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
||||
public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture;
|
||||
|
||||
private Localization() { }
|
||||
public Localization(string defaultCulture, IDictionary<ulong, string> cultureInfoNames)
|
||||
public Localization(string defaultCulture, IDictionary<ulong, string> cultureInfoNames, DbHandler db)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
if (string.IsNullOrWhiteSpace(defaultCulture))
|
||||
DefaultCultureInfo = new CultureInfo("en-US");
|
||||
else
|
||||
@ -62,7 +64,7 @@ namespace NadekoBot.Services
|
||||
return;
|
||||
}
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
gc.Locale = ci.Name;
|
||||
@ -80,7 +82,7 @@ namespace NadekoBot.Services
|
||||
CultureInfo throwaway;
|
||||
if (GuildCultureInfos.TryRemove(guildId, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
gc.Locale = null;
|
||||
@ -91,7 +93,7 @@ namespace NadekoBot.Services
|
||||
|
||||
public void SetDefaultCulture(CultureInfo ci)
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.Locale = ci.Name;
|
||||
|
@ -6,6 +6,7 @@ using System.Xml.Linq;
|
||||
using NLog;
|
||||
using System.Diagnostics;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
@ -15,6 +16,10 @@ namespace NadekoBot.Services
|
||||
|
||||
private readonly ImmutableDictionary<string, ImmutableDictionary<string, string>> responseStrings;
|
||||
private readonly Logger _log;
|
||||
/// <summary>
|
||||
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
||||
/// </summary>
|
||||
private readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
||||
|
||||
public NadekoStrings()
|
||||
{
|
||||
@ -44,7 +49,7 @@ namespace NadekoBot.Services
|
||||
return fileName.Substring(dotIndex, secondDotINdex - dotIndex);
|
||||
}
|
||||
|
||||
public string GetString(string text, CultureInfo cultureInfo)
|
||||
private string GetString(string text, CultureInfo cultureInfo)
|
||||
{
|
||||
if (!responseStrings.TryGetValue(cultureInfo.Name.ToLowerInvariant(), out ImmutableDictionary<string, string> strings))
|
||||
return null;
|
||||
@ -52,5 +57,34 @@ namespace NadekoBot.Services
|
||||
strings.TryGetValue(text, out string val);
|
||||
return val;
|
||||
}
|
||||
|
||||
public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName)
|
||||
{
|
||||
var text = GetString(lowerModuleTypeName + "_" + key, cultureInfo);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
||||
text = GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName,
|
||||
params object[] replacements)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(GetText(key, cultureInfo, lowerModuleTypeName), replacements);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ namespace NadekoBot.Services.Impl
|
||||
public class StatsService : IStatsService
|
||||
{
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly DateTime _started;
|
||||
|
||||
public const string BotVersion = "1.4";
|
||||
@ -36,10 +37,10 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
private readonly Timer _carbonitexTimer;
|
||||
|
||||
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler)
|
||||
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler, IBotCredentials creds)
|
||||
{
|
||||
|
||||
_client = client;
|
||||
_creds = creds;
|
||||
|
||||
_started = DateTime.Now;
|
||||
_client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter));
|
||||
@ -117,7 +118,7 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
_carbonitexTimer = new Timer(async (state) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||
if (string.IsNullOrWhiteSpace(_creds.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
@ -126,7 +127,7 @@ namespace NadekoBot.Services.Impl
|
||||
using (var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "servercount", _client.Guilds.Count.ToString() },
|
||||
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
||||
{ "key", _creds.CarbonKey }}))
|
||||
{
|
||||
content.Headers.Clear();
|
||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||
@ -158,7 +159,7 @@ namespace NadekoBot.Services.Impl
|
||||
Author: [{Author}] | Library: [{Library}]
|
||||
Bot Version: [{BotVersion}]
|
||||
Bot ID: {curUser.Id}
|
||||
Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
|
||||
Owner ID(s): {string.Join(", ", _creds.OwnerIds)}
|
||||
Uptime: {GetUptimeString()}
|
||||
Servers: {_client.Guilds.Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||
Commands Ran this session: {CommandsRan}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
class PlaylistFullException : Exception
|
||||
{
|
@ -8,16 +8,11 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using NadekoBot.Services.Music;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
public enum MusicType
|
||||
{
|
||||
Radio,
|
||||
Normal,
|
||||
Local,
|
||||
Soundcloud
|
||||
}
|
||||
|
||||
public enum StreamState
|
||||
{
|
||||
@ -29,6 +24,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
public class MusicPlayer
|
||||
{
|
||||
public const string MusicDataPath = "data/musicdata";
|
||||
private IAudioClient AudioClient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -58,6 +54,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
private readonly List<Song> _playlist = new List<Song>();
|
||||
private readonly Logger _log;
|
||||
private readonly IGoogleApiService _google;
|
||||
|
||||
public IReadOnlyCollection<Song> Playlist => _playlist;
|
||||
|
||||
@ -88,9 +85,10 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
public event Action<Song, int> SongRemoved = delegate { };
|
||||
|
||||
public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume)
|
||||
public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume, IGoogleApiService google)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_google = google;
|
||||
|
||||
OutputTextChannel = outputChannel;
|
||||
Volume = defaultVolume ?? 1.0f;
|
||||
@ -324,7 +322,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3))
|
||||
.Distinct();
|
||||
|
||||
var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids);
|
||||
var durations = await _google.GetVideoDurationsAsync(ids);
|
||||
|
||||
toUpdate.ForEach(s =>
|
||||
{
|
||||
@ -337,7 +335,6 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
|
@ -1,24 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
using Discord;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules;
|
||||
using NadekoBot.Services.Impl;
|
||||
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
public class MusicService
|
||||
{
|
||||
private readonly IGoogleApiService _google;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly ILocalization _localization;
|
||||
private GoogleApiService google;
|
||||
|
||||
public ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
||||
|
||||
public MusicService(IGoogleApiService google)
|
||||
public MusicService(IGoogleApiService google, NadekoStrings strings, ILocalization localization)
|
||||
{
|
||||
_google = google;
|
||||
_strings = strings;
|
||||
_localization = localization;
|
||||
}
|
||||
|
||||
public MusicPlayer GetPlayer(ulong guildId)
|
||||
@ -30,7 +34,7 @@ namespace NadekoBot.Services.Music
|
||||
public MusicPlayer GetOrCreatePlayer(ulong guildId, IVoiceChannel voiceCh, ITextChannel textCh)
|
||||
{
|
||||
string GetText(string text, params object[] replacements) =>
|
||||
NadekoTopLevelModule.GetTextStatic(text, NadekoBot.Localization.GetCultureInfo(textCh.Guild), nameof(Modules.Music.Music).ToLowerInvariant(), replacements);
|
||||
_strings.GetText(text, _localization.GetCultureInfo(textCh.Guild), "Music".ToLowerInvariant(), replacements);
|
||||
|
||||
return MusicPlayers.GetOrAdd(guildId, server =>
|
||||
{
|
||||
@ -40,7 +44,7 @@ namespace NadekoBot.Services.Music
|
||||
//todo move to cached variable
|
||||
vol = uow.GuildConfigs.For(guildId, set => set).DefaultMusicVolume;
|
||||
}
|
||||
var mp = new MusicPlayer(voiceCh, textCh, vol);
|
||||
var mp = new MusicPlayer(voiceCh, textCh, vol, _google);
|
||||
IUserMessage playingMessage = null;
|
||||
IUserMessage lastFinishedMessage = null;
|
||||
mp.OnCompleted += async (s, song) =>
|
||||
@ -64,7 +68,7 @@ namespace NadekoBot.Services.Music
|
||||
|
||||
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal)
|
||||
{
|
||||
var relatedVideos = (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList();
|
||||
var relatedVideos = (await _google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList();
|
||||
if (relatedVideos.Count > 0)
|
||||
await QueueSong(await textCh.Guild.GetCurrentUserAsync(),
|
||||
textCh,
|
||||
@ -148,7 +152,7 @@ namespace NadekoBot.Services.Music
|
||||
public async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||
{
|
||||
string GetText(string text, params object[] replacements) =>
|
||||
NadekoTopLevelModule.GetTextStatic(text, NadekoBot.Localization.GetCultureInfo(textCh.Guild), nameof(Modules.Music.Music).ToLowerInvariant(), replacements);
|
||||
_strings.GetText(text, _localization.GetCultureInfo(textCh.Guild), "Music".ToLowerInvariant(), replacements);
|
||||
|
||||
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
||||
{
|
||||
|
@ -9,8 +9,9 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using Discord;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
public class SongInfo
|
||||
{
|
||||
@ -29,7 +30,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
private string _queuerName;
|
||||
public string QueuerName { get{
|
||||
return Discord.Format.Sanitize(_queuerName);
|
||||
return Format.Sanitize(_queuerName);
|
||||
} set { _queuerName = value; } }
|
||||
|
||||
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
||||
@ -143,7 +144,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
||||
{
|
||||
BytesSent = (ulong) SkipTo * 3840 * 50;
|
||||
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
||||
var filename = Path.Combine(MusicPlayer.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
||||
|
||||
var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
|
||||
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
@ -6,7 +6,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
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.
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using VideoLibrary;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
public static class SongHandler
|
||||
{
|
||||
@ -49,6 +47,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
})
|
||||
{ TotalTime = TimeSpan.MaxValue };
|
||||
}
|
||||
var sc = SoundCloud.GetInstance(_creds);
|
||||
if (SoundCloud.Default.IsSoundCloudLink(query))
|
||||
{
|
||||
var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false);
|
@ -4,28 +4,34 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Services.Music
|
||||
{
|
||||
public class SoundCloud
|
||||
{
|
||||
private static readonly SoundCloud _instance = new SoundCloud();
|
||||
public static SoundCloud Default => _instance;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
//todo make a service
|
||||
private static SoundCloud _instance = null;
|
||||
public static SoundCloud GetInstance(IBotCredentials creds) => _instance ?? (_instance = new SoundCloud(creds));
|
||||
|
||||
static SoundCloud() { }
|
||||
public SoundCloud() { }
|
||||
public SoundCloud(IBotCredentials creds)
|
||||
{
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
public async Task<SoundCloudVideo> ResolveVideoAsync(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
|
||||
throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
|
||||
if (string.IsNullOrWhiteSpace(_creds.SoundCloudClientId))
|
||||
throw new ArgumentNullException(nameof(_creds.SoundCloudClientId));
|
||||
|
||||
string response = "";
|
||||
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
response = await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={NadekoBot.Credentials.SoundCloudClientId}").ConfigureAwait(false);
|
||||
response = await http.GetStringAsync($"http://api.soundcloud.com/resolve?url={url}&client_id={_creds.SoundCloudClientId}").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
@ -44,13 +50,13 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
|
||||
throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
|
||||
if (string.IsNullOrWhiteSpace(_creds.SoundCloudClientId))
|
||||
throw new ArgumentNullException(nameof(_creds.SoundCloudClientId));
|
||||
|
||||
var response = "";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
response = await http.GetStringAsync($"http://api.soundcloud.com/tracks?q={Uri.EscapeDataString(query)}&client_id={NadekoBot.Credentials.SoundCloudClientId}").ConfigureAwait(false);
|
||||
response = await http.GetStringAsync($"http://api.soundcloud.com/tracks?q={Uri.EscapeDataString(query)}&client_id={_creds.SoundCloudClientId}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var responseObj = JsonConvert.DeserializeObject<SoundCloudVideo[]>(response).Where(s => s.Streamable).FirstOrDefault();
|
||||
@ -74,8 +80,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
[JsonProperty("permalink_url")]
|
||||
public string TrackLink { get; set; } = "";
|
||||
public string artwork_url { get; set; } = "";
|
||||
[JsonIgnore]
|
||||
public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Credentials.SoundCloudClientId}";
|
||||
public string GetStreamLink(IBotCredentials creds) => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={creds.SoundCloudClientId}";
|
||||
}
|
||||
public class SoundCloudUser
|
||||
{
|
68
src/NadekoBot/Services/Searches/SearchesService.cs
Normal file
68
src/NadekoBot/Services/Searches/SearchesService.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using NadekoBot.Extensions;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace NadekoBot.Services.Searches
|
||||
{
|
||||
public class SearchesService
|
||||
{
|
||||
public async Task<string> DapiSearch(string tag, DapiSearchType type)
|
||||
{
|
||||
tag = tag?.Replace(" ", "_");
|
||||
var website = "";
|
||||
switch (type)
|
||||
{
|
||||
case DapiSearchType.Safebooru:
|
||||
website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Gelbooru:
|
||||
website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Rule34:
|
||||
website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Konachan:
|
||||
website = $"https://konachan.com/post.xml?s=post&q=index&limit=100&tags={tag}";
|
||||
break;
|
||||
case DapiSearchType.Yandere:
|
||||
website = $"https://yande.re/post.xml?limit=100&tags={tag}";
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
var toReturn = await Task.Run(async () =>
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.AddFakeHeaders();
|
||||
var data = await http.GetStreamAsync(website).ConfigureAwait(false);
|
||||
var doc = new XmlDocument();
|
||||
doc.Load(data);
|
||||
|
||||
var node = doc.LastChild.ChildNodes[new NadekoRandom().Next(0, doc.LastChild.ChildNodes.Count)];
|
||||
|
||||
var url = node.Attributes["file_url"].Value;
|
||||
if (!url.StartsWith("http"))
|
||||
url = "https:" + url;
|
||||
return url;
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
return toReturn;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DapiSearchType
|
||||
{
|
||||
Safebooru,
|
||||
Gelbooru,
|
||||
Konachan,
|
||||
Rule34,
|
||||
Yandere
|
||||
}
|
||||
}
|
53
src/NadekoBot/Services/ServiceProvider.cs
Normal file
53
src/NadekoBot/Services/ServiceProvider.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public interface INServiceProvider : IServiceProvider
|
||||
{
|
||||
T GetService<T>();
|
||||
}
|
||||
|
||||
public class NServiceProvider : INServiceProvider
|
||||
{
|
||||
public class ServiceProviderBuilder
|
||||
{
|
||||
private ConcurrentDictionary<Type, object> _dict = new ConcurrentDictionary<Type, object>();
|
||||
|
||||
public ServiceProviderBuilder Add<T>(T obj)
|
||||
{
|
||||
_dict.TryAdd(typeof(T), obj);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NServiceProvider Build()
|
||||
{
|
||||
return new NServiceProvider(_dict);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ImmutableDictionary<Type, object> _services;
|
||||
|
||||
private NServiceProvider() { }
|
||||
public NServiceProvider(IDictionary<Type, object> services)
|
||||
{
|
||||
this._services = services.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
public T GetService<T>()
|
||||
{
|
||||
return (T)((IServiceProvider)(this)).GetService(typeof(T));
|
||||
}
|
||||
|
||||
object IServiceProvider.GetService(Type serviceType)
|
||||
{
|
||||
_services.TryGetValue(serviceType, out var toReturn);
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Modules.CustomReactions;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.TypeReaders
|
||||
{
|
||||
public class CommandTypeReader : TypeReader
|
||||
{
|
||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var cmd = NadekoBot.CommandService.Commands.FirstOrDefault(c =>
|
||||
c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
|
||||
if (cmd == null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandOrCrTypeReader : CommandTypeReader
|
||||
{
|
||||
public override async Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
|
||||
if (CustomReactions.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||
{
|
||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||
}
|
||||
var guild = context.Guild;
|
||||
if (guild != null)
|
||||
{
|
||||
CustomReaction[] crs;
|
||||
if (CustomReactions.GuildReactions.TryGetValue(guild.Id, out crs))
|
||||
{
|
||||
if (crs.Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||
{
|
||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cmd = await base.Read(context, input);
|
||||
if (cmd.IsSuccess)
|
||||
{
|
||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First()));
|
||||
}
|
||||
return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandOrCrInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public CommandOrCrInfo(string input)
|
||||
{
|
||||
this.Name = input;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ namespace NadekoBot.Extensions
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
private const string arrow_left = "⬅";
|
||||
private const string arrow_right = "➡";
|
||||
private static readonly IEmote arrow_left = Emote.Parse("⬅");
|
||||
private static readonly IEmote arrow_right = Emote.Parse("➡");
|
||||
|
||||
public static string ToBase64(this string plainText)
|
||||
{
|
||||
@ -27,8 +27,8 @@ namespace NadekoBot.Extensions
|
||||
return Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
|
||||
public static string RealSummary(this CommandInfo cmd) => string.Format(cmd.Summary, cmd.Module.GetTopLevelModule().Prefix);
|
||||
public static string RealRemarks(this CommandInfo cmd) => string.Format(cmd.Remarks, cmd.Module.GetTopLevelModule().Prefix);
|
||||
public static string RealSummary(this CommandInfo cmd) => string.Format(cmd.Summary, ".");
|
||||
public static string RealRemarks(this CommandInfo cmd) => string.Format(cmd.Remarks, ".");
|
||||
|
||||
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
||||
{
|
||||
@ -40,7 +40,7 @@ namespace NadekoBot.Extensions
|
||||
/// <summary>
|
||||
/// danny kamisama
|
||||
/// </summary>
|
||||
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true)
|
||||
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordShardedClient client, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true)
|
||||
{
|
||||
lastPage += 1;
|
||||
var embed = pageFunc(currentPage);
|
||||
@ -53,7 +53,8 @@ namespace NadekoBot.Extensions
|
||||
if (currentPage >= lastPage && lastPage == 1)
|
||||
return;
|
||||
|
||||
await msg.AddReactionAsync(arrow_left).ConfigureAwait(false);
|
||||
|
||||
await msg.AddReactionAsync( arrow_left).ConfigureAwait(false);
|
||||
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
@ -62,7 +63,7 @@ namespace NadekoBot.Extensions
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.Emoji.Name == arrow_left)
|
||||
if (r.Emote.Name == arrow_left.Name)
|
||||
{
|
||||
if (currentPage == 1)
|
||||
return;
|
||||
@ -71,7 +72,7 @@ namespace NadekoBot.Extensions
|
||||
toSend.AddPaginatedFooter(currentPage, lastPage);
|
||||
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
|
||||
}
|
||||
else if (r.Emoji.Name == arrow_right)
|
||||
else if (r.Emote.Name == arrow_right.Name)
|
||||
{
|
||||
if (lastPage == null || lastPage > currentPage)
|
||||
{
|
||||
@ -85,7 +86,7 @@ namespace NadekoBot.Extensions
|
||||
catch (Exception ex) { Console.WriteLine(ex); }
|
||||
};
|
||||
|
||||
using (msg.OnReaction(changePage, changePage))
|
||||
using (msg.OnReaction(client, changePage, changePage))
|
||||
{
|
||||
await Task.Delay(30000).ConfigureAwait(false);
|
||||
}
|
||||
@ -101,12 +102,12 @@ namespace NadekoBot.Extensions
|
||||
return embed.WithFooter(efb => efb.WithText(curPage.ToString()));
|
||||
}
|
||||
|
||||
public static ReactionEventWrapper OnReaction(this IUserMessage msg, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
|
||||
public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordShardedClient client, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
|
||||
{
|
||||
if (reactionRemoved == null)
|
||||
reactionRemoved = delegate { };
|
||||
|
||||
var wrap = new ReactionEventWrapper(msg);
|
||||
var wrap = new ReactionEventWrapper(client, msg);
|
||||
wrap.OnReactionAdded += reactionAdded;
|
||||
wrap.OnReactionRemoved += reactionRemoved;
|
||||
return wrap;
|
||||
@ -141,8 +142,6 @@ namespace NadekoBot.Extensions
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static string GetPrefix(this ModuleInfo module) => NadekoBot.ModulePrefixes[module.GetTopLevelModule().Name];
|
||||
|
||||
public static ModuleInfo GetTopLevelModule(this ModuleInfo module)
|
||||
{
|
||||
while (module.Parent != null)
|
||||
@ -221,9 +220,6 @@ namespace NadekoBot.Extensions
|
||||
public static async Task<IUserMessage> SendFileAsync(this IUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) =>
|
||||
await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false);
|
||||
|
||||
public static bool IsAuthor(this IUserMessage msg) =>
|
||||
NadekoBot.Client.CurrentUser.Id == msg.Author.Id;
|
||||
|
||||
public static IEnumerable<IUser> Members(this IRole role) =>
|
||||
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
||||
|
||||
|
@ -1,11 +1,6 @@
|
||||
using Discord;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Classes
|
||||
namespace NadekoBot.Extensions
|
||||
{
|
||||
public static class MusicExtensions
|
||||
{
|
Loading…
Reference in New Issue
Block a user