Merge pull request #74 from Kwoth/dev

ups
This commit is contained in:
samvaio 2017-01-29 19:08:05 +05:30 committed by GitHub
commit c75a625aa7
33 changed files with 512 additions and 192 deletions

@ -1 +1 @@
Subproject commit 7c0cce6d35b04d883cf5ec2d775b051e4bc8739f
Subproject commit 4506fc5a54fe31d826649dc413467c52a3cd7896

View File

@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Administration
var channel = msg.Channel as SocketTextChannel;
if (channel == null)
return;
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id))
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune")
await msg.DeleteAsync().ConfigureAwait(false);
}
catch (Exception ex)

View File

@ -25,7 +25,6 @@ namespace NadekoBot.Modules.Administration
static AutoAssignRoleCommands()
{
_log = LogManager.GetCurrentClassLogger();
var sw = Stopwatch.StartNew();
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
@ -46,9 +45,6 @@ namespace NadekoBot.Modules.Administration
}
catch (Exception ex) { _log.Warn(ex); }
};
sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration
@ -22,8 +23,8 @@ namespace NadekoBot.Modules.Administration
private static Logger _log { get; }
public static List<PlayingStatus> RotatingStatusMessages { get; }
public static bool RotatingStatuses { get; private set; } = false;
//todo wtf is with this while(true) in constructor
private static Timer _t { get; }
static PlayingRotateCommands()
{
_log = LogManager.GetCurrentClassLogger();
@ -31,48 +32,43 @@ namespace NadekoBot.Modules.Administration
RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages;
RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses;
var t = Task.Run(async () =>
_t = new Timer(async (_) =>
{
var index = 0;
do
try
{
try
if (!RotatingStatuses)
return;
else
{
if (!RotatingStatuses)
continue;
else
{
if (index >= RotatingStatusMessages.Count)
index = 0;
if (index >= RotatingStatusMessages.Count)
index = 0;
if (!RotatingStatusMessages.Any())
continue;
var status = RotatingStatusMessages[index++].Status;
if (string.IsNullOrWhiteSpace(status))
continue;
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value()));
var shards = NadekoBot.Client.Shards;
for (int i = 0; i < shards.Count; i++)
if (!RotatingStatusMessages.Any())
return;
var status = RotatingStatusMessages[index++].Status;
if (string.IsNullOrWhiteSpace(status))
return;
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value()));
var shards = NadekoBot.Client.Shards;
for (int i = 0; i < shards.Count; i++)
{
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i))));
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
catch (Exception ex)
{
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i))));
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
catch (Exception ex)
{
_log.Warn(ex);
}
_log.Warn(ex);
}
}
}
catch (Exception ex)
{
_log.Warn("Rotating playing status errored.\n" + ex);
}
finally
{
await Task.Delay(TimeSpan.FromMinutes(1));
}
} while (true);
});
}
catch (Exception ex)
{
_log.Warn("Rotating playing status errored.\n" + ex);
}
}, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
@ -92,7 +88,7 @@ namespace NadekoBot.Modules.Administration
}
},
{ "%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
{ "%time%", () => DateTime.Now.ToString("hh:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
{ "%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
{ "%shardcount%", () => NadekoBot.Client.Shards.Count.ToString() },
};

View File

@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Administration
if (ids[1].ToUpperInvariant().StartsWith("C:"))
{
var cid = ulong.Parse(ids[1].Substring(2));
var ch = (await server.GetTextChannelsAsync()).Where(c => c.Id == cid).FirstOrDefault();
var ch = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
if (ch == null)
{
return;
@ -159,9 +159,7 @@ namespace NadekoBot.Modules.Administration
[OwnerOnly]
public async Task Announce([Remainder] string message)
{
var channels = await Task.WhenAll(NadekoBot.Client.GetGuilds().Select(g =>
g.GetDefaultChannelAsync()
)).ConfigureAwait(false);
var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray();
if (channels == null)
return;
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"🆕 Message from {Context.User} `[Bot Owner]`:", message)))

View File

@ -4,9 +4,11 @@ using Discord.WebSocket;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
@ -17,24 +19,76 @@ namespace NadekoBot.Modules.Administration
[Group]
public class ServerGreetCommands : ModuleBase
{
//make this to a field in the guildconfig table
class GreetSettings
{
public int AutoDeleteGreetMessagesTimer { get; set; }
public int AutoDeleteByeMessagesTimer { get; set; }
public ulong GreetMessageChannelId { get; set; }
public ulong ByeMessageChannelId { get; set; }
public bool SendDmGreetMessage { get; set; }
public string DmGreetMessageText { get; set; }
public bool SendChannelGreetMessage { get; set; }
public string ChannelGreetMessageText { get; set; }
public bool SendChannelByeMessage { get; set; }
public string ChannelByeMessageText { get; set; }
public static GreetSettings Create(GuildConfig g) => new GreetSettings()
{
AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer,
AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer,
GreetMessageChannelId = g.GreetMessageChannelId,
ByeMessageChannelId = g.ByeMessageChannelId,
SendDmGreetMessage = g.SendDmGreetMessage,
DmGreetMessageText = g.DmGreetMessageText,
SendChannelGreetMessage = g.SendChannelGreetMessage,
ChannelGreetMessageText = g.ChannelGreetMessageText,
SendChannelByeMessage = g.SendChannelByeMessage,
ChannelByeMessageText = g.ChannelByeMessageText,
};
}
private static Logger _log { get; }
private static ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache { get; } = new ConcurrentDictionary<ulong, GreetSettings>();
static ServerGreetCommands()
{
NadekoBot.Client.UserJoined += UserJoined;
NadekoBot.Client.UserLeft += UserLeft;
_log = LogManager.GetCurrentClassLogger();
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, (g) => GreetSettings.Create(g)));
}
private static GreetSettings GetOrAddSettingsForGuild(ulong guildId)
{
GreetSettings settings;
GuildConfigsCache.TryGetValue(guildId, out settings);
if (settings != null)
return settings;
using (var uow = DbHandler.UnitOfWork())
{
var gc = uow.GuildConfigs.For(guildId, set => set);
settings = GreetSettings.Create(gc);
}
GuildConfigsCache.TryAdd(guildId, settings);
return settings;
}
//todo optimize ASAP
private static async Task UserLeft(IGuildUser user)
{
try
{
GuildConfig conf;
using (var uow = DbHandler.UnitOfWork())
{
conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
}
var conf = GetOrAddSettingsForGuild(user.GuildId);
if (!conf.SendChannelByeMessage) return;
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
@ -62,11 +116,7 @@ namespace NadekoBot.Modules.Administration
{
try
{
GuildConfig conf;
using (var uow = DbHandler.UnitOfWork())
{
conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
}
var conf = GetOrAddSettingsForGuild(user.GuildId);
if (conf.SendChannelGreetMessage)
{
@ -133,6 +183,9 @@ namespace NadekoBot.Modules.Administration
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);
}
}
@ -159,6 +212,9 @@ namespace NadekoBot.Modules.Administration
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
conf.GreetMessageChannelId = channelId;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
await uow.CompleteAsync().ConfigureAwait(false);
}
return enabled;
@ -201,6 +257,9 @@ namespace NadekoBot.Modules.Administration
conf.ChannelGreetMessageText = message;
greetMsgEnabled = conf.SendChannelGreetMessage;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
uow.Complete();
}
return greetMsgEnabled;
@ -227,6 +286,9 @@ namespace NadekoBot.Modules.Administration
var conf = uow.GuildConfigs.For(guildId, set => set);
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
await uow.CompleteAsync().ConfigureAwait(false);
}
return enabled;
@ -269,6 +331,9 @@ namespace NadekoBot.Modules.Administration
conf.DmGreetMessageText = message;
greetMsgEnabled = conf.SendDmGreetMessage;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
uow.Complete();
}
return greetMsgEnabled;
@ -296,6 +361,9 @@ namespace NadekoBot.Modules.Administration
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
conf.ByeMessageChannelId = channelId;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
await uow.CompleteAsync();
}
return enabled;
@ -338,6 +406,9 @@ namespace NadekoBot.Modules.Administration
conf.ChannelByeMessageText = message;
byeMsgEnabled = conf.SendChannelByeMessage;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
uow.Complete();
}
return byeMsgEnabled;
@ -356,16 +427,19 @@ namespace NadekoBot.Modules.Administration
await Context.Channel.SendConfirmAsync(" Automatic deletion of bye messages has been **disabled**.").ConfigureAwait(false);
}
private static async Task SetByeDel(ulong id, int timer)
private static async Task SetByeDel(ulong guildId, int timer)
{
if (timer < 0 || timer > 600)
return;
using (var uow = DbHandler.UnitOfWork())
{
var conf = uow.GuildConfigs.For(id, set => set);
var conf = uow.GuildConfigs.For(guildId, set => set);
conf.AutoDeleteByeMessagesTimer = timer;
var toAdd = GreetSettings.Create(conf);
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
await uow.CompleteAsync().ConfigureAwait(false);
}
}

View File

@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration
{
try
{
await (await guild.GetOwnerAsync()).SendErrorAsync(
await guild.Owner.SendErrorAsync(
"⚠️ I don't have **manage server** and/or **manage channels** permission," +
$" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false);
}
@ -75,16 +75,16 @@ namespace NadekoBot.Modules.Administration
var beforeVch = before.VoiceChannel;
if (beforeVch != null)
{
var textChannel = (await guild.GetTextChannelsAsync()).Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
var textChannel = guild.TextChannels.Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
if (textChannel != null)
await textChannel.AddPermissionOverwriteAsync(user,
new OverwritePermissions(readMessages: PermValue.Deny,
sendMessages: PermValue.Deny)).ConfigureAwait(false);
}
var afterVch = after.VoiceChannel;
if (afterVch != null && guild.AFKChannelId != afterVch.Id)
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
{
var textChannel = (await guild.GetTextChannelsAsync())
ITextChannel textChannel = guild.TextChannels
.Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
.FirstOrDefault();
if (textChannel == null)

View File

@ -36,10 +36,8 @@ namespace NadekoBot.Modules.ClashOfClans
.GetAllWars()
.Select(cw =>
{
cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)
?.GetTextChannelAsync(cw.ChannelId)
.GetAwaiter()
.GetResult();
cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)?
.GetTextChannel(cw.ChannelId);
return cw;
})
.Where(cw => cw.Channel != null)
@ -322,7 +320,7 @@ namespace NadekoBot.Modules.ClashOfClans
public static async Task<ClashWar> CreateWar(string enemyClan, int size, ulong serverId, ulong channelId)
{
var channel = await NadekoBot.Client.GetGuild(serverId)?.GetTextChannelAsync(channelId);
var channel = NadekoBot.Client.GetGuild(serverId)?.GetTextChannel(channelId);
using (var uow = DbHandler.UnitOfWork())
{
var cw = new ClashWar

View File

@ -10,14 +10,16 @@ using NadekoBot.Extensions;
using NLog;
using System.Diagnostics;
using Discord.WebSocket;
using System;
namespace NadekoBot.Modules.CustomReactions
{
[NadekoModule("CustomReactions", ".")]
public class CustomReactions : DiscordModule
{
public static ConcurrentHashSet<CustomReaction> GlobalReactions { get; } = new ConcurrentHashSet<CustomReaction>();
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>> GuildReactions { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>();
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
public static CustomReaction[] GlobalReactions => _globalReactions;
public static ConcurrentDictionary<ulong, CustomReaction[]> GuildReactions { get; } = new ConcurrentDictionary<ulong, CustomReaction[]>();
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
@ -30,8 +32,8 @@ namespace NadekoBot.Modules.CustomReactions
using (var uow = DbHandler.UnitOfWork())
{
var items = uow.CustomReactions.GetAll();
GuildReactions = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet<CustomReaction>(g)));
GlobalReactions = new ConcurrentHashSet<CustomReaction>(items.Where(g => g.GuildId == null || g.GuildId == 0));
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
_globalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
}
sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
@ -46,32 +48,46 @@ namespace NadekoBot.Modules.CustomReactions
return false;
var content = umsg.Content.Trim().ToLowerInvariant();
ConcurrentHashSet<CustomReaction> reactions;
CustomReaction[] reactions;
GuildReactions.TryGetValue(channel.Guild.Id, out reactions);
if (reactions != null && reactions.Any())
{
var reaction = reactions.Where(cr =>
var rs = reactions.Where(cr =>
{
if (cr == null)
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault();
if (reaction != null)
{
if (reaction.Response != "-")
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
}).ToArray();
ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old);
return true;
if (rs.Length != 0)
{
var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
if (reaction != null)
{
if (reaction.Response != "-")
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old);
return true;
}
}
}
var greaction = GlobalReactions.Where(cr =>
var grs = GlobalReactions.Where(cr =>
{
if (cr == null)
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault();
}).ToArray();
if (grs.Length == 0)
return false;
var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
if (greaction != null)
{
@ -114,12 +130,19 @@ namespace NadekoBot.Modules.CustomReactions
if (channel == null)
{
GlobalReactions.Add(cr);
Array.Resize(ref _globalReactions, _globalReactions.Length + 1);
_globalReactions[_globalReactions.Length - 1] = cr;
}
else
{
var reactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
reactions.Add(cr);
var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id,
Array.Empty<CustomReaction>(),
(k, old) =>
{
Array.Resize(ref old, old.Length + 1);
old[old.Length - 1] = cr;
return old;
});
}
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
@ -136,17 +159,17 @@ namespace NadekoBot.Modules.CustomReactions
{
if (page < 1 || page > 1000)
return;
ConcurrentHashSet<CustomReaction> customReactions;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions;
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
else
{
var lastPage = customReactions.Count / 20;
var lastPage = customReactions.Length / 20;
await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
new EmbedBuilder().WithOkColor()
.WithTitle("Custom reactions")
@ -167,11 +190,11 @@ namespace NadekoBot.Modules.CustomReactions
[Priority(1)]
public async Task ListCustReact(All x)
{
ConcurrentHashSet<CustomReaction> customReactions;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions;
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
@ -195,11 +218,11 @@ namespace NadekoBot.Modules.CustomReactions
{
if (page < 1 || page > 10000)
return;
ConcurrentHashSet<CustomReaction> customReactions;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions;
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
@ -225,13 +248,13 @@ namespace NadekoBot.Modules.CustomReactions
[NadekoCommand, Usage, Description, Aliases]
public async Task ShowCustReact(int id)
{
ConcurrentHashSet<CustomReaction> customReactions;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions;
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ });
var found = customReactions.FirstOrDefault(cr => cr.Id == id);
var found = customReactions.FirstOrDefault(cr => cr?.Id == id);
if (found == null)
await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false);
@ -265,13 +288,17 @@ namespace NadekoBot.Modules.CustomReactions
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null)
{
uow.CustomReactions.Remove(toDelete);
GlobalReactions.RemoveWhere(cr => cr.Id == toDelete.Id);
//todo i can dramatically improve performance of this, if Ids are ordered.
_globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
success = true;
}
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId)
{
uow.CustomReactions.Remove(toDelete);
GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()).RemoveWhere(cr => cr.Id == toDelete.Id);
GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) =>
{
return old.Where(cr => cr?.Id != toDelete.Id).ToArray();
});
success = true;
}
if (success)
@ -312,8 +339,10 @@ namespace NadekoBot.Modules.CustomReactions
{
if (page < 1)
return;
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList();
var lastPage = ordered.Count / 9;
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToArray();
if (!ordered.Any())
return;
var lastPage = ordered.Length / 9;
await Context.Channel.SendPaginatedConfirmAsync(page,
(curPage) => ordered.Skip((curPage - 1) * 9)
.Take(9)

View File

@ -1,9 +1,11 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
@ -25,9 +27,13 @@ namespace NadekoBot.Modules.CustomReactions
if(ch == null)
return "";
var usrs = (ch.Guild.GetUsersAsync().GetAwaiter().GetResult());
var g = ch.Guild as SocketGuild;
if(g == null)
return "";
return usrs.Skip(new NadekoRandom().Next(0,usrs.Count-1)).Shuffle().FirstOrDefault()?.Mention ?? "";
var users = g.Users.ToArray();
return users[new NadekoRandom().Next(0, users.Length-1)].Mention;
} }
//{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } }
};

View File

@ -59,14 +59,14 @@ namespace NadekoBot.Modules.Gambling
catch
{
try { await msg.DeleteAsync().ConfigureAwait(false); }
catch { }
catch { return; }
}
}
using (msg.OnReaction(async (r) =>
{
try
{
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
{
try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { }
}

View File

@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling
var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown);
var membersArray = members as IUser[] ?? members.ToArray();
var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}** ID: `{usr.Id}`").ConfigureAwait(false);
await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -69,6 +69,7 @@ namespace NadekoBot.Modules.Games
private readonly ConcurrentDictionary<string, IGuildUser> submissions = new ConcurrentDictionary<string, IGuildUser>();
public IReadOnlyDictionary<string, IGuildUser> Submissions => submissions;
private readonly ConcurrentHashSet<ulong> usersWhoSubmitted = new ConcurrentHashSet<ulong>();
private readonly ConcurrentHashSet<ulong> usersWhoVoted = new ConcurrentHashSet<ulong>();
private int spamCount = 0;
@ -190,10 +191,6 @@ namespace NadekoBot.Modules.Games
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
catch { }
}
//user didn't input something already
IGuildUser throwaway;
if (submissions.TryGetValue(input, out throwaway))
return;
var inputWords = input.Split(' '); //get all words
if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters
@ -207,9 +204,15 @@ namespace NadekoBot.Modules.Games
return;
}
if (!usersWhoSubmitted.Add(guildUser.Id))
return;
//try adding it to the list of answers
if (!submissions.TryAdd(input, guildUser))
{
usersWhoSubmitted.TryRemove(guildUser.Id);
return;
}
// all good. valid input. answer recorded
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");

View File

@ -189,13 +189,13 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
catch (Exception ex) { _log.Warn(ex); }
}
public string GetHangman() => $@"\_\_\_\_\_\_\_\_\_
| |
| |
{(Errors > 0 ? "😲" : " ")} |
{(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} |
{(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} |
/-\";
public string GetHangman() => $@". ┌─────┐
................
................
.{(Errors > 0 ? ".............😲" : "")}
.{(Errors > 1 ? "............./" : "")} {(Errors > 2 ? "|" : "")} {(Errors > 3 ? "\\" : "")}
.{(Errors > 4 ? "............../" : "")} {(Errors > 5 ? "\\" : "")}
/-\";
public void Dispose()
{

View File

@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Games
return;
}
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord);
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman());
}
}
}

View File

@ -76,9 +76,9 @@ namespace NadekoBot.Modules.Games.Trivia
questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound ||
ex.StatusCode == System.Net.HttpStatusCode.Forbidden ||
ex.StatusCode == System.Net.HttpStatusCode.BadRequest)
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
ex.HttpCode == System.Net.HttpStatusCode.BadRequest)
{
return;
}
@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Games.Trivia
await questionMessage.ModifyAsync(m => m.Embed = questionEmbed.WithFooter(efb => efb.WithText(CurrentQuestion.GetHint())).Build())
.ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound || ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
{
break;
}

View File

@ -711,14 +711,11 @@ namespace NadekoBot.Modules.Music
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
//todo only author or owner
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task DeletePlaylist([Remainder] int id)
{
bool success = false;
MusicPlaylist pl = null;
try
@ -747,7 +744,7 @@ namespace NadekoBot.Modules.Music
}
catch (Exception ex)
{
Console.WriteLine(ex);
_log.Warn(ex);
}
}

View File

@ -1,4 +1,7 @@
using Discord;
using AngleSharp;
using AngleSharp.Dom.Html;
using AngleSharp.Extensions;
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
@ -8,6 +11,7 @@ using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@ -52,6 +56,116 @@ namespace NadekoBot.Modules.Searches
}, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
}
[NadekoCommand, Usage, Description, Aliases]
[Priority(1)]
public async Task Mal([Remainder] string name)
{
if (string.IsNullOrWhiteSpace(name))
return;
var fullQueryLink = "https://myanimelist.net/profile/" + name;
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
var imageElem = document.QuerySelector("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-left > div.user-profile > div.user-image > img");
var imageUrl = ((IHtmlImageElement)imageElem)?.Source ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png";
var stats = document.QuerySelectorAll("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-right > div#statistics > div.user-statistics-stats > div.stats > div.clearfix > ul.stats-status > li > span").Select(x => x.InnerHtml).ToList();
var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc");
var favAnime = "No favorite anime yet";
if (favorites[0].QuerySelector("p") == null)
favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
.Shuffle()
.Take(3)
.Select(x =>
{
var elem = (IHtmlAnchorElement)x;
return $"[{elem.InnerHtml}]({elem.Href})";
}));
//var favManga = "No favorite manga yet.";
//if (favorites[1].QuerySelector("p") == null)
// favManga = string.Join("\n", favorites[1].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
// .Take(3)
// .Select(x =>
// {
// var elem = (IHtmlAnchorElement)x;
// return $"[{elem.InnerHtml}]({elem.Href})";
// }));
var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li")
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))
.ToList();
var daysAndMean = document.QuerySelectorAll("div.anime:nth-child(1) > div:nth-child(2) > div")
.Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray())
.ToArray();
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle($"{name}'s MAL profile")
.AddField(efb => efb.WithName("💚 Watching").WithValue(stats[0]).WithIsInline(true))
.AddField(efb => efb.WithName("💙 Completed").WithValue(stats[1]).WithIsInline(true));
if (info.Count < 3)
embed.AddField(efb => efb.WithName("💛 On-Hold").WithValue(stats[2]).WithIsInline(true));
embed
.AddField(efb => efb.WithName("💔 Dropped").WithValue(stats[3]).WithIsInline(true))
.AddField(efb => efb.WithName("⚪ Plan to watch").WithValue(stats[4]).WithIsInline(true))
.AddField(efb => efb.WithName("🕐 " + daysAndMean[0][0]).WithValue(daysAndMean[0][1]).WithIsInline(true))
.AddField(efb => efb.WithName("📊 " + daysAndMean[1][0]).WithValue(daysAndMean[1][1]).WithIsInline(true))
.AddField(efb => efb.WithName(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true))
.AddField(efb => efb.WithName(MalInfoToEmoji(info[1].Item1) + " " + info[1].Item1).WithValue(info[1].Item2.TrimTo(20)).WithIsInline(true));
if (info.Count > 2)
embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[2].Item1) + " " + info[2].Item1).WithValue(info[2].Item2.TrimTo(20)).WithIsInline(true));
//if(info.Count > 3)
// embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[3].Item1) + " " + info[3].Item1).WithValue(info[3].Item2).WithIsInline(true))
embed
.WithDescription($@"
** https://myanimelist.net/animelist/{ name } **
**Top 3 Favorite Anime:**
{favAnime}"
//**[Manga List](https://myanimelist.net/mangalist/{name})**
//💚`Reading:` {stats[5]}
//💙`Completed:` {stats[6]}
//💔`Dropped:` {stats[8]}
//⚪`Plan to read:` {stats[9]}
//**Top 3 Favorite Manga:**
//{favManga}"
)
.WithUrl(fullQueryLink)
.WithImageUrl(imageUrl);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
private static string MalInfoToEmoji(string info) {
info = info.Trim().ToLowerInvariant();
switch (info)
{
case "gender":
return "🚁";
case "location":
return "🗺";
case "last online":
return "👥";
case "birthday":
return "📆";
default:
return "❔";
}
}
[NadekoCommand, Usage, Description, Aliases]
[Priority(0)]
public Task Mal(IUser usr) => Mal(usr.Username);
[NadekoCommand, Usage, Description, Aliases]
public async Task Anime([Remainder] string query)
{

View File

@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Searches
MemoryStream ms = new MemoryStream();
res.CopyTo(ms);
ms.Position = 0;
await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link: **https://osu.ppy.sh/u/{Uri.EscapeDataString(usr)}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link:** <https://new.ppy.sh/u/{Uri.EscapeDataString(usr)}>\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
}
catch (Exception ex)
{

View File

@ -60,9 +60,9 @@ namespace NadekoBot.Modules.Searches
.WithThumbnailUrl(rankimg)
.AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true))
.AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
.AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
.AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
.AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true))
.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))

View File

@ -105,7 +105,7 @@ namespace NadekoBot.Modules.Searches
var server = NadekoBot.Client.GetGuild(fs.GuildId);
if (server == null)
return;
var channel = await server.GetTextChannelAsync(fs.ChannelId);
var channel = server.GetTextChannel(fs.ChannelId);
if (channel == null)
return;
try

View File

@ -117,31 +117,49 @@ namespace NadekoBot.Modules.Searches
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
try
{
var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false);
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
.WithDescription(res.Link)
.WithImageUrl(res.Link)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
catch
{
_log.Warn("Falling back to Imgur search.");
var elems = document.QuerySelectorAll("a.image-list-link");
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
if (!elems.Any())
return;
var elems = document.QuerySelectorAll("a.image-list-link");
var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement);
if (!elems.Any())
return;
if (img?.Source == null)
return;
var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement);
var source = img.Source.Replace("b.", ".");
if (img?.Source == null)
return;
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl(fullQueryLink)
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
.WithDescription(source)
.WithImageUrl(source)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
var source = img.Source.Replace("b.", ".");
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl(fullQueryLink)
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
.WithDescription(source)
.WithImageUrl(source)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]
@ -150,34 +168,51 @@ namespace NadekoBot.Modules.Searches
terms = terms?.Trim();
if (string.IsNullOrWhiteSpace(terms))
return;
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
try
{
var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
.WithDescription(res.Link)
.WithImageUrl(res.Link)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
catch
{
_log.Warn("Falling back to Imgur");
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
var elems = document.QuerySelectorAll("a.image-list-link").ToList();
var elems = document.QuerySelectorAll("a.image-list-link").ToList();
if (!elems.Any())
return;
if (!elems.Any())
return;
var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement);
var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement);
if (img?.Source == null)
return;
if (img?.Source == null)
return;
var source = img.Source.Replace("b.", ".");
var source = img.Source.Replace("b.", ".");
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl(fullQueryLink)
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
.WithDescription(source)
.WithImageUrl(source)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
var embed = new EmbedBuilder()
.WithOkColor()
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
.WithUrl(fullQueryLink)
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
.WithDescription(source)
.WithImageUrl(source)
.WithTitle(Context.User.Mention);
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]
@ -260,7 +295,7 @@ namespace NadekoBot.Modules.Searches
.WithTitle(Context.User.Mention)
.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"))
.ConfigureAwait(false);
await Context.Channel.EmbedAsync(embed.WithDescription(String.Concat(desc))).ConfigureAwait(false);

View File

@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Utility
}
private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) =>
$"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content;
$"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
public static readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers = new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
private static Logger _log { get; }

View File

@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Utility
{
_log = LogManager.GetCurrentClassLogger();
this.Repeater = repeater;
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult();
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId);
if (Channel == null)
return;
Task.Run(Run);
@ -69,12 +69,12 @@ namespace NadekoBot.Modules.Utility
{
oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false);
}
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
{
_log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id);
return;
}
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound)
{
_log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id);
return;

View File

@ -68,9 +68,7 @@ namespace NadekoBot.Modules.Utility
}
else
{
var t = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannelAsync(r.ChannelId).ConfigureAwait(false);
if (t != null)
ch = await t.Value;
ch = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannel(r.ChannelId);
}
if (ch == null)
return;

View File

@ -116,15 +116,18 @@ namespace NadekoBot.Modules.Utility
var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync())
.Where(u => u.Game?.Name?.ToUpperInvariant() == game)
.Select(u => u.Username)
.Shuffle()
.Take(60)
.ToList();
int i = 0;
if (!arr.Any())
await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false);
else
else {
await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2)
.Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```")
.ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]

View File

@ -75,7 +75,8 @@ namespace NadekoBot
//initialize Services
CommandService = new CommandService(new CommandServiceConfig() {
CaseSensitiveCommands = false
CaseSensitiveCommands = false,
DefaultRunMode = RunMode.Sync
});
Google = new GoogleApiService();
CommandHandler = new CommandHandler(Client, CommandService);

View File

@ -177,7 +177,7 @@ namespace NadekoBot.Resources {
}
/// <summary>
/// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%.
/// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%.
/// </summary>
public static string addplaying_desc {
get {
@ -4406,6 +4406,33 @@ namespace NadekoBot.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to mal.
/// </summary>
public static string mal_cmd {
get {
return ResourceManager.GetString("mal_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Shows basic info from myanimelist profile..
/// </summary>
public static string mal_desc {
get {
return ResourceManager.GetString("mal_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}mal straysocks`.
/// </summary>
public static string mal_usage {
get {
return ResourceManager.GetString("mal_usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to manga mang mq.
/// </summary>

View File

@ -292,7 +292,7 @@
<value>addplaying adpl</value>
</data>
<data name="addplaying_desc" xml:space="preserve">
<value>Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%</value>
<value>Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%</value>
</data>
<data name="addplaying_usage" xml:space="preserve">
<value>`{0}adpl`</value>
@ -1376,7 +1376,6 @@
</data>
<data name="plant_usage" xml:space="preserve">
<value>`{0}plant` or `{0}plant 5`</value>
<comment> </comment>
</data>
<data name="gencurrency_cmd" xml:space="preserve">
<value>gencurrency gc</value>
@ -3025,4 +3024,13 @@
<data name="waifuinfo_usage" xml:space="preserve">
<value>`{0}waifuinfo @MyCrush` or `{0}waifuinfo`</value>
</data>
<data name="mal_cmd" xml:space="preserve">
<value>mal</value>
</data>
<data name="mal_desc" xml:space="preserve">
<value>Shows basic info from myanimelist profile.</value>
</data>
<data name="mal_usage" xml:space="preserve">
<value>`{0}mal straysocks`</value>
</data>
</root>

View File

@ -159,8 +159,8 @@ namespace NadekoBot.Services
private async Task<bool> WordFiltered(IGuild guild, SocketUserMessage usrMsg)
{
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id);
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id);
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
{
@ -222,6 +222,7 @@ namespace NadekoBot.Services
return;
// maybe this message is a custom reaction
// todo log custom reaction executions. return struct with info
var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false);
if (crExecuted) //if it was, don't execute the command
return;

View File

@ -8,13 +8,19 @@ using System.Text.RegularExpressions;
using Google.Apis.Urlshortener.v1;
using Google.Apis.Urlshortener.v1.Data;
using NLog;
using Google.Apis.Customsearch.v1;
using Google.Apis.Customsearch.v1.Data;
namespace NadekoBot.Services.Impl
{
public class GoogleApiService : IGoogleApiService
{
const string search_engine_id = "018084019232060951019:hs5piey28-e";
private YouTubeService yt;
private UrlshortenerService sh;
private CustomsearchService cs;
private Logger _log { get; }
public GoogleApiService()
@ -22,13 +28,14 @@ namespace NadekoBot.Services.Impl
var bcs = new BaseClientService.Initializer
{
ApplicationName = "Nadeko Bot",
ApiKey = NadekoBot.Credentials.GoogleApiKey
ApiKey = NadekoBot.Credentials.GoogleApiKey,
};
_log = LogManager.GetCurrentClassLogger();
yt = new YouTubeService(bcs);
sh = new UrlshortenerService(bcs);
cs = new CustomsearchService(bcs);
}
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
{
@ -150,7 +157,7 @@ namespace NadekoBot.Services.Impl
return toReturn;
}
//todo AsyncEnumerable
public async Task<IReadOnlyDictionary<string,TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds)
public async Task<IReadOnlyDictionary<string, TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds)
{
var videoIdsList = videoIds as List<string> ?? videoIds.ToList();
@ -179,5 +186,34 @@ namespace NadekoBot.Services.Impl
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)
{
if (string.IsNullOrWhiteSpace(query))
throw new ArgumentNullException(nameof(query));
var req = cs.Cse.List(query);
req.Cx = search_engine_id;
req.Num = 1;
req.Fields = "items(image(contextLink,thumbnailLink),link)";
req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image;
req.Start = start;
var search = await req.ExecuteAsync().ConfigureAwait(false);
return new ImageResult(search.Items[0].Image, search.Items[0].Link);
}
}
}

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl
private DiscordShardedClient client;
private DateTime started;
public const string BotVersion = "1.1.4";
public const string BotVersion = "1.1.5";
public string Author => "Kwoth#2560";
public string Library => "Discord.Net";

View File

@ -237,7 +237,7 @@
},
{
"Title":"Careers in Psychology: Opportunities in a Changing World",
"Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelor’s and graduate level."
"Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level."
},
{
"Title":"Philosophy of Psychology",