Games done, admin half done
This commit is contained in:
parent
3797fbd439
commit
355425bf80
@ -7,82 +7,54 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using Discord.WebSocket;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using static NadekoBot.Modules.Permissions.Permissions;
|
using NadekoBot.Services.Administration;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using NLog;
|
|
||||||
using NadekoBot.Modules.Permissions;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
[NadekoModule("Administration", ".")]
|
|
||||||
public partial class Administration : NadekoTopLevelModule
|
public partial class Administration : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentHashSet<ulong> deleteMessagesOnCommand;
|
private IGuild _nadekoSupportServer;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly AdministrationService _admin;
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
public Administration(DbHandler db, AdministrationService admin)
|
||||||
|
|
||||||
static Administration()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_db = db;
|
||||||
NadekoBot.CommandHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
_admin = admin;
|
||||||
|
|
||||||
deleteMessagesOnCommand = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
////todo permissions
|
||||||
{
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
var _ = Task.Run(async () =>
|
//[RequireContext(ContextType.Guild)]
|
||||||
{
|
//[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
try
|
//public async Task ResetPermissions()
|
||||||
{
|
//{
|
||||||
var channel = msg.Channel as SocketTextChannel;
|
// using (var uow = _db.UnitOfWork)
|
||||||
if (channel == null)
|
// {
|
||||||
return;
|
// var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
|
// config.Permissions = Permissionv2.GetDefaultPermlist;
|
||||||
await msg.DeleteAsync().ConfigureAwait(false);
|
// await uow.CompleteAsync();
|
||||||
}
|
// UpdateCache(config);
|
||||||
catch (Exception ex)
|
// }
|
||||||
{
|
// await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
||||||
_log.Warn(ex, "Delmsgoncmd errored...");
|
//}
|
||||||
}
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
});
|
//[OwnerOnly]
|
||||||
return Task.CompletedTask;
|
//public async Task ResetGlobalPermissions()
|
||||||
}
|
//{
|
||||||
|
// using (var uow = _db.UnitOfWork)
|
||||||
|
// {
|
||||||
|
// var gc = uow.BotConfig.GetOrCreate();
|
||||||
|
// gc.BlockedCommands.Clear();
|
||||||
|
// gc.BlockedModules.Clear();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
// GlobalPermissionCommands.BlockedCommands.Clear();
|
||||||
[RequireContext(ContextType.Guild)]
|
// GlobalPermissionCommands.BlockedModules.Clear();
|
||||||
[RequireUserPermission(GuildPermission.Administrator)]
|
// await uow.CompleteAsync();
|
||||||
public async Task ResetPermissions()
|
// }
|
||||||
{
|
// await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
//}
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
|
||||||
config.Permissions = Permissionv2.GetDefaultPermlist;
|
|
||||||
await uow.CompleteAsync();
|
|
||||||
UpdateCache(config);
|
|
||||||
}
|
|
||||||
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[OwnerOnly]
|
|
||||||
public async Task ResetGlobalPermissions()
|
|
||||||
{
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var gc = uow.BotConfig.GetOrCreate();
|
|
||||||
gc.BlockedCommands.Clear();
|
|
||||||
gc.BlockedModules.Clear();
|
|
||||||
|
|
||||||
GlobalPermissionCommands.BlockedCommands.Clear();
|
|
||||||
GlobalPermissionCommands.BlockedModules.Clear();
|
|
||||||
await uow.CompleteAsync();
|
|
||||||
}
|
|
||||||
await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -91,7 +63,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task Delmsgoncmd()
|
public async Task Delmsgoncmd()
|
||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
enabled = conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand;
|
enabled = conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand;
|
||||||
@ -100,12 +72,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
deleteMessagesOnCommand.Add(Context.Guild.Id);
|
_admin.DeleteMessagesOnCommand.Add(Context.Guild.Id);
|
||||||
await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false);
|
await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
deleteMessagesOnCommand.TryRemove(Context.Guild.Id);
|
_admin.DeleteMessagesOnCommand.TryRemove(Context.Guild.Id);
|
||||||
await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false);
|
await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,19 +426,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await Context.Channel.SendMessageAsync(send).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(send).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IGuild _nadekoSupportServer;
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Donators()
|
public async Task Donators()
|
||||||
{
|
{
|
||||||
IEnumerable<Donator> donatorsOrdered;
|
IEnumerable<Donator> donatorsOrdered;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
|
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync(GetText("donators"), string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("donators"), string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
||||||
|
|
||||||
_nadekoSupportServer = _nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850);
|
_nadekoSupportServer = _nadekoSupportServer ?? (await Context.Client.GetGuildAsync(117523346618318850));
|
||||||
|
|
||||||
var patreonRole = _nadekoSupportServer?.GetRole(236667642088259585);
|
var patreonRole = _nadekoSupportServer?.GetRole(236667642088259585);
|
||||||
if (patreonRole == null)
|
if (patreonRole == null)
|
||||||
@ -482,7 +453,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task Donadd(IUser donator, int amount)
|
public async Task Donadd(IUser donator, int amount)
|
||||||
{
|
{
|
||||||
Donator don;
|
Donator don;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
don = uow.Donators.AddOrUpdateDonator(donator.Id, donator.Username, amount);
|
don = uow.Donators.AddOrUpdateDonator(donator.Id, donator.Username, amount);
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
|
@ -4,6 +4,7 @@ using Discord.WebSocket;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
@ -19,232 +20,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class MuteCommands : NadekoSubmodule
|
public class MuteCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
|
private readonly MuteService _service;
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
|
private readonly DbHandler _db;
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> UnmuteTimers { get; }
|
|
||||||
= new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>>();
|
|
||||||
|
|
||||||
public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
public MuteCommands(MuteService service, DbHandler db)
|
||||||
public static event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
|
||||||
|
|
||||||
|
|
||||||
public enum MuteType {
|
|
||||||
Voice,
|
|
||||||
Chat,
|
|
||||||
All
|
|
||||||
}
|
|
||||||
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
|
||||||
|
|
||||||
private static readonly new Logger _log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
static MuteCommands()
|
|
||||||
{
|
{
|
||||||
var configs = NadekoBot.AllGuildConfigs;
|
_service = service;
|
||||||
GuildMuteRoles = new ConcurrentDictionary<ulong, string>(configs
|
_db = db;
|
||||||
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
|
||||||
.ToDictionary(c => c.GuildId, c => c.MuteRoleName));
|
|
||||||
|
|
||||||
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(configs.ToDictionary(
|
|
||||||
k => k.GuildId,
|
|
||||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
|
||||||
));
|
|
||||||
|
|
||||||
foreach (var conf in configs)
|
|
||||||
{
|
|
||||||
foreach (var x in conf.UnmuteTimers)
|
|
||||||
{
|
|
||||||
TimeSpan after;
|
|
||||||
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
|
|
||||||
{
|
|
||||||
after = TimeSpan.FromMinutes(2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
after = x.UnmuteAt - DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
StartUnmuteTimer(conf.GuildId, x.UserId, after);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NadekoBot.Client.UserJoined += Client_UserJoined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task Client_UserJoined(IGuildUser usr)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted);
|
|
||||||
|
|
||||||
if (muted == null || !muted.Contains(usr.Id))
|
|
||||||
return;
|
|
||||||
await MuteUser(usr).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task MuteUser(IGuildUser usr)
|
|
||||||
{
|
|
||||||
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
|
||||||
var muteRole = await GetMuteRole(usr.Guild);
|
|
||||||
if (!usr.RoleIds.Contains(muteRole.Id))
|
|
||||||
await usr.AddRoleAsync(muteRole).ConfigureAwait(false);
|
|
||||||
StopUnmuteTimer(usr.GuildId, usr.Id);
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.For(usr.Guild.Id,
|
|
||||||
set => set.Include(gc => gc.MutedUsers)
|
|
||||||
.Include(gc => gc.UnmuteTimers));
|
|
||||||
config.MutedUsers.Add(new MutedUserId()
|
|
||||||
{
|
|
||||||
UserId = usr.Id
|
|
||||||
});
|
|
||||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
|
||||||
muted.Add(usr.Id);
|
|
||||||
|
|
||||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
UserMuted(usr, MuteType.All);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task UnmuteUser(IGuildUser usr)
|
|
||||||
{
|
|
||||||
StopUnmuteTimer(usr.GuildId, usr.Id);
|
|
||||||
try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { }
|
|
||||||
try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers)
|
|
||||||
.Include(gc => gc.UnmuteTimers));
|
|
||||||
config.MutedUsers.Remove(new MutedUserId()
|
|
||||||
{
|
|
||||||
UserId = usr.Id
|
|
||||||
});
|
|
||||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
|
||||||
muted.TryRemove(usr.Id);
|
|
||||||
|
|
||||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
UserUnmuted(usr, MuteType.All);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<IRole>GetMuteRole(IGuild guild)
|
|
||||||
{
|
|
||||||
const string defaultMuteRoleName = "nadeko-mute";
|
|
||||||
|
|
||||||
var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
|
|
||||||
|
|
||||||
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
|
|
||||||
if (muteRole == null)
|
|
||||||
{
|
|
||||||
|
|
||||||
//if it doesn't exist, create it
|
|
||||||
try { muteRole = await guild.CreateRoleAsync(muteRoleName, GuildPermissions.None).ConfigureAwait(false); }
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one
|
|
||||||
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ??
|
|
||||||
await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!toOverwrite.PermissionOverwrites.Select(x => x.Permissions).Contains(denyOverwrite))
|
|
||||||
{
|
|
||||||
await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Task.Delay(200).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return muteRole;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task TimedMute(IGuildUser user, TimeSpan after)
|
|
||||||
{
|
|
||||||
await MuteUser(user).ConfigureAwait(false); // mute the user. This will also remove any previous unmute timers
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.For(user.GuildId, set => set.Include(x => x.UnmuteTimers));
|
|
||||||
config.UnmuteTimers.Add(new UnmuteTimer()
|
|
||||||
{
|
|
||||||
UserId = user.Id,
|
|
||||||
UnmuteAt = DateTime.UtcNow + after,
|
|
||||||
}); // add teh unmute timer to the database
|
|
||||||
uow.Complete();
|
|
||||||
}
|
|
||||||
StartUnmuteTimer(user.GuildId, user.Id, after); // start the timer
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void StartUnmuteTimer(ulong guildId, ulong userId, TimeSpan after)
|
|
||||||
{
|
|
||||||
//load the unmute timers for this guild
|
|
||||||
var userUnmuteTimers = UnmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
|
|
||||||
|
|
||||||
//unmute timer to be added
|
|
||||||
var toAdd = new Timer(async _ =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var guild = NadekoBot.Client.GetGuild(guildId); // load the guild
|
|
||||||
if (guild == null)
|
|
||||||
{
|
|
||||||
RemoveUnmuteTimerFromDb(guildId, userId);
|
|
||||||
return; // if guild can't be found, just remove the timer from db
|
|
||||||
}
|
|
||||||
// unmute the user, this will also remove the timer from the db
|
|
||||||
await UnmuteUser(guild.GetUser(userId)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
RemoveUnmuteTimerFromDb(guildId, userId); // if unmute errored, just remove unmute from db
|
|
||||||
Administration._log.Warn("Couldn't unmute user {0} in guild {1}", userId, guildId);
|
|
||||||
Administration._log.Warn(ex);
|
|
||||||
}
|
|
||||||
}, null, after, Timeout.InfiniteTimeSpan);
|
|
||||||
|
|
||||||
//add it, or stop the old one and add this one
|
|
||||||
userUnmuteTimers.AddOrUpdate(userId, (key) => toAdd, (key, old) =>
|
|
||||||
{
|
|
||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
return toAdd;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void StopUnmuteTimer(ulong guildId, ulong userId)
|
|
||||||
{
|
|
||||||
if (!UnmuteTimers.TryGetValue(guildId, out ConcurrentDictionary<ulong, Timer> userUnmuteTimers)) return;
|
|
||||||
|
|
||||||
if (userUnmuteTimers.TryRemove(userId, out Timer removed))
|
|
||||||
{
|
|
||||||
removed.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RemoveUnmuteTimerFromDb(ulong guildId, ulong userId)
|
|
||||||
{
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var config = uow.GuildConfigs.For(guildId, set => set.Include(x => x.UnmuteTimers));
|
|
||||||
config.UnmuteTimers.RemoveWhere(x => x.UserId == userId);
|
|
||||||
uow.Complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -257,11 +39,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
config.MuteRoleName = name;
|
config.MuteRoleName = name;
|
||||||
GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
|
_service.GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false);
|
await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false);
|
||||||
@ -283,7 +65,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await MuteUser(user).ConfigureAwait(false);
|
await _service.MuteUser(user).ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("user_muted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_muted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -303,7 +85,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await TimedMute(user, TimeSpan.FromMinutes(minutes)).ConfigureAwait(false);
|
await _service.TimedMute(user, TimeSpan.FromMinutes(minutes)).ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("user_muted_time", Format.Bold(user.ToString()), minutes).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_muted_time", Format.Bold(user.ToString()), minutes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -321,7 +103,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await UnmuteUser(user).ConfigureAwait(false);
|
await _service.UnmuteUser(user).ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("user_unmuted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_unmuted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -337,8 +119,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.AddRoleAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
await _service.MuteUser(user, MuteType.Chat).ConfigureAwait(false);
|
||||||
UserMuted(user, MuteType.Chat);
|
|
||||||
await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -354,8 +135,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.RemoveRoleAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
await _service.UnmuteUser(user, MuteType.Chat).ConfigureAwait(false);
|
||||||
UserUnmuted(user, MuteType.Chat);
|
|
||||||
await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -367,12 +147,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||||
public async Task VoiceMute(IGuildUser user)
|
public async Task VoiceMute([Remainder] IGuildUser user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.ModifyAsync(usr => usr.Mute = true).ConfigureAwait(false);
|
await _service.MuteUser(user, MuteType.Voice).ConfigureAwait(false);
|
||||||
UserMuted(user, MuteType.Voice);
|
|
||||||
await ReplyConfirmLocalized("user_voice_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_voice_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -384,12 +163,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||||
public async Task VoiceUnmute(IGuildUser user)
|
public async Task VoiceUnmute([Remainder] IGuildUser user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.ModifyAsync(usr => usr.Mute = false).ConfigureAwait(false);
|
await _service.UnmuteUser(user, MuteType.Voice).ConfigureAwait(false);
|
||||||
UserUnmuted(user, MuteType.Voice);
|
|
||||||
await ReplyConfirmLocalized("user_voice_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("user_voice_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -15,6 +15,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
@ -23,34 +24,20 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class SelfCommands : NadekoSubmodule
|
public class SelfCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static volatile bool _forwardDMs;
|
private readonly DbHandler _db;
|
||||||
private static volatile bool _forwardDMsToAllOwners;
|
|
||||||
|
|
||||||
private static readonly object _locker = new object();
|
private static readonly object _locker = new object();
|
||||||
|
private readonly SelfService _service;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly IImagesService _images;
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
public SelfCommands(DbHandler db, SelfService service, DiscordShardedClient client,
|
||||||
|
IImagesService images)
|
||||||
static SelfCommands()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_db = db;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
_service = service;
|
||||||
{
|
_client = client;
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
_images = images;
|
||||||
_forwardDMs = config.ForwardMessages;
|
|
||||||
_forwardDMsToAllOwners = config.ForwardToAllOwners;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
while (!NadekoBot.Ready)
|
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
foreach (var cmd in NadekoBot.BotConfig.StartupCommands)
|
|
||||||
{
|
|
||||||
await NadekoBot.CommandHandler.ExecuteExternal(cmd.GuildId, cmd.ChannelId, cmd.CommandText);
|
|
||||||
await Task.Delay(400).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -69,7 +56,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
VoiceChannelId = guser.VoiceChannel?.Id,
|
VoiceChannelId = guser.VoiceChannel?.Id,
|
||||||
VoiceChannelName = guser.VoiceChannel?.Name,
|
VoiceChannelName = guser.VoiceChannel?.Name,
|
||||||
};
|
};
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.BotConfig
|
uow.BotConfig
|
||||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
@ -96,7 +83,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
page -= 1;
|
page -= 1;
|
||||||
IEnumerable<StartupCommand> scmds;
|
IEnumerable<StartupCommand> scmds;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
scmds = uow.BotConfig
|
scmds = uow.BotConfig
|
||||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
@ -148,7 +135,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task StartupCommandRemove([Remainder] string cmdText)
|
public async Task StartupCommandRemove([Remainder] string cmdText)
|
||||||
{
|
{
|
||||||
StartupCommand cmd;
|
StartupCommand cmd;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var cmds = uow.BotConfig
|
var cmds = uow.BotConfig
|
||||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
@ -174,7 +161,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task StartupCommandsClear()
|
public async Task StartupCommandsClear()
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.BotConfig
|
uow.BotConfig
|
||||||
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
@ -190,14 +177,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ForwardMessages()
|
public async Task ForwardMessages()
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
lock (_locker)
|
_service.ForwardDMs = config.ForwardMessages = !config.ForwardMessages;
|
||||||
_forwardDMs = config.ForwardMessages = !config.ForwardMessages;
|
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
if (_forwardDMs)
|
if (_service.ForwardDMs)
|
||||||
await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false);
|
await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false);
|
await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false);
|
||||||
@ -207,83 +193,83 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ForwardToAll()
|
public async Task ForwardToAll()
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
_forwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners;
|
_service.ForwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners;
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
if (_forwardDMsToAllOwners)
|
if (_service.ForwardDMsToAllOwners)
|
||||||
await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false);
|
await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false);
|
await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task HandleDmForwarding(IUserMessage msg, ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels)
|
//todo dm forwarding
|
||||||
{
|
//public async Task HandleDmForwarding(IUserMessage msg, ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels)
|
||||||
if (_forwardDMs && ownerChannels.Length > 0)
|
//{
|
||||||
{
|
// if (_service.ForwardDMs && ownerChannels.Length > 0)
|
||||||
var title = GetTextStatic("dm_from",
|
// {
|
||||||
NadekoBot.Localization.DefaultCultureInfo,
|
// var title = _strings.GetText("dm_from",
|
||||||
typeof(Administration).Name.ToLowerInvariant()) +
|
// NadekoBot.Localization.DefaultCultureInfo,
|
||||||
$" [{msg.Author}]({msg.Author.Id})";
|
// typeof(Administration).Name.ToLowerInvariant()) +
|
||||||
|
// $" [{msg.Author}]({msg.Author.Id})";
|
||||||
|
|
||||||
var attachamentsTxt = GetTextStatic("attachments",
|
// var attachamentsTxt = GetTextStatic("attachments",
|
||||||
NadekoBot.Localization.DefaultCultureInfo,
|
// NadekoBot.Localization.DefaultCultureInfo,
|
||||||
typeof(Administration).Name.ToLowerInvariant());
|
// typeof(Administration).Name.ToLowerInvariant());
|
||||||
|
|
||||||
var toSend = msg.Content;
|
// var toSend = msg.Content;
|
||||||
|
|
||||||
if (msg.Attachments.Count > 0)
|
// if (msg.Attachments.Count > 0)
|
||||||
{
|
// {
|
||||||
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" +
|
// toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" +
|
||||||
string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
// string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (_forwardDMsToAllOwners)
|
// if (_service.ForwardDMsToAllOwners)
|
||||||
{
|
// {
|
||||||
var allOwnerChannels = await Task.WhenAll(ownerChannels
|
// var allOwnerChannels = await Task.WhenAll(ownerChannels
|
||||||
.Select(x => x.Value))
|
// .Select(x => x.Value))
|
||||||
.ConfigureAwait(false);
|
// .ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await ownerCh.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
_log.Warn("Can't contact owner with id {0}", ownerCh.Recipient.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var firstOwnerChannel = await ownerChannels[0];
|
|
||||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id))
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// await ownerCh.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// _log.Warn("Can't contact owner with id {0}", ownerCh.Recipient.Id);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// var firstOwnerChannel = await ownerChannels[0];
|
||||||
|
// if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
// // ignored
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ConnectShard(int shardid)
|
public async Task ConnectShard(int shardid)
|
||||||
{
|
{
|
||||||
var shard = NadekoBot.Client.GetShard(shardid);
|
var shard = _client.GetShard(shardid);
|
||||||
|
|
||||||
if (shard == null)
|
if (shard == null)
|
||||||
{
|
{
|
||||||
@ -307,15 +293,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task Leave([Remainder] string guildStr)
|
public async Task Leave([Remainder] string guildStr)
|
||||||
{
|
{
|
||||||
guildStr = guildStr.Trim().ToUpperInvariant();
|
guildStr = guildStr.Trim().ToUpperInvariant();
|
||||||
var server = NadekoBot.Client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ??
|
var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ??
|
||||||
NadekoBot.Client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
|
_client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||||
|
|
||||||
if (server == null)
|
if (server == null)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("no_server").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_server").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (server.OwnerId != NadekoBot.Client.CurrentUser.Id)
|
if (server.OwnerId != _client.CurrentUser.Id)
|
||||||
{
|
{
|
||||||
await server.LeaveAsync().ConfigureAwait(false);
|
await server.LeaveAsync().ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("left_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("left_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
||||||
@ -351,7 +337,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (string.IsNullOrWhiteSpace(newName))
|
if (string.IsNullOrWhiteSpace(newName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
|
await _client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("bot_name", Format.Bold(newName)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("bot_name", Format.Bold(newName)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -360,7 +346,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task SetStatus([Remainder] SettableUserStatus status)
|
public async Task SetStatus([Remainder] SettableUserStatus status)
|
||||||
{
|
{
|
||||||
await NadekoBot.Client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false);
|
await _client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("bot_status", Format.Bold(status.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("bot_status", Format.Bold(status.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -380,7 +366,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await sr.CopyToAsync(imgStream);
|
await sr.CopyToAsync(imgStream);
|
||||||
imgStream.Position = 0;
|
imgStream.Position = 0;
|
||||||
|
|
||||||
await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Avatar = new Image(imgStream)).ConfigureAwait(false);
|
await _client.CurrentUser.ModifyAsync(u => u.Avatar = new Image(imgStream)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +377,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task SetGame([Remainder] string game = null)
|
public async Task SetGame([Remainder] string game = null)
|
||||||
{
|
{
|
||||||
await NadekoBot.Client.SetGameAsync(game).ConfigureAwait(false);
|
await _client.SetGameAsync(game).ConfigureAwait(false);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
|
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -402,7 +388,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
name = name ?? "";
|
name = name ?? "";
|
||||||
|
|
||||||
await NadekoBot.Client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false);
|
await _client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("set_stream").ConfigureAwait(false);
|
await ReplyConfirmLocalized("set_stream").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -418,7 +404,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (ids.Length != 2)
|
if (ids.Length != 2)
|
||||||
return;
|
return;
|
||||||
var sid = ulong.Parse(ids[0]);
|
var sid = ulong.Parse(ids[0]);
|
||||||
var server = NadekoBot.Client.Guilds.FirstOrDefault(s => s.Id == sid);
|
var server = _client.Guilds.FirstOrDefault(s => s.Id == sid);
|
||||||
|
|
||||||
if (server == null)
|
if (server == null)
|
||||||
return;
|
return;
|
||||||
@ -455,7 +441,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task Announce([Remainder] string message)
|
public async Task Announce([Remainder] string message)
|
||||||
{
|
{
|
||||||
var channels = NadekoBot.Client.Guilds.Select(g => g.DefaultChannel).ToArray();
|
var channels = _client.Guilds.Select(g => g.DefaultChannel).ToArray();
|
||||||
if (channels == null)
|
if (channels == null)
|
||||||
return;
|
return;
|
||||||
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message)))
|
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message)))
|
||||||
@ -468,7 +454,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ReloadImages()
|
public async Task ReloadImages()
|
||||||
{
|
{
|
||||||
var time = await NadekoBot.Images.Reload().ConfigureAwait(false);
|
var time = _images.Reload();
|
||||||
await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.DataStructures;
|
|
||||||
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.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
@ -18,158 +13,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class ServerGreetCommands : NadekoSubmodule
|
public class ServerGreetCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//make this to a field in the guildconfig table
|
private readonly GreetSettingsService _greetService;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
private new static Logger _log { get; }
|
public ServerGreetCommands(GreetSettingsService greetService, DbHandler db)
|
||||||
private static readonly GreetSettingsService greetService;
|
|
||||||
|
|
||||||
static ServerGreetCommands()
|
|
||||||
{
|
{
|
||||||
NadekoBot.Client.UserJoined += UserJoined;
|
_greetService = greetService;
|
||||||
NadekoBot.Client.UserLeft += UserLeft;
|
_db = db;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
//todo di
|
|
||||||
greetService = NadekoBot.GreetSettingsService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task UserLeft(IGuildUser user)
|
|
||||||
{
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var conf = greetService.GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
|
|
||||||
if (!conf.SendChannelByeMessage) return;
|
|
||||||
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
|
||||||
|
|
||||||
if (channel == null) //maybe warn the server owner that the channel is missing
|
|
||||||
return;
|
|
||||||
CREmbed embedData;
|
|
||||||
if (CREmbed.TryParse(conf.ChannelByeMessageText, out embedData))
|
|
||||||
{
|
|
||||||
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Description = embedData.Description?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Title = embedData.Title?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
|
||||||
if (conf.AutoDeleteByeMessagesTimer > 0)
|
|
||||||
{
|
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
if (string.IsNullOrWhiteSpace(msg))
|
|
||||||
return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
|
|
||||||
if (conf.AutoDeleteByeMessagesTimer > 0)
|
|
||||||
{
|
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task UserJoined(IGuildUser user)
|
|
||||||
{
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var conf = greetService.GetOrAddSettingsForGuild(user.GuildId);
|
|
||||||
|
|
||||||
if (conf.SendChannelGreetMessage)
|
|
||||||
{
|
|
||||||
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId);
|
|
||||||
if (channel != null) //maybe warn the server owner that the channel is missing
|
|
||||||
{
|
|
||||||
|
|
||||||
CREmbed embedData;
|
|
||||||
if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData))
|
|
||||||
{
|
|
||||||
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Description = embedData.Description?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
|
||||||
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
|
||||||
{
|
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
|
|
||||||
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
|
||||||
{
|
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf.SendDmGreetMessage)
|
|
||||||
{
|
|
||||||
var channel = await user.CreateDMChannelAsync();
|
|
||||||
|
|
||||||
if (channel != null)
|
|
||||||
{
|
|
||||||
CREmbed embedData;
|
|
||||||
if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData))
|
|
||||||
{
|
|
||||||
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Description = embedData.Description?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = conf.DmGreetMessageText.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
await channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -180,7 +30,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (timer < 0 || timer > 600)
|
if (timer < 0 || timer > 600)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await ServerGreetCommands.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
await _greetService.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||||
|
|
||||||
if (timer > 0)
|
if (timer > 0)
|
||||||
await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false);
|
await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false);
|
||||||
@ -188,29 +38,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await ReplyConfirmLocalized("greetdel_off").ConfigureAwait(false);
|
await ReplyConfirmLocalized("greetdel_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetGreetDel(ulong id, int timer)
|
|
||||||
{
|
|
||||||
if (timer < 0 || timer > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var conf = uow.GuildConfigs.For(id, set => set);
|
|
||||||
conf.AutoDeleteGreetMessagesTimer = timer;
|
|
||||||
|
|
||||||
var toAdd = GreetSettings.Create(conf);
|
|
||||||
greetService.GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
|
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||||
public async Task Greet()
|
public async Task Greet()
|
||||||
{
|
{
|
||||||
var enabled = await greetService.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
var enabled = await _greetService.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
await ReplyConfirmLocalized("greet_on").ConfigureAwait(false);
|
await ReplyConfirmLocalized("greet_on").ConfigureAwait(false);
|
||||||
@ -226,7 +59,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
string channelGreetMessageText;
|
string channelGreetMessageText;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
channelGreetMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelGreetMessageText;
|
channelGreetMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelGreetMessageText;
|
||||||
}
|
}
|
||||||
@ -234,7 +67,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendGreetEnabled = greetService.SetGreetMessage(Context.Guild.Id, ref text);
|
var sendGreetEnabled = _greetService.SetGreetMessage(Context.Guild.Id, ref text);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false);
|
await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false);
|
||||||
if (!sendGreetEnabled)
|
if (!sendGreetEnabled)
|
||||||
@ -246,7 +79,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||||
public async Task GreetDm()
|
public async Task GreetDm()
|
||||||
{
|
{
|
||||||
var enabled = await greetService.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
|
var enabled = await _greetService.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false);
|
await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false);
|
||||||
@ -262,7 +95,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
GuildConfig config;
|
GuildConfig config;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
config = uow.GuildConfigs.For(Context.Guild.Id);
|
config = uow.GuildConfigs.For(Context.Guild.Id);
|
||||||
}
|
}
|
||||||
@ -270,7 +103,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendGreetEnabled = greetService.SetGreetDmMessage(Context.Guild.Id, ref text);
|
var sendGreetEnabled = _greetService.SetGreetDmMessage(Context.Guild.Id, ref text);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false);
|
await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false);
|
||||||
if (!sendGreetEnabled)
|
if (!sendGreetEnabled)
|
||||||
@ -282,7 +115,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||||
public async Task Bye()
|
public async Task Bye()
|
||||||
{
|
{
|
||||||
var enabled = await greetService.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
var enabled = await _greetService.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
await ReplyConfirmLocalized("bye_on").ConfigureAwait(false);
|
await ReplyConfirmLocalized("bye_on").ConfigureAwait(false);
|
||||||
@ -298,7 +131,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
string byeMessageText;
|
string byeMessageText;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
byeMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelByeMessageText;
|
byeMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelByeMessageText;
|
||||||
}
|
}
|
||||||
@ -306,7 +139,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendByeEnabled = greetService.SetByeMessage(Context.Guild.Id, ref text);
|
var sendByeEnabled = _greetService.SetByeMessage(Context.Guild.Id, ref text);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false);
|
await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false);
|
||||||
if (!sendByeEnabled)
|
if (!sendByeEnabled)
|
||||||
@ -318,7 +151,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||||
public async Task ByeDel(int timer = 30)
|
public async Task ByeDel(int timer = 30)
|
||||||
{
|
{
|
||||||
await greetService.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
await _greetService.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||||
|
|
||||||
if (timer > 0)
|
if (timer > 0)
|
||||||
await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false);
|
await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false);
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -18,6 +19,16 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class UserPunishCommands : NadekoSubmodule
|
public class UserPunishCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly MuteService _muteService;
|
||||||
|
|
||||||
|
public UserPunishCommands(DbHandler db, MuteService muteService)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
|
||||||
|
_muteService = muteService;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<PunishmentAction?> InternalWarn(IGuild guild, ulong userId, string modName, string reason)
|
private async Task<PunishmentAction?> InternalWarn(IGuild guild, ulong userId, string modName, string reason)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(reason))
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
@ -36,7 +47,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
int warnings = 1;
|
int warnings = 1;
|
||||||
List<WarningPunishment> ps;
|
List<WarningPunishment> ps;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments))
|
ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments))
|
||||||
.WarnPunishments;
|
.WarnPunishments;
|
||||||
@ -62,9 +73,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
case PunishmentAction.Mute:
|
case PunishmentAction.Mute:
|
||||||
if (p.Time == 0)
|
if (p.Time == 0)
|
||||||
await MuteCommands.MuteUser(user).ConfigureAwait(false);
|
await _muteService.MuteUser(user).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false);
|
await _muteService.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
case PunishmentAction.Kick:
|
case PunishmentAction.Kick:
|
||||||
await user.KickAsync().ConfigureAwait(false);
|
await user.KickAsync().ConfigureAwait(false);
|
||||||
@ -147,7 +158,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (page < 0)
|
if (page < 0)
|
||||||
return;
|
return;
|
||||||
Warning[] warnings;
|
Warning[] warnings;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
warnings = uow.Warnings.For(Context.Guild.Id, userId);
|
warnings = uow.Warnings.For(Context.Guild.Id, userId);
|
||||||
}
|
}
|
||||||
@ -192,7 +203,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
public async Task Warnclear(ulong userId)
|
public async Task Warnclear(ulong userId)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false);
|
await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false);
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
@ -212,7 +223,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (number <= 0)
|
if (number <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||||
ps.RemoveAll(x => x.Count == number);
|
ps.RemoveAll(x => x.Count == number);
|
||||||
@ -239,7 +250,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (number <= 0)
|
if (number <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||||
var p = ps.FirstOrDefault(x => x.Count == number);
|
var p = ps.FirstOrDefault(x => x.Count == number);
|
||||||
@ -260,7 +271,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task WarnPunishList()
|
public async Task WarnPunishList()
|
||||||
{
|
{
|
||||||
WarningPunishment[] ps;
|
WarningPunishment[] ps;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments))
|
ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments))
|
||||||
.WarnPunishments
|
.WarnPunishments
|
||||||
|
@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
@ -18,86 +19,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class VcRoleCommands : NadekoSubmodule
|
public class VcRoleCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
private readonly VcRoleService _service;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
static VcRoleCommands()
|
public VcRoleCommands(VcRoleService service, DbHandler db)
|
||||||
{
|
{
|
||||||
NadekoBot.Client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
|
_service = service;
|
||||||
VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
|
_db = db;
|
||||||
foreach (var gconf in NadekoBot.AllGuildConfigs)
|
|
||||||
{
|
|
||||||
var g = NadekoBot.Client.GetGuild(gconf.GuildId);
|
|
||||||
if (g == null)
|
|
||||||
continue; //todo delete everything from db if guild doesn't exist?
|
|
||||||
|
|
||||||
var infos = new ConcurrentDictionary<ulong, IRole>();
|
|
||||||
VcRoles.TryAdd(gconf.GuildId, infos);
|
|
||||||
foreach (var ri in gconf.VcRoleInfos)
|
|
||||||
{
|
|
||||||
var role = g.GetRole(ri.RoleId);
|
|
||||||
if (role == null)
|
|
||||||
continue; //todo remove this entry from db
|
|
||||||
|
|
||||||
infos.TryAdd(ri.VoiceChannelId, role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState,
|
|
||||||
SocketVoiceState newState)
|
|
||||||
{
|
|
||||||
|
|
||||||
var gusr = usr as SocketGuildUser;
|
|
||||||
if (gusr == null)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var oldVc = oldState.VoiceChannel;
|
|
||||||
var newVc = newState.VoiceChannel;
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (oldVc != newVc)
|
|
||||||
{
|
|
||||||
ulong guildId;
|
|
||||||
guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
|
|
||||||
|
|
||||||
if (VcRoles.TryGetValue(guildId, out ConcurrentDictionary<ulong, IRole> guildVcRoles))
|
|
||||||
{
|
|
||||||
//remove old
|
|
||||||
if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out IRole role))
|
|
||||||
{
|
|
||||||
if (gusr.Roles.Contains(role))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
|
||||||
await Task.Delay(500).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await Task.Delay(200).ConfigureAwait(false);
|
|
||||||
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
|
||||||
await Task.Delay(500).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//add new
|
|
||||||
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
|
|
||||||
{
|
|
||||||
if (!gusr.Roles.Contains(role))
|
|
||||||
await gusr.AddRoleAsync(role).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Administration._log.Warn(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -118,14 +46,14 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var guildVcRoles = VcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
|
var guildVcRoles = _service.VcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
|
||||||
|
|
||||||
if (role == null)
|
if (role == null)
|
||||||
{
|
{
|
||||||
if (guildVcRoles.TryRemove(vc.Id, out role))
|
if (guildVcRoles.TryRemove(vc.Id, out role))
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("vcrole_removed", Format.Bold(vc.Name)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("vcrole_removed", Format.Bold(vc.Name)).ConfigureAwait(false);
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||||
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id);
|
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id);
|
||||||
@ -136,7 +64,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
guildVcRoles.AddOrUpdate(vc.Id, role, (key, old) => role);
|
guildVcRoles.AddOrUpdate(vc.Id, role, (key, old) => role);
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||||
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id); // remove old one
|
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id); // remove old one
|
||||||
@ -157,7 +85,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
var guild = (SocketGuild) Context.Guild;
|
var guild = (SocketGuild) Context.Guild;
|
||||||
string text;
|
string text;
|
||||||
if (VcRoles.TryGetValue(Context.Guild.Id, out ConcurrentDictionary<ulong, IRole> roles))
|
if (_service.VcRoles.TryGetValue(Context.Guild.Id, out ConcurrentDictionary<ulong, IRole> roles))
|
||||||
{
|
{
|
||||||
if (!roles.Any())
|
if (!roles.Any())
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -21,140 +22,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class VoicePlusTextCommands : NadekoSubmodule
|
public class VoicePlusTextCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private new static readonly Logger _log;
|
private readonly VplusTService _service;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
private static readonly Regex _channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
public VoicePlusTextCommands(VplusTService service, DbHandler db)
|
||||||
|
|
||||||
private static readonly ConcurrentHashSet<ulong> _voicePlusTextCache;
|
|
||||||
private static readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
|
||||||
static VoicePlusTextCommands()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_service = service;
|
||||||
var sw = Stopwatch.StartNew();
|
_db = db;
|
||||||
|
|
||||||
_voicePlusTextCache = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
|
|
||||||
NadekoBot.Client.UserVoiceStateUpdated += UserUpdatedEventHandler;
|
|
||||||
|
|
||||||
sw.Stop();
|
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after)
|
|
||||||
{
|
|
||||||
var user = (iuser as SocketGuildUser);
|
|
||||||
var guild = user?.Guild;
|
|
||||||
|
|
||||||
if (guild == null)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var botUserPerms = guild.CurrentUser.GuildPermissions;
|
|
||||||
|
|
||||||
if (before.VoiceChannel == after.VoiceChannel)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
if (!_voicePlusTextCache.Contains(guild.Id))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await guild.Owner.SendErrorAsync(
|
|
||||||
GetTextStatic("vt_exit",
|
|
||||||
NadekoBot.Localization.GetCultureInfo(guild),
|
|
||||||
typeof(Administration).Name.ToLowerInvariant(),
|
|
||||||
Format.Bold(guild.Name))).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
|
|
||||||
_voicePlusTextCache.TryRemove(guild.Id);
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var semaphore = _guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var beforeVch = before.VoiceChannel;
|
|
||||||
if (beforeVch != null)
|
|
||||||
{
|
|
||||||
var beforeRoleName = GetRoleName(beforeVch);
|
|
||||||
var beforeRole = guild.Roles.FirstOrDefault(x => x.Name == beforeRoleName);
|
|
||||||
if (beforeRole != null)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_log.Info("Removing role " + beforeRoleName + " from user " + user.Username);
|
|
||||||
await user.RemoveRoleAsync(beforeRole).ConfigureAwait(false);
|
|
||||||
await Task.Delay(200).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var afterVch = after.VoiceChannel;
|
|
||||||
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
|
||||||
{
|
|
||||||
var roleName = GetRoleName(afterVch);
|
|
||||||
var roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName) ??
|
|
||||||
(IRole) await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
ITextChannel textChannel = guild.TextChannels
|
|
||||||
.FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant());
|
|
||||||
if (textChannel == null)
|
|
||||||
{
|
|
||||||
var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
|
||||||
|
|
||||||
try { await guild.CurrentUser.AddRoleAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
|
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
|
||||||
await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
|
|
||||||
readMessages: PermValue.Allow,
|
|
||||||
sendMessages: PermValue.Allow))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
|
||||||
await created.AddPermissionOverwriteAsync(guild.EveryoneRole, new OverwritePermissions(
|
|
||||||
readMessages: PermValue.Deny,
|
|
||||||
sendMessages: PermValue.Deny))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
_log.Warn("Adding role " + roleToAdd.Name + " to user " + user.Username);
|
|
||||||
await user.AddRoleAsync(roleToAdd).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetChannelName(string voiceName) =>
|
|
||||||
_channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
|
||||||
|
|
||||||
private static string GetRoleName(IVoiceChannel ch) =>
|
|
||||||
"nvoice-" + ch.Id;
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
@ -184,7 +60,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool isEnabled;
|
bool isEnabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(guild.Id, set => set);
|
var conf = uow.GuildConfigs.For(guild.Id, set => set);
|
||||||
isEnabled = conf.VoicePlusTextEnabled = !conf.VoicePlusTextEnabled;
|
isEnabled = conf.VoicePlusTextEnabled = !conf.VoicePlusTextEnabled;
|
||||||
@ -192,7 +68,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
if (!isEnabled)
|
if (!isEnabled)
|
||||||
{
|
{
|
||||||
_voicePlusTextCache.TryRemove(guild.Id);
|
_service.VoicePlusTextCache.TryRemove(guild.Id);
|
||||||
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
||||||
{
|
{
|
||||||
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
@ -207,7 +83,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await ReplyConfirmLocalized("vt_disabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("vt_disabled").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_voicePlusTextCache.Add(guild.Id);
|
_service.VoicePlusTextCache.Add(guild.Id);
|
||||||
await ReplyConfirmLocalized("vt_enabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("vt_enabled").ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -236,7 +112,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var voiceChannels = await guild.GetVoiceChannelsAsync().ConfigureAwait(false);
|
var voiceChannels = await guild.GetVoiceChannelsAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var boundTextChannels = textChannels.Where(c => c.Name.EndsWith("-voice"));
|
var boundTextChannels = textChannels.Where(c => c.Name.EndsWith("-voice"));
|
||||||
var validTxtChannelNames = new HashSet<string>(voiceChannels.Select(c => GetChannelName(c.Name).ToLowerInvariant()));
|
var validTxtChannelNames = new HashSet<string>(voiceChannels.Select(c => _service.GetChannelName(c.Name).ToLowerInvariant()));
|
||||||
var invalidTxtChannels = boundTextChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
var invalidTxtChannels = boundTextChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
|
||||||
|
|
||||||
foreach (var c in invalidTxtChannels)
|
foreach (var c in invalidTxtChannels)
|
||||||
@ -246,7 +122,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
|
|
||||||
var boundRoles = guild.Roles.Where(r => r.Name.StartsWith("nvoice-"));
|
var boundRoles = guild.Roles.Where(r => r.Name.StartsWith("nvoice-"));
|
||||||
var validRoleNames = new HashSet<string>(voiceChannels.Select(c => GetRoleName(c).ToLowerInvariant()));
|
var validRoleNames = new HashSet<string>(voiceChannels.Select(c => _service.GetRoleName(c).ToLowerInvariant()));
|
||||||
var invalidRoles = boundRoles.Where(r => !validRoleNames.Contains(r.Name));
|
var invalidRoles = boundRoles.Where(r => !validRoleNames.Contains(r.Name));
|
||||||
|
|
||||||
foreach (var r in invalidRoles)
|
foreach (var r in invalidRoles)
|
||||||
|
@ -21,9 +21,16 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class Acropobia : NadekoSubmodule
|
public class Acropobia : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
||||||
|
|
||||||
|
public Acropobia(DiscordShardedClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Acro(int time = 60)
|
public async Task Acro(int time = 60)
|
||||||
@ -32,7 +39,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = new AcrophobiaGame(channel, time);
|
var game = new AcrophobiaGame(_client, _strings, channel, time);
|
||||||
if (AcrophobiaGames.TryAdd(channel.Id, game))
|
if (AcrophobiaGames.TryAdd(channel.Id, game))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -59,6 +66,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
Voting
|
Voting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo Isolate, this shouldn't print or anything like that.
|
||||||
public class AcrophobiaGame
|
public class AcrophobiaGame
|
||||||
{
|
{
|
||||||
private readonly ITextChannel _channel;
|
private readonly ITextChannel _channel;
|
||||||
@ -79,10 +87,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
//text, votes
|
//text, votes
|
||||||
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public AcrophobiaGame(ITextChannel channel, int time)
|
public AcrophobiaGame(DiscordShardedClient client, NadekoStrings strings, ITextChannel channel, int time)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_client = client;
|
||||||
|
_strings = strings;
|
||||||
|
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_time = time;
|
_time = time;
|
||||||
@ -123,7 +135,7 @@ $@"--
|
|||||||
|
|
||||||
public async Task Run()
|
public async Task Run()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += PotentialAcro;
|
_client.MessageReceived += PotentialAcro;
|
||||||
var embed = GetEmbed();
|
var embed = GetEmbed();
|
||||||
|
|
||||||
//SUBMISSIONS PHASE
|
//SUBMISSIONS PHASE
|
||||||
@ -292,14 +304,14 @@ $@"--
|
|||||||
|
|
||||||
public void EnsureStopped()
|
public void EnsureStopped()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= PotentialAcro;
|
_client.MessageReceived -= PotentialAcro;
|
||||||
if (!_source.IsCancellationRequested)
|
if (!_source.IsCancellationRequested)
|
||||||
_source.Cancel();
|
_source.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetText(string key, params object[] replacements)
|
private string GetText(string key, params object[] replacements)
|
||||||
=> GetTextStatic(key,
|
=> _strings.GetText(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(_channel.Guild),
|
_channel.Guild.Id,
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using NadekoBot.Services.Games;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
@ -19,72 +13,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class CleverBotCommands : NadekoSubmodule
|
public class CleverBotCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private new static Logger _log { get; }
|
private readonly DbHandler _db;
|
||||||
|
private readonly GamesService _games;
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; }
|
public CleverBotCommands(DbHandler db, GamesService games)
|
||||||
|
|
||||||
static CleverBotCommands()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_db = db;
|
||||||
var sw = Stopwatch.StartNew();
|
_games = games;
|
||||||
|
|
||||||
CleverbotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
|
||||||
NadekoBot.AllGuildConfigs
|
|
||||||
.Where(gc => gc.CleverbotEnabled)
|
|
||||||
.ToDictionary(gc => gc.GuildId, gc => new Lazy<ChatterBotSession>(() => new ChatterBotSession(gc.GuildId), true)));
|
|
||||||
|
|
||||||
sw.Stop();
|
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string PrepareMessage(IUserMessage msg, out ChatterBotSession cleverbot)
|
|
||||||
{
|
|
||||||
var channel = msg.Channel as ITextChannel;
|
|
||||||
cleverbot = null;
|
|
||||||
|
|
||||||
if (channel == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Lazy<ChatterBotSession> lazyCleverbot;
|
|
||||||
if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out lazyCleverbot))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
cleverbot = lazyCleverbot.Value;
|
|
||||||
|
|
||||||
var nadekoId = NadekoBot.Client.CurrentUser.Id;
|
|
||||||
var normalMention = $"<@{nadekoId}> ";
|
|
||||||
var nickMention = $"<@!{nadekoId}> ";
|
|
||||||
string message;
|
|
||||||
if (msg.Content.StartsWith(normalMention))
|
|
||||||
{
|
|
||||||
message = msg.Content.Substring(normalMention.Length).Trim();
|
|
||||||
}
|
|
||||||
else if (msg.Content.StartsWith(nickMention))
|
|
||||||
{
|
|
||||||
message = msg.Content.Substring(nickMention.Length).Trim();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<bool> TryAsk(ChatterBotSession cleverbot, ITextChannel channel, string message)
|
|
||||||
{
|
|
||||||
await channel.TriggerTypingAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var response = await cleverbot.Think(message).ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -94,10 +29,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
Lazy<ChatterBotSession> throwaway;
|
if (_games.CleverbotGuilds.TryRemove(channel.Guild.Id, out Lazy<ChatterBotSession> throwaway))
|
||||||
if (CleverbotGuilds.TryRemove(channel.Guild.Id, out throwaway))
|
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
@ -106,9 +40,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy<ChatterBotSession>(() => new ChatterBotSession(Context.Guild.Id), true));
|
_games.CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy<ChatterBotSession>(() => new ChatterBotSession(Context.Guild.Id), true));
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, true);
|
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, true);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
@ -118,41 +52,6 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChatterBotSession
|
|
||||||
{
|
|
||||||
private static NadekoRandom rng { get; } = new NadekoRandom();
|
|
||||||
public string ChatterbotId { get; }
|
|
||||||
public string ChannelId { get; }
|
|
||||||
private int _botId = 6;
|
|
||||||
|
|
||||||
public ChatterBotSession(ulong channelId)
|
|
||||||
{
|
|
||||||
ChannelId = channelId.ToString().ToBase64();
|
|
||||||
ChatterbotId = rng.Next(0, 1000000).ToString().ToBase64();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string apiEndpoint => "http://api.program-o.com/v2/chatbot/" +
|
|
||||||
$"?bot_id={_botId}&" +
|
|
||||||
"say={0}&" +
|
|
||||||
$"convo_id=nadekobot_{ChatterbotId}_{ChannelId}&" +
|
|
||||||
"format=json";
|
|
||||||
|
|
||||||
public async Task<string> Think(string message)
|
|
||||||
{
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
var res = await http.GetStringAsync(string.Format(apiEndpoint, message)).ConfigureAwait(false);
|
|
||||||
var cbr = JsonConvert.DeserializeObject<ChatterBotResponse>(res);
|
|
||||||
//Console.WriteLine(cbr.Convo_id);
|
|
||||||
return cbr.BotSay.Replace("<br/>", "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChatterBotResponse
|
|
||||||
{
|
|
||||||
public string Convo_id { get; set; }
|
|
||||||
public string BotSay { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -56,6 +56,7 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
public class HangmanGame: IDisposable
|
public class HangmanGame: IDisposable
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
public IMessageChannel GameChannel { get; }
|
public IMessageChannel GameChannel { get; }
|
||||||
public HashSet<char> Guesses { get; } = new HashSet<char>();
|
public HashSet<char> Guesses { get; } = new HashSet<char>();
|
||||||
@ -81,9 +82,11 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
|
|
||||||
public event Action<HangmanGame> OnEnded;
|
public event Action<HangmanGame> OnEnded;
|
||||||
|
|
||||||
public HangmanGame(IMessageChannel channel, string type)
|
public HangmanGame(DiscordShardedClient client, IMessageChannel channel, string type)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_client = client;
|
||||||
|
|
||||||
this.GameChannel = channel;
|
this.GameChannel = channel;
|
||||||
this.TermType = type.ToTitleCase();
|
this.TermType = type.ToTitleCase();
|
||||||
}
|
}
|
||||||
@ -95,12 +98,12 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
if (this.Term == null)
|
if (this.Term == null)
|
||||||
throw new KeyNotFoundException("Can't find a term with that type. Use hangmanlist command.");
|
throw new KeyNotFoundException("Can't find a term with that type. Use hangmanlist command.");
|
||||||
// start listening for answers when game starts
|
// start listening for answers when game starts
|
||||||
NadekoBot.Client.MessageReceived += PotentialGuess;
|
_client.MessageReceived += PotentialGuess;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task End()
|
public async Task End()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
_client.MessageReceived -= PotentialGuess;
|
||||||
OnEnded(this);
|
OnEnded(this);
|
||||||
var toSend = "Game ended. You **" + (Errors >= MaxErrors ? "LOSE" : "WIN") + "**!\n" + GetHangman();
|
var toSend = "Game ended. You **" + (Errors >= MaxErrors ? "LOSE" : "WIN") + "**!\n" + GetHangman();
|
||||||
var embed = new EmbedBuilder().WithTitle("Hangman Game")
|
var embed = new EmbedBuilder().WithTitle("Hangman Game")
|
||||||
@ -199,7 +202,7 @@ namespace NadekoBot.Modules.Games.Hangman
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
_client.MessageReceived -= PotentialGuess;
|
||||||
OnEnded = null;
|
OnEnded = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Concurrent;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Modules.Games.Hangman;
|
using NadekoBot.Modules.Games.Hangman;
|
||||||
using Discord;
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
@ -14,6 +15,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class HangmanCommands : NadekoSubmodule
|
public class HangmanCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public HangmanCommands(DiscordShardedClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -25,7 +33,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Hangman([Remainder]string type = "All")
|
public async Task Hangman([Remainder]string type = "All")
|
||||||
{
|
{
|
||||||
var hm = new HangmanGame(Context.Channel, type);
|
var hm = new HangmanGame(_client, Context.Channel, type);
|
||||||
|
|
||||||
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
||||||
{
|
{
|
||||||
@ -35,8 +43,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
hm.OnEnded += g =>
|
hm.OnEnded += g =>
|
||||||
{
|
{
|
||||||
HangmanGame throwaway;
|
HangmanGames.TryRemove(g.GameChannel.Id, out HangmanGame throwaway);
|
||||||
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
|
||||||
};
|
};
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -45,8 +52,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
try { await Context.Channel.SendErrorAsync(GetText("hangman_start_errored") + " " + ex.Message).ConfigureAwait(false); } catch { }
|
try { await Context.Channel.SendErrorAsync(GetText("hangman_start_errored") + " " + ex.Message).ConfigureAwait(false); } catch { }
|
||||||
HangmanGame throwaway;
|
HangmanGames.TryRemove(Context.Channel.Id, out HangmanGame throwaway);
|
||||||
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
|
||||||
throwaway.Dispose();
|
throwaway.Dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
147
src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs
Normal file
147
src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Games;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Games.Models
|
||||||
|
{
|
||||||
|
public class TypingGame
|
||||||
|
{
|
||||||
|
public const float WORD_VALUE = 4.5f;
|
||||||
|
public ITextChannel Channel { get; }
|
||||||
|
public string CurrentSentence { get; private set; }
|
||||||
|
public bool IsActive { get; private set; }
|
||||||
|
private readonly Stopwatch sw;
|
||||||
|
private readonly List<ulong> finishedUserIds;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly GamesService _games;
|
||||||
|
|
||||||
|
private Logger _log { get; }
|
||||||
|
|
||||||
|
public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_games = games;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
this.Channel = channel;
|
||||||
|
IsActive = false;
|
||||||
|
sw = new Stopwatch();
|
||||||
|
finishedUserIds = new List<ulong>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Stop()
|
||||||
|
{
|
||||||
|
if (!IsActive) return false;
|
||||||
|
_client.MessageReceived -= AnswerReceived;
|
||||||
|
finishedUserIds.Clear();
|
||||||
|
IsActive = false;
|
||||||
|
sw.Stop();
|
||||||
|
sw.Reset();
|
||||||
|
try { await Channel.SendConfirmAsync("Typing contest stopped.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
if (IsActive) return; // can't start running game
|
||||||
|
IsActive = true;
|
||||||
|
CurrentSentence = GetRandomSentence();
|
||||||
|
var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Channel.SendConfirmAsync($@":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.").ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
||||||
|
var msg = await Channel.SendMessageAsync("Starting new typing contest in **3**...").ConfigureAwait(false);
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await msg.ModifyAsync(m => m.Content = "Starting new typing contest in **2**...").ConfigureAwait(false);
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
await msg.ModifyAsync(m => m.Content = "Starting new typing contest in **1**...").ConfigureAwait(false);
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
|
||||||
|
await msg.ModifyAsync(m => m.Content = Format.Bold(Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions())).ConfigureAwait(false);
|
||||||
|
sw.Start();
|
||||||
|
HandleAnswers();
|
||||||
|
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
i--;
|
||||||
|
if (!IsActive)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await Stop().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetRandomSentence()
|
||||||
|
{
|
||||||
|
if (_games.TypingArticles.Any())
|
||||||
|
return _games.TypingArticles[new NadekoRandom().Next(0, _games.TypingArticles.Count)].Text;
|
||||||
|
else
|
||||||
|
return $"No typing articles found. Use {NadekoBot.Prefix}typeadd command to add a new article for typing.";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAnswers()
|
||||||
|
{
|
||||||
|
_client.MessageReceived += AnswerReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AnswerReceived(SocketMessage imsg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (imsg.Author.IsBot)
|
||||||
|
return;
|
||||||
|
var msg = imsg as SocketUserMessage;
|
||||||
|
if (msg == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.Channel == null || this.Channel.Id != msg.Channel.Id) return;
|
||||||
|
|
||||||
|
var guess = msg.Content;
|
||||||
|
|
||||||
|
var distance = CurrentSentence.LevenshteinDistance(guess);
|
||||||
|
var decision = Judge(distance, guess.Length);
|
||||||
|
if (decision && !finishedUserIds.Contains(msg.Author.Id))
|
||||||
|
{
|
||||||
|
var elapsed = sw.Elapsed;
|
||||||
|
var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
|
||||||
|
finishedUserIds.Add(msg.Author.Id);
|
||||||
|
await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle($"{msg.Author} finished the race!")
|
||||||
|
.AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*").WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
if (finishedUserIds.Count % 4 == 0)
|
||||||
|
{
|
||||||
|
await this.Channel.SendConfirmAsync($":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Judge(int errors, int textLength) => errors <= textLength / 25;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ 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 NadekoBot.Services.Games;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -28,89 +29,20 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class PlantPickCommands : NadekoSubmodule
|
public class PlantPickCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentHashSet<ulong> generationChannels { get; }
|
private readonly CurrencyHandler _ch;
|
||||||
//channelid/message
|
private readonly BotConfig _bc;
|
||||||
private static ConcurrentDictionary<ulong, List<IUserMessage>> plantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
private readonly GamesService _games;
|
||||||
//channelId/last generation
|
private readonly DbHandler _db;
|
||||||
private static ConcurrentDictionary<ulong, DateTime> lastGenerations { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
|
||||||
|
|
||||||
static PlantPickCommands()
|
public PlantPickCommands(BotConfig bc, CurrencyHandler ch, GamesService games,
|
||||||
|
DbHandler db)
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
|
_bc = bc;
|
||||||
generationChannels = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs
|
_ch = ch;
|
||||||
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
_games = games;
|
||||||
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task PotentialFlowerGeneration(SocketMessage imsg)
|
|
||||||
{
|
|
||||||
var msg = imsg as SocketUserMessage;
|
|
||||||
if (msg == null || msg.IsAuthor() || msg.Author.IsBot)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var channel = imsg.Channel as ITextChannel;
|
|
||||||
if (channel == null)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
if (!generationChannels.Contains(channel.Id))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
|
|
||||||
var rng = new NadekoRandom();
|
|
||||||
|
|
||||||
//todo i'm stupid :rofl: wtg kwoth. real async programming :100: :ok_hand: :100: :100: :thumbsup:
|
|
||||||
if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
|
|
||||||
return;
|
|
||||||
|
|
||||||
var num = rng.Next(1, 101) + NadekoBot.BotConfig.CurrencyGenerationChance * 100;
|
|
||||||
|
|
||||||
if (num > 100)
|
|
||||||
{
|
|
||||||
lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
|
|
||||||
|
|
||||||
var dropAmount = NadekoBot.BotConfig.CurrencyDropAmount;
|
|
||||||
|
|
||||||
if (dropAmount > 0)
|
|
||||||
{
|
|
||||||
var msgs = new IUserMessage[dropAmount];
|
|
||||||
var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name];
|
|
||||||
var toSend = dropAmount == 1
|
|
||||||
? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign)
|
|
||||||
+ " " + GetLocalText(channel, "pick_sn", prefix)
|
|
||||||
: GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign)
|
|
||||||
+ " " + GetLocalText(channel, "pick_pl", prefix);
|
|
||||||
var file = GetRandomCurrencyImage();
|
|
||||||
using (var fileStream = file.Value.ToStream())
|
|
||||||
{
|
|
||||||
var sent = await channel.SendFileAsync(
|
|
||||||
fileStream,
|
|
||||||
file.Key,
|
|
||||||
toSend).ConfigureAwait(false);
|
|
||||||
|
|
||||||
msgs[0] = sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetLocalText(ITextChannel channel, string key, params object[] replacements) =>
|
|
||||||
NadekoTopLevelModule.GetTextStatic(key,
|
|
||||||
NadekoBot.Localization.GetCultureInfo(channel.GuildId),
|
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
|
||||||
replacements);
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Pick()
|
public async Task Pick()
|
||||||
@ -120,16 +52,15 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages)
|
if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<IUserMessage> msgs;
|
|
||||||
|
|
||||||
try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
if (!plantedFlowers.TryRemove(channel.Id, out msgs))
|
if (!_games.PlantedFlowers.TryRemove(channel.Id, out List<IUserMessage> msgs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
||||||
|
|
||||||
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
|
await _ch.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {_bc.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
|
||||||
var msg = await ReplyConfirmLocalized("picked", msgs.Count + NadekoBot.BotConfig.CurrencySign)
|
var msg = await ReplyConfirmLocalized("picked", msgs.Count + _bc.CurrencySign)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
msg.DeleteAfter(10);
|
msg.DeleteAfter(10);
|
||||||
}
|
}
|
||||||
@ -141,21 +72,21 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (amount < 1)
|
if (amount < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
var removed = await _ch.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {_bc.CurrencyName}", amount, false).ConfigureAwait(false);
|
||||||
if (!removed)
|
if (!removed)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("not_enough", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyErrorLocalized("not_enough", _bc.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgData = GetRandomCurrencyImage();
|
var imgData = _games.GetRandomCurrencyImage();
|
||||||
|
|
||||||
//todo upload all currency images to transfer.sh and use that one as cdn
|
//todo upload all currency images to transfer.sh and use that one as cdn
|
||||||
//and then
|
//and then
|
||||||
|
|
||||||
var msgToSend = GetText("planted",
|
var msgToSend = GetText("planted",
|
||||||
Format.Bold(Context.User.ToString()),
|
Format.Bold(Context.User.ToString()),
|
||||||
amount + NadekoBot.BotConfig.CurrencySign,
|
amount + _bc.CurrencySign,
|
||||||
Prefix);
|
Prefix);
|
||||||
|
|
||||||
if (amount > 1)
|
if (amount > 1)
|
||||||
@ -172,7 +103,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var msgs = new IUserMessage[amount];
|
var msgs = new IUserMessage[amount];
|
||||||
msgs[0] = msg;
|
msgs[0] = msg;
|
||||||
|
|
||||||
plantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) =>
|
_games.PlantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) =>
|
||||||
{
|
{
|
||||||
old.AddRange(msgs);
|
old.AddRange(msgs);
|
||||||
return old;
|
return old;
|
||||||
@ -190,7 +121,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var guildConfig = uow.GuildConfigs.For(channel.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
|
var guildConfig = uow.GuildConfigs.For(channel.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
|
||||||
|
|
||||||
@ -198,13 +129,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
||||||
{
|
{
|
||||||
guildConfig.GenerateCurrencyChannelIds.Add(toAdd);
|
guildConfig.GenerateCurrencyChannelIds.Add(toAdd);
|
||||||
generationChannels.Add(channel.Id);
|
_games.GenerationChannels.Add(channel.Id);
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
guildConfig.GenerateCurrencyChannelIds.Remove(toAdd);
|
guildConfig.GenerateCurrencyChannelIds.Remove(toAdd);
|
||||||
generationChannels.TryRemove(channel.Id);
|
_games.GenerationChannels.TryRemove(channel.Id);
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
@ -218,14 +149,6 @@ namespace NadekoBot.Modules.Games
|
|||||||
await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
|
|
||||||
{
|
|
||||||
var rng = new NadekoRandom();
|
|
||||||
var images = NadekoBot.Images.Currency;
|
|
||||||
|
|
||||||
return images[rng.Next(0, images.Length)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ImageSharp.Processing;
|
using ImageSharp.Processing;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
@ -19,6 +20,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
public class PollCommands : NadekoSubmodule
|
public class PollCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public PollCommands(DiscordShardedClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
@ -54,7 +61,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (data.Length < 3)
|
if (data.Length < 3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var poll = new Poll(Context.Message, data[0], data.Skip(1), isPublic: isPublic);
|
var poll = new Poll(_client, _strings, Context.Message, data[0], data.Skip(1), isPublic: isPublic);
|
||||||
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
|
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
|
||||||
{
|
{
|
||||||
await poll.StartPoll().ConfigureAwait(false);
|
await poll.StartPoll().ConfigureAwait(false);
|
||||||
@ -83,10 +90,16 @@ namespace NadekoBot.Modules.Games
|
|||||||
private string[] answers { get; }
|
private string[] answers { get; }
|
||||||
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
|
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
|
||||||
private readonly string _question;
|
private readonly string _question;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
public bool IsPublic { get; }
|
public bool IsPublic { get; }
|
||||||
|
|
||||||
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
public Poll(DiscordShardedClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
||||||
{
|
{
|
||||||
|
_client = client;
|
||||||
|
_strings = strings;
|
||||||
|
|
||||||
_originalMessage = umsg;
|
_originalMessage = umsg;
|
||||||
_guild = ((ITextChannel)umsg.Channel).Guild;
|
_guild = ((ITextChannel)umsg.Channel).Guild;
|
||||||
_question = question;
|
_question = question;
|
||||||
@ -134,7 +147,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public async Task StartPoll()
|
public async Task StartPoll()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += Vote;
|
_client.MessageReceived += Vote;
|
||||||
var msgToSend = GetText("poll_created", Format.Bold(_originalMessage.Author.Username)) + "\n\n" + Format.Bold(_question) + "\n";
|
var msgToSend = GetText("poll_created", Format.Bold(_originalMessage.Author.Username)) + "\n\n" + Format.Bold(_question) + "\n";
|
||||||
var num = 1;
|
var num = 1;
|
||||||
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||||
@ -147,7 +160,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public async Task StopPoll()
|
public async Task StopPoll()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= Vote;
|
_client.MessageReceived -= Vote;
|
||||||
await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,8 +218,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string GetText(string key, params object[] replacements)
|
private string GetText(string key, params object[] replacements)
|
||||||
=> NadekoTopLevelModule.GetTextStatic(key,
|
=> _strings.GetText(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(_guild.Id),
|
_guild.Id,
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,11 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Commands.Models;
|
using NadekoBot.Modules.Games.Models;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services.Games;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -19,145 +16,18 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
public class TypingGame
|
|
||||||
{
|
|
||||||
public const float WORD_VALUE = 4.5f;
|
|
||||||
public ITextChannel Channel { get; }
|
|
||||||
public string CurrentSentence { get; private set; }
|
|
||||||
public bool IsActive { get; private set; }
|
|
||||||
private readonly Stopwatch sw;
|
|
||||||
private readonly List<ulong> finishedUserIds;
|
|
||||||
private Logger _log { get; }
|
|
||||||
|
|
||||||
public TypingGame(ITextChannel channel)
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
this.Channel = channel;
|
|
||||||
IsActive = false;
|
|
||||||
sw = new Stopwatch();
|
|
||||||
finishedUserIds = new List<ulong>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Stop()
|
|
||||||
{
|
|
||||||
if (!IsActive) return false;
|
|
||||||
NadekoBot.Client.MessageReceived -= AnswerReceived;
|
|
||||||
finishedUserIds.Clear();
|
|
||||||
IsActive = false;
|
|
||||||
sw.Stop();
|
|
||||||
sw.Reset();
|
|
||||||
try { await Channel.SendConfirmAsync("Typing contest stopped.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Start()
|
|
||||||
{
|
|
||||||
if (IsActive) return; // can't start running game
|
|
||||||
IsActive = true;
|
|
||||||
CurrentSentence = GetRandomSentence();
|
|
||||||
var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Channel.SendConfirmAsync($@":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.").ConfigureAwait(false);
|
|
||||||
|
|
||||||
|
|
||||||
var msg = await Channel.SendMessageAsync("Starting new typing contest in **3**...").ConfigureAwait(false);
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await msg.ModifyAsync(m => m.Content = "Starting new typing contest in **2**...").ConfigureAwait(false);
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
await msg.ModifyAsync(m => m.Content = "Starting new typing contest in **1**...").ConfigureAwait(false);
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
|
|
||||||
await msg.ModifyAsync(m => m.Content = Format.Bold(Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions())).ConfigureAwait(false);
|
|
||||||
sw.Start();
|
|
||||||
HandleAnswers();
|
|
||||||
|
|
||||||
while (i > 0)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
i--;
|
|
||||||
if (!IsActive)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await Stop().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetRandomSentence()
|
|
||||||
{
|
|
||||||
if (SpeedTypingCommands.TypingArticles.Any())
|
|
||||||
return SpeedTypingCommands.TypingArticles[new NadekoRandom().Next(0, SpeedTypingCommands.TypingArticles.Count)].Text;
|
|
||||||
else
|
|
||||||
return $"No typing articles found. Use {NadekoBot.ModulePrefixes[typeof(Games).Name]}typeadd command to add a new article for typing.";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleAnswers()
|
|
||||||
{
|
|
||||||
NadekoBot.Client.MessageReceived += AnswerReceived;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AnswerReceived(SocketMessage imsg)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (imsg.Author.IsBot)
|
|
||||||
return;
|
|
||||||
var msg = imsg as SocketUserMessage;
|
|
||||||
if (msg == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this.Channel == null || this.Channel.Id != msg.Channel.Id) return;
|
|
||||||
|
|
||||||
var guess = msg.Content;
|
|
||||||
|
|
||||||
var distance = CurrentSentence.LevenshteinDistance(guess);
|
|
||||||
var decision = Judge(distance, guess.Length);
|
|
||||||
if (decision && !finishedUserIds.Contains(msg.Author.Id))
|
|
||||||
{
|
|
||||||
var elapsed = sw.Elapsed;
|
|
||||||
var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
|
|
||||||
finishedUserIds.Add(msg.Author.Id);
|
|
||||||
await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithTitle($"{msg.Author} finished the race!")
|
|
||||||
.AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*").WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true)))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
if (finishedUserIds.Count % 4 == 0)
|
|
||||||
{
|
|
||||||
await this.Channel.SendConfirmAsync($":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Judge(int errors, int textLength) => errors <= textLength / 25;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class SpeedTypingCommands : NadekoSubmodule
|
public class SpeedTypingCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
|
||||||
|
|
||||||
private const string _typingArticlesPath = "data/typing_articles2.json";
|
|
||||||
|
|
||||||
static SpeedTypingCommands()
|
|
||||||
{
|
|
||||||
try { TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(_typingArticlesPath)); } catch { }
|
|
||||||
}
|
|
||||||
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
||||||
|
private readonly GamesService _games;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public SpeedTypingCommands(DiscordShardedClient client, GamesService games)
|
||||||
|
{
|
||||||
|
_games = games;
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -165,7 +35,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(channel));
|
var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel));
|
||||||
|
|
||||||
if (game.IsActive)
|
if (game.IsActive)
|
||||||
{
|
{
|
||||||
@ -202,13 +72,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
TypingArticles.Add(new TypingArticle
|
_games.TypingArticles.Add(new TypingArticle
|
||||||
{
|
{
|
||||||
Title = $"Text added on {DateTime.UtcNow} by {Context.User}",
|
Title = $"Text added on {DateTime.UtcNow} by {Context.User}",
|
||||||
Text = text.SanitizeMentions(),
|
Text = text.SanitizeMentions(),
|
||||||
});
|
});
|
||||||
|
|
||||||
File.WriteAllText(_typingArticlesPath, JsonConvert.SerializeObject(TypingArticles));
|
//todo move this to service
|
||||||
|
File.WriteAllText(_games.TypingArticlesPath, JsonConvert.SerializeObject(_games.TypingArticles));
|
||||||
|
|
||||||
await channel.SendConfirmAsync("Added new article for typing game.").ConfigureAwait(false);
|
await channel.SendConfirmAsync("Added new article for typing game.").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -222,7 +93,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (page < 1)
|
if (page < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var articles = TypingArticles.Skip((page - 1) * 15).Take(15).ToArray();
|
var articles = _games.TypingArticles.Skip((page - 1) * 15).Take(15).ToArray();
|
||||||
|
|
||||||
if (!articles.Any())
|
if (!articles.Any())
|
||||||
{
|
{
|
||||||
@ -242,13 +113,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
index -= 1;
|
index -= 1;
|
||||||
if (index < 0 || index >= TypingArticles.Count)
|
if (index < 0 || index >= _games.TypingArticles.Count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var removed = TypingArticles[index];
|
var removed = _games.TypingArticles[index];
|
||||||
TypingArticles.RemoveAt(index);
|
_games.TypingArticles.RemoveAt(index);
|
||||||
|
|
||||||
File.WriteAllText(_typingArticlesPath, JsonConvert.SerializeObject(TypingArticles));
|
File.WriteAllText(_games.TypingArticlesPath, JsonConvert.SerializeObject(_games.TypingArticles));
|
||||||
|
|
||||||
await channel.SendConfirmAsync($"`Removed typing article:` #{index + 1} - {removed.Text.TrimTo(50)}")
|
await channel.SendConfirmAsync($"`Removed typing article:` #{index + 1} - {removed.Text.TrimTo(50)}")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
@ -1,8 +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 NLog;
|
using NadekoBot.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -20,6 +21,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
||||||
|
|
||||||
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public TicTacToeCommands(DiscordShardedClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -39,7 +46,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
game = new TicTacToe(channel, (IGuildUser)Context.User);
|
game = new TicTacToe(_strings, _client, channel, (IGuildUser)Context.User);
|
||||||
_games.Add(channel.Id, game);
|
_games.Add(channel.Id, game);
|
||||||
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
||||||
|
|
||||||
@ -79,10 +86,15 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
private IUserMessage _previousMessage;
|
private IUserMessage _previousMessage;
|
||||||
private Timer _timeoutTimer;
|
private Timer _timeoutTimer;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
public TicTacToe(ITextChannel channel, IGuildUser firstUser)
|
public TicTacToe(NadekoStrings strings, DiscordShardedClient client, ITextChannel channel, IGuildUser firstUser)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
|
_strings = strings;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
_users = new[] { firstUser, null };
|
_users = new[] { firstUser, null };
|
||||||
_state = new int?[,] {
|
_state = new int?[,] {
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
@ -95,8 +107,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string GetText(string key, params object[] replacements) =>
|
private string GetText(string key, params object[] replacements) =>
|
||||||
NadekoTopLevelModule.GetTextStatic(key,
|
_strings.GetText(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(_channel.GuildId),
|
_channel.GuildId,
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
|
|
||||||
@ -206,7 +218,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
}, null, 15000, Timeout.Infinite);
|
}, null, 15000, Timeout.Infinite);
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
_client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
|
|
||||||
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
||||||
@ -283,14 +295,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
reason = GetText("ttt_matched_three");
|
reason = GetText("ttt_matched_three");
|
||||||
_winner = _users[_curUserIndex];
|
_winner = _users[_curUserIndex];
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
_client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
else if (IsDraw())
|
else if (IsDraw())
|
||||||
{
|
{
|
||||||
reason = GetText("ttt_a_draw");
|
reason = GetText("ttt_a_draw");
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
_client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ using Discord.Net;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -18,6 +19,10 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly BotConfig _bc;
|
||||||
|
private readonly CurrencyHandler _ch;
|
||||||
|
|
||||||
public IGuild Guild { get; }
|
public IGuild Guild { get; }
|
||||||
public ITextChannel Channel { get; }
|
public ITextChannel Channel { get; }
|
||||||
@ -38,9 +43,15 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
|
|
||||||
public int WinRequirement { get; }
|
public int WinRequirement { get; }
|
||||||
|
|
||||||
public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq, bool isPokemon)
|
public TriviaGame(NadekoStrings strings, DiscordShardedClient client, BotConfig bc,
|
||||||
|
CurrencyHandler ch, IGuild guild, ITextChannel channel,
|
||||||
|
bool showHints, int winReq, bool isPokemon)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_strings = strings;
|
||||||
|
_client = client;
|
||||||
|
_bc = bc;
|
||||||
|
_ch = ch;
|
||||||
|
|
||||||
ShowHints = showHints;
|
ShowHints = showHints;
|
||||||
Guild = guild;
|
Guild = guild;
|
||||||
@ -50,8 +61,8 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string GetText(string key, params object[] replacements) =>
|
private string GetText(string key, params object[] replacements) =>
|
||||||
NadekoTopLevelModule.GetTextStatic(key,
|
_strings.GetText(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(Channel.GuildId),
|
Channel.GuildId,
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
|
|
||||||
@ -99,7 +110,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
//receive messages
|
//receive messages
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += PotentialGuess;
|
_client.MessageReceived += PotentialGuess;
|
||||||
|
|
||||||
//allow people to guess
|
//allow people to guess
|
||||||
GameActive = true;
|
GameActive = true;
|
||||||
@ -128,7 +139,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
GameActive = false;
|
GameActive = false;
|
||||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
_client.MessageReceived -= PotentialGuess;
|
||||||
}
|
}
|
||||||
if (!triviaCancelSource.IsCancellationRequested)
|
if (!triviaCancelSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@ -214,9 +225,9 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
var reward = NadekoBot.BotConfig.TriviaCurrencyReward;
|
var reward = _bc.TriviaCurrencyReward;
|
||||||
if (reward > 0)
|
if (reward > 0)
|
||||||
await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
await _ch.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
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.Modules.Games.Trivia;
|
using NadekoBot.Modules.Games.Trivia;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -14,8 +17,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class TriviaCommands : NadekoSubmodule
|
public class TriviaCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly CurrencyHandler _ch;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly BotConfig _bc;
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||||
|
|
||||||
|
public TriviaCommands(DiscordShardedClient client, BotConfig bc, CurrencyHandler ch)
|
||||||
|
{
|
||||||
|
_ch = ch;
|
||||||
|
_client = client;
|
||||||
|
_bc = bc;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task Trivia([Remainder] string additionalArgs = "")
|
public Task Trivia([Remainder] string additionalArgs = "")
|
||||||
@ -35,7 +49,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var showHints = !additionalArgs.Contains("nohint");
|
var showHints = !additionalArgs.Contains("nohint");
|
||||||
var isPokemon = additionalArgs.Contains("pokemon");
|
var isPokemon = additionalArgs.Contains("pokemon");
|
||||||
|
|
||||||
var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq, isPokemon);
|
var trivia = new TriviaGame(_strings, _client, _bc, _ch, channel.Guild, channel, showHints, winReq, isPokemon);
|
||||||
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -14,19 +14,20 @@ using System.Net.Http;
|
|||||||
using ImageSharp;
|
using ImageSharp;
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NadekoBot.Services.Games;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
[NadekoModule("Games", ">")]
|
|
||||||
public partial class Games : NadekoTopLevelModule
|
public partial class Games : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static readonly ImmutableArray<string> _8BallResponses = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray();
|
private readonly GamesService _games;
|
||||||
|
private readonly IImagesService _images;
|
||||||
|
|
||||||
private static readonly Timer _t = new Timer((_) =>
|
public Games(GamesService games, IImagesService images)
|
||||||
{
|
{
|
||||||
_girlRatings.Clear();
|
_games = games;
|
||||||
|
_images = images;
|
||||||
}, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1));
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Choose([Remainder] string list = null)
|
public async Task Choose([Remainder] string list = null)
|
||||||
@ -48,7 +49,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||||
.AddField(efb => efb.WithName("❓ " + GetText("question") ).WithValue(question).WithIsInline(false))
|
.AddField(efb => efb.WithName("❓ " + GetText("question") ).WithValue(question).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("🎱 " + GetText("8ball")).WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
.AddField(efb => efb.WithName("🎱 " + GetText("8ball")).WithValue(_games.EightBallResponses[new NadekoRandom().Next(0, _games.EightBallResponses.Length)]).WithIsInline(false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -94,7 +95,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
else if ((pick == 0 && nadekoPick == 1) ||
|
else if ((pick == 0 && nadekoPick == 1) ||
|
||||||
(pick == 1 && nadekoPick == 2) ||
|
(pick == 1 && nadekoPick == 2) ||
|
||||||
(pick == 2 && nadekoPick == 0))
|
(pick == 2 && nadekoPick == 0))
|
||||||
msg = GetText("rps_win", NadekoBot.Client.CurrentUser.Mention,
|
msg = GetText("rps_win", Context.Client.CurrentUser.Mention,
|
||||||
getRpsPick(nadekoPick), getRpsPick(pick));
|
getRpsPick(nadekoPick), getRpsPick(pick));
|
||||||
else
|
else
|
||||||
msg = GetText("rps_win", Context.User.Mention, getRpsPick(pick),
|
msg = GetText("rps_win", Context.User.Mention, getRpsPick(pick),
|
||||||
@ -103,73 +104,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<ulong, GirlRating> _girlRatings = new ConcurrentDictionary<ulong, GirlRating>();
|
|
||||||
|
|
||||||
public class GirlRating
|
|
||||||
{
|
|
||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
public double Crazy { get; }
|
|
||||||
public double Hot { get; }
|
|
||||||
public int Roll { get; }
|
|
||||||
public string Advice { get; }
|
|
||||||
public AsyncLazy<string> Url { get; }
|
|
||||||
|
|
||||||
public GirlRating(double crazy, double hot, int roll, string advice)
|
|
||||||
{
|
|
||||||
Crazy = crazy;
|
|
||||||
Hot = hot;
|
|
||||||
Roll = roll;
|
|
||||||
Advice = advice; // convenient to have it here, even though atm there are only few different ones.
|
|
||||||
|
|
||||||
Url = new AsyncLazy<string>(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var ms = new MemoryStream(NadekoBot.Images.WifeMatrix.ToArray(), false))
|
|
||||||
using (var img = new ImageSharp.Image(ms))
|
|
||||||
{
|
|
||||||
const int minx = 35;
|
|
||||||
const int miny = 385;
|
|
||||||
const int length = 345;
|
|
||||||
|
|
||||||
var pointx = (int)(minx + length * (Hot / 10));
|
|
||||||
var pointy = (int)(miny - length * ((Crazy - 4) / 6));
|
|
||||||
|
|
||||||
using (var pointMs = new MemoryStream(NadekoBot.Images.RategirlDot.ToArray(), false))
|
|
||||||
using (var pointImg = new ImageSharp.Image(pointMs))
|
|
||||||
{
|
|
||||||
img.DrawImage(pointImg, 100, default(Size), new Point(pointx - 10, pointy - 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
string url;
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
using (var imgStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
img.Save(imgStream);
|
|
||||||
var byteContent = new ByteArrayContent(imgStream.ToArray());
|
|
||||||
http.AddFakeHeaders();
|
|
||||||
|
|
||||||
var reponse = await http.PutAsync("https://transfer.sh/img.png", byteContent);
|
|
||||||
url = await reponse.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn(ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task RateGirl(IGuildUser usr)
|
public async Task RateGirl(IGuildUser usr)
|
||||||
{
|
{
|
||||||
var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl);
|
var gr = _games.GirlRatings.GetOrAdd(usr.Id, GetGirl);
|
||||||
var img = await gr.Url;
|
var img = await gr.Url;
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Girl Rating For " + usr)
|
.WithTitle("Girl Rating For " + usr)
|
||||||
@ -255,7 +195,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
"and maybe look at how to replicate that.";
|
"and maybe look at how to replicate that.";
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GirlRating(crazy, hot, roll, advice);
|
return new GirlRating(_images, crazy, hot, roll, advice);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -1,184 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
|
||||||
{
|
|
||||||
public class GoogleTranslator
|
|
||||||
{
|
|
||||||
private static GoogleTranslator _instance;
|
|
||||||
public static GoogleTranslator Instance = _instance ?? (_instance = new GoogleTranslator());
|
|
||||||
|
|
||||||
public IEnumerable<string> Languages => _languageDictionary.Keys.OrderBy(x => x);
|
|
||||||
private readonly Dictionary<string, string> _languageDictionary;
|
|
||||||
|
|
||||||
static GoogleTranslator() { }
|
|
||||||
private GoogleTranslator() {
|
|
||||||
_languageDictionary = new Dictionary<string, string>() {
|
|
||||||
{ "afrikaans", "af"},
|
|
||||||
{ "albanian", "sq"},
|
|
||||||
{ "arabic", "ar"},
|
|
||||||
{ "armenian", "hy"},
|
|
||||||
{ "azerbaijani", "az"},
|
|
||||||
{ "basque", "eu"},
|
|
||||||
{ "belarusian", "be"},
|
|
||||||
{ "bengali", "bn"},
|
|
||||||
{ "bulgarian", "bg"},
|
|
||||||
{ "catalan", "ca"},
|
|
||||||
{ "chinese-traditional", "zh-TW"},
|
|
||||||
{ "chinese-simplified", "zh-CN"},
|
|
||||||
{ "chinese", "zh-CN"},
|
|
||||||
{ "croatian", "hr"},
|
|
||||||
{ "czech", "cs"},
|
|
||||||
{ "danish", "da"},
|
|
||||||
{ "dutch", "nl"},
|
|
||||||
{ "english", "en"},
|
|
||||||
{ "esperanto", "eo"},
|
|
||||||
{ "estonian", "et"},
|
|
||||||
{ "filipino", "tl"},
|
|
||||||
{ "finnish", "fi"},
|
|
||||||
{ "french", "fr"},
|
|
||||||
{ "galician", "gl"},
|
|
||||||
{ "german", "de"},
|
|
||||||
{ "georgian", "ka"},
|
|
||||||
{ "greek", "el"},
|
|
||||||
{ "haitian Creole", "ht"},
|
|
||||||
{ "hebrew", "iw"},
|
|
||||||
{ "hindi", "hi"},
|
|
||||||
{ "hungarian", "hu"},
|
|
||||||
{ "icelandic", "is"},
|
|
||||||
{ "indonesian", "id"},
|
|
||||||
{ "irish", "ga"},
|
|
||||||
{ "italian", "it"},
|
|
||||||
{ "japanese", "ja"},
|
|
||||||
{ "korean", "ko"},
|
|
||||||
{ "lao", "lo"},
|
|
||||||
{ "latin", "la"},
|
|
||||||
{ "latvian", "lv"},
|
|
||||||
{ "lithuanian", "lt"},
|
|
||||||
{ "macedonian", "mk"},
|
|
||||||
{ "malay", "ms"},
|
|
||||||
{ "maltese", "mt"},
|
|
||||||
{ "norwegian", "no"},
|
|
||||||
{ "persian", "fa"},
|
|
||||||
{ "polish", "pl"},
|
|
||||||
{ "portuguese", "pt"},
|
|
||||||
{ "romanian", "ro"},
|
|
||||||
{ "russian", "ru"},
|
|
||||||
{ "serbian", "sr"},
|
|
||||||
{ "slovak", "sk"},
|
|
||||||
{ "slovenian", "sl"},
|
|
||||||
{ "spanish", "es"},
|
|
||||||
{ "swahili", "sw"},
|
|
||||||
{ "swedish", "sv"},
|
|
||||||
{ "tamil", "ta"},
|
|
||||||
{ "telugu", "te"},
|
|
||||||
{ "thai", "th"},
|
|
||||||
{ "turkish", "tr"},
|
|
||||||
{ "ukrainian", "uk"},
|
|
||||||
{ "urdu", "ur"},
|
|
||||||
{ "vietnamese", "vi"},
|
|
||||||
{ "welsh", "cy"},
|
|
||||||
{ "yiddish", "yi"},
|
|
||||||
|
|
||||||
{ "af", "af"},
|
|
||||||
{ "sq", "sq"},
|
|
||||||
{ "ar", "ar"},
|
|
||||||
{ "hy", "hy"},
|
|
||||||
{ "az", "az"},
|
|
||||||
{ "eu", "eu"},
|
|
||||||
{ "be", "be"},
|
|
||||||
{ "bn", "bn"},
|
|
||||||
{ "bg", "bg"},
|
|
||||||
{ "ca", "ca"},
|
|
||||||
{ "zh-tw", "zh-TW"},
|
|
||||||
{ "zh-cn", "zh-CN"},
|
|
||||||
{ "hr", "hr"},
|
|
||||||
{ "cs", "cs"},
|
|
||||||
{ "da", "da"},
|
|
||||||
{ "nl", "nl"},
|
|
||||||
{ "en", "en"},
|
|
||||||
{ "eo", "eo"},
|
|
||||||
{ "et", "et"},
|
|
||||||
{ "tl", "tl"},
|
|
||||||
{ "fi", "fi"},
|
|
||||||
{ "fr", "fr"},
|
|
||||||
{ "gl", "gl"},
|
|
||||||
{ "de", "de"},
|
|
||||||
{ "ka", "ka"},
|
|
||||||
{ "el", "el"},
|
|
||||||
{ "ht", "ht"},
|
|
||||||
{ "iw", "iw"},
|
|
||||||
{ "hi", "hi"},
|
|
||||||
{ "hu", "hu"},
|
|
||||||
{ "is", "is"},
|
|
||||||
{ "id", "id"},
|
|
||||||
{ "ga", "ga"},
|
|
||||||
{ "it", "it"},
|
|
||||||
{ "ja", "ja"},
|
|
||||||
{ "ko", "ko"},
|
|
||||||
{ "lo", "lo"},
|
|
||||||
{ "la", "la"},
|
|
||||||
{ "lv", "lv"},
|
|
||||||
{ "lt", "lt"},
|
|
||||||
{ "mk", "mk"},
|
|
||||||
{ "ms", "ms"},
|
|
||||||
{ "mt", "mt"},
|
|
||||||
{ "no", "no"},
|
|
||||||
{ "fa", "fa"},
|
|
||||||
{ "pl", "pl"},
|
|
||||||
{ "pt", "pt"},
|
|
||||||
{ "ro", "ro"},
|
|
||||||
{ "ru", "ru"},
|
|
||||||
{ "sr", "sr"},
|
|
||||||
{ "sk", "sk"},
|
|
||||||
{ "sl", "sl"},
|
|
||||||
{ "es", "es"},
|
|
||||||
{ "sw", "sw"},
|
|
||||||
{ "sv", "sv"},
|
|
||||||
{ "ta", "ta"},
|
|
||||||
{ "te", "te"},
|
|
||||||
{ "th", "th"},
|
|
||||||
{ "tr", "tr"},
|
|
||||||
{ "uk", "uk"},
|
|
||||||
{ "ur", "ur"},
|
|
||||||
{ "vi", "vi"},
|
|
||||||
{ "cy", "cy"},
|
|
||||||
{ "yi", "yi"},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage)
|
|
||||||
{
|
|
||||||
string text;
|
|
||||||
|
|
||||||
if(!_languageDictionary.ContainsKey(sourceLanguage) ||
|
|
||||||
!_languageDictionary.ContainsKey(targetLanguage))
|
|
||||||
throw new ArgumentException();
|
|
||||||
|
|
||||||
|
|
||||||
var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
|
||||||
ConvertToLanguageCode(sourceLanguage),
|
|
||||||
ConvertToLanguageCode(targetLanguage),
|
|
||||||
WebUtility.UrlEncode(sourceText));
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
|
||||||
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string.Concat(JArray.Parse(text)[0].Select(x => x[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ConvertToLanguageCode(string language)
|
|
||||||
{
|
|
||||||
string mode;
|
|
||||||
_languageDictionary.TryGetValue(language, out mode);
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Searches.Models;
|
using NadekoBot.Modules.Searches.Models;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
@ -19,27 +20,11 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[Group]
|
[Group]
|
||||||
public class JokeCommands : NadekoSubmodule
|
public class JokeCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static List<WoWJoke> wowJokes { get; } = new List<WoWJoke>();
|
private readonly SearchesService _searches;
|
||||||
private static List<MagicItem> magicItems { get; } = new List<MagicItem>();
|
|
||||||
private new static readonly Logger _log;
|
|
||||||
|
|
||||||
static JokeCommands()
|
public JokeCommands(SearchesService searches)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_searches = searches;
|
||||||
|
|
||||||
if (File.Exists("data/wowjokes.json"))
|
|
||||||
{
|
|
||||||
wowJokes = JsonConvert.DeserializeObject<List<WoWJoke>>(File.ReadAllText("data/wowjokes.json"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_log.Warn("data/wowjokes.json is missing. WOW Jokes are not loaded.");
|
|
||||||
|
|
||||||
if (File.Exists("data/magicitems.json"))
|
|
||||||
{
|
|
||||||
magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_log.Warn("data/magicitems.json is missing. Magic items are not loaded.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -75,24 +60,24 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task WowJoke()
|
public async Task WowJoke()
|
||||||
{
|
{
|
||||||
if (!wowJokes.Any())
|
if (!_searches.WowJokes.Any())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("jokes_not_loaded").ConfigureAwait(false);
|
await ReplyErrorLocalized("jokes_not_loaded").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var joke = wowJokes[new NadekoRandom().Next(0, wowJokes.Count)];
|
var joke = _searches.WowJokes[new NadekoRandom().Next(0, _searches.WowJokes.Count)];
|
||||||
await Context.Channel.SendConfirmAsync(joke.Question, joke.Answer).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(joke.Question, joke.Answer).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task MagicItem()
|
public async Task MagicItem()
|
||||||
{
|
{
|
||||||
if (!wowJokes.Any())
|
if (!_searches.WowJokes.Any())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("magicitems_not_loaded").ConfigureAwait(false);
|
await ReplyErrorLocalized("magicitems_not_loaded").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var item = magicItems[new NadekoRandom().Next(0, magicItems.Count)];
|
var item = _searches.MagicItems[new NadekoRandom().Next(0, _searches.MagicItems.Count)];
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("✨" + item.Name, item.Description).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("✨" + item.Name, item.Description).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
obj["name"].GetHashCode();
|
obj["name"].GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] trashTalk { get; } = { "Better ban your counters. You are going to carry the game anyway.",
|
private static readonly string[] trashTalk = { "Better ban your counters. You are going to carry the game anyway.",
|
||||||
"Go with the flow. Don't think. Just ban one of these.",
|
"Go with the flow. Don't think. Just ban one of these.",
|
||||||
"DONT READ BELOW! Ban Urgot mid OP 100%. Im smurf Diamond 1.",
|
"DONT READ BELOW! Ban Urgot mid OP 100%. Im smurf Diamond 1.",
|
||||||
"Ask your teammates what would they like to play, and ban that.",
|
"Ask your teammates what would they like to play, and ban that.",
|
||||||
@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var data = JObject.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/champs/mostBanned?" +
|
var data = JObject.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/champs/mostBanned?" +
|
||||||
$"api_key={NadekoBot.Credentials.LoLApiKey}&page=1&" +
|
$"api_key={_creds.LoLApiKey}&page=1&" +
|
||||||
$"limit={showCount}")
|
$"limit={showCount}")
|
||||||
.ConfigureAwait(false))["data"] as JArray;
|
.ConfigureAwait(false))["data"] as JArray;
|
||||||
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
||||||
@ -127,7 +127,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
// await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
// await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// var allData = JArray.Parse(await Classes.http.GetStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Credentials.LOLAPIKey}").ConfigureAwait(false));
|
// var allData = JArray.Parse(await Classes.http.GetStringAsync($"http://api.champion.gg/champion/{name}?api_key={_creds.LOLAPIKey}").ConfigureAwait(false));
|
||||||
// JToken data = null;
|
// JToken data = null;
|
||||||
// if (role != null)
|
// if (role != null)
|
||||||
// {
|
// {
|
||||||
@ -168,7 +168,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
// roles[i] = ">" + roles[i] + "<";
|
// roles[i] = ">" + roles[i] + "<";
|
||||||
// }
|
// }
|
||||||
// var general = JArray.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/" +
|
// var general = JArray.Parse(await http.GetStringAsync($"http://api.champion.gg/stats/" +
|
||||||
// $"champs/{name}?api_key={NadekoBot.Credentials.LOLAPIKey}")
|
// $"champs/{name}?api_key={_creds.LOLAPIKey}")
|
||||||
// .ConfigureAwait(false))
|
// .ConfigureAwait(false))
|
||||||
// .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
// .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
|
||||||
// if (general == null)
|
// if (general == null)
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
using NadekoBot.Extensions;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches.Models
|
|
||||||
{
|
|
||||||
public class ImdbMovie
|
|
||||||
{
|
|
||||||
public bool Status { get; set; }
|
|
||||||
public string Id { get; set; }
|
|
||||||
public string Title { get; set; }
|
|
||||||
public string OriginalTitle { get; set; }
|
|
||||||
public string Year { get; set; }
|
|
||||||
public string Rating { get; set; }
|
|
||||||
public string Plot { get; set; }
|
|
||||||
public string Poster { get; set; }
|
|
||||||
public List<string> Genres { get; set; }
|
|
||||||
public string ImdbURL { get; set; }
|
|
||||||
|
|
||||||
public Dictionary<string, string> Aka { get; set; }
|
|
||||||
|
|
||||||
public override string ToString() =>
|
|
||||||
$@"`Title:` {WebUtility.HtmlDecode(Title)} {(string.IsNullOrEmpty(OriginalTitle) ? "" : $"({OriginalTitle})")}
|
|
||||||
`Year:` {Year}
|
|
||||||
`Rating:` {Rating}
|
|
||||||
`Genre:` {GenresAsString}
|
|
||||||
`Link:` <{ImdbURL}>
|
|
||||||
`Plot:` {System.Net.WebUtility.HtmlDecode(Plot.TrimTo(500))}
|
|
||||||
`Poster:` " + NadekoBot.Google.ShortenUrl(Poster).GetAwaiter().GetResult();
|
|
||||||
public string GenresAsString =>
|
|
||||||
string.Join(", ", Genres);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.API;
|
using Discord.API;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -12,7 +13,7 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB
|
|||||||
{
|
{
|
||||||
private const string queryUrl = "http://www.omdbapi.com/?t={0}&y=&plot=full&r=json";
|
private const string queryUrl = "http://www.omdbapi.com/?t={0}&y=&plot=full&r=json";
|
||||||
|
|
||||||
public static async Task<OmdbMovie> FindMovie(string name)
|
public static async Task<OmdbMovie> FindMovie(string name, IGoogleApiService google)
|
||||||
{
|
{
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
@ -20,7 +21,7 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB
|
|||||||
var movie = JsonConvert.DeserializeObject<OmdbMovie>(res);
|
var movie = JsonConvert.DeserializeObject<OmdbMovie>(res);
|
||||||
if (movie?.Title == null)
|
if (movie?.Title == null)
|
||||||
return null;
|
return null;
|
||||||
movie.Poster = await NadekoBot.Google.ShortenUrl(movie.Poster);
|
movie.Poster = await google.ShortenUrl(movie.Poster);
|
||||||
return movie;
|
return movie;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@ -17,6 +18,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[Group]
|
[Group]
|
||||||
public class OsuCommands : NadekoSubmodule
|
public class OsuCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly IGoogleApiService _google;
|
||||||
|
private readonly IBotCredentials _creds;
|
||||||
|
|
||||||
|
public OsuCommands(IGoogleApiService google, IBotCredentials creds)
|
||||||
|
{
|
||||||
|
_google = google;
|
||||||
|
_creds = creds;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Osu(string usr, [Remainder] string mode = null)
|
public async Task Osu(string usr, [Remainder] string mode = null)
|
||||||
{
|
{
|
||||||
@ -51,7 +61,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Osub([Remainder] string map)
|
public async Task Osub([Remainder] string map)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
|
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("osu_api_key").ConfigureAwait(false);
|
await ReplyErrorLocalized("osu_api_key").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -65,7 +75,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var mapId = ResolveMap(map);
|
var mapId = ResolveMap(map);
|
||||||
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&{mapId}";
|
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={_creds.OsuApiKey}&{mapId}";
|
||||||
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0];
|
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0];
|
||||||
var sb = new System.Text.StringBuilder();
|
var sb = new System.Text.StringBuilder();
|
||||||
var starRating = Math.Round(double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2);
|
var starRating = Math.Round(double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2);
|
||||||
@ -86,7 +96,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public async Task Osu5(string user, [Remainder] string mode = null)
|
public async Task Osu5(string user, [Remainder] string mode = null)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
|
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("An osu! API key is required.").ConfigureAwait(false);
|
await channel.SendErrorAsync("An osu! API key is required.").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -107,12 +117,12 @@ namespace NadekoBot.Modules.Searches
|
|||||||
m = ResolveGameMode(mode);
|
m = ResolveGameMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var reqString = $"https://osu.ppy.sh/api/get_user_best?k={NadekoBot.Credentials.OsuApiKey}&u={Uri.EscapeDataString(user)}&type=string&limit=5&m={m}";
|
var reqString = $"https://osu.ppy.sh/api/get_user_best?k={_creds.OsuApiKey}&u={Uri.EscapeDataString(user)}&type=string&limit=5&m={m}";
|
||||||
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false));
|
||||||
var sb = new System.Text.StringBuilder($"`Top 5 plays for {user}:`\n```xl" + Environment.NewLine);
|
var sb = new System.Text.StringBuilder($"`Top 5 plays for {user}:`\n```xl" + Environment.NewLine);
|
||||||
foreach (var item in obj)
|
foreach (var item in obj)
|
||||||
{
|
{
|
||||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&b={item["beatmap_id"]}";
|
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={_creds.OsuApiKey}&b={item["beatmap_id"]}";
|
||||||
var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0];
|
var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0];
|
||||||
var pp = Math.Round(double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2);
|
var pp = Math.Round(double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2);
|
||||||
var acc = CalculateAcc(item, m);
|
var acc = CalculateAcc(item, m);
|
||||||
|
@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Placelist()
|
public async Task Placelist()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.ModulePrefixes[typeof(Searches).Name]),
|
await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.Prefix),
|
||||||
typesStr)
|
typesStr)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Searches.Models;
|
using NadekoBot.Modules.Searches.Models;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -17,28 +18,14 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[Group]
|
[Group]
|
||||||
public class PokemonSearchCommands : NadekoSubmodule
|
public class PokemonSearchCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Dictionary<string, SearchPokemon> pokemons { get; } = new Dictionary<string, SearchPokemon>();
|
private readonly SearchesService _searches;
|
||||||
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities { get; } = new Dictionary<string, SearchPokemonAbility>();
|
|
||||||
|
|
||||||
public const string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json";
|
public Dictionary<string, SearchPokemon> Pokemons => _searches.Pokemons;
|
||||||
|
public Dictionary<string, SearchPokemonAbility> PokemonAbilities => _searches.PokemonAbilities;
|
||||||
|
|
||||||
public const string PokemonListFile = "data/pokemon/pokemon_list7.json";
|
public PokemonSearchCommands(SearchesService searches)
|
||||||
private new static readonly Logger _log;
|
|
||||||
|
|
||||||
static PokemonSearchCommands()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_searches = searches;
|
||||||
|
|
||||||
if (File.Exists(PokemonListFile))
|
|
||||||
{
|
|
||||||
pokemons = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemon>>(File.ReadAllText(PokemonListFile));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_log.Warn(PokemonListFile + " is missing. Pokemon abilities not loaded.");
|
|
||||||
if (File.Exists(PokemonAbilitiesFile))
|
|
||||||
pokemonAbilities = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemonAbility>>(File.ReadAllText(PokemonAbilitiesFile));
|
|
||||||
else
|
|
||||||
_log.Warn(PokemonAbilitiesFile + " is missing. Pokemon abilities not loaded.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -48,7 +35,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (string.IsNullOrWhiteSpace(pokemon))
|
if (string.IsNullOrWhiteSpace(pokemon))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var kvp in pokemons)
|
foreach (var kvp in Pokemons)
|
||||||
{
|
{
|
||||||
if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant())
|
if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant())
|
||||||
{
|
{
|
||||||
@ -71,7 +58,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
ability = ability?.Trim().ToUpperInvariant().Replace(" ", "");
|
ability = ability?.Trim().ToUpperInvariant().Replace(" ", "");
|
||||||
if (string.IsNullOrWhiteSpace(ability))
|
if (string.IsNullOrWhiteSpace(ability))
|
||||||
return;
|
return;
|
||||||
foreach (var kvp in pokemonAbilities)
|
foreach (var kvp in PokemonAbilities)
|
||||||
{
|
{
|
||||||
if (kvp.Key.ToUpperInvariant() == ability)
|
if (kvp.Key.ToUpperInvariant() == ability)
|
||||||
{
|
{
|
||||||
|
@ -1,195 +1,30 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord;
|
using Discord;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Net.Http;
|
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
public class StreamStatus
|
|
||||||
{
|
|
||||||
public bool IsLive { get; set; }
|
|
||||||
public string ApiLink { get; set; }
|
|
||||||
public string Views { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HitboxResponse {
|
|
||||||
public bool Success { get; set; } = true;
|
|
||||||
[JsonProperty("media_is_live")]
|
|
||||||
public string MediaIsLive { get; set; }
|
|
||||||
public bool IsLive => MediaIsLive == "1";
|
|
||||||
[JsonProperty("media_views")]
|
|
||||||
public string Views { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TwitchResponse
|
|
||||||
{
|
|
||||||
public string Error { get; set; } = null;
|
|
||||||
public bool IsLive => Stream != null;
|
|
||||||
public StreamInfo Stream { get; set; }
|
|
||||||
|
|
||||||
public class StreamInfo
|
|
||||||
{
|
|
||||||
public int Viewers { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BeamResponse
|
|
||||||
{
|
|
||||||
public string Error { get; set; } = null;
|
|
||||||
|
|
||||||
[JsonProperty("online")]
|
|
||||||
public bool IsLive { get; set; }
|
|
||||||
public int ViewersCurrent { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StreamNotFoundException : Exception
|
|
||||||
{
|
|
||||||
public StreamNotFoundException(string message) : base("Stream '" + message + "' not found.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class StreamNotificationCommands : NadekoSubmodule
|
public class StreamNotificationCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static readonly Timer _checkTimer;
|
private readonly DbHandler _db;
|
||||||
private static readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
private readonly StreamNotificationService _service;
|
||||||
|
|
||||||
private static bool firstPass { get; set; } = true;
|
public StreamNotificationCommands(DbHandler db, StreamNotificationService service)
|
||||||
|
|
||||||
static StreamNotificationCommands()
|
|
||||||
{
|
{
|
||||||
_checkTimer = new Timer(async (state) =>
|
_db = db;
|
||||||
{
|
_service = service;
|
||||||
var oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(_cachedStatuses);
|
|
||||||
_cachedStatuses.Clear();
|
|
||||||
IEnumerable<FollowedStream> streams;
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
streams = uow.GuildConfigs.GetAllFollowedStreams();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.WhenAll(streams.Select(async fs =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
|
|
||||||
if (firstPass)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamStatus oldStatus;
|
|
||||||
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
|
|
||||||
oldStatus.IsLive != newStatus.IsLive)
|
|
||||||
{
|
|
||||||
var server = NadekoBot.Client.GetGuild(fs.GuildId);
|
|
||||||
var channel = server?.GetTextChannel(fs.ChannelId);
|
|
||||||
if (channel == null)
|
|
||||||
return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await channel.EmbedAsync(fs.GetEmbed(newStatus, channel.Guild.Id)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
firstPass = false;
|
|
||||||
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
|
|
||||||
{
|
|
||||||
string response;
|
|
||||||
StreamStatus result;
|
|
||||||
switch (stream.Type)
|
|
||||||
{
|
|
||||||
case FollowedStream.FollowedStreamType.Hitbox:
|
|
||||||
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
|
|
||||||
if (checkCache && _cachedStatuses.TryGetValue(hitboxUrl, out result))
|
|
||||||
return result;
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
|
|
||||||
if (!hbData.Success)
|
|
||||||
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
|
||||||
result = new StreamStatus()
|
|
||||||
{
|
|
||||||
IsLive = hbData.IsLive,
|
|
||||||
ApiLink = hitboxUrl,
|
|
||||||
Views = hbData.Views
|
|
||||||
};
|
|
||||||
_cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
|
|
||||||
return result;
|
|
||||||
case FollowedStream.FollowedStreamType.Twitch:
|
|
||||||
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
|
|
||||||
if (checkCache && _cachedStatuses.TryGetValue(twitchUrl, out result))
|
|
||||||
return result;
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
|
|
||||||
if (twData.Error != null)
|
|
||||||
{
|
|
||||||
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
|
||||||
}
|
|
||||||
result = new StreamStatus()
|
|
||||||
{
|
|
||||||
IsLive = twData.IsLive,
|
|
||||||
ApiLink = twitchUrl,
|
|
||||||
Views = twData.Stream?.Viewers.ToString() ?? "0"
|
|
||||||
};
|
|
||||||
_cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
|
|
||||||
return result;
|
|
||||||
case FollowedStream.FollowedStreamType.Beam:
|
|
||||||
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
|
|
||||||
if (checkCache && _cachedStatuses.TryGetValue(beamUrl, out result))
|
|
||||||
return result;
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
|
|
||||||
if (bmData.Error != null)
|
|
||||||
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
|
||||||
result = new StreamStatus()
|
|
||||||
{
|
|
||||||
IsLive = bmData.IsLive,
|
|
||||||
ApiLink = beamUrl,
|
|
||||||
Views = bmData.ViewersCurrent.ToString()
|
|
||||||
};
|
|
||||||
_cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
|
|
||||||
return result;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -218,7 +53,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public async Task ListStreams()
|
public async Task ListStreams()
|
||||||
{
|
{
|
||||||
IEnumerable<FollowedStream> streams;
|
IEnumerable<FollowedStream> streams;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
streams = uow.GuildConfigs
|
streams = uow.GuildConfigs
|
||||||
.For(Context.Guild.Id,
|
.For(Context.Guild.Id,
|
||||||
@ -260,7 +95,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool removed;
|
bool removed;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.FollowedStreams));
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.FollowedStreams));
|
||||||
removed = config.FollowedStreams.Remove(fs);
|
removed = config.FollowedStreams.Remove(fs);
|
||||||
@ -287,7 +122,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var streamStatus = (await GetStreamStatus(new FollowedStream
|
var streamStatus = (await _service.GetStreamStatus(new FollowedStream
|
||||||
{
|
{
|
||||||
Username = stream,
|
Username = stream,
|
||||||
Type = platform,
|
Type = platform,
|
||||||
@ -325,7 +160,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
StreamStatus status;
|
StreamStatus status;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
status = await GetStreamStatus(fs).ConfigureAwait(false);
|
status = await _service.GetStreamStatus(fs).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -333,53 +168,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams))
|
uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams))
|
||||||
.FollowedStreams
|
.FollowedStreams
|
||||||
.Add(fs);
|
.Add(fs);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await channel.EmbedAsync(fs.GetEmbed(status, Context.Guild.Id), GetText("stream_tracked")).ConfigureAwait(false);
|
await channel.EmbedAsync(_service.GetEmbed(fs, status, Context.Guild.Id), GetText("stream_tracked")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FollowedStreamExtensions
|
|
||||||
{
|
|
||||||
public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status, ulong guildId)
|
|
||||||
{
|
|
||||||
var embed = new EmbedBuilder().WithTitle(fs.Username)
|
|
||||||
.WithUrl(fs.GetLink())
|
|
||||||
.AddField(efb => efb.WithName(fs.GetText("status"))
|
|
||||||
.WithValue(status.IsLive ? "Online" : "Offline")
|
|
||||||
.WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName(fs.GetText("viewers"))
|
|
||||||
.WithValue(status.IsLive ? status.Views : "-")
|
|
||||||
.WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName(fs.GetText("platform"))
|
|
||||||
.WithValue(fs.Type.ToString())
|
|
||||||
.WithIsInline(true))
|
|
||||||
.WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor);
|
|
||||||
|
|
||||||
return embed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetText(this FollowedStream fs, string key, params object[] replacements) =>
|
|
||||||
NadekoTopLevelModule.GetTextStatic(key,
|
|
||||||
NadekoBot.Localization.GetCultureInfo(fs.GuildId),
|
|
||||||
typeof(Searches).Name.ToLowerInvariant(),
|
|
||||||
replacements);
|
|
||||||
|
|
||||||
public static string GetLink(this FollowedStream fs)
|
|
||||||
{
|
|
||||||
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
|
|
||||||
return $"http://www.hitbox.tv/{fs.Username}/";
|
|
||||||
if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
|
|
||||||
return $"http://www.twitch.tv/{fs.Username}/";
|
|
||||||
if (fs.Type == FollowedStream.FollowedStreamType.Beam)
|
|
||||||
return $"https://beam.pro/{fs.Username}/";
|
|
||||||
return "??";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,54 +7,23 @@ using System.Threading.Tasks;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
public struct UserChannelPair
|
|
||||||
{
|
|
||||||
public ulong UserId { get; set; }
|
|
||||||
public ulong ChannelId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class TranslateCommands : NadekoSubmodule
|
public class TranslateCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, bool> translatedChannels { get; } = new ConcurrentDictionary<ulong, bool>();
|
private readonly SearchesService _searches;
|
||||||
private static ConcurrentDictionary<UserChannelPair, string> userLanguages { get; } = new ConcurrentDictionary<UserChannelPair, string>();
|
private readonly IGoogleApiService _google;
|
||||||
|
|
||||||
static TranslateCommands()
|
public TranslateCommands(SearchesService searches, IGoogleApiService google)
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += async (msg) =>
|
_searches = searches;
|
||||||
{
|
_google = google;
|
||||||
try
|
|
||||||
{
|
|
||||||
var umsg = msg as SocketUserMessage;
|
|
||||||
if (umsg == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool autoDelete;
|
|
||||||
if (!translatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete))
|
|
||||||
return;
|
|
||||||
var key = new UserChannelPair()
|
|
||||||
{
|
|
||||||
UserId = umsg.Author.Id,
|
|
||||||
ChannelId = umsg.Channel.Id,
|
|
||||||
};
|
|
||||||
|
|
||||||
string langs;
|
|
||||||
if (!userLanguages.TryGetValue(key, out langs))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
if (autoDelete)
|
|
||||||
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
|
||||||
await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -63,7 +32,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
var translation = await TranslateInternal(langs, text);
|
var translation = await _searches.Translate(langs, text);
|
||||||
await Context.Channel.SendConfirmAsync(GetText("translation") + " " + langs, translation).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("translation") + " " + langs, translation).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -72,19 +41,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> TranslateInternal(string langs, [Remainder] string text = null)
|
|
||||||
{
|
|
||||||
var langarr = langs.ToLowerInvariant().Split('>');
|
|
||||||
if (langarr.Length != 2)
|
|
||||||
throw new ArgumentException();
|
|
||||||
var from = langarr[0];
|
|
||||||
var to = langarr[1];
|
|
||||||
text = text?.Trim();
|
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
|
||||||
throw new ArgumentException();
|
|
||||||
return (await GoogleTranslator.Instance.Translate(text, from, to).ConfigureAwait(false)).SanitizeMentions();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AutoDeleteAutoTranslate
|
public enum AutoDeleteAutoTranslate
|
||||||
{
|
{
|
||||||
Del,
|
Del,
|
||||||
@ -101,18 +57,17 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (autoDelete == AutoDeleteAutoTranslate.Del)
|
if (autoDelete == AutoDeleteAutoTranslate.Del)
|
||||||
{
|
{
|
||||||
translatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true);
|
_searches.TranslatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true);
|
||||||
await ReplyConfirmLocalized("atl_ad_started").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_ad_started").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool throwaway;
|
if (_searches.TranslatedChannels.TryRemove(channel.Id, out var throwaway))
|
||||||
if (translatedChannels.TryRemove(channel.Id, out throwaway))
|
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("atl_stopped").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_stopped").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (translatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del))
|
if (_searches.TranslatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del))
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("atl_started").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_started").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -130,7 +85,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(langs))
|
if (string.IsNullOrWhiteSpace(langs))
|
||||||
{
|
{
|
||||||
if (userLanguages.TryRemove(ucp, out langs))
|
if (_searches.UserLanguages.TryRemove(ucp, out langs))
|
||||||
await ReplyConfirmLocalized("atl_removed").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_removed").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,13 +96,13 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var from = langarr[0];
|
var from = langarr[0];
|
||||||
var to = langarr[1];
|
var to = langarr[1];
|
||||||
|
|
||||||
if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
|
if (!_google.Languages.Contains(from) || !_google.Languages.Contains(to))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("invalid_lang").ConfigureAwait(false);
|
await ReplyErrorLocalized("invalid_lang").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
userLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
_searches.UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
||||||
|
|
||||||
await ReplyConfirmLocalized("atl_set", from, to).ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_set", from, to).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -156,7 +111,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Translangs()
|
public async Task Translangs()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", 3);
|
await Context.Channel.SendTableAsync(_google.Languages, str => $"{str,-15}", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ using Newtonsoft.Json;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -17,18 +16,27 @@ using NadekoBot.Modules.Searches.Commands.Models;
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom.Html;
|
using AngleSharp.Dom.Html;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using System.Xml;
|
|
||||||
using Configuration = AngleSharp.Configuration;
|
using Configuration = AngleSharp.Configuration;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using ImageSharp.Processing.Processors;
|
|
||||||
using ImageSharp;
|
using ImageSharp;
|
||||||
|
using NadekoBot.Services.Searches;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
[NadekoModule("Searches", "~")]
|
|
||||||
public partial class Searches : NadekoTopLevelModule
|
public partial class Searches : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
|
private readonly IBotCredentials _creds;
|
||||||
|
private readonly IGoogleApiService _google;
|
||||||
|
private readonly SearchesService _searches;
|
||||||
|
|
||||||
|
public Searches(IBotCredentials creds, IGoogleApiService google, SearchesService searches)
|
||||||
|
{
|
||||||
|
_creds = creds;
|
||||||
|
_google = google;
|
||||||
|
_searches = searches;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Weather([Remainder] string query)
|
public async Task Weather([Remainder] string query)
|
||||||
{
|
{
|
||||||
@ -59,16 +67,16 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Time([Remainder] string arg)
|
public async Task Time([Remainder] string arg)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(arg) || string.IsNullOrWhiteSpace(NadekoBot.Credentials.GoogleApiKey))
|
if (string.IsNullOrWhiteSpace(arg) || string.IsNullOrWhiteSpace(_creds.GoogleApiKey))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var res = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/geocode/json?address={arg}&key={NadekoBot.Credentials.GoogleApiKey}").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/geocode/json?address={arg}&key={_creds.GoogleApiKey}").ConfigureAwait(false);
|
||||||
var obj = JsonConvert.DeserializeObject<GeolocationResult>(res);
|
var obj = JsonConvert.DeserializeObject<GeolocationResult>(res);
|
||||||
|
|
||||||
var currentSeconds = DateTime.UtcNow.UnixTimestamp();
|
var currentSeconds = DateTime.UtcNow.UnixTimestamp();
|
||||||
var timeRes = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/timezone/json?location={obj.results[0].Geometry.Location.Lat},{obj.results[0].Geometry.Location.Lng}×tamp={currentSeconds}&key={NadekoBot.Credentials.GoogleApiKey}").ConfigureAwait(false);
|
var timeRes = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/timezone/json?location={obj.results[0].Geometry.Location.Lat},{obj.results[0].Geometry.Location.Lng}×tamp={currentSeconds}&key={_creds.GoogleApiKey}").ConfigureAwait(false);
|
||||||
var timeObj = JsonConvert.DeserializeObject<TimeZoneResult>(timeRes);
|
var timeObj = JsonConvert.DeserializeObject<TimeZoneResult>(timeRes);
|
||||||
|
|
||||||
var time = DateTime.UtcNow.AddSeconds(timeObj.DstOffset + timeObj.RawOffset);
|
var time = DateTime.UtcNow.AddSeconds(timeObj.DstOffset + timeObj.RawOffset);
|
||||||
@ -81,7 +89,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public async Task Youtube([Remainder] string query = null)
|
public async Task Youtube([Remainder] string query = null)
|
||||||
{
|
{
|
||||||
if (!await ValidateQuery(Context.Channel, query).ConfigureAwait(false)) return;
|
if (!await ValidateQuery(Context.Channel, query).ConfigureAwait(false)) return;
|
||||||
var result = (await NadekoBot.Google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault();
|
var result = (await _google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault();
|
||||||
if (string.IsNullOrWhiteSpace(result))
|
if (string.IsNullOrWhiteSpace(result))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("no_results").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_results").ConfigureAwait(false);
|
||||||
@ -97,7 +105,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (!(await ValidateQuery(Context.Channel, query).ConfigureAwait(false))) return;
|
if (!(await ValidateQuery(Context.Channel, query).ConfigureAwait(false))) return;
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var movie = await OmdbProvider.FindMovie(query);
|
var movie = await OmdbProvider.FindMovie(query, _google);
|
||||||
if (movie == null)
|
if (movie == null)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("imdb_fail").ConfigureAwait(false);
|
await ReplyErrorLocalized("imdb_fail").ConfigureAwait(false);
|
||||||
@ -137,7 +145,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false);
|
var res = await _google.GetImageAsync(terms).ConfigureAwait(false);
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
||||||
@ -189,7 +197,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
|
var res = await _google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
||||||
@ -239,7 +247,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (string.IsNullOrWhiteSpace(ffs))
|
if (string.IsNullOrWhiteSpace(ffs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("<" + await NadekoBot.Google.ShortenUrl($"http://lmgtfy.com/?q={ Uri.EscapeUriString(ffs) }") + ">")
|
await Context.Channel.SendConfirmAsync("<" + await _google.ShortenUrl($"http://lmgtfy.com/?q={ Uri.EscapeUriString(ffs) }") + ">")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +257,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var shortened = await NadekoBot.Google.ShortenUrl(arg).ConfigureAwait(false);
|
var shortened = await _google.ShortenUrl(arg).ConfigureAwait(false);
|
||||||
|
|
||||||
if (shortened == arg)
|
if (shortened == arg)
|
||||||
{
|
{
|
||||||
@ -315,7 +323,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithFooter(efb => efb.WithText(totalResults));
|
.WithFooter(efb => efb.WithText(totalResults));
|
||||||
|
|
||||||
var desc = await Task.WhenAll(results.Select(async res =>
|
var desc = await Task.WhenAll(results.Select(async res =>
|
||||||
$"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n"))
|
$"[{Format.Bold(res?.Title)}]({(await _google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
await Context.Channel.EmbedAsync(embed.WithDescription(string.Concat(desc))).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed.WithDescription(string.Concat(desc))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -339,7 +347,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (items == null || items.Length == 0)
|
if (items == null || items.Length == 0)
|
||||||
throw new KeyNotFoundException("Cannot find a card by that name");
|
throw new KeyNotFoundException("Cannot find a card by that name");
|
||||||
var item = items[new NadekoRandom().Next(0, items.Length)];
|
var item = items[new NadekoRandom().Next(0, items.Length)];
|
||||||
var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString());
|
var storeUrl = await _google.ShortenUrl(item["store_url"].ToString());
|
||||||
var cost = item["cost"].ToString();
|
var cost = item["cost"].ToString();
|
||||||
var desc = item["text"].ToString();
|
var desc = item["text"].ToString();
|
||||||
var types = string.Join(",\n", item["types"].ToObject<string[]>());
|
var types = string.Join(",\n", item["types"].ToObject<string[]>());
|
||||||
@ -351,7 +359,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.AddField(efb => efb.WithName(GetText("store_url")).WithValue(storeUrl).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("store_url")).WithValue(storeUrl).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("cost")).WithValue(cost).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("cost")).WithValue(cost).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(GetText("types")).WithValue(types).WithIsInline(true));
|
.AddField(efb => efb.WithName(GetText("types")).WithValue(types).WithIsInline(true));
|
||||||
//.AddField(efb => efb.WithName("Store Url").WithValue(await NadekoBot.Google.ShortenUrl(items[0]["store_url"].ToString())).WithIsInline(true));
|
//.AddField(efb => efb.WithName("Store Url").WithValue(await _google.ShortenUrl(items[0]["store_url"].ToString())).WithIsInline(true));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -369,7 +377,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(_creds.MashapeKey))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -379,7 +387,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", _creds.MashapeKey);
|
||||||
var response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}")
|
var response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
@ -422,7 +430,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Yodify([Remainder] string query = null)
|
public async Task Yodify([Remainder] string query = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(_creds.MashapeKey))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -435,7 +443,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", _creds.MashapeKey);
|
||||||
http.DefaultRequestHeaders.Add("Accept", "text/plain");
|
http.DefaultRequestHeaders.Add("Accept", "text/plain");
|
||||||
var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(query)}").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(query)}").ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
@ -457,7 +465,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task UrbanDict([Remainder] string query = null)
|
public async Task UrbanDict([Remainder] string query = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(_creds.MashapeKey))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -531,7 +539,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(_creds.MashapeKey))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -542,7 +550,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", _creds.MashapeKey);
|
||||||
res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(query)}.json").ConfigureAwait(false);
|
res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(query)}.json").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,7 +663,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
usr = (IGuildUser)Context.User;
|
usr = (IGuildUser)Context.User;
|
||||||
|
|
||||||
var avatarUrl = usr.RealAvatarUrl();
|
var avatarUrl = usr.RealAvatarUrl();
|
||||||
var shortenedAvatarUrl = await NadekoBot.Google.ShortenUrl(avatarUrl).ConfigureAwait(false);
|
var shortenedAvatarUrl = await _google.ShortenUrl(avatarUrl).ConfigureAwait(false);
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.AddField(efb => efb.WithName("Username").WithValue(usr.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Username").WithValue(usr.ToString()).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Avatar Url").WithValue(shortenedAvatarUrl).WithIsInline(false))
|
.AddField(efb => efb.WithName("Avatar Url").WithValue(shortenedAvatarUrl).WithIsInline(false))
|
||||||
@ -682,7 +690,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var found = items["items"][0];
|
var found = items["items"][0];
|
||||||
var response = $@"`{GetText("title")}` {found["title"]}
|
var response = $@"`{GetText("title")}` {found["title"]}
|
||||||
`{GetText("quality")}` {found["quality"]}
|
`{GetText("quality")}` {found["quality"]}
|
||||||
`{GetText("url")}:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}";
|
`{GetText("url")}:` {await _google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}";
|
||||||
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -769,7 +777,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
tag = tag?.Trim() ?? "";
|
tag = tag?.Trim() ?? "";
|
||||||
|
|
||||||
var url = await InternalDapiSearch(tag, type).ConfigureAwait(false);
|
var url = await _searches.DapiSearch(tag, type).ConfigureAwait(false);
|
||||||
|
|
||||||
if (url == null)
|
if (url == null)
|
||||||
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
||||||
|
@ -21,6 +21,8 @@ using NadekoBot.Services.Searches;
|
|||||||
using NadekoBot.Services.ClashOfClans;
|
using NadekoBot.Services.ClashOfClans;
|
||||||
using NadekoBot.Services.Music;
|
using NadekoBot.Services.Music;
|
||||||
using NadekoBot.Services.CustomReactions;
|
using NadekoBot.Services.CustomReactions;
|
||||||
|
using NadekoBot.Services.Games;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
|
|
||||||
namespace NadekoBot
|
namespace NadekoBot
|
||||||
{
|
{
|
||||||
@ -73,11 +75,10 @@ namespace NadekoBot
|
|||||||
});
|
});
|
||||||
|
|
||||||
var google = new GoogleApiService(credentials);
|
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 localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), db);
|
||||||
|
var strings = new NadekoStrings(localization);
|
||||||
|
|
||||||
|
var greetSettingsService = new GreetSettingsService(Client, AllGuildConfigs, db);
|
||||||
|
|
||||||
var commandService = new CommandService(new CommandServiceConfig()
|
var commandService = new CommandService(new CommandServiceConfig()
|
||||||
{
|
{
|
||||||
@ -97,10 +98,18 @@ namespace NadekoBot
|
|||||||
|
|
||||||
//module services
|
//module services
|
||||||
var utilityService = new UtilityService(AllGuildConfigs, Client, BotConfig, db);
|
var utilityService = new UtilityService(AllGuildConfigs, Client, BotConfig, db);
|
||||||
var searchesService = new SearchesService();
|
var searchesService = new SearchesService(Client, google, db);
|
||||||
var clashService = new ClashOfClansService(Client, db, localization, strings);
|
var clashService = new ClashOfClansService(Client, db, localization, strings);
|
||||||
var musicService = new MusicService(google, strings, localization, db, soundcloud, credentials);
|
var musicService = new MusicService(google, strings, localization, db, soundcloud, credentials);
|
||||||
var crService = new CustomReactionsService(db, Client);
|
var crService = new CustomReactionsService(db, Client);
|
||||||
|
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, strings, images);
|
||||||
|
#region administration
|
||||||
|
var administrationService = new AdministrationService(AllGuildConfigs, commandHandler);
|
||||||
|
var selfService = new SelfService(this, commandHandler, db, BotConfig);
|
||||||
|
var vcRoleService = new VcRoleService(Client, AllGuildConfigs);
|
||||||
|
var vPlusTService = new VplusTService(Client, AllGuildConfigs, strings, db);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
//initialize Services
|
//initialize Services
|
||||||
Services = new NServiceProvider.ServiceProviderBuilder() //todo all Adds should be interfaces
|
Services = new NServiceProvider.ServiceProviderBuilder() //todo all Adds should be interfaces
|
||||||
@ -124,6 +133,10 @@ namespace NadekoBot
|
|||||||
.Add<MusicService>(musicService)
|
.Add<MusicService>(musicService)
|
||||||
.Add<GreetSettingsService>(greetSettingsService)
|
.Add<GreetSettingsService>(greetSettingsService)
|
||||||
.Add<CustomReactionsService>(crService)
|
.Add<CustomReactionsService>(crService)
|
||||||
|
.Add<GamesService>(gamesService)
|
||||||
|
.Add(selfService)
|
||||||
|
.Add(vcRoleService)
|
||||||
|
.Add(vPlusTService)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
commandHandler.AddServices(Services);
|
commandHandler.AddServices(Services);
|
||||||
|
@ -29,21 +29,22 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="data\**\*;credentials.json;credentials_example.json" />
|
<Compile Remove="data\**\*;credentials.json;credentials_example.json" />
|
||||||
<Compile Remove="Modules\Administration\**" />
|
<Compile Remove="Modules\Administration\**" />
|
||||||
<Compile Remove="Modules\Games\**" />
|
|
||||||
<Compile Remove="Modules\NSFW\**" />
|
<Compile Remove="Modules\NSFW\**" />
|
||||||
<Compile Remove="Modules\Permissions\**" />
|
<Compile Remove="Modules\Permissions\**" />
|
||||||
<Compile Remove="Modules\Searches\**" />
|
|
||||||
<EmbeddedResource Remove="Modules\Administration\**" />
|
<EmbeddedResource Remove="Modules\Administration\**" />
|
||||||
<EmbeddedResource Remove="Modules\Games\**" />
|
|
||||||
<EmbeddedResource Remove="Modules\NSFW\**" />
|
<EmbeddedResource Remove="Modules\NSFW\**" />
|
||||||
<EmbeddedResource Remove="Modules\Permissions\**" />
|
<EmbeddedResource Remove="Modules\Permissions\**" />
|
||||||
<EmbeddedResource Remove="Modules\Searches\**" />
|
|
||||||
<None Remove="Modules\Administration\**" />
|
<None Remove="Modules\Administration\**" />
|
||||||
<None Remove="Modules\Games\**" />
|
|
||||||
<None Remove="Modules\NSFW\**" />
|
<None Remove="Modules\NSFW\**" />
|
||||||
<None Remove="Modules\Permissions\**" />
|
<None Remove="Modules\Permissions\**" />
|
||||||
<None Remove="Modules\Searches\**" />
|
|
||||||
<Compile Remove="Modules\Gambling\Commands\Lucky7Commands.cs" />
|
<Compile Remove="Modules\Gambling\Commands\Lucky7Commands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Administration.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\MuteCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\SelfCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\ServerGreetCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\UserPunishCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\VcRoleCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\VoicePlusTextCommands.cs" />
|
||||||
<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>
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class AdministrationService
|
||||||
|
{
|
||||||
|
public readonly ConcurrentHashSet<ulong> DeleteMessagesOnCommand;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public AdministrationService(IEnumerable<GuildConfig> gcs, CommandHandler cmdHandler)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(gcs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||||
|
cmdHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var channel = msg.Channel as SocketTextChannel;
|
||||||
|
if (channel == null)
|
||||||
|
return;
|
||||||
|
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
|
||||||
|
await msg.DeleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn("Delmsgoncmd errored...");
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
275
src/NadekoBot/Services/Administration/MuteService.cs
Normal file
275
src/NadekoBot/Services/Administration/MuteService.cs
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class MuteService
|
||||||
|
{
|
||||||
|
public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
|
||||||
|
public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
|
||||||
|
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> UnmuteTimers { get; }
|
||||||
|
= new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>>();
|
||||||
|
|
||||||
|
public event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
||||||
|
public event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
||||||
|
|
||||||
|
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
||||||
|
|
||||||
|
private readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
|
public MuteService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, DbHandler db)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_db = db;
|
||||||
|
|
||||||
|
GuildMuteRoles = new ConcurrentDictionary<ulong, string>(gcs
|
||||||
|
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
||||||
|
.ToDictionary(c => c.GuildId, c => c.MuteRoleName));
|
||||||
|
|
||||||
|
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(gcs.ToDictionary(
|
||||||
|
k => k.GuildId,
|
||||||
|
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach (var conf in gcs)
|
||||||
|
{
|
||||||
|
foreach (var x in conf.UnmuteTimers)
|
||||||
|
{
|
||||||
|
TimeSpan after;
|
||||||
|
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
after = TimeSpan.FromMinutes(2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
after = x.UnmuteAt - DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
StartUnmuteTimer(conf.GuildId, x.UserId, after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.UserJoined += Client_UserJoined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Client_UserJoined(IGuildUser usr)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted);
|
||||||
|
|
||||||
|
if (muted == null || !muted.Contains(usr.Id))
|
||||||
|
return;
|
||||||
|
await MuteUser(usr).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MuteUser(IGuildUser usr, MuteType type = MuteType.All)
|
||||||
|
{
|
||||||
|
if (type == MuteType.All)
|
||||||
|
{
|
||||||
|
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
||||||
|
var muteRole = await GetMuteRole(usr.Guild);
|
||||||
|
if (!usr.RoleIds.Contains(muteRole.Id))
|
||||||
|
await usr.AddRoleAsync(muteRole).ConfigureAwait(false);
|
||||||
|
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(usr.Guild.Id,
|
||||||
|
set => set.Include(gc => gc.MutedUsers)
|
||||||
|
.Include(gc => gc.UnmuteTimers));
|
||||||
|
config.MutedUsers.Add(new MutedUserId()
|
||||||
|
{
|
||||||
|
UserId = usr.Id
|
||||||
|
});
|
||||||
|
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
||||||
|
muted.Add(usr.Id);
|
||||||
|
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||||
|
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
UserMuted(usr, MuteType.All);
|
||||||
|
}
|
||||||
|
else if (type == MuteType.Voice)
|
||||||
|
{
|
||||||
|
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
||||||
|
UserMuted(usr, MuteType.Voice);
|
||||||
|
}
|
||||||
|
else if (type == MuteType.Chat)
|
||||||
|
{
|
||||||
|
await usr.AddRoleAsync(await GetMuteRole(usr.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||||
|
UserMuted(usr, MuteType.Chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UnmuteUser(IGuildUser usr, MuteType type = MuteType.All)
|
||||||
|
{
|
||||||
|
if (type == MuteType.All)
|
||||||
|
{
|
||||||
|
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||||
|
try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { }
|
||||||
|
try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers)
|
||||||
|
.Include(gc => gc.UnmuteTimers));
|
||||||
|
config.MutedUsers.Remove(new MutedUserId()
|
||||||
|
{
|
||||||
|
UserId = usr.Id
|
||||||
|
});
|
||||||
|
if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
|
||||||
|
muted.TryRemove(usr.Id);
|
||||||
|
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||||
|
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
UserUnmuted(usr, MuteType.All);
|
||||||
|
}
|
||||||
|
else if (type == MuteType.Voice)
|
||||||
|
{
|
||||||
|
await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false);
|
||||||
|
UserUnmuted(usr, MuteType.Voice);
|
||||||
|
}
|
||||||
|
else if (type == MuteType.Chat)
|
||||||
|
{
|
||||||
|
await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||||
|
UserUnmuted(usr, MuteType.Chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IRole> GetMuteRole(IGuild guild)
|
||||||
|
{
|
||||||
|
const string defaultMuteRoleName = "nadeko-mute";
|
||||||
|
|
||||||
|
var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
|
||||||
|
|
||||||
|
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
|
||||||
|
if (muteRole == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
//if it doesn't exist, create it
|
||||||
|
try { muteRole = await guild.CreateRoleAsync(muteRoleName, GuildPermissions.None).ConfigureAwait(false); }
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one
|
||||||
|
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ??
|
||||||
|
await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!toOverwrite.PermissionOverwrites.Select(x => x.Permissions).Contains(denyOverwrite))
|
||||||
|
{
|
||||||
|
await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return muteRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task TimedMute(IGuildUser user, TimeSpan after)
|
||||||
|
{
|
||||||
|
await MuteUser(user).ConfigureAwait(false); // mute the user. This will also remove any previous unmute timers
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(user.GuildId, set => set.Include(x => x.UnmuteTimers));
|
||||||
|
config.UnmuteTimers.Add(new UnmuteTimer()
|
||||||
|
{
|
||||||
|
UserId = user.Id,
|
||||||
|
UnmuteAt = DateTime.UtcNow + after,
|
||||||
|
}); // add teh unmute timer to the database
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
StartUnmuteTimer(user.GuildId, user.Id, after); // start the timer
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartUnmuteTimer(ulong guildId, ulong userId, TimeSpan after)
|
||||||
|
{
|
||||||
|
//load the unmute timers for this guild
|
||||||
|
var userUnmuteTimers = UnmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
|
||||||
|
|
||||||
|
//unmute timer to be added
|
||||||
|
var toAdd = new Timer(async _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var guild = _client.GetGuild(guildId); // load the guild
|
||||||
|
if (guild == null)
|
||||||
|
{
|
||||||
|
RemoveUnmuteTimerFromDb(guildId, userId);
|
||||||
|
return; // if guild can't be found, just remove the timer from db
|
||||||
|
}
|
||||||
|
// unmute the user, this will also remove the timer from the db
|
||||||
|
await UnmuteUser(guild.GetUser(userId)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
RemoveUnmuteTimerFromDb(guildId, userId); // if unmute errored, just remove unmute from db
|
||||||
|
_log.Warn("Couldn't unmute user {0} in guild {1}", userId, guildId);
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
}, null, after, Timeout.InfiniteTimeSpan);
|
||||||
|
|
||||||
|
//add it, or stop the old one and add this one
|
||||||
|
userUnmuteTimers.AddOrUpdate(userId, (key) => toAdd, (key, old) =>
|
||||||
|
{
|
||||||
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
return toAdd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopUnmuteTimer(ulong guildId, ulong userId)
|
||||||
|
{
|
||||||
|
if (!UnmuteTimers.TryGetValue(guildId, out ConcurrentDictionary<ulong, Timer> userUnmuteTimers)) return;
|
||||||
|
|
||||||
|
if (userUnmuteTimers.TryRemove(userId, out Timer removed))
|
||||||
|
{
|
||||||
|
removed.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveUnmuteTimerFromDb(ulong guildId, ulong userId)
|
||||||
|
{
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(guildId, set => set.Include(x => x.UnmuteTimers));
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == userId);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MuteType
|
||||||
|
{
|
||||||
|
Voice,
|
||||||
|
Chat,
|
||||||
|
All
|
||||||
|
}
|
||||||
|
}
|
48
src/NadekoBot/Services/Administration/SelfService.cs
Normal file
48
src/NadekoBot/Services/Administration/SelfService.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class SelfService
|
||||||
|
{
|
||||||
|
public volatile bool ForwardDMs;
|
||||||
|
public volatile bool ForwardDMsToAllOwners;
|
||||||
|
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly NadekoBot _bot;
|
||||||
|
private readonly CommandHandler _cmdHandler;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
|
public SelfService(NadekoBot bot, CommandHandler cmdHandler, DbHandler db,
|
||||||
|
BotConfig bc)
|
||||||
|
{
|
||||||
|
_bot = bot;
|
||||||
|
_cmdHandler = cmdHandler;
|
||||||
|
_db = db;
|
||||||
|
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
|
ForwardDMs = config.ForwardMessages;
|
||||||
|
ForwardDMsToAllOwners = config.ForwardToAllOwners;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while (!bot.Ready)
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
foreach (var cmd in bc.StartupCommands)
|
||||||
|
{
|
||||||
|
await cmdHandler.ExecuteExternal(cmd.GuildId, cmd.ChannelId, cmd.CommandText);
|
||||||
|
await Task.Delay(400).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
src/NadekoBot/Services/Administration/VcRoleService.cs
Normal file
102
src/NadekoBot/Services/Administration/VcRoleService.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class VcRoleService
|
||||||
|
{
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
|
||||||
|
|
||||||
|
public VcRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
|
||||||
|
VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
|
||||||
|
foreach (var gconf in gcs)
|
||||||
|
{
|
||||||
|
var g = client.GetGuild(gconf.GuildId);
|
||||||
|
if (g == null)
|
||||||
|
continue; //todo delete everything from db if guild doesn't exist?
|
||||||
|
|
||||||
|
var infos = new ConcurrentDictionary<ulong, IRole>();
|
||||||
|
VcRoles.TryAdd(gconf.GuildId, infos);
|
||||||
|
foreach (var ri in gconf.VcRoleInfos)
|
||||||
|
{
|
||||||
|
var role = g.GetRole(ri.RoleId);
|
||||||
|
if (role == null)
|
||||||
|
continue; //todo remove this entry from db
|
||||||
|
|
||||||
|
infos.TryAdd(ri.VoiceChannelId, role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState,
|
||||||
|
SocketVoiceState newState)
|
||||||
|
{
|
||||||
|
|
||||||
|
var gusr = usr as SocketGuildUser;
|
||||||
|
if (gusr == null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var oldVc = oldState.VoiceChannel;
|
||||||
|
var newVc = newState.VoiceChannel;
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (oldVc != newVc)
|
||||||
|
{
|
||||||
|
ulong guildId;
|
||||||
|
guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
|
||||||
|
|
||||||
|
if (VcRoles.TryGetValue(guildId, out ConcurrentDictionary<ulong, IRole> guildVcRoles))
|
||||||
|
{
|
||||||
|
//remove old
|
||||||
|
if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out IRole role))
|
||||||
|
{
|
||||||
|
if (gusr.Roles.Contains(role))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//add new
|
||||||
|
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
|
||||||
|
{
|
||||||
|
if (!gusr.Roles.Contains(role))
|
||||||
|
await gusr.AddRoleAsync(role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
src/NadekoBot/Services/Administration/VplusTService.cs
Normal file
157
src/NadekoBot/Services/Administration/VplusTService.cs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class VplusTService
|
||||||
|
{
|
||||||
|
private readonly Regex _channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public VplusTService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
|
||||||
|
DbHandler db)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_strings = strings;
|
||||||
|
_db = db;
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
VoicePlusTextCache = new ConcurrentHashSet<ulong>(gcs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
|
||||||
|
_client.UserVoiceStateUpdated += UserUpdatedEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after)
|
||||||
|
{
|
||||||
|
var user = (iuser as SocketGuildUser);
|
||||||
|
var guild = user?.Guild;
|
||||||
|
|
||||||
|
if (guild == null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var botUserPerms = guild.CurrentUser.GuildPermissions;
|
||||||
|
|
||||||
|
if (before.VoiceChannel == after.VoiceChannel)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
if (!VoicePlusTextCache.Contains(guild.Id))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await guild.Owner.SendErrorAsync(
|
||||||
|
_strings.GetText("vt_exit",
|
||||||
|
guild.Id,
|
||||||
|
"Administration".ToLowerInvariant(),
|
||||||
|
Format.Bold(guild.Name))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
|
||||||
|
VoicePlusTextCache.TryRemove(guild.Id);
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var semaphore = _guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var beforeVch = before.VoiceChannel;
|
||||||
|
if (beforeVch != null)
|
||||||
|
{
|
||||||
|
var beforeRoleName = GetRoleName(beforeVch);
|
||||||
|
var beforeRole = guild.Roles.FirstOrDefault(x => x.Name == beforeRoleName);
|
||||||
|
if (beforeRole != null)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_log.Info("Removing role " + beforeRoleName + " from user " + user.Username);
|
||||||
|
await user.RemoveRoleAsync(beforeRole).ConfigureAwait(false);
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var afterVch = after.VoiceChannel;
|
||||||
|
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
||||||
|
{
|
||||||
|
var roleName = GetRoleName(afterVch);
|
||||||
|
var roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName) ??
|
||||||
|
(IRole)await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
ITextChannel textChannel = guild.TextChannels
|
||||||
|
.FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant());
|
||||||
|
if (textChannel == null)
|
||||||
|
{
|
||||||
|
var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
||||||
|
|
||||||
|
try { await guild.CurrentUser.AddRoleAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
|
||||||
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
|
||||||
|
readMessages: PermValue.Allow,
|
||||||
|
sendMessages: PermValue.Allow))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
await created.AddPermissionOverwriteAsync(guild.EveryoneRole, new OverwritePermissions(
|
||||||
|
readMessages: PermValue.Deny,
|
||||||
|
sendMessages: PermValue.Deny))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
_log.Warn("Adding role " + roleToAdd.Name + " to user " + user.Username);
|
||||||
|
await user.AddRoleAsync(roleToAdd).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetChannelName(string voiceName) =>
|
||||||
|
_channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||||
|
|
||||||
|
public string GetRoleName(IVoiceChannel ch) =>
|
||||||
|
"nvoice-" + ch.Id;
|
||||||
|
}
|
||||||
|
}
|
@ -544,7 +544,7 @@ namespace NadekoBot.Services
|
|||||||
//////int price;
|
//////int price;
|
||||||
//////if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
|
//////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 success = await _ch.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
|
||||||
////// if (!success)
|
////// if (!success)
|
||||||
////// {
|
////// {
|
||||||
////// 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, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command."));
|
||||||
|
@ -19,7 +19,7 @@ namespace NadekoBot.Services
|
|||||||
var optionsBuilder = new DbContextOptionsBuilder();
|
var optionsBuilder = new DbContextOptionsBuilder();
|
||||||
optionsBuilder.UseSqlite(creds.Db.ConnectionString);
|
optionsBuilder.UseSqlite(creds.Db.ConnectionString);
|
||||||
options = optionsBuilder.Options;
|
options = optionsBuilder.Options;
|
||||||
//switch (NadekoBot.Credentials.Db.Type.ToUpperInvariant())
|
//switch (_creds.Db.Type.ToUpperInvariant())
|
||||||
//{
|
//{
|
||||||
// case "SQLITE":
|
// case "SQLITE":
|
||||||
// dbType = typeof(NadekoSqliteContext);
|
// dbType = typeof(NadekoSqliteContext);
|
||||||
|
8
src/NadekoBot/Services/Games/ChatterBotResponse.cs
Normal file
8
src/NadekoBot/Services/Games/ChatterBotResponse.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace NadekoBot.Services.Games
|
||||||
|
{
|
||||||
|
public class ChatterBotResponse
|
||||||
|
{
|
||||||
|
public string Convo_id { get; set; }
|
||||||
|
public string BotSay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
39
src/NadekoBot/Services/Games/ChatterBotSession.cs
Normal file
39
src/NadekoBot/Services/Games/ChatterBotSession.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using NadekoBot.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Games
|
||||||
|
{
|
||||||
|
public class ChatterBotSession
|
||||||
|
{
|
||||||
|
private static NadekoRandom rng { get; } = new NadekoRandom();
|
||||||
|
public string ChatterbotId { get; }
|
||||||
|
public string ChannelId { get; }
|
||||||
|
private int _botId = 6;
|
||||||
|
|
||||||
|
public ChatterBotSession(ulong channelId)
|
||||||
|
{
|
||||||
|
ChannelId = channelId.ToString().ToBase64();
|
||||||
|
ChatterbotId = rng.Next(0, 1000000).ToString().ToBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string apiEndpoint => "http://api.program-o.com/v2/chatbot/" +
|
||||||
|
$"?bot_id={_botId}&" +
|
||||||
|
"say={0}&" +
|
||||||
|
$"convo_id=nadekobot_{ChatterbotId}_{ChannelId}&" +
|
||||||
|
"format=json";
|
||||||
|
|
||||||
|
public async Task<string> Think(string message)
|
||||||
|
{
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
var res = await http.GetStringAsync(string.Format(apiEndpoint, message)).ConfigureAwait(false);
|
||||||
|
var cbr = JsonConvert.DeserializeObject<ChatterBotResponse>(res);
|
||||||
|
//Console.WriteLine(cbr.Convo_id);
|
||||||
|
return cbr.BotSay.Replace("<br/>", "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
206
src/NadekoBot/Services/Games/GamesService.cs
Normal file
206
src/NadekoBot/Services/Games/GamesService.cs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Games
|
||||||
|
{
|
||||||
|
public class GamesService
|
||||||
|
{
|
||||||
|
private readonly BotConfig _bc;
|
||||||
|
|
||||||
|
public readonly ConcurrentDictionary<ulong, GirlRating> GirlRatings = new ConcurrentDictionary<ulong, GirlRating>();
|
||||||
|
public readonly ImmutableArray<string> EightBallResponses;
|
||||||
|
|
||||||
|
private readonly Timer _t;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
private readonly IImagesService _images;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; }
|
||||||
|
|
||||||
|
public readonly string TypingArticlesPath = "data/typing_articles2.json";
|
||||||
|
public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
||||||
|
|
||||||
|
public GamesService(DiscordShardedClient client, BotConfig bc, IEnumerable<GuildConfig> gcs,
|
||||||
|
NadekoStrings strings, IImagesService images)
|
||||||
|
{
|
||||||
|
_bc = bc;
|
||||||
|
_client = client;
|
||||||
|
_strings = strings;
|
||||||
|
_images = images;
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
//8ball
|
||||||
|
EightBallResponses = _bc.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray();
|
||||||
|
|
||||||
|
//girl ratings
|
||||||
|
_t = new Timer((_) =>
|
||||||
|
{
|
||||||
|
GirlRatings.Clear();
|
||||||
|
|
||||||
|
}, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1));
|
||||||
|
|
||||||
|
//cleverbot
|
||||||
|
CleverbotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
||||||
|
gcs.Where(gc => gc.CleverbotEnabled)
|
||||||
|
.ToDictionary(gc => gc.GuildId, gc => new Lazy<ChatterBotSession>(() => new ChatterBotSession(gc.GuildId), true)));
|
||||||
|
|
||||||
|
//plantpick
|
||||||
|
client.MessageReceived += PotentialFlowerGeneration;
|
||||||
|
GenerationChannels = new ConcurrentHashSet<ulong>(gcs
|
||||||
|
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(TypingArticlesPath));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn("Error while loading typing articles {0}", ex.ToString());
|
||||||
|
TypingArticles = new List<TypingArticle>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string PrepareMessage(IUserMessage msg, out ChatterBotSession cleverbot)
|
||||||
|
{
|
||||||
|
var channel = msg.Channel as ITextChannel;
|
||||||
|
cleverbot = null;
|
||||||
|
|
||||||
|
if (channel == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Lazy<ChatterBotSession> lazyCleverbot;
|
||||||
|
if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out lazyCleverbot))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
cleverbot = lazyCleverbot.Value;
|
||||||
|
|
||||||
|
var nadekoId = _client.CurrentUser.Id;
|
||||||
|
var normalMention = $"<@{nadekoId}> ";
|
||||||
|
var nickMention = $"<@!{nadekoId}> ";
|
||||||
|
string message;
|
||||||
|
if (msg.Content.StartsWith(normalMention))
|
||||||
|
{
|
||||||
|
message = msg.Content.Substring(normalMention.Length).Trim();
|
||||||
|
}
|
||||||
|
else if (msg.Content.StartsWith(nickMention))
|
||||||
|
{
|
||||||
|
message = msg.Content.Substring(nickMention.Length).Trim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> TryAsk(ChatterBotSession cleverbot, ITextChannel channel, string message)
|
||||||
|
{
|
||||||
|
await channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var response = await cleverbot.Think(message).ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentHashSet<ulong> GenerationChannels { get; }
|
||||||
|
//channelid/message
|
||||||
|
public ConcurrentDictionary<ulong, List<IUserMessage>> PlantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
||||||
|
//channelId/last generation
|
||||||
|
public ConcurrentDictionary<ulong, DateTime> LastGenerations { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||||
|
|
||||||
|
public KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
|
||||||
|
{
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
return _images.Currency[rng.Next(0, _images.Currency.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetText(ITextChannel ch, string key, params object[] rep)
|
||||||
|
=> _strings.GetText(key, ch.GuildId, "Games".ToLowerInvariant(), rep);
|
||||||
|
|
||||||
|
private Task PotentialFlowerGeneration(SocketMessage imsg)
|
||||||
|
{
|
||||||
|
var msg = imsg as SocketUserMessage;
|
||||||
|
if (msg == null || msg.Author.IsBot)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var channel = imsg.Channel as ITextChannel;
|
||||||
|
if (channel == null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
if (!GenerationChannels.Contains(channel.Id))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
//todo i'm stupid :rofl: wtg kwoth. real async programming :100: :ok_hand: :100: :100: :thumbsup:
|
||||||
|
if (DateTime.Now - TimeSpan.FromSeconds(_bc.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
|
||||||
|
return;
|
||||||
|
|
||||||
|
var num = rng.Next(1, 101) + _bc.CurrencyGenerationChance * 100;
|
||||||
|
|
||||||
|
if (num > 100)
|
||||||
|
{
|
||||||
|
LastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
|
||||||
|
|
||||||
|
var dropAmount = _bc.CurrencyDropAmount;
|
||||||
|
|
||||||
|
if (dropAmount > 0)
|
||||||
|
{
|
||||||
|
var msgs = new IUserMessage[dropAmount];
|
||||||
|
var prefix = NadekoBot.Prefix;
|
||||||
|
var toSend = dropAmount == 1
|
||||||
|
? GetText(channel, "curgen_sn", _bc.CurrencySign)
|
||||||
|
+ " " + GetText(channel, "pick_sn", prefix)
|
||||||
|
: GetText(channel, "curgen_pl", dropAmount, _bc.CurrencySign)
|
||||||
|
+ " " + GetText(channel, "pick_pl", prefix);
|
||||||
|
var file = GetRandomCurrencyImage();
|
||||||
|
using (var fileStream = file.Value.ToStream())
|
||||||
|
{
|
||||||
|
var sent = await channel.SendFileAsync(
|
||||||
|
fileStream,
|
||||||
|
file.Key,
|
||||||
|
toSend).ConfigureAwait(false);
|
||||||
|
|
||||||
|
msgs[0] = sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
src/NadekoBot/Services/Games/GirlRating.cs
Normal file
71
src/NadekoBot/Services/Games/GirlRating.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using ImageSharp;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Games
|
||||||
|
{
|
||||||
|
public class GirlRating
|
||||||
|
{
|
||||||
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public double Crazy { get; }
|
||||||
|
public double Hot { get; }
|
||||||
|
public int Roll { get; }
|
||||||
|
public string Advice { get; }
|
||||||
|
public AsyncLazy<string> Url { get; }
|
||||||
|
|
||||||
|
public GirlRating(IImagesService _images, double crazy, double hot, int roll, string advice)
|
||||||
|
{
|
||||||
|
Crazy = crazy;
|
||||||
|
Hot = hot;
|
||||||
|
Roll = roll;
|
||||||
|
Advice = advice; // convenient to have it here, even though atm there are only few different ones.
|
||||||
|
|
||||||
|
Url = new AsyncLazy<string>(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(_images.WifeMatrix.ToArray(), false))
|
||||||
|
using (var img = new ImageSharp.Image(ms))
|
||||||
|
{
|
||||||
|
const int minx = 35;
|
||||||
|
const int miny = 385;
|
||||||
|
const int length = 345;
|
||||||
|
|
||||||
|
var pointx = (int)(minx + length * (Hot / 10));
|
||||||
|
var pointy = (int)(miny - length * ((Crazy - 4) / 6));
|
||||||
|
|
||||||
|
using (var pointMs = new MemoryStream(_images.RategirlDot.ToArray(), false))
|
||||||
|
using (var pointImg = new ImageSharp.Image(pointMs))
|
||||||
|
{
|
||||||
|
img.DrawImage(pointImg, 100, default(Size), new Point(pointx - 10, pointy - 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
string url;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
using (var imgStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
img.Save(imgStream);
|
||||||
|
var byteContent = new ByteArrayContent(imgStream.ToArray());
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
|
||||||
|
var reponse = await http.PutAsync("https://transfer.sh/img.png", byteContent);
|
||||||
|
url = await reponse.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace NadekoBot.Modules.Games.Commands.Models
|
namespace NadekoBot.Services.Games
|
||||||
{
|
{
|
||||||
public class TypingArticle
|
public class TypingArticle
|
||||||
{
|
{
|
@ -1,6 +1,10 @@
|
|||||||
using NadekoBot.Extensions;
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -15,11 +19,158 @@ namespace NadekoBot.Services
|
|||||||
private readonly DbHandler _db;
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache;
|
public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
public GreetSettingsService(IEnumerable<GuildConfig> guildConfigs, DbHandler db)
|
public GreetSettingsService(DiscordShardedClient client, IEnumerable<GuildConfig> guildConfigs, DbHandler db)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
|
_client = client;
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(guildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(guildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
||||||
|
|
||||||
|
_client.UserJoined += UserJoined;
|
||||||
|
_client.UserLeft += UserLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UserLeft(IGuildUser user)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||||
|
|
||||||
|
if (!conf.SendChannelByeMessage) return;
|
||||||
|
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
||||||
|
|
||||||
|
if (channel == null) //maybe warn the server owner that the channel is missing
|
||||||
|
return;
|
||||||
|
CREmbed embedData;
|
||||||
|
if (CREmbed.TryParse(conf.ChannelByeMessageText, out embedData))
|
||||||
|
{
|
||||||
|
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Description = embedData.Description?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Title = embedData.Title?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
||||||
|
if (conf.AutoDeleteByeMessagesTimer > 0)
|
||||||
|
{
|
||||||
|
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
if (string.IsNullOrWhiteSpace(msg))
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
|
||||||
|
if (conf.AutoDeleteByeMessagesTimer > 0)
|
||||||
|
{
|
||||||
|
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UserJoined(IGuildUser user)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||||
|
|
||||||
|
if (conf.SendChannelGreetMessage)
|
||||||
|
{
|
||||||
|
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId);
|
||||||
|
if (channel != null) //maybe warn the server owner that the channel is missing
|
||||||
|
{
|
||||||
|
|
||||||
|
CREmbed embedData;
|
||||||
|
if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData))
|
||||||
|
{
|
||||||
|
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Description = embedData.Description?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
||||||
|
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
||||||
|
{
|
||||||
|
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
if (!string.IsNullOrWhiteSpace(msg))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
|
||||||
|
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
||||||
|
{
|
||||||
|
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.SendDmGreetMessage)
|
||||||
|
{
|
||||||
|
var channel = await user.CreateDMChannelAsync();
|
||||||
|
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
CREmbed embedData;
|
||||||
|
if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData))
|
||||||
|
{
|
||||||
|
embedData.PlainText = embedData.PlainText?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Description = embedData.Description?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var msg = conf.DmGreetMessageText.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
|
||||||
|
if (!string.IsNullOrWhiteSpace(msg))
|
||||||
|
{
|
||||||
|
await channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||||
@ -210,6 +361,23 @@ namespace NadekoBot.Services
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SetGreetDel(ulong id, int timer)
|
||||||
|
{
|
||||||
|
if (timer < 0 || timer > 600)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
var conf = uow.GuildConfigs.For(id, set => set);
|
||||||
|
conf.AutoDeleteGreetMessagesTimer = timer;
|
||||||
|
|
||||||
|
var toAdd = GreetSettings.Create(conf);
|
||||||
|
GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
|
||||||
|
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GreetSettings
|
public class GreetSettings
|
||||||
|
@ -17,7 +17,8 @@ namespace NadekoBot.Services
|
|||||||
string CarbonKey { get; }
|
string CarbonKey { get; }
|
||||||
|
|
||||||
DBConfig Db { get; }
|
DBConfig Db { get; }
|
||||||
string SoundCloudClientId { get; set; }
|
string SoundCloudClientId { get; }
|
||||||
|
string OsuApiKey { get; }
|
||||||
|
|
||||||
bool IsOwner(IUser u);
|
bool IsOwner(IUser u);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Google.Apis.Customsearch.v1.Data;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -6,12 +7,28 @@ namespace NadekoBot.Services
|
|||||||
{
|
{
|
||||||
public interface IGoogleApiService
|
public interface IGoogleApiService
|
||||||
{
|
{
|
||||||
|
IEnumerable<string> Languages { get; }
|
||||||
|
|
||||||
Task<IEnumerable<string>> GetVideosByKeywordsAsync(string keywords, int count = 1);
|
Task<IEnumerable<string>> GetVideosByKeywordsAsync(string keywords, int count = 1);
|
||||||
Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1);
|
Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1);
|
||||||
Task<IEnumerable<string>> GetRelatedVideosAsync(string url, int count = 1);
|
Task<IEnumerable<string>> GetRelatedVideosAsync(string url, int count = 1);
|
||||||
Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50);
|
Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50);
|
||||||
Task<IReadOnlyDictionary<string, TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds);
|
Task<IReadOnlyDictionary<string, TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds);
|
||||||
|
Task<ImageResult> GetImageAsync(string query, int start = 1);
|
||||||
|
Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage);
|
||||||
|
|
||||||
Task<string> ShortenUrl(string url);
|
Task<string> ShortenUrl(string url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct ImageResult
|
||||||
|
{
|
||||||
|
public Result.ImageData Image { get; }
|
||||||
|
public string Link { get; }
|
||||||
|
|
||||||
|
public ImageResult(Result.ImageData image, string link)
|
||||||
|
{
|
||||||
|
this.Image = image;
|
||||||
|
this.Link = link;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
? "d0bd7768e3a1a2d15430f0dccb871117"
|
? "d0bd7768e3a1a2d15430f0dccb871117"
|
||||||
: _soundcloudClientId;
|
: _soundcloudClientId;
|
||||||
}
|
}
|
||||||
set {
|
private set {
|
||||||
_soundcloudClientId = value;
|
_soundcloudClientId = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@ using Google.Apis.Urlshortener.v1;
|
|||||||
using Google.Apis.Urlshortener.v1.Data;
|
using Google.Apis.Urlshortener.v1.Data;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Google.Apis.Customsearch.v1;
|
using Google.Apis.Customsearch.v1;
|
||||||
using Google.Apis.Customsearch.v1.Data;
|
using System.Net.Http;
|
||||||
|
using System.Net;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Impl
|
namespace NadekoBot.Services.Impl
|
||||||
{
|
{
|
||||||
@ -39,6 +41,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
sh = new UrlshortenerService(bcs);
|
sh = new UrlshortenerService(bcs);
|
||||||
cs = new CustomsearchService(bcs);
|
cs = new CustomsearchService(bcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
|
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(keywords))
|
if (string.IsNullOrWhiteSpace(keywords))
|
||||||
@ -190,18 +193,6 @@ namespace NadekoBot.Services.Impl
|
|||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ImageResult
|
|
||||||
{
|
|
||||||
public Result.ImageData Image { get; }
|
|
||||||
public string Link { get; }
|
|
||||||
|
|
||||||
public ImageResult(Result.ImageData image, string link)
|
|
||||||
{
|
|
||||||
this.Image = image;
|
|
||||||
this.Link = link;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ImageResult> GetImageAsync(string query, int start = 1)
|
public async Task<ImageResult> GetImageAsync(string query, int start = 1)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
@ -218,5 +209,168 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
return new ImageResult(search.Items[0].Image, search.Items[0].Link);
|
return new ImageResult(search.Items[0].Image, search.Items[0].Link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> Languages => _languageDictionary.Keys.OrderBy(x => x);
|
||||||
|
private readonly Dictionary<string, string> _languageDictionary = new Dictionary<string, string>() {
|
||||||
|
{ "afrikaans", "af"},
|
||||||
|
{ "albanian", "sq"},
|
||||||
|
{ "arabic", "ar"},
|
||||||
|
{ "armenian", "hy"},
|
||||||
|
{ "azerbaijani", "az"},
|
||||||
|
{ "basque", "eu"},
|
||||||
|
{ "belarusian", "be"},
|
||||||
|
{ "bengali", "bn"},
|
||||||
|
{ "bulgarian", "bg"},
|
||||||
|
{ "catalan", "ca"},
|
||||||
|
{ "chinese-traditional", "zh-TW"},
|
||||||
|
{ "chinese-simplified", "zh-CN"},
|
||||||
|
{ "chinese", "zh-CN"},
|
||||||
|
{ "croatian", "hr"},
|
||||||
|
{ "czech", "cs"},
|
||||||
|
{ "danish", "da"},
|
||||||
|
{ "dutch", "nl"},
|
||||||
|
{ "english", "en"},
|
||||||
|
{ "esperanto", "eo"},
|
||||||
|
{ "estonian", "et"},
|
||||||
|
{ "filipino", "tl"},
|
||||||
|
{ "finnish", "fi"},
|
||||||
|
{ "french", "fr"},
|
||||||
|
{ "galician", "gl"},
|
||||||
|
{ "german", "de"},
|
||||||
|
{ "georgian", "ka"},
|
||||||
|
{ "greek", "el"},
|
||||||
|
{ "haitian Creole", "ht"},
|
||||||
|
{ "hebrew", "iw"},
|
||||||
|
{ "hindi", "hi"},
|
||||||
|
{ "hungarian", "hu"},
|
||||||
|
{ "icelandic", "is"},
|
||||||
|
{ "indonesian", "id"},
|
||||||
|
{ "irish", "ga"},
|
||||||
|
{ "italian", "it"},
|
||||||
|
{ "japanese", "ja"},
|
||||||
|
{ "korean", "ko"},
|
||||||
|
{ "lao", "lo"},
|
||||||
|
{ "latin", "la"},
|
||||||
|
{ "latvian", "lv"},
|
||||||
|
{ "lithuanian", "lt"},
|
||||||
|
{ "macedonian", "mk"},
|
||||||
|
{ "malay", "ms"},
|
||||||
|
{ "maltese", "mt"},
|
||||||
|
{ "norwegian", "no"},
|
||||||
|
{ "persian", "fa"},
|
||||||
|
{ "polish", "pl"},
|
||||||
|
{ "portuguese", "pt"},
|
||||||
|
{ "romanian", "ro"},
|
||||||
|
{ "russian", "ru"},
|
||||||
|
{ "serbian", "sr"},
|
||||||
|
{ "slovak", "sk"},
|
||||||
|
{ "slovenian", "sl"},
|
||||||
|
{ "spanish", "es"},
|
||||||
|
{ "swahili", "sw"},
|
||||||
|
{ "swedish", "sv"},
|
||||||
|
{ "tamil", "ta"},
|
||||||
|
{ "telugu", "te"},
|
||||||
|
{ "thai", "th"},
|
||||||
|
{ "turkish", "tr"},
|
||||||
|
{ "ukrainian", "uk"},
|
||||||
|
{ "urdu", "ur"},
|
||||||
|
{ "vietnamese", "vi"},
|
||||||
|
{ "welsh", "cy"},
|
||||||
|
{ "yiddish", "yi"},
|
||||||
|
|
||||||
|
{ "af", "af"},
|
||||||
|
{ "sq", "sq"},
|
||||||
|
{ "ar", "ar"},
|
||||||
|
{ "hy", "hy"},
|
||||||
|
{ "az", "az"},
|
||||||
|
{ "eu", "eu"},
|
||||||
|
{ "be", "be"},
|
||||||
|
{ "bn", "bn"},
|
||||||
|
{ "bg", "bg"},
|
||||||
|
{ "ca", "ca"},
|
||||||
|
{ "zh-tw", "zh-TW"},
|
||||||
|
{ "zh-cn", "zh-CN"},
|
||||||
|
{ "hr", "hr"},
|
||||||
|
{ "cs", "cs"},
|
||||||
|
{ "da", "da"},
|
||||||
|
{ "nl", "nl"},
|
||||||
|
{ "en", "en"},
|
||||||
|
{ "eo", "eo"},
|
||||||
|
{ "et", "et"},
|
||||||
|
{ "tl", "tl"},
|
||||||
|
{ "fi", "fi"},
|
||||||
|
{ "fr", "fr"},
|
||||||
|
{ "gl", "gl"},
|
||||||
|
{ "de", "de"},
|
||||||
|
{ "ka", "ka"},
|
||||||
|
{ "el", "el"},
|
||||||
|
{ "ht", "ht"},
|
||||||
|
{ "iw", "iw"},
|
||||||
|
{ "hi", "hi"},
|
||||||
|
{ "hu", "hu"},
|
||||||
|
{ "is", "is"},
|
||||||
|
{ "id", "id"},
|
||||||
|
{ "ga", "ga"},
|
||||||
|
{ "it", "it"},
|
||||||
|
{ "ja", "ja"},
|
||||||
|
{ "ko", "ko"},
|
||||||
|
{ "lo", "lo"},
|
||||||
|
{ "la", "la"},
|
||||||
|
{ "lv", "lv"},
|
||||||
|
{ "lt", "lt"},
|
||||||
|
{ "mk", "mk"},
|
||||||
|
{ "ms", "ms"},
|
||||||
|
{ "mt", "mt"},
|
||||||
|
{ "no", "no"},
|
||||||
|
{ "fa", "fa"},
|
||||||
|
{ "pl", "pl"},
|
||||||
|
{ "pt", "pt"},
|
||||||
|
{ "ro", "ro"},
|
||||||
|
{ "ru", "ru"},
|
||||||
|
{ "sr", "sr"},
|
||||||
|
{ "sk", "sk"},
|
||||||
|
{ "sl", "sl"},
|
||||||
|
{ "es", "es"},
|
||||||
|
{ "sw", "sw"},
|
||||||
|
{ "sv", "sv"},
|
||||||
|
{ "ta", "ta"},
|
||||||
|
{ "te", "te"},
|
||||||
|
{ "th", "th"},
|
||||||
|
{ "tr", "tr"},
|
||||||
|
{ "uk", "uk"},
|
||||||
|
{ "ur", "ur"},
|
||||||
|
{ "vi", "vi"},
|
||||||
|
{ "cy", "cy"},
|
||||||
|
{ "yi", "yi"},
|
||||||
|
};
|
||||||
|
|
||||||
|
public async Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage)
|
||||||
|
{
|
||||||
|
string text;
|
||||||
|
|
||||||
|
if (!_languageDictionary.ContainsKey(sourceLanguage) ||
|
||||||
|
!_languageDictionary.ContainsKey(targetLanguage))
|
||||||
|
throw new ArgumentException();
|
||||||
|
|
||||||
|
|
||||||
|
var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
||||||
|
ConvertToLanguageCode(sourceLanguage),
|
||||||
|
ConvertToLanguageCode(targetLanguage),
|
||||||
|
WebUtility.UrlEncode(sourceText));
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
||||||
|
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string.Concat(JArray.Parse(text)[0].Select(x => x[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ConvertToLanguageCode(string language)
|
||||||
|
{
|
||||||
|
string mode;
|
||||||
|
_languageDictionary.TryGetValue(language, out mode);
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ using NLog;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace NadekoBot.Services
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
@ -20,10 +21,13 @@ namespace NadekoBot.Services
|
|||||||
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
private readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
||||||
|
private readonly ILocalization _localization;
|
||||||
|
|
||||||
public NadekoStrings()
|
public NadekoStrings(ILocalization loc)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_localization = loc;
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
var allLangsDict = new Dictionary<string, ImmutableDictionary<string, string>>(); // lang:(name:value)
|
var allLangsDict = new Dictionary<string, ImmutableDictionary<string, string>>(); // lang:(name:value)
|
||||||
foreach (var file in Directory.GetFiles(stringsPath))
|
foreach (var file in Directory.GetFiles(stringsPath))
|
||||||
@ -58,6 +62,9 @@ namespace NadekoBot.Services
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetText(string key, ulong guildId, string lowerModuleTypeName, params object[] replacements) =>
|
||||||
|
GetText(key, _localization.GetCultureInfo(guildId), lowerModuleTypeName);
|
||||||
|
|
||||||
public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName)
|
public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName)
|
||||||
{
|
{
|
||||||
var text = GetString(lowerModuleTypeName + "_" + key, cultureInfo);
|
var text = GetString(lowerModuleTypeName + "_" + key, cultureInfo);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace NadekoBot.Modules.Searches.Models
|
namespace NadekoBot.Services.Searches
|
||||||
{
|
{
|
||||||
class MagicItem
|
public class MagicItem
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches.Models
|
namespace NadekoBot.Services.Searches
|
||||||
{
|
{
|
||||||
public class SearchPokemon
|
public class SearchPokemon
|
||||||
{
|
{
|
@ -1,4 +1,12 @@
|
|||||||
using NadekoBot.Extensions;
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
@ -7,6 +15,101 @@ namespace NadekoBot.Services.Searches
|
|||||||
{
|
{
|
||||||
public class SearchesService
|
public class SearchesService
|
||||||
{
|
{
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly IGoogleApiService _google;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
public ConcurrentDictionary<ulong, bool> TranslatedChannels { get; } = new ConcurrentDictionary<ulong, bool>();
|
||||||
|
public ConcurrentDictionary<UserChannelPair, string> UserLanguages { get; } = new ConcurrentDictionary<UserChannelPair, string>();
|
||||||
|
|
||||||
|
public readonly string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json";
|
||||||
|
public readonly string PokemonListFile = "data/pokemon/pokemon_list7.json";
|
||||||
|
public Dictionary<string, SearchPokemon> Pokemons { get; } = new Dictionary<string, SearchPokemon>();
|
||||||
|
public Dictionary<string, SearchPokemonAbility> PokemonAbilities { get; } = new Dictionary<string, SearchPokemonAbility>();
|
||||||
|
|
||||||
|
public List<WoWJoke> WowJokes { get; } = new List<WoWJoke>();
|
||||||
|
public List<MagicItem> MagicItems { get; } = new List<MagicItem>();
|
||||||
|
|
||||||
|
public SearchesService(DiscordShardedClient client, IGoogleApiService google, DbHandler db)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_google = google;
|
||||||
|
_db = db;
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
//translate commands
|
||||||
|
_client.MessageReceived += async (msg) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var umsg = msg as SocketUserMessage;
|
||||||
|
if (umsg == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out var autoDelete))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var key = new UserChannelPair()
|
||||||
|
{
|
||||||
|
UserId = umsg.Author.Id,
|
||||||
|
ChannelId = umsg.Channel.Id,
|
||||||
|
};
|
||||||
|
|
||||||
|
string langs;
|
||||||
|
if (!UserLanguages.TryGetValue(key, out langs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var text = await Translate(langs, umsg.Resolve(TagHandling.Ignore))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
if (autoDelete)
|
||||||
|
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
|
await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
};
|
||||||
|
|
||||||
|
//pokemon commands
|
||||||
|
if (File.Exists(PokemonListFile))
|
||||||
|
{
|
||||||
|
Pokemons = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemon>>(File.ReadAllText(PokemonListFile));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_log.Warn(PokemonListFile + " is missing. Pokemon abilities not loaded.");
|
||||||
|
if (File.Exists(PokemonAbilitiesFile))
|
||||||
|
PokemonAbilities = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemonAbility>>(File.ReadAllText(PokemonAbilitiesFile));
|
||||||
|
else
|
||||||
|
_log.Warn(PokemonAbilitiesFile + " is missing. Pokemon abilities not loaded.");
|
||||||
|
|
||||||
|
//joke commands
|
||||||
|
if (File.Exists("data/wowjokes.json"))
|
||||||
|
{
|
||||||
|
WowJokes = JsonConvert.DeserializeObject<List<WoWJoke>>(File.ReadAllText("data/wowjokes.json"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_log.Warn("data/wowjokes.json is missing. WOW Jokes are not loaded.");
|
||||||
|
|
||||||
|
if (File.Exists("data/magicitems.json"))
|
||||||
|
{
|
||||||
|
MagicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_log.Warn("data/magicitems.json is missing. Magic items are not loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Translate(string langs, string text = null)
|
||||||
|
{
|
||||||
|
var langarr = langs.ToLowerInvariant().Split('>');
|
||||||
|
if (langarr.Length != 2)
|
||||||
|
throw new ArgumentException();
|
||||||
|
var from = langarr[0];
|
||||||
|
var to = langarr[1];
|
||||||
|
text = text?.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
|
throw new ArgumentException();
|
||||||
|
return (await _google.Translate(text, from, to).ConfigureAwait(false)).SanitizeMentions();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string> DapiSearch(string tag, DapiSearchType type)
|
public async Task<string> DapiSearch(string tag, DapiSearchType type)
|
||||||
{
|
{
|
||||||
tag = tag?.Replace(" ", "_");
|
tag = tag?.Replace(" ", "_");
|
||||||
@ -65,4 +168,18 @@ namespace NadekoBot.Services.Searches
|
|||||||
Rule34,
|
Rule34,
|
||||||
Yandere
|
Yandere
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct UserChannelPair
|
||||||
|
{
|
||||||
|
public ulong UserId { get; set; }
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class StreamStatus
|
||||||
|
{
|
||||||
|
public bool IsLive { get; set; }
|
||||||
|
public string ApiLink { get; set; }
|
||||||
|
public string Views { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
11
src/NadekoBot/Services/Searches/StreamNotFoundException.cs
Normal file
11
src/NadekoBot/Services/Searches/StreamNotFoundException.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Searches
|
||||||
|
{
|
||||||
|
public class StreamNotFoundException : Exception
|
||||||
|
{
|
||||||
|
public StreamNotFoundException(string message) : base($"Stream '{message}' not found.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
190
src/NadekoBot/Services/Searches/StreamNotificationService.cs
Normal file
190
src/NadekoBot/Services/Searches/StreamNotificationService.cs
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Searches
|
||||||
|
{
|
||||||
|
public class StreamNotificationService
|
||||||
|
{
|
||||||
|
private readonly Timer _streamCheckTimer;
|
||||||
|
private bool firstStreamNotifPass { get; set; } = true;
|
||||||
|
private readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
||||||
|
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
|
||||||
|
public StreamNotificationService(DbHandler db, DiscordShardedClient client, NadekoStrings strings)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_client = client;
|
||||||
|
_strings = strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamNotificationService()
|
||||||
|
{
|
||||||
|
_streamCheckTimer = new Timer(async (state) =>
|
||||||
|
{
|
||||||
|
var oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(_cachedStatuses);
|
||||||
|
_cachedStatuses.Clear();
|
||||||
|
IEnumerable<FollowedStream> streams;
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
streams = uow.GuildConfigs.GetAllFollowedStreams();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(streams.Select(async fs =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
|
||||||
|
if (firstStreamNotifPass)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamStatus oldStatus;
|
||||||
|
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
|
||||||
|
oldStatus.IsLive != newStatus.IsLive)
|
||||||
|
{
|
||||||
|
var server = _client.GetGuild(fs.GuildId);
|
||||||
|
var channel = server?.GetTextChannel(fs.ChannelId);
|
||||||
|
if (channel == null)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await channel.EmbedAsync(GetEmbed(fs, newStatus, channel.Guild.Id)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
firstStreamNotifPass = false;
|
||||||
|
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
|
||||||
|
{
|
||||||
|
string response;
|
||||||
|
StreamStatus result;
|
||||||
|
switch (stream.Type)
|
||||||
|
{
|
||||||
|
case FollowedStream.FollowedStreamType.Hitbox:
|
||||||
|
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
|
||||||
|
if (checkCache && _cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||||
|
return result;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
|
||||||
|
if (!hbData.Success)
|
||||||
|
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
||||||
|
result = new StreamStatus()
|
||||||
|
{
|
||||||
|
IsLive = hbData.IsLive,
|
||||||
|
ApiLink = hitboxUrl,
|
||||||
|
Views = hbData.Views
|
||||||
|
};
|
||||||
|
_cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
|
||||||
|
return result;
|
||||||
|
case FollowedStream.FollowedStreamType.Twitch:
|
||||||
|
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
|
||||||
|
if (checkCache && _cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||||
|
return result;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
|
||||||
|
if (twData.Error != null)
|
||||||
|
{
|
||||||
|
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
||||||
|
}
|
||||||
|
result = new StreamStatus()
|
||||||
|
{
|
||||||
|
IsLive = twData.IsLive,
|
||||||
|
ApiLink = twitchUrl,
|
||||||
|
Views = twData.Stream?.Viewers.ToString() ?? "0"
|
||||||
|
};
|
||||||
|
_cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
|
||||||
|
return result;
|
||||||
|
case FollowedStream.FollowedStreamType.Beam:
|
||||||
|
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
|
||||||
|
if (checkCache && _cachedStatuses.TryGetValue(beamUrl, out result))
|
||||||
|
return result;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
|
||||||
|
if (bmData.Error != null)
|
||||||
|
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
|
||||||
|
result = new StreamStatus()
|
||||||
|
{
|
||||||
|
IsLive = bmData.IsLive,
|
||||||
|
ApiLink = beamUrl,
|
||||||
|
Views = bmData.ViewersCurrent.ToString()
|
||||||
|
};
|
||||||
|
_cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
|
||||||
|
return result;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmbedBuilder GetEmbed(FollowedStream fs, StreamStatus status, ulong guildId)
|
||||||
|
{
|
||||||
|
var embed = new EmbedBuilder().WithTitle(fs.Username)
|
||||||
|
.WithUrl(GetLink(fs))
|
||||||
|
.AddField(efb => efb.WithName(GetText(fs, "status"))
|
||||||
|
.WithValue(status.IsLive ? "Online" : "Offline")
|
||||||
|
.WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText(fs, "viewers"))
|
||||||
|
.WithValue(status.IsLive ? status.Views : "-")
|
||||||
|
.WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText(fs, "platform"))
|
||||||
|
.WithValue(fs.Type.ToString())
|
||||||
|
.WithIsInline(true))
|
||||||
|
.WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor);
|
||||||
|
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetText(FollowedStream fs, string key, params object[] replacements) =>
|
||||||
|
_strings.GetText(key,
|
||||||
|
fs.GuildId,
|
||||||
|
"Searches".ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
|
public string GetLink(FollowedStream fs)
|
||||||
|
{
|
||||||
|
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
|
||||||
|
return $"http://www.hitbox.tv/{fs.Username}/";
|
||||||
|
if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
|
||||||
|
return $"http://www.twitch.tv/{fs.Username}/";
|
||||||
|
if (fs.Type == FollowedStream.FollowedStreamType.Beam)
|
||||||
|
return $"https://beam.pro/{fs.Username}/";
|
||||||
|
return "??";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/NadekoBot/Services/Searches/StreamResponses.cs
Normal file
35
src/NadekoBot/Services/Searches/StreamResponses.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Searches
|
||||||
|
{
|
||||||
|
public class HitboxResponse
|
||||||
|
{
|
||||||
|
public bool Success { get; set; } = true;
|
||||||
|
[JsonProperty("media_is_live")]
|
||||||
|
public string MediaIsLive { get; set; }
|
||||||
|
public bool IsLive => MediaIsLive == "1";
|
||||||
|
[JsonProperty("media_views")]
|
||||||
|
public string Views { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TwitchResponse
|
||||||
|
{
|
||||||
|
public string Error { get; set; } = null;
|
||||||
|
public bool IsLive => Stream != null;
|
||||||
|
public StreamInfo Stream { get; set; }
|
||||||
|
|
||||||
|
public class StreamInfo
|
||||||
|
{
|
||||||
|
public int Viewers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BeamResponse
|
||||||
|
{
|
||||||
|
public string Error { get; set; } = null;
|
||||||
|
|
||||||
|
[JsonProperty("online")]
|
||||||
|
public bool IsLive { get; set; }
|
||||||
|
public int ViewersCurrent { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace NadekoBot.Modules.Searches.Models
|
namespace NadekoBot.Services.Searches
|
||||||
{
|
{
|
||||||
public class WoWJoke
|
public class WoWJoke
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user