Utility and nsfw work
This commit is contained in:
parent
d08bc60be5
commit
2df415341c
@ -1,46 +1,13 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Services;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NadekoBot.Attributes
|
namespace NadekoBot.Attributes
|
||||||
{
|
{
|
||||||
[System.AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
sealed class NadekoModuleAttribute : GroupAttribute
|
sealed class NadekoModuleAttribute : GroupAttribute
|
||||||
{
|
{
|
||||||
//modulename / prefix
|
public NadekoModuleAttribute(string moduleName) : base("")
|
||||||
private static Dictionary<string, string> modulePrefixes = null;
|
|
||||||
public static Dictionary<string, string> ModulePrefixes {
|
|
||||||
get {
|
|
||||||
if (modulePrefixes != null)
|
|
||||||
return modulePrefixes;
|
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
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 System.Threading.Tasks;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using System;
|
||||||
|
using NadekoBot.Services.Impl;
|
||||||
|
using Discord;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Attributes
|
namespace NadekoBot.Attributes
|
||||||
{
|
{
|
||||||
public class OwnerOnlyAttribute : PreconditionAttribute
|
public class OwnerOnlyAttribute : PreconditionAttribute
|
||||||
{
|
{
|
||||||
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) =>
|
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand, IServiceProvider services)
|
||||||
Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
|
{
|
||||||
|
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 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
|
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.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -6,10 +7,16 @@ namespace NadekoBot.TypeReaders
|
|||||||
{
|
{
|
||||||
public class GuildTypeReader : TypeReader
|
public class GuildTypeReader : TypeReader
|
||||||
{
|
{
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public GuildTypeReader(DiscordShardedClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||||
{
|
{
|
||||||
input = input.Trim().ToLowerInvariant();
|
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
|
var guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToLowerInvariant() == input) ?? //by id
|
||||||
guilds.FirstOrDefault(g => g.Name.Trim().ToLowerInvariant() == input); //by name
|
guilds.FirstOrDefault(g => g.Name.Trim().ToLowerInvariant() == input); //by name
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -7,10 +8,17 @@ namespace NadekoBot.TypeReaders
|
|||||||
{
|
{
|
||||||
public class ModuleTypeReader : TypeReader
|
public class ModuleTypeReader : TypeReader
|
||||||
{
|
{
|
||||||
|
private readonly CommandService _cmds;
|
||||||
|
|
||||||
|
public ModuleTypeReader(CommandService cmds)
|
||||||
|
{
|
||||||
|
_cmds = cmds;
|
||||||
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||||
{
|
{
|
||||||
input = input.ToUpperInvariant();
|
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)
|
if (module == null)
|
||||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
||||||
|
|
||||||
@ -20,10 +28,17 @@ namespace NadekoBot.TypeReaders
|
|||||||
|
|
||||||
public class ModuleOrCrTypeReader : TypeReader
|
public class ModuleOrCrTypeReader : TypeReader
|
||||||
{
|
{
|
||||||
|
private readonly CommandService _cmds;
|
||||||
|
|
||||||
|
public ModuleOrCrTypeReader(CommandService cmds)
|
||||||
|
{
|
||||||
|
_cmds = cmds;
|
||||||
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
|
||||||
{
|
{
|
||||||
input = input.ToLowerInvariant();
|
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")
|
if (module == null && input != "actualcustomreactions")
|
||||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
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.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
|
|
||||||
namespace NadekoBot.Migrations
|
namespace NadekoBot.Migrations
|
||||||
{
|
{
|
||||||
|
@ -23,8 +23,6 @@ namespace NadekoBot.Modules.Music
|
|||||||
[DontAutoLoad]
|
[DontAutoLoad]
|
||||||
public class Music : NadekoTopLevelModule
|
public class Music : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public const string MusicDataPath = "data/musicdata";
|
|
||||||
|
|
||||||
private static MusicService music;
|
private static MusicService music;
|
||||||
|
|
||||||
static Music()
|
static Music()
|
||||||
|
@ -11,15 +11,21 @@ using NadekoBot.Extensions;
|
|||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.NSFW
|
namespace NadekoBot.Modules.NSFW
|
||||||
{
|
{
|
||||||
[NadekoModule("NSFW", "~")]
|
[NadekoModule("NSFW")]
|
||||||
public class NSFW : NadekoTopLevelModule
|
public class NSFW : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
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)
|
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||||
{
|
{
|
||||||
@ -142,11 +148,11 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
#endif
|
#endif
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Yandere([Remainder] string tag = null)
|
public Task Yandere([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Yandere);
|
=> InternalDapiCommand(tag, DapiSearchType.Yandere);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Konachan([Remainder] string tag = null)
|
public Task Konachan([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Konachan);
|
=> InternalDapiCommand(tag, DapiSearchType.Konachan);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task E621([Remainder] string tag = null)
|
public async Task E621([Remainder] string tag = null)
|
||||||
@ -167,7 +173,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Rule34([Remainder] string tag = null)
|
public Task Rule34([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Rule34);
|
=> InternalDapiCommand(tag, DapiSearchType.Rule34);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Danbooru([Remainder] string tag = null)
|
public async Task Danbooru([Remainder] string tag = null)
|
||||||
@ -210,7 +216,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Gelbooru([Remainder] string tag = null)
|
public Task Gelbooru([Remainder] string tag = null)
|
||||||
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
=> InternalDapiCommand(tag, DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Boobs()
|
public async Task Boobs()
|
||||||
@ -270,23 +276,23 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Task<string> GetRule34ImageLink(string tag) =>
|
public Task<string> GetRule34ImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34);
|
_service.DapiSearch(tag, DapiSearchType.Rule34);
|
||||||
|
|
||||||
public static Task<string> GetYandereImageLink(string tag) =>
|
public Task<string> GetYandereImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Yandere);
|
_service.DapiSearch(tag, DapiSearchType.Yandere);
|
||||||
|
|
||||||
public static Task<string> GetKonachanImageLink(string tag) =>
|
public Task<string> GetKonachanImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Konachan);
|
_service.DapiSearch(tag, DapiSearchType.Konachan);
|
||||||
|
|
||||||
public static Task<string> GetGelbooruImageLink(string tag) =>
|
public Task<string> GetGelbooruImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
_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() ?? "";
|
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)
|
if (url == null)
|
||||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@ -16,20 +17,23 @@ namespace NadekoBot.Modules
|
|||||||
public readonly string ModuleTypeName;
|
public readonly string ModuleTypeName;
|
||||||
public readonly string LowerModuleTypeName;
|
public readonly string LowerModuleTypeName;
|
||||||
|
|
||||||
|
|
||||||
|
//todo :thinking:
|
||||||
|
public NadekoStrings _strings { get; set; }
|
||||||
|
public ILocalization _localization { get; set; }
|
||||||
|
|
||||||
protected NadekoTopLevelModule(bool isTopLevelModule = true)
|
protected NadekoTopLevelModule(bool isTopLevelModule = true)
|
||||||
{
|
{
|
||||||
//if it's top level module
|
//if it's top level module
|
||||||
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
||||||
LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
|
LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
|
||||||
|
Prefix = NadekoBot.Prefix;
|
||||||
if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out Prefix))
|
|
||||||
Prefix = "?err?";
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void BeforeExecute()
|
protected override void BeforeExecute()
|
||||||
{
|
{
|
||||||
_cultureInfo = NadekoBot.Localization.GetCultureInfo(Context.Guild?.Id);
|
_cultureInfo =_localization.GetCultureInfo(Context.Guild?.Id);
|
||||||
|
|
||||||
_log.Info("Culture info is {0}", _cultureInfo);
|
_log.Info("Culture info is {0}", _cultureInfo);
|
||||||
}
|
}
|
||||||
@ -53,46 +57,12 @@ namespace NadekoBot.Modules
|
|||||||
// var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo);
|
// var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo);
|
||||||
// return Context.Channel.SendErrorAsync(title, text, url, footer);
|
// 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) =>
|
protected string GetText(string key) =>
|
||||||
GetTextStatic(key, _cultureInfo, LowerModuleTypeName);
|
_strings.GetText(key, _cultureInfo, LowerModuleTypeName);
|
||||||
|
|
||||||
protected string GetText(string key, params object[] replacements) =>
|
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)
|
public Task<IUserMessage> ErrorLocalized(string textKey, params object[] replacements)
|
||||||
{
|
{
|
||||||
|
@ -20,20 +20,6 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
[NadekoModule("Permissions", ";")]
|
[NadekoModule("Permissions", ";")]
|
||||||
public partial class Permissions : NadekoTopLevelModule
|
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
|
//guildid, root permission
|
||||||
public static ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
|
public static ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
|
||||||
new ConcurrentDictionary<ulong, PermissionCache>();
|
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)
|
public async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type)
|
||||||
{
|
{
|
||||||
@ -787,55 +779,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithImageUrl(url)
|
.WithImageUrl(url)
|
||||||
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
.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)
|
public async Task<bool> ValidateQuery(IMessageChannel ch, string query)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(query)) return true;
|
if (!string.IsNullOrWhiteSpace(query)) return true;
|
||||||
|
@ -1,48 +1,32 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
public partial class 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]
|
[Group]
|
||||||
public class CommandMapCommands : NadekoSubmodule
|
public class CommandMapCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//guildId, (trigger, mapping)
|
private readonly UtilityService _service;
|
||||||
public static ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
|
private readonly DbHandler _db;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
static CommandMapCommands()
|
public CommandMapCommands(UtilityService service, DbHandler db, DiscordShardedClient client)
|
||||||
{
|
{
|
||||||
var eq = new CommandAliasEqualityComparer();
|
_service = service;
|
||||||
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
|
_db = db;
|
||||||
NadekoBot.AllGuildConfigs.ToDictionary(
|
_client = client;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -61,14 +45,14 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
ConcurrentDictionary<string, string> maps;
|
ConcurrentDictionary<string, string> maps;
|
||||||
string throwaway;
|
string throwaway;
|
||||||
if (!AliasMaps.TryGetValue(Context.Guild.Id, out maps) ||
|
if (!_service.AliasMaps.TryGetValue(Context.Guild.Id, out maps) ||
|
||||||
!maps.TryRemove(trigger, out throwaway))
|
!maps.TryRemove(trigger, out throwaway))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("alias_remove_fail", Format.Code(trigger)).ConfigureAwait(false);
|
await ReplyErrorLocalized("alias_remove_fail", Format.Code(trigger)).ConfigureAwait(false);
|
||||||
return;
|
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 config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||||
var toAdd = new CommandAlias()
|
var toAdd = new CommandAlias()
|
||||||
@ -83,9 +67,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await ReplyConfirmLocalized("alias_removed", Format.Code(trigger)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("alias_removed", Format.Code(trigger)).ConfigureAwait(false);
|
||||||
return;
|
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));
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||||
config.CommandAliases.Add(new CommandAlias()
|
config.CommandAliases.Add(new CommandAlias()
|
||||||
@ -100,7 +84,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
});
|
});
|
||||||
}, (_, map) =>
|
}, (_, 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 config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases));
|
||||||
var toAdd = new CommandAlias()
|
var toAdd = new CommandAlias()
|
||||||
@ -131,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ConcurrentDictionary<string, string> maps;
|
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);
|
await ReplyErrorLocalized("aliases_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -139,7 +123,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
var arr = maps.ToArray();
|
var arr = maps.ToArray();
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) =>
|
await Context.Channel.SendPaginatedConfirmAsync(_client, page + 1, (curPage) =>
|
||||||
{
|
{
|
||||||
return new EmbedBuilder().WithOkColor()
|
return new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(GetText("alias_list"))
|
.WithTitle(GetText("alias_list"))
|
||||||
|
@ -15,60 +15,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class CrossServerTextChannel : NadekoSubmodule
|
public class CrossServerTextChannel : NadekoSubmodule
|
||||||
{
|
{
|
||||||
static CrossServerTextChannel()
|
private readonly UtilityService _service;
|
||||||
|
|
||||||
|
public CrossServerTextChannel(UtilityService service)
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
_service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unload()
|
|
||||||
{
|
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
@ -76,7 +29,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
var token = new NadekoRandom().Next();
|
var token = new NadekoRandom().Next();
|
||||||
var set = new ConcurrentHashSet<ITextChannel>();
|
var set = new ConcurrentHashSet<ITextChannel>();
|
||||||
if (Subscribers.TryAdd(token, set))
|
if (_service.Subscribers.TryAdd(token, set))
|
||||||
{
|
{
|
||||||
set.Add((ITextChannel) Context.Channel);
|
set.Add((ITextChannel) Context.Channel);
|
||||||
await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString())
|
await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString())
|
||||||
@ -90,7 +43,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public async Task Jcsc(int token)
|
public async Task Jcsc(int token)
|
||||||
{
|
{
|
||||||
ConcurrentHashSet<ITextChannel> set;
|
ConcurrentHashSet<ITextChannel> set;
|
||||||
if (!Subscribers.TryGetValue(token, out set))
|
if (!_service.Subscribers.TryGetValue(token, out set))
|
||||||
return;
|
return;
|
||||||
set.Add((ITextChannel) Context.Channel);
|
set.Add((ITextChannel) Context.Channel);
|
||||||
await ReplyConfirmLocalized("csc_join").ConfigureAwait(false);
|
await ReplyConfirmLocalized("csc_join").ConfigureAwait(false);
|
||||||
@ -101,7 +54,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||||
public async Task Lcsc()
|
public async Task Lcsc()
|
||||||
{
|
{
|
||||||
foreach (var subscriber in Subscribers)
|
foreach (var subscriber in _service.Subscribers)
|
||||||
{
|
{
|
||||||
subscriber.Value.TryRemove((ITextChannel) Context.Channel);
|
subscriber.Value.TryRemove((ITextChannel) Context.Channel);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -14,6 +16,17 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class InfoCommands : NadekoSubmodule
|
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]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ServerInfo(string guildName = null)
|
public async Task ServerInfo(string guildName = null)
|
||||||
@ -24,7 +37,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (string.IsNullOrWhiteSpace(guildName))
|
if (string.IsNullOrWhiteSpace(guildName))
|
||||||
guild = channel.Guild;
|
guild = channel.Guild;
|
||||||
else
|
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)
|
if (guild == null)
|
||||||
return;
|
return;
|
||||||
var ownername = await guild.GetUserAsync(guild.OwnerId);
|
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))
|
.AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true))
|
||||||
.WithImageUrl(guild.IconUrl)
|
.WithImageUrl(guild.IconUrl)
|
||||||
.WithColor(NadekoBot.OkColor);
|
.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);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -101,36 +114,36 @@ namespace NadekoBot.Modules.Utility
|
|||||||
embed.WithThumbnailUrl(user.RealAvatarUrl());
|
embed.WithThumbnailUrl(user.RealAvatarUrl());
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task Activity(int page = 1)
|
public async Task Activity(int page = 1)
|
||||||
{
|
|
||||||
const int activityPerPage = 15;
|
|
||||||
page -= 1;
|
|
||||||
|
|
||||||
if (page < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int startCount = page * activityPerPage;
|
|
||||||
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage))
|
|
||||||
{
|
{
|
||||||
str.AppendLine(GetText("activity_line",
|
const int activityPerPage = 15;
|
||||||
++startCount,
|
page -= 1;
|
||||||
Format.Bold(kvp.Key.ToString()),
|
|
||||||
kvp.Value / NadekoBot.Stats.GetUptime().TotalSeconds, kvp.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
if (page < 0)
|
||||||
.WithTitle(GetText("activity_page", page + 1))
|
return;
|
||||||
.WithOkColor()
|
|
||||||
.WithFooter(efb => efb.WithText(GetText("activity_users_total",
|
int startCount = page * activityPerPage;
|
||||||
NadekoBot.CommandHandler.UserMessagesSent.Count)))
|
|
||||||
.WithDescription(str.ToString()));
|
StringBuilder str = new StringBuilder();
|
||||||
|
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 / _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",
|
||||||
|
_ch.UserMessagesSent.Count)))
|
||||||
|
.WithDescription(str.ToString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,19 +1,17 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.Net;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Modules.Utility.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
@ -22,140 +20,15 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class RepeatCommands : NadekoSubmodule
|
public class RepeatCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//guildid/RepeatRunners
|
private readonly UtilityService _service;
|
||||||
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
private static bool _ready;
|
public RepeatCommands(UtilityService service, DiscordShardedClient client, DbHandler db)
|
||||||
|
|
||||||
public class RepeatRunner
|
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
_service = service;
|
||||||
|
_client = client;
|
||||||
private CancellationTokenSource source { get; set; }
|
_db = db;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -163,11 +36,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task RepeatInvoke(int index)
|
public async Task RepeatInvoke(int index)
|
||||||
{
|
{
|
||||||
if (!_ready)
|
if (!_service.RepeaterReady)
|
||||||
return;
|
return;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
ConcurrentQueue<RepeatRunner> rep;
|
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var rep))
|
||||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false);
|
await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -193,14 +65,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task RepeatRemove(int index)
|
public async Task RepeatRemove(int index)
|
||||||
{
|
{
|
||||||
if (!_ready)
|
if (!_service.RepeaterReady)
|
||||||
return;
|
return;
|
||||||
if (index < 1)
|
if (index < 1)
|
||||||
return;
|
return;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
|
|
||||||
ConcurrentQueue<RepeatRunner> rep;
|
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var rep))
|
||||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var repeaterList = rep.ToList();
|
var repeaterList = rep.ToList();
|
||||||
@ -215,7 +86,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
repeater.Stop();
|
repeater.Stop();
|
||||||
repeaterList.RemoveAt(index);
|
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));
|
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);
|
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"),
|
await Context.Channel.SendConfirmAsync(GetText("message_repeater"),
|
||||||
GetText("repeater_stopped", index + 1) + $"\n\n{repeater}").ConfigureAwait(false);
|
GetText("repeater_stopped", index + 1) + $"\n\n{repeater}").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -234,7 +105,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task Repeat(int minutes, [Remainder] string message)
|
public async Task Repeat(int minutes, [Remainder] string message)
|
||||||
{
|
{
|
||||||
if (!_ready)
|
if (!_service.RepeaterReady)
|
||||||
return;
|
return;
|
||||||
if (minutes < 1 || minutes > 10080)
|
if (minutes < 1 || minutes > 10080)
|
||||||
return;
|
return;
|
||||||
@ -250,7 +121,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
Message = message
|
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));
|
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);
|
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);
|
old.Enqueue(rep);
|
||||||
return old;
|
return old;
|
||||||
@ -282,10 +153,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task RepeatList()
|
public async Task RepeatList()
|
||||||
{
|
{
|
||||||
if (!_ready)
|
if (!_service.RepeaterReady)
|
||||||
return;
|
return;
|
||||||
ConcurrentQueue<RepeatRunner> repRunners;
|
if (!_service.Repeaters.TryGetValue(Context.Guild.Id, out var repRunners))
|
||||||
if (!Repeaters.TryGetValue(Context.Guild.Id, out repRunners))
|
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false);
|
await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
@ -22,16 +22,20 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class PatreonCommands : NadekoSubmodule
|
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;
|
_creds = creds;
|
||||||
}
|
_config = config;
|
||||||
|
_db = db;
|
||||||
public static void Unload()
|
_currency = currency;
|
||||||
{
|
patreon = PatreonThingy.GetInstance(creds, db, currency);
|
||||||
patreon.Updater.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -46,7 +50,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ClaimPatreonRewards()
|
public async Task ClaimPatreonRewards()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken))
|
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
|
||||||
return;
|
return;
|
||||||
if (DateTime.UtcNow.Day < 5)
|
if (DateTime.UtcNow.Day < 5)
|
||||||
{
|
{
|
||||||
@ -65,11 +69,11 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyConfirmLocalized("clpa_success", amount + _config.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var rem = (patreon.Interval - (DateTime.UtcNow - patreon.LastUpdate));
|
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()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription(GetText("clpa_fail"))
|
.WithDescription(GetText("clpa_fail"))
|
||||||
.AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already")))
|
.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 class PatreonThingy
|
||||||
{
|
{
|
||||||
public static PatreonThingy _instance = new PatreonThingy();
|
//todo quickly hacked while rewriting, fix this
|
||||||
public static PatreonThingy Instance => _instance;
|
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);
|
private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
@ -96,10 +102,17 @@ namespace NadekoBot.Modules.Utility
|
|||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public readonly TimeSpan Interval = TimeSpan.FromHours(1);
|
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;
|
return;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval);
|
Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval);
|
||||||
@ -116,7 +129,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken);
|
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken);
|
||||||
var data = new PatreonData()
|
var data = new PatreonData()
|
||||||
{
|
{
|
||||||
Links = new PatreonDataLinks()
|
Links = new PatreonDataLinks()
|
||||||
@ -170,7 +183,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
var amount = data.Reward.attributes.amount_cents;
|
var amount = data.Reward.attributes.amount_cents;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var users = uow._context.Set<RewardedUser>();
|
var users = uow._context.Set<RewardedUser>();
|
||||||
var usr = users.FirstOrDefault(x => x.PatreonUserId == data.User.id);
|
var usr = users.FirstOrDefault(x => x.PatreonUserId == data.User.id);
|
||||||
@ -185,7 +198,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
AmountRewardedThisMonth = amount,
|
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);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
return amount;
|
return amount;
|
||||||
@ -197,7 +210,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
usr.AmountRewardedThisMonth = amount;
|
usr.AmountRewardedThisMonth = amount;
|
||||||
usr.PatreonUserId = data.User.id;
|
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);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
return amount;
|
return amount;
|
||||||
@ -211,7 +224,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
usr.AmountRewardedThisMonth = amount;
|
usr.AmountRewardedThisMonth = amount;
|
||||||
usr.PatreonUserId = data.User.id;
|
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);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
return toAward;
|
return toAward;
|
||||||
|
@ -17,6 +17,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class QuoteCommands : NadekoSubmodule
|
public class QuoteCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
|
public QuoteCommands(DbHandler db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ListQuotes(int page = 1)
|
public async Task ListQuotes(int page = 1)
|
||||||
@ -27,7 +34,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
IEnumerable<Quote> quotes;
|
IEnumerable<Quote> quotes;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
quotes = uow.Quotes.GetGroup(Context.Guild.Id, page * 16, 16);
|
quotes = uow.Quotes.GetGroup(Context.Guild.Id, page * 16, 16);
|
||||||
}
|
}
|
||||||
@ -50,7 +57,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
keyword = keyword.ToUpperInvariant();
|
keyword = keyword.ToUpperInvariant();
|
||||||
|
|
||||||
Quote quote;
|
Quote quote;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
quote =
|
quote =
|
||||||
await uow.Quotes.GetRandomQuoteByKeywordAsync(Context.Guild.Id, keyword).ConfigureAwait(false);
|
await uow.Quotes.GetRandomQuoteByKeywordAsync(Context.Guild.Id, keyword).ConfigureAwait(false);
|
||||||
@ -87,7 +94,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
keyword = keyword.ToUpperInvariant();
|
keyword = keyword.ToUpperInvariant();
|
||||||
|
|
||||||
Quote keywordquote;
|
Quote keywordquote;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
keywordquote =
|
keywordquote =
|
||||||
await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text)
|
await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text)
|
||||||
@ -108,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (id < 0)
|
if (id < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var qfromid = uow.Quotes.Get(id);
|
var qfromid = uow.Quotes.Get(id);
|
||||||
CREmbed crembed;
|
CREmbed crembed;
|
||||||
@ -146,7 +153,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
keyword = keyword.ToUpperInvariant();
|
keyword = keyword.ToUpperInvariant();
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.Quotes.Add(new Quote
|
uow.Quotes.Add(new Quote
|
||||||
{
|
{
|
||||||
@ -169,7 +176,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
var success = false;
|
var success = false;
|
||||||
string response;
|
string response;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var q = uow.Quotes.Get(id);
|
var q = uow.Quotes.Get(id);
|
||||||
|
|
||||||
@ -201,7 +208,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
keyword = keyword.ToUpperInvariant();
|
keyword = keyword.ToUpperInvariant();
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.Quotes.RemoveAllByKeyword(Context.Guild.Id, keyword.ToUpperInvariant());
|
uow.Quotes.RemoveAllByKeyword(Context.Guild.Id, keyword.ToUpperInvariant());
|
||||||
|
|
||||||
|
@ -19,89 +19,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class RemindCommands : NadekoSubmodule
|
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)?$",
|
private readonly UtilityService _service;
|
||||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
private static string remindMessageFormat { get; }
|
public RemindCommands(UtilityService service, DbHandler db)
|
||||||
|
|
||||||
private static readonly IDictionary<string, Func<Reminder, string>> _replacements = new Dictionary<string, Func<Reminder, string>>
|
|
||||||
{
|
{
|
||||||
{ "%message%" , (r) => r.Message },
|
_service = service;
|
||||||
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
_db = db;
|
||||||
{ "%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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MeOrHere
|
public enum MeOrHere
|
||||||
@ -139,7 +63,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
public async Task RemindInternal(ulong targetId, bool isPrivate, string timeStr, [Remainder] string message)
|
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)
|
if (m.Length == 0)
|
||||||
{
|
{
|
||||||
@ -150,7 +74,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
string output = "";
|
string output = "";
|
||||||
var namesAndValues = new Dictionary<string, int>();
|
var namesAndValues = new Dictionary<string, int>();
|
||||||
|
|
||||||
foreach (var groupName in _regex.GetGroupNames())
|
foreach (var groupName in _service.Remind.Regex.GetGroupNames())
|
||||||
{
|
{
|
||||||
if (groupName == "0") continue;
|
if (groupName == "0") continue;
|
||||||
int value;
|
int value;
|
||||||
@ -191,7 +115,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
ServerId = Context.Guild.Id
|
ServerId = Context.Guild.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.Reminders.Add(rem);
|
uow.Reminders.Add(rem);
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
@ -210,7 +134,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
await StartReminder(rem, cancelAllToken);
|
await _service.Remind.StartReminder(rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -220,7 +144,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim();
|
uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim();
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
@ -2,17 +2,8 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
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;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
@ -22,108 +13,17 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public class UnitConverterCommands : NadekoSubmodule
|
public class UnitConverterCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
private readonly UtilityService _service;
|
||||||
private new static readonly Logger _log;
|
|
||||||
private static Timer _timer;
|
|
||||||
private static readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0);
|
|
||||||
|
|
||||||
static UnitConverterCommands()
|
public UnitConverterCommands(UtilityService service)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_service = service;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ConvertList()
|
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"))
|
.Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist"))
|
||||||
.WithColor(NadekoBot.OkColor),
|
.WithColor(NadekoBot.OkColor),
|
||||||
(embed, g) => embed.AddField(efb =>
|
(embed, g) => embed.AddField(efb =>
|
||||||
@ -135,8 +35,8 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Convert(string origin, string target, decimal value)
|
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 originUnit = _service.Converter.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 targetUnit = _service.Converter.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
|
||||||
if (originUnit == null || targetUnit == null)
|
if (originUnit == null || targetUnit == null)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false);
|
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)));
|
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
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
[NadekoModule("Utility", ".")]
|
[NadekoModule("Utility")]
|
||||||
public partial class Utility : NadekoTopLevelModule
|
public partial class Utility : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
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));
|
_client = client;
|
||||||
_rotatingRoleColors.Clear();
|
_stats = stats;
|
||||||
|
_service = service;
|
||||||
|
//_music = music;
|
||||||
|
_creds = creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
//[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -355,11 +363,11 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (page < 1)
|
if (page < 1)
|
||||||
return;
|
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}")
|
.Select(x => $"{x.Count()} {x.Key}")
|
||||||
.ToArray());
|
.ToArray());
|
||||||
|
|
||||||
var allShardStrings = NadekoBot.Client.Shards
|
var allShardStrings = _client.Shards
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
GetText("shard_stats_txt", x.ShardId.ToString(),
|
GetText("shard_stats_txt", x.ShardId.ToString(),
|
||||||
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.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));
|
var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25));
|
||||||
@ -386,7 +394,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ShardId(IGuild guild)
|
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);
|
await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -394,10 +402,8 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Stats()
|
public async Task Stats()
|
||||||
{
|
{
|
||||||
var stats = NadekoBot.Stats;
|
|
||||||
|
|
||||||
var shardId = Context.Guild != null
|
var shardId = Context.Guild != null
|
||||||
? NadekoBot.Client.GetShardIdFor(Context.Guild)
|
? _client.GetShardIdFor(Context.Guild)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(
|
await Context.Channel.EmbedAsync(
|
||||||
@ -405,21 +411,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
||||||
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
|
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
|
||||||
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
.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("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("botid")).WithValue(_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("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("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("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("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("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("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
||||||
GetText("presence_txt",
|
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
|
#if !GLOBAL_NADEKO
|
||||||
.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
//.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
||||||
NadekoBot.MusicService.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
// _music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
||||||
NadekoBot.MusicService.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
// _music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -427,7 +433,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Showemojis([Remainder] string emojis)
|
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)));
|
var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url)));
|
||||||
|
|
||||||
@ -446,7 +452,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (page < 0)
|
if (page < 0)
|
||||||
return;
|
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())
|
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 System.Threading.Tasks;
|
||||||
using NadekoBot.Modules.Permissions;
|
using NadekoBot.Modules.Permissions;
|
||||||
using NadekoBot.TypeReaders;
|
using NadekoBot.TypeReaders;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using NadekoBot.Modules.Music;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NadekoBot.Services.Music;
|
using NadekoBot.Modules.Utility;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
|
|
||||||
namespace NadekoBot
|
namespace NadekoBot
|
||||||
{
|
{
|
||||||
@ -26,109 +25,122 @@ namespace NadekoBot
|
|||||||
{
|
{
|
||||||
private Logger _log;
|
private Logger _log;
|
||||||
|
|
||||||
public static Color OkColor { get; }
|
/* I don't know how to make this not be static
|
||||||
public static Color ErrorColor { get; }
|
* 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; }
|
||||||
|
|
||||||
|
//todo placeholder, will be guild-based
|
||||||
|
public static string Prefix { get; } = ".";
|
||||||
|
|
||||||
public static CommandService CommandService { get; private set; }
|
public ImmutableArray<GuildConfig> AllGuildConfigs { get; }
|
||||||
public static CommandHandler CommandHandler { get; private set; }
|
public BotConfig BotConfig { get; }
|
||||||
public static DiscordShardedClient Client { get; private set; }
|
|
||||||
public static BotCredentials Credentials { get; }
|
|
||||||
|
|
||||||
public static Localization Localization { get; private set; }
|
public DiscordShardedClient Client { get; }
|
||||||
public static NadekoStrings Strings { get; private set; }
|
public bool Ready { get; private set; }
|
||||||
|
|
||||||
public static GoogleApiService Google { get; private set; }
|
public INServiceProvider Services { get; }
|
||||||
public static StatsService Stats { get; private set; }
|
|
||||||
public static IImagesService Images { get; private set; }
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, string> ModulePrefixes { get; private set; }
|
public NadekoBot()
|
||||||
public static bool Ready { get; private set; }
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
SetupLogger();
|
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();
|
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray();
|
||||||
BotConfig = uow.BotConfig.GetOrCreate();
|
BotConfig = uow.BotConfig.GetOrCreate();
|
||||||
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
||||||
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
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
|
Client = new DiscordShardedClient(new DiscordSocketConfig
|
||||||
{
|
{
|
||||||
MessageCacheSize = 10,
|
MessageCacheSize = 10,
|
||||||
LogLevel = LogSeverity.Warning,
|
LogLevel = LogSeverity.Warning,
|
||||||
TotalShards = Credentials.TotalShards,
|
TotalShards = credentials.TotalShards,
|
||||||
ConnectionTimeout = int.MaxValue,
|
ConnectionTimeout = int.MaxValue,
|
||||||
#if !GLOBAL_NADEKO
|
AlwaysDownloadUsers = true,
|
||||||
//AlwaysDownloadUsers = true,
|
|
||||||
#endif
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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
|
#if GLOBAL_NADEKO
|
||||||
Client.Log += Client_Log;
|
Client.Log += Client_Log;
|
||||||
#endif
|
#endif
|
||||||
// initialize response strings
|
}
|
||||||
Strings = new NadekoStrings();
|
|
||||||
|
|
||||||
//initialize Services
|
public async Task RunAsync(params string[] args)
|
||||||
Localization = new Localization(NadekoBot.BotConfig.Locale, NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale));
|
{
|
||||||
CommandService = new CommandService(new CommandServiceConfig() {
|
var creds = Services.GetService<IBotCredentials>();
|
||||||
CaseSensitiveCommands = false,
|
var stats = Services.GetService<IStatsService>();
|
||||||
DefaultRunMode = RunMode.Sync
|
var commandHandler = Services.GetService<CommandHandler>();
|
||||||
});
|
var commandService = Services.GetService<CommandService>();
|
||||||
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());
|
|
||||||
|
|
||||||
|
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
//connect
|
//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.StartAsync().ConfigureAwait(false);
|
||||||
//await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
// wait for all shards to be ready
|
// wait for all shards to be ready
|
||||||
int readyCount = 0;
|
int readyCount = 0;
|
||||||
@ -138,25 +150,21 @@ namespace NadekoBot
|
|||||||
while (readyCount < Client.Shards.Count)
|
while (readyCount < Client.Shards.Count)
|
||||||
await Task.Delay(100).ConfigureAwait(false);
|
await Task.Delay(100).ConfigureAwait(false);
|
||||||
|
|
||||||
Stats.Initialize();
|
stats.Initialize();
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Info("Connected in " + sw.Elapsed.TotalSeconds.ToString("F2"));
|
_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
|
// 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
|
#if !GLOBAL_NADEKO
|
||||||
await CommandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
//todo uncomment this
|
||||||
|
//await commandService.AddModuleAsync<Music>().ConfigureAwait(false);
|
||||||
#endif
|
#endif
|
||||||
Ready = true;
|
Ready = true;
|
||||||
_log.Info(await Stats.Print().ConfigureAwait(false));
|
_log.Info(await stats.Print().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Client_Log(LogMessage arg)
|
private Task Client_Log(LogMessage arg)
|
||||||
|
@ -27,7 +27,37 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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">
|
<None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@ -44,7 +74,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
<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="libvideo" Version="1.0.1" />
|
||||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
||||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
<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" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" 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.Configuration.Json" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
<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="NLog" Version="5.0.0-beta03" />
|
||||||
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -6,18 +6,11 @@ using System.Threading.Tasks;
|
|||||||
using Discord;
|
using Discord;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Modules.Permissions;
|
|
||||||
using Discord.Net;
|
using Discord.Net;
|
||||||
using NadekoBot.Extensions;
|
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.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace NadekoBot.Services
|
namespace NadekoBot.Services
|
||||||
@ -35,6 +28,9 @@ namespace NadekoBot.Services
|
|||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordShardedClient _client;
|
||||||
private readonly CommandService _commandService;
|
private readonly CommandService _commandService;
|
||||||
private readonly Logger _log;
|
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>>();
|
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>();
|
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||||
private readonly Timer _clearUsersOnShortCooldown;
|
private readonly Timer _clearUsersOnShortCooldown;
|
||||||
|
|
||||||
public CommandHandler(DiscordShardedClient client, CommandService commandService)
|
public CommandHandler(DiscordShardedClient client, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_commandService = commandService;
|
_commandService = commandService;
|
||||||
|
_creds = credentials;
|
||||||
|
_bot = bot;
|
||||||
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
_clearUsersOnShortCooldown = new Timer(_ =>
|
_clearUsersOnShortCooldown = new Timer(_ =>
|
||||||
@ -58,11 +57,16 @@ namespace NadekoBot.Services
|
|||||||
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddServices(INServiceProvider services)
|
||||||
|
{
|
||||||
|
_services = services;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText)
|
public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText)
|
||||||
{
|
{
|
||||||
if (guildId != null)
|
if (guildId != null)
|
||||||
{
|
{
|
||||||
var guild = NadekoBot.Client.GetGuild(guildId.Value);
|
var guild = _client.GetGuild(guildId.Value);
|
||||||
var channel = guild?.GetChannel(channelId) as SocketTextChannel;
|
var channel = guild?.GetChannel(channelId) as SocketTextChannel;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
{
|
{
|
||||||
@ -87,28 +91,28 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
|
|
||||||
_client.GetGuilds().SelectMany(g => g.Users);
|
_client.Guilds.SelectMany(g => g.Users);
|
||||||
|
|
||||||
LoadOwnerChannels();
|
LoadOwnerChannels();
|
||||||
|
|
||||||
if (!ownerChannels.Any())
|
if (!ownerChannels.Any())
|
||||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||||
else
|
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.MessageReceived += MessageReceivedHandler;
|
||||||
_client.MessageUpdated += (oldmsg, newMsg, channel) =>
|
_client.MessageUpdated += (oldmsg, newMsg, channel) =>
|
||||||
{
|
{
|
||||||
var ignore = Task.Run(async () =>
|
var ignore = Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var usrMsg = newMsg as SocketUserMessage;
|
var usrMsg = newMsg as SocketUserMessage;
|
||||||
var guild = (usrMsg?.Channel as ITextChannel)?.Guild;
|
var guild = (usrMsg?.Channel as ITextChannel)?.Guild;
|
||||||
|
////todo invite filtering
|
||||||
if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
//if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||||
await WordFiltered(guild, usrMsg).ConfigureAwait(false);
|
// await WordFiltered(guild, usrMsg).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -124,7 +128,7 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
private void LoadOwnerChannels()
|
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>>();
|
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
||||||
|
|
||||||
foreach (var s in _client.Shards)
|
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)
|
.Select(x => x.Value)
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
}
|
}
|
||||||
private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild)
|
////todo cleverbot
|
||||||
{
|
//private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild)
|
||||||
if (guild == null)
|
//{
|
||||||
return false;
|
// if (guild == null)
|
||||||
try
|
// return false;
|
||||||
{
|
// try
|
||||||
var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out Games.ChatterBotSession cbs);
|
// {
|
||||||
if (message == null || cbs == null)
|
// var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out Games.ChatterBotSession cbs);
|
||||||
return false;
|
// if (message == null || cbs == null)
|
||||||
|
// return false;
|
||||||
|
|
||||||
PermissionCache pc = Permissions.GetCache(guild.Id);
|
// PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||||
if (!pc.Permissions.CheckPermissions(usrMsg,
|
// if (!pc.Permissions.CheckPermissions(usrMsg,
|
||||||
NadekoBot.ModulePrefixes[typeof(Games).Name] + "cleverbot",
|
// NadekoBot.Prefix + "cleverbot",
|
||||||
typeof(Games).Name,
|
// typeof(Games).Name,
|
||||||
out int index))
|
// out int index))
|
||||||
{
|
// {
|
||||||
//todo print in guild actually
|
// //todo print in guild actually
|
||||||
var returnMsg =
|
// var returnMsg =
|
||||||
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||||
_log.Info(returnMsg);
|
// _log.Info(returnMsg);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
|
// var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
|
||||||
if (cleverbotExecuted)
|
// if (cleverbotExecuted)
|
||||||
{
|
// {
|
||||||
_log.Info($@"CleverBot Executed
|
// _log.Info($@"CleverBot Executed
|
||||||
Server: {guild.Name} [{guild.Id}]
|
//Server: {guild.Name} [{guild.Id}]
|
||||||
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
//Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||||
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
//UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||||
Message: {usrMsg.Content}");
|
//Message: {usrMsg.Content}");
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
// catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||||
return false;
|
// return false;
|
||||||
}
|
//}
|
||||||
|
////todo blacklisting
|
||||||
private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) =>
|
//private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) =>
|
||||||
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
// (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
// BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
// BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||||
|
|
||||||
private const float _oneThousandth = 1.0f / 1000;
|
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" +
|
"User: {0}\n\t" +
|
||||||
"Server: {1}\n\t" +
|
"Server: {1}\n\t" +
|
||||||
"Channel: {2}\n\t" +
|
"Channel: {2}\n\t" +
|
||||||
@ -206,18 +212,14 @@ namespace NadekoBot.Services
|
|||||||
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
|
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
|
||||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||||
usrMsg.Content, // {3}
|
usrMsg.Content // {3}
|
||||||
exec1 * _oneThousandth, // {4}
|
|
||||||
exec2 * _oneThousandth, // {5}
|
|
||||||
exec3 * _oneThousandth, // {6}
|
|
||||||
total * _oneThousandth // {7}
|
|
||||||
);
|
);
|
||||||
return Task.CompletedTask;
|
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" +
|
"User: {0}\n\t" +
|
||||||
"Server: {1}\n\t" +
|
"Server: {1}\n\t" +
|
||||||
"Channel: {2}\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.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||||
usrMsg.Content,// {3}
|
usrMsg.Content,// {3}
|
||||||
exec.Result.ErrorReason, // {4}
|
exec.Result.ErrorReason // {4}
|
||||||
exec1 * _oneThousandth, // {5}
|
|
||||||
exec2 * _oneThousandth, // {6}
|
|
||||||
exec3 * _oneThousandth, // {7}
|
|
||||||
total * _oneThousandth // {8}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
////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)
|
////todo word filtering
|
||||||
{
|
//private async Task<bool> WordFiltered(IGuild guild, IUserMessage usrMsg)
|
||||||
if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
|
//{
|
||||||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
|
// var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
|
||||||
usrMsg.Content.IsDiscordInvite())
|
// var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
|
||||||
{
|
// var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||||
try
|
// if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||||
{
|
// {
|
||||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
// foreach (var word in wordsInMessage)
|
||||||
return true;
|
// {
|
||||||
}
|
// if (filteredChannelWords.Contains(word) ||
|
||||||
catch (HttpException ex)
|
// filteredServerWords.Contains(word))
|
||||||
{
|
// {
|
||||||
_log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
// try
|
||||||
return true;
|
// {
|
||||||
}
|
// await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||||
}
|
// }
|
||||||
return false;
|
// catch (HttpException ex)
|
||||||
}
|
// {
|
||||||
|
// _log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||||
private async Task<bool> WordFiltered(IGuild guild, IUserMessage usrMsg)
|
// }
|
||||||
{
|
// return true;
|
||||||
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)
|
// return false;
|
||||||
{
|
//}
|
||||||
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)
|
private Task MessageReceivedHandler(SocketMessage msg)
|
||||||
{
|
{
|
||||||
@ -288,7 +287,7 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
try
|
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;
|
return;
|
||||||
|
|
||||||
var usrMsg = msg as SocketUserMessage;
|
var usrMsg = msg as SocketUserMessage;
|
||||||
@ -325,140 +324,144 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
var execTime = Environment.TickCount;
|
var execTime = Environment.TickCount;
|
||||||
|
|
||||||
if (guild != null && guild.OwnerId != usrMsg.Author.Id)
|
////todo word and invite filtering
|
||||||
{
|
//if (guild != null && guild.OwnerId != usrMsg.Author.Id)
|
||||||
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
//{
|
||||||
return;
|
// if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||||
|
// return;
|
||||||
|
|
||||||
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
// if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (IsBlacklisted(guild, usrMsg))
|
////todo blacklisting
|
||||||
return;
|
//if (IsBlacklisted(guild, usrMsg))
|
||||||
|
// return;
|
||||||
var exec1 = Environment.TickCount - execTime;
|
|
||||||
|
|
||||||
|
//var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
|
||||||
var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false);
|
//if (cleverBotRan)
|
||||||
if (cleverBotRan)
|
// return;
|
||||||
return;
|
|
||||||
|
|
||||||
var exec2 = Environment.TickCount - execTime;
|
var exec2 = Environment.TickCount - execTime;
|
||||||
|
|
||||||
// maybe this message is a custom reaction
|
////todo custom reactions
|
||||||
// todo log custom reaction executions. return struct with info
|
//// maybe this message is a custom reaction
|
||||||
var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
|
//// todo log custom reaction executions. return struct with info
|
||||||
if (cr != null) //if it was, don't execute the command
|
//var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
|
||||||
{
|
//if (cr != null) //if it was, don't execute the command
|
||||||
try
|
//{
|
||||||
{
|
// try
|
||||||
if (guild != null)
|
// {
|
||||||
{
|
// if (guild != null)
|
||||||
PermissionCache pc = Permissions.GetCache(guild.Id);
|
// {
|
||||||
|
// PermissionCache pc = Permissions.GetCache(guild.Id);
|
||||||
|
|
||||||
if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
|
// if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
|
||||||
out int index))
|
// out int index))
|
||||||
{
|
// {
|
||||||
//todo print in guild actually
|
// //todo print in guild actually
|
||||||
var returnMsg =
|
// var returnMsg =
|
||||||
$"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
|
||||||
_log.Info(returnMsg);
|
// _log.Info(returnMsg);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
await cr.Send(usrMsg).ConfigureAwait(false);
|
// await cr.Send(usrMsg).ConfigureAwait(false);
|
||||||
|
|
||||||
if (cr.AutoDeleteTrigger)
|
// if (cr.AutoDeleteTrigger)
|
||||||
{
|
// {
|
||||||
try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
// try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
_log.Warn("Sending CREmbed failed");
|
// _log.Warn("Sending CREmbed failed");
|
||||||
_log.Warn(ex);
|
// _log.Warn(ex);
|
||||||
}
|
// }
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
var exec3 = Environment.TickCount - execTime;
|
var exec3 = Environment.TickCount - execTime;
|
||||||
|
|
||||||
string messageContent = usrMsg.Content;
|
string messageContent = usrMsg.Content;
|
||||||
if (guild != null)
|
////todo alias mapping
|
||||||
{
|
// if (guild != null)
|
||||||
if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
|
// {
|
||||||
{
|
// if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
|
||||||
|
// {
|
||||||
|
|
||||||
var keys = maps.Keys
|
// var keys = maps.Keys
|
||||||
.OrderByDescending(x => x.Length);
|
// .OrderByDescending(x => x.Length);
|
||||||
|
|
||||||
var lowerMessageContent = messageContent.ToLowerInvariant();
|
// var lowerMessageContent = messageContent.ToLowerInvariant();
|
||||||
foreach (var k in keys)
|
// foreach (var k in keys)
|
||||||
{
|
// {
|
||||||
string newMessageContent;
|
// string newMessageContent;
|
||||||
if (lowerMessageContent.StartsWith(k + " "))
|
// if (lowerMessageContent.StartsWith(k + " "))
|
||||||
newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length);
|
// newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length);
|
||||||
else if (lowerMessageContent == k)
|
// else if (lowerMessageContent == k)
|
||||||
newMessageContent = maps[k];
|
// newMessageContent = maps[k];
|
||||||
else
|
// else
|
||||||
continue;
|
// continue;
|
||||||
|
|
||||||
_log.Info(@"--Mapping Command--
|
// _log.Info(@"--Mapping Command--
|
||||||
GuildId: {0}
|
//GuildId: {0}
|
||||||
Trigger: {1}
|
//Trigger: {1}
|
||||||
Mapping: {2}", guild.Id, messageContent, newMessageContent);
|
//Mapping: {2}", guild.Id, messageContent, newMessageContent);
|
||||||
var oldMessageContent = messageContent;
|
// var oldMessageContent = messageContent;
|
||||||
messageContent = newMessageContent;
|
// messageContent = newMessageContent;
|
||||||
|
|
||||||
try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
|
// try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
// execute the command and measure the time it took
|
// 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))
|
||||||
execTime = Environment.TickCount - execTime;
|
{
|
||||||
|
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)
|
if (exec.Result.IsSuccess)
|
||||||
{
|
|
||||||
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
|
||||||
await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
|
||||||
{
|
|
||||||
LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime);
|
|
||||||
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
|
|
||||||
{
|
{
|
||||||
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
|
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
||||||
try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
|
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, 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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
// rofl, gotta do this to prevent dm help message being sent to
|
if (int.TryParse(usrMsg.Content, out int vote)) return;
|
||||||
// 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)
|
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||||
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling);
|
=> 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);
|
var searchResult = _commandService.Search(context, input);
|
||||||
if (!searchResult.IsSuccess)
|
if (!searchResult.IsSuccess)
|
||||||
return new ExecuteCommandResult(null, null, searchResult);
|
return new ExecuteCommandResult(null, null, searchResult);
|
||||||
@ -505,50 +508,55 @@ namespace NadekoBot.Services
|
|||||||
var module = cmd.Module.GetTopLevelModule();
|
var module = cmd.Module.GetTopLevelModule();
|
||||||
if (context.Guild != null)
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
////todo perms
|
||||||
if (module.Name == typeof(Permissions).Name)
|
//PermissionCache pc = Permissions.GetCache(context.Guild.Id);
|
||||||
{
|
//if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out int index))
|
||||||
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)
|
|
||||||
//{
|
//{
|
||||||
// var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
|
// var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)context.Guild)}** is preventing this action.";
|
||||||
// if (!success)
|
// 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" &&
|
////todo perms
|
||||||
(GlobalPermissionCommands.BlockedCommands.Contains(cmd.Aliases.First().ToLowerInvariant()) ||
|
//if (cmd.Name != "resetglobalperms" &&
|
||||||
GlobalPermissionCommands.BlockedModules.Contains(module.Name.ToLowerInvariant())))
|
// (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."));
|
//{
|
||||||
}
|
// 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
|
// Bot will ignore commands which are ran more often than what specified by
|
||||||
// GlobalCommandsCooldown constant (miliseconds)
|
// GlobalCommandsCooldown constant (miliseconds)
|
||||||
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
|
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
|
||||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."));
|
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."));
|
||||||
|
|
||||||
if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
|
////todo cmdcds
|
||||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "That command is on a cooldown for you."));
|
//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."));
|
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 System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Gambling;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
|
|
||||||
namespace NadekoBot.Services
|
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);
|
var success = await RemoveCurrencyAsync(author.Id, reason, amount);
|
||||||
|
|
||||||
if (success && sendMessage)
|
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;
|
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)
|
if (amount < 0)
|
||||||
throw new ArgumentNullException(nameof(amount));
|
throw new ArgumentNullException(nameof(amount));
|
||||||
@ -28,7 +36,7 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
if (uow == null)
|
if (uow == null)
|
||||||
{
|
{
|
||||||
using (uow = DbHandler.UnitOfWork())
|
using (uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow);
|
var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
@ -39,7 +47,7 @@ namespace NadekoBot.Services
|
|||||||
return InternalRemoveCurrency(authorId, reason, amount, uow);
|
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);
|
var success = uow.Currency.TryUpdateState(authorId, -amount);
|
||||||
if (!success)
|
if (!success)
|
||||||
@ -53,15 +61,15 @@ namespace NadekoBot.Services
|
|||||||
return true;
|
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);
|
await AddCurrencyAsync(author.Id, reason, amount);
|
||||||
|
|
||||||
if (sendMessage)
|
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)
|
if (amount < 0)
|
||||||
throw new ArgumentNullException(nameof(amount));
|
throw new ArgumentNullException(nameof(amount));
|
||||||
@ -74,7 +82,7 @@ namespace NadekoBot.Services
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (uow == null)
|
if (uow == null)
|
||||||
using (uow = DbHandler.UnitOfWork())
|
using (uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.Currency.TryUpdateState(receiverId, amount);
|
uow.Currency.TryUpdateState(receiverId, amount);
|
||||||
uow.CurrencyTransactions.Add(transaction);
|
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
|
public class PlaylistSong : DbEntity
|
||||||
{
|
{
|
||||||
@ -10,4 +8,12 @@ namespace NadekoBot.Services.Database.Models
|
|||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum MusicType
|
||||||
|
{
|
||||||
|
Radio,
|
||||||
|
Normal,
|
||||||
|
Local,
|
||||||
|
Soundcloud
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,19 +7,17 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
public class DbHandler
|
public class DbHandler
|
||||||
{
|
{
|
||||||
private static DbHandler _instance = null;
|
|
||||||
public static DbHandler Instance = _instance ?? (_instance = new DbHandler());
|
|
||||||
private readonly DbContextOptions options;
|
private readonly DbContextOptions options;
|
||||||
|
|
||||||
private string connectionString { get; }
|
private string connectionString { get; }
|
||||||
|
|
||||||
static DbHandler() { }
|
static DbHandler() { }
|
||||||
|
|
||||||
private DbHandler()
|
public DbHandler(IBotCredentials creds)
|
||||||
{
|
{
|
||||||
connectionString = NadekoBot.Credentials.Db.ConnectionString;
|
connectionString = creds.Db.ConnectionString;
|
||||||
var optionsBuilder = new DbContextOptionsBuilder();
|
var optionsBuilder = new DbContextOptionsBuilder();
|
||||||
optionsBuilder.UseSqlite(NadekoBot.Credentials.Db.ConnectionString);
|
optionsBuilder.UseSqlite(creds.Db.ConnectionString);
|
||||||
options = optionsBuilder.Options;
|
options = optionsBuilder.Options;
|
||||||
//switch (NadekoBot.Credentials.Db.Type.ToUpperInvariant())
|
//switch (NadekoBot.Credentials.Db.Type.ToUpperInvariant())
|
||||||
//{
|
//{
|
||||||
@ -44,10 +42,7 @@ namespace NadekoBot.Services
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IUnitOfWork GetUnitOfWork() =>
|
public IUnitOfWork UnitOfWork =>
|
||||||
new UnitOfWork(GetDbContext());
|
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<SocketReaction> OnReactionRemoved = delegate { };
|
||||||
public event Action OnReactionsCleared = delegate { };
|
public event Action OnReactionsCleared = delegate { };
|
||||||
|
|
||||||
public ReactionEventWrapper(IUserMessage msg)
|
public ReactionEventWrapper(DiscordShardedClient client, IUserMessage msg)
|
||||||
{
|
{
|
||||||
Message = msg ?? throw new ArgumentNullException(nameof(msg));
|
Message = msg ?? throw new ArgumentNullException(nameof(msg));
|
||||||
|
_client = client;
|
||||||
|
|
||||||
NadekoBot.Client.ReactionAdded += Discord_ReactionAdded;
|
_client.ReactionAdded += Discord_ReactionAdded;
|
||||||
NadekoBot.Client.ReactionRemoved += Discord_ReactionRemoved;
|
_client.ReactionRemoved += Discord_ReactionRemoved;
|
||||||
NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared;
|
_client.ReactionsCleared += Discord_ReactionsCleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
|
private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
|
||||||
@ -62,15 +63,17 @@ namespace NadekoBot.Services.Discord
|
|||||||
|
|
||||||
public void UnsubAll()
|
public void UnsubAll()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.ReactionAdded -= Discord_ReactionAdded;
|
_client.ReactionAdded -= Discord_ReactionAdded;
|
||||||
NadekoBot.Client.ReactionRemoved -= Discord_ReactionRemoved;
|
_client.ReactionRemoved -= Discord_ReactionRemoved;
|
||||||
NadekoBot.Client.ReactionsCleared -= Discord_ReactionsCleared;
|
_client.ReactionsCleared -= Discord_ReactionsCleared;
|
||||||
OnReactionAdded = null;
|
OnReactionAdded = null;
|
||||||
OnReactionRemoved = null;
|
OnReactionRemoved = null;
|
||||||
OnReactionsCleared = null;
|
OnReactionsCleared = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool disposing = false;
|
private bool disposing = false;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
|
@ -12,11 +12,14 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
public class GreetSettingsService
|
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)
|
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||||
@ -27,7 +30,7 @@ namespace NadekoBot.Services
|
|||||||
if (settings != null)
|
if (settings != null)
|
||||||
return settings;
|
return settings;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||||
settings = GreetSettings.Create(gc);
|
settings = GreetSettings.Create(gc);
|
||||||
@ -47,7 +50,7 @@ namespace NadekoBot.Services
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
conf.DmGreetMessageText = settings.DmGreetMessageText?.SanitizeMentions();
|
conf.DmGreetMessageText = settings.DmGreetMessageText?.SanitizeMentions();
|
||||||
@ -78,7 +81,7 @@ namespace NadekoBot.Services
|
|||||||
public async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
|
public async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
|
||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
|
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
|
||||||
@ -100,7 +103,7 @@ namespace NadekoBot.Services
|
|||||||
throw new ArgumentNullException(nameof(message));
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
|
||||||
bool greetMsgEnabled;
|
bool greetMsgEnabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
conf.ChannelGreetMessageText = message;
|
conf.ChannelGreetMessageText = message;
|
||||||
@ -117,7 +120,7 @@ namespace NadekoBot.Services
|
|||||||
public async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
|
public async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
|
||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
||||||
@ -138,7 +141,7 @@ namespace NadekoBot.Services
|
|||||||
throw new ArgumentNullException(nameof(message));
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
|
||||||
bool greetMsgEnabled;
|
bool greetMsgEnabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId);
|
var conf = uow.GuildConfigs.For(guildId);
|
||||||
conf.DmGreetMessageText = message;
|
conf.DmGreetMessageText = message;
|
||||||
@ -155,7 +158,7 @@ namespace NadekoBot.Services
|
|||||||
public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
|
public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
|
||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
|
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
|
||||||
@ -177,7 +180,7 @@ namespace NadekoBot.Services
|
|||||||
throw new ArgumentNullException(nameof(message));
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
|
||||||
bool byeMsgEnabled;
|
bool byeMsgEnabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
conf.ChannelByeMessageText = message;
|
conf.ChannelByeMessageText = message;
|
||||||
@ -196,7 +199,7 @@ namespace NadekoBot.Services
|
|||||||
if (timer < 0 || timer > 600)
|
if (timer < 0 || timer > 600)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||||
conf.AutoDeleteByeMessagesTimer = timer;
|
conf.AutoDeleteByeMessagesTimer = timer;
|
||||||
|
@ -14,8 +14,10 @@ namespace NadekoBot.Services
|
|||||||
string MashapeKey { get; }
|
string MashapeKey { get; }
|
||||||
string LoLApiKey { get; }
|
string LoLApiKey { get; }
|
||||||
string PatreonAccessToken { get; }
|
string PatreonAccessToken { get; }
|
||||||
|
string CarbonKey { get; }
|
||||||
|
|
||||||
DBConfig Db { get; }
|
DBConfig Db { get; }
|
||||||
|
string SoundCloudClientId { get; set; }
|
||||||
|
|
||||||
bool IsOwner(IUser u);
|
bool IsOwner(IUser u);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,6 @@ namespace NadekoBot.Services
|
|||||||
ImmutableArray<byte> WifeMatrix { get; }
|
ImmutableArray<byte> WifeMatrix { get; }
|
||||||
ImmutableArray<byte> RategirlDot { 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
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
public interface IStatsService
|
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();
|
Task<string> Print();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,14 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
private Logger _log { get; }
|
private Logger _log { get; }
|
||||||
|
|
||||||
public GoogleApiService()
|
public GoogleApiService(IBotCredentials creds)
|
||||||
{
|
{
|
||||||
|
_creds = creds;
|
||||||
|
|
||||||
var bcs = new BaseClientService.Initializer
|
var bcs = new BaseClientService.Initializer
|
||||||
{
|
{
|
||||||
ApplicationName = "Nadeko Bot",
|
ApplicationName = "Nadeko Bot",
|
||||||
ApiKey = NadekoBot.Credentials.GoogleApiKey,
|
ApiKey = _creds.GoogleApiKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_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 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)
|
public async Task<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1)
|
||||||
{
|
{
|
||||||
@ -110,7 +113,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
if (string.IsNullOrWhiteSpace(url))
|
if (string.IsNullOrWhiteSpace(url))
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.GoogleApiKey))
|
if (string.IsNullOrWhiteSpace(_creds.GoogleApiKey))
|
||||||
return url;
|
return url;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -44,19 +44,13 @@ namespace NadekoBot.Services.Impl
|
|||||||
public ImmutableArray<byte> WifeMatrix { get; private set; }
|
public ImmutableArray<byte> WifeMatrix { get; private set; }
|
||||||
public ImmutableArray<byte> RategirlDot { get; private set; }
|
public ImmutableArray<byte> RategirlDot { get; private set; }
|
||||||
|
|
||||||
private ImagesService()
|
public ImagesService()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
this.Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IImagesService> Create()
|
public TimeSpan Reload()
|
||||||
{
|
|
||||||
var srvc = new ImagesService();
|
|
||||||
await srvc.Reload().ConfigureAwait(false);
|
|
||||||
return srvc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TimeSpan> Reload() => Task.Run(() =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -101,6 +95,6 @@ namespace NadekoBot.Services.Impl
|
|||||||
_log.Error(ex);
|
_log.Error(ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,17 +12,19 @@ using NLog;
|
|||||||
|
|
||||||
namespace NadekoBot.Services
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
public class Localization
|
public class Localization : ILocalization
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
||||||
public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture;
|
public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture;
|
||||||
|
|
||||||
private Localization() { }
|
private Localization() { }
|
||||||
public Localization(string defaultCulture, IDictionary<ulong, string> cultureInfoNames)
|
public Localization(string defaultCulture, IDictionary<ulong, string> cultureInfoNames, DbHandler db)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_db = db;
|
||||||
if (string.IsNullOrWhiteSpace(defaultCulture))
|
if (string.IsNullOrWhiteSpace(defaultCulture))
|
||||||
DefaultCultureInfo = new CultureInfo("en-US");
|
DefaultCultureInfo = new CultureInfo("en-US");
|
||||||
else
|
else
|
||||||
@ -62,7 +64,7 @@ namespace NadekoBot.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||||
gc.Locale = ci.Name;
|
gc.Locale = ci.Name;
|
||||||
@ -80,7 +82,7 @@ namespace NadekoBot.Services
|
|||||||
CultureInfo throwaway;
|
CultureInfo throwaway;
|
||||||
if (GuildCultureInfos.TryRemove(guildId, out 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);
|
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||||
gc.Locale = null;
|
gc.Locale = null;
|
||||||
@ -91,7 +93,7 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
public void SetDefaultCulture(CultureInfo ci)
|
public void SetDefaultCulture(CultureInfo ci)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var bc = uow.BotConfig.GetOrCreate();
|
var bc = uow.BotConfig.GetOrCreate();
|
||||||
bc.Locale = ci.Name;
|
bc.Locale = ci.Name;
|
||||||
|
@ -6,6 +6,7 @@ using System.Xml.Linq;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NadekoBot.Services
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
@ -15,6 +16,10 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
private readonly ImmutableDictionary<string, ImmutableDictionary<string, string>> responseStrings;
|
private readonly ImmutableDictionary<string, ImmutableDictionary<string, string>> responseStrings;
|
||||||
private readonly Logger _log;
|
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()
|
public NadekoStrings()
|
||||||
{
|
{
|
||||||
@ -44,7 +49,7 @@ namespace NadekoBot.Services
|
|||||||
return fileName.Substring(dotIndex, secondDotINdex - dotIndex);
|
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))
|
if (!responseStrings.TryGetValue(cultureInfo.Name.ToLowerInvariant(), out ImmutableDictionary<string, string> strings))
|
||||||
return null;
|
return null;
|
||||||
@ -52,5 +57,34 @@ namespace NadekoBot.Services
|
|||||||
strings.TryGetValue(text, out string val);
|
strings.TryGetValue(text, out string val);
|
||||||
return 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
|
public class StatsService : IStatsService
|
||||||
{
|
{
|
||||||
private readonly DiscordShardedClient _client;
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly IBotCredentials _creds;
|
||||||
private readonly DateTime _started;
|
private readonly DateTime _started;
|
||||||
|
|
||||||
public const string BotVersion = "1.4";
|
public const string BotVersion = "1.4";
|
||||||
@ -36,10 +37,10 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
private readonly Timer _carbonitexTimer;
|
private readonly Timer _carbonitexTimer;
|
||||||
|
|
||||||
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler)
|
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler, IBotCredentials creds)
|
||||||
{
|
{
|
||||||
|
|
||||||
_client = client;
|
_client = client;
|
||||||
|
_creds = creds;
|
||||||
|
|
||||||
_started = DateTime.Now;
|
_started = DateTime.Now;
|
||||||
_client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter));
|
_client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter));
|
||||||
@ -117,7 +118,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
_carbonitexTimer = new Timer(async (state) =>
|
_carbonitexTimer = new Timer(async (state) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
if (string.IsNullOrWhiteSpace(_creds.CarbonKey))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -126,7 +127,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
using (var content = new FormUrlEncodedContent(
|
using (var content = new FormUrlEncodedContent(
|
||||||
new Dictionary<string, string> {
|
new Dictionary<string, string> {
|
||||||
{ "servercount", _client.Guilds.Count.ToString() },
|
{ "servercount", _client.Guilds.Count.ToString() },
|
||||||
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
{ "key", _creds.CarbonKey }}))
|
||||||
{
|
{
|
||||||
content.Headers.Clear();
|
content.Headers.Clear();
|
||||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||||
@ -158,7 +159,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
Author: [{Author}] | Library: [{Library}]
|
Author: [{Author}] | Library: [{Library}]
|
||||||
Bot Version: [{BotVersion}]
|
Bot Version: [{BotVersion}]
|
||||||
Bot ID: {curUser.Id}
|
Bot ID: {curUser.Id}
|
||||||
Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
|
Owner ID(s): {string.Join(", ", _creds.OwnerIds)}
|
||||||
Uptime: {GetUptimeString()}
|
Uptime: {GetUptimeString()}
|
||||||
Servers: {_client.Guilds.Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
Servers: {_client.Guilds.Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||||
Commands Ran this session: {CommandsRan}
|
Commands Ran this session: {CommandsRan}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
class PlaylistFullException : Exception
|
class PlaylistFullException : Exception
|
||||||
{
|
{
|
@ -8,16 +8,11 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
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
|
public enum StreamState
|
||||||
{
|
{
|
||||||
@ -29,6 +24,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
public class MusicPlayer
|
public class MusicPlayer
|
||||||
{
|
{
|
||||||
|
public const string MusicDataPath = "data/musicdata";
|
||||||
private IAudioClient AudioClient { get; set; }
|
private IAudioClient AudioClient { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -58,6 +54,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
private readonly List<Song> _playlist = new List<Song>();
|
private readonly List<Song> _playlist = new List<Song>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly IGoogleApiService _google;
|
||||||
|
|
||||||
public IReadOnlyCollection<Song> Playlist => _playlist;
|
public IReadOnlyCollection<Song> Playlist => _playlist;
|
||||||
|
|
||||||
@ -88,9 +85,10 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
public event Action<Song, int> SongRemoved = delegate { };
|
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();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_google = google;
|
||||||
|
|
||||||
OutputTextChannel = outputChannel;
|
OutputTextChannel = outputChannel;
|
||||||
Volume = defaultVolume ?? 1.0f;
|
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))
|
var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3))
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids);
|
var durations = await _google.GetVideoDurationsAsync(ids);
|
||||||
|
|
||||||
toUpdate.ForEach(s =>
|
toUpdate.ForEach(s =>
|
||||||
{
|
{
|
||||||
@ -337,7 +335,6 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
|
@ -1,24 +1,28 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Modules.Music.Classes;
|
|
||||||
using Discord;
|
using Discord;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules;
|
using NadekoBot.Modules;
|
||||||
|
using NadekoBot.Services.Impl;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Music
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
public class MusicService
|
public class MusicService
|
||||||
{
|
{
|
||||||
private readonly IGoogleApiService _google;
|
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 ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
||||||
|
|
||||||
public MusicService(IGoogleApiService google)
|
public MusicService(IGoogleApiService google, NadekoStrings strings, ILocalization localization)
|
||||||
{
|
{
|
||||||
_google = google;
|
_google = google;
|
||||||
|
_strings = strings;
|
||||||
|
_localization = localization;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MusicPlayer GetPlayer(ulong guildId)
|
public MusicPlayer GetPlayer(ulong guildId)
|
||||||
@ -30,7 +34,7 @@ namespace NadekoBot.Services.Music
|
|||||||
public MusicPlayer GetOrCreatePlayer(ulong guildId, IVoiceChannel voiceCh, ITextChannel textCh)
|
public MusicPlayer GetOrCreatePlayer(ulong guildId, IVoiceChannel voiceCh, ITextChannel textCh)
|
||||||
{
|
{
|
||||||
string GetText(string text, params object[] replacements) =>
|
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 =>
|
return MusicPlayers.GetOrAdd(guildId, server =>
|
||||||
{
|
{
|
||||||
@ -40,7 +44,7 @@ namespace NadekoBot.Services.Music
|
|||||||
//todo move to cached variable
|
//todo move to cached variable
|
||||||
vol = uow.GuildConfigs.For(guildId, set => set).DefaultMusicVolume;
|
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 playingMessage = null;
|
||||||
IUserMessage lastFinishedMessage = null;
|
IUserMessage lastFinishedMessage = null;
|
||||||
mp.OnCompleted += async (s, song) =>
|
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)
|
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)
|
if (relatedVideos.Count > 0)
|
||||||
await QueueSong(await textCh.Guild.GetCurrentUserAsync(),
|
await QueueSong(await textCh.Guild.GetCurrentUserAsync(),
|
||||||
textCh,
|
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)
|
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) =>
|
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)
|
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
||||||
{
|
{
|
||||||
|
@ -9,8 +9,9 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
public class SongInfo
|
public class SongInfo
|
||||||
{
|
{
|
||||||
@ -29,7 +30,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
private string _queuerName;
|
private string _queuerName;
|
||||||
public string QueuerName { get{
|
public string QueuerName { get{
|
||||||
return Discord.Format.Sanitize(_queuerName);
|
return Format.Sanitize(_queuerName);
|
||||||
} set { _queuerName = value; } }
|
} set { _queuerName = value; } }
|
||||||
|
|
||||||
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
||||||
@ -143,7 +144,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
BytesSent = (ulong) SkipTo * 3840 * 50;
|
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 inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
|
||||||
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
@ -6,7 +6,7 @@ using System.IO;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a buffer for a song file. It will create multiples files to ensure, that radio don't fill up disk space.
|
/// 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;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
using VideoLibrary;
|
using VideoLibrary;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
public static class SongHandler
|
public static class SongHandler
|
||||||
{
|
{
|
||||||
@ -49,6 +47,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
})
|
})
|
||||||
{ TotalTime = TimeSpan.MaxValue };
|
{ TotalTime = TimeSpan.MaxValue };
|
||||||
}
|
}
|
||||||
|
var sc = SoundCloud.GetInstance(_creds);
|
||||||
if (SoundCloud.Default.IsSoundCloudLink(query))
|
if (SoundCloud.Default.IsSoundCloudLink(query))
|
||||||
{
|
{
|
||||||
var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false);
|
var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false);
|
@ -4,28 +4,34 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Services.Music
|
||||||
{
|
{
|
||||||
public class SoundCloud
|
public class SoundCloud
|
||||||
{
|
{
|
||||||
private static readonly SoundCloud _instance = new SoundCloud();
|
private readonly IBotCredentials _creds;
|
||||||
public static SoundCloud Default => _instance;
|
|
||||||
|
//todo make a service
|
||||||
|
private static SoundCloud _instance = null;
|
||||||
|
public static SoundCloud GetInstance(IBotCredentials creds) => _instance ?? (_instance = new SoundCloud(creds));
|
||||||
|
|
||||||
static SoundCloud() { }
|
static SoundCloud() { }
|
||||||
public SoundCloud() { }
|
public SoundCloud(IBotCredentials creds)
|
||||||
|
{
|
||||||
|
_creds = creds;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<SoundCloudVideo> ResolveVideoAsync(string url)
|
public async Task<SoundCloudVideo> ResolveVideoAsync(string url)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(url))
|
if (string.IsNullOrWhiteSpace(url))
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
|
if (string.IsNullOrWhiteSpace(_creds.SoundCloudClientId))
|
||||||
throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
|
throw new ArgumentNullException(nameof(_creds.SoundCloudClientId));
|
||||||
|
|
||||||
string response = "";
|
string response = "";
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
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))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
throw new ArgumentNullException(nameof(query));
|
throw new ArgumentNullException(nameof(query));
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.SoundCloudClientId))
|
if (string.IsNullOrWhiteSpace(_creds.SoundCloudClientId))
|
||||||
throw new ArgumentNullException(nameof(NadekoBot.Credentials.SoundCloudClientId));
|
throw new ArgumentNullException(nameof(_creds.SoundCloudClientId));
|
||||||
|
|
||||||
var response = "";
|
var response = "";
|
||||||
using (var http = new HttpClient())
|
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();
|
var responseObj = JsonConvert.DeserializeObject<SoundCloudVideo[]>(response).Where(s => s.Streamable).FirstOrDefault();
|
||||||
@ -74,8 +80,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
[JsonProperty("permalink_url")]
|
[JsonProperty("permalink_url")]
|
||||||
public string TrackLink { get; set; } = "";
|
public string TrackLink { get; set; } = "";
|
||||||
public string artwork_url { get; set; } = "";
|
public string artwork_url { get; set; } = "";
|
||||||
[JsonIgnore]
|
public string GetStreamLink(IBotCredentials creds) => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={creds.SoundCloudClientId}";
|
||||||
public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Credentials.SoundCloudClientId}";
|
|
||||||
}
|
}
|
||||||
public class SoundCloudUser
|
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
|
public static class Extensions
|
||||||
{
|
{
|
||||||
private const string arrow_left = "⬅";
|
private static readonly IEmote arrow_left = Emote.Parse("⬅");
|
||||||
private const string arrow_right = "➡";
|
private static readonly IEmote arrow_right = Emote.Parse("➡");
|
||||||
|
|
||||||
public static string ToBase64(this string plainText)
|
public static string ToBase64(this string plainText)
|
||||||
{
|
{
|
||||||
@ -27,8 +27,8 @@ namespace NadekoBot.Extensions
|
|||||||
return Convert.ToBase64String(plainTextBytes);
|
return Convert.ToBase64String(plainTextBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string RealSummary(this CommandInfo cmd) => string.Format(cmd.Summary, 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, cmd.Module.GetTopLevelModule().Prefix);
|
public static string RealRemarks(this CommandInfo cmd) => string.Format(cmd.Remarks, ".");
|
||||||
|
|
||||||
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
||||||
{
|
{
|
||||||
@ -40,7 +40,7 @@ namespace NadekoBot.Extensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// danny kamisama
|
/// danny kamisama
|
||||||
/// </summary>
|
/// </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;
|
lastPage += 1;
|
||||||
var embed = pageFunc(currentPage);
|
var embed = pageFunc(currentPage);
|
||||||
@ -53,7 +53,8 @@ namespace NadekoBot.Extensions
|
|||||||
if (currentPage >= lastPage && lastPage == 1)
|
if (currentPage >= lastPage && lastPage == 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await msg.AddReactionAsync(arrow_left).ConfigureAwait(false);
|
|
||||||
|
await msg.AddReactionAsync( arrow_left).ConfigureAwait(false);
|
||||||
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
|
await msg.AddReactionAsync(arrow_right).ConfigureAwait(false);
|
||||||
|
|
||||||
await Task.Delay(2000).ConfigureAwait(false);
|
await Task.Delay(2000).ConfigureAwait(false);
|
||||||
@ -62,7 +63,7 @@ namespace NadekoBot.Extensions
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (r.Emoji.Name == arrow_left)
|
if (r.Emote.Name == arrow_left.Name)
|
||||||
{
|
{
|
||||||
if (currentPage == 1)
|
if (currentPage == 1)
|
||||||
return;
|
return;
|
||||||
@ -71,7 +72,7 @@ namespace NadekoBot.Extensions
|
|||||||
toSend.AddPaginatedFooter(currentPage, lastPage);
|
toSend.AddPaginatedFooter(currentPage, lastPage);
|
||||||
await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false);
|
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)
|
if (lastPage == null || lastPage > currentPage)
|
||||||
{
|
{
|
||||||
@ -85,7 +86,7 @@ namespace NadekoBot.Extensions
|
|||||||
catch (Exception ex) { Console.WriteLine(ex); }
|
catch (Exception ex) { Console.WriteLine(ex); }
|
||||||
};
|
};
|
||||||
|
|
||||||
using (msg.OnReaction(changePage, changePage))
|
using (msg.OnReaction(client, changePage, changePage))
|
||||||
{
|
{
|
||||||
await Task.Delay(30000).ConfigureAwait(false);
|
await Task.Delay(30000).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -101,12 +102,12 @@ namespace NadekoBot.Extensions
|
|||||||
return embed.WithFooter(efb => efb.WithText(curPage.ToString()));
|
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)
|
if (reactionRemoved == null)
|
||||||
reactionRemoved = delegate { };
|
reactionRemoved = delegate { };
|
||||||
|
|
||||||
var wrap = new ReactionEventWrapper(msg);
|
var wrap = new ReactionEventWrapper(client, msg);
|
||||||
wrap.OnReactionAdded += reactionAdded;
|
wrap.OnReactionAdded += reactionAdded;
|
||||||
wrap.OnReactionRemoved += reactionRemoved;
|
wrap.OnReactionRemoved += reactionRemoved;
|
||||||
return wrap;
|
return wrap;
|
||||||
@ -141,8 +142,6 @@ namespace NadekoBot.Extensions
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPrefix(this ModuleInfo module) => NadekoBot.ModulePrefixes[module.GetTopLevelModule().Name];
|
|
||||||
|
|
||||||
public static ModuleInfo GetTopLevelModule(this ModuleInfo module)
|
public static ModuleInfo GetTopLevelModule(this ModuleInfo module)
|
||||||
{
|
{
|
||||||
while (module.Parent != null)
|
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) =>
|
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);
|
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) =>
|
public static IEnumerable<IUser> Members(this IRole role) =>
|
||||||
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty<IUser>();
|
||||||
|
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
using Discord;
|
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
|
public static class MusicExtensions
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user