Merged with dev

This commit is contained in:
Master Kwoth 2017-05-17 14:28:50 +02:00
commit 2344624838
16 changed files with 153 additions and 106 deletions

View File

@ -26,7 +26,7 @@ Commands and aliases | Description | Usage
`.renamerole` `.renr` | Renames a role. The role you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole` `.renamerole` `.renr` | Renames a role. The role you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole`
`.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User`
`.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role`
`.rolehoist` `.rh` | Toggles if this role is displayed in the sidebar or not **Requires ManageRoles server permission.** | `.rh Guests true` or `.rh "Space Wizards" true `.rolehoist` `.rh` | Toggles if this role is displayed in the sidebar or not **Requires ManageRoles server permission.** | `.rh Guests true` or `.rh "Space Wizards" true`
`.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55`
`.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"`
`.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"`
@ -73,7 +73,7 @@ Commands and aliases | Description | Usage
`.lsar` | Lists all self-assignable roles. | `.lsar` `.lsar` | Lists all self-assignable roles. | `.lsar`
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar`
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer`
`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` `.iamnot` `.iamn` | Removes a specified role from you. Role must be on a list of self-assignable roles. | `.iamn Gamer`
`.scadd` | Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. **Bot owner only** | `.scadd .stats` `.scadd` | Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. **Bot owner only** | `.scadd .stats`
`.sclist` | Lists all startup commands in the order they will be executed in. **Bot owner only** | `.sclist` `.sclist` | Lists all startup commands in the order they will be executed in. **Bot owner only** | `.sclist`
`.wait` | Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. **Bot owner only** | `.wait 3000` `.wait` | Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. **Bot owner only** | `.wait 3000`
@ -94,11 +94,11 @@ Commands and aliases | Description | Usage
`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages` `.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages`
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` `.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` `.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` `.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.me/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.`
`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm` `.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm`
`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`. `.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.me/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`.
`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye`
`.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.me/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.`
`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30`
`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person` `.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person`
`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy` `.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy`
@ -170,7 +170,7 @@ Commands and aliases | Description | Usage
`$buy` | Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you. | `$buy 2` `$buy` | Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you. | `$buy 2`
`$shopadd` | Adds an item to the shop by specifying type price and name. Available types are role and list. **Requires Administrator server permission.** | `$shopadd role 1000 Rich` `$shopadd` | Adds an item to the shop by specifying type price and name. Available types are role and list. **Requires Administrator server permission.** | `$shopadd role 1000 Rich`
`$shoplistadd` | Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. **Requires Administrator server permission.** | `$shoplistadd 1 Uni-que-Steam-Key` `$shoplistadd` | Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. **Requires Administrator server permission.** | `$shoplistadd 1 Uni-que-Steam-Key`
`$shoprem` `$shoprm` | Removes an item from the shop by its color. **Requires Administrator server permission.** | `$shoprm 1` `$shoprem` `$shoprm` | Removes an item from the shop by its ID. **Requires Administrator server permission.** | `$shoprm 1`
`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot owner only** | `$slotstats` `$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot owner only** | `$slotstats`
`$slottest` | Tests to see how much slots payout for X number of plays. **Bot owner only** | `$slottest 1000` `$slottest` | Tests to see how much slots payout for X number of plays. **Bot owner only** | `$slottest 1000`
`$slot` | Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user. | `$slot 5` `$slot` | Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user. | `$slot 5`
@ -311,8 +311,8 @@ Commands and aliases | Description | Usage
`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop` `;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop`
`;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw` `;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw`
`;listglobalperms` `;lgp` | Lists global permissions set by the bot owner. **Bot owner only** | `;lgp` `;listglobalperms` `;lgp` | Lists global permissions set by the bot owner. **Bot owner only** | `;lgp`
`;globalmodule` `;gmod` | Enable or disable a module from use on all servers. **Bot owner only** | `;gmod nsfw disable` `;globalmodule` `;gmod` | Toggles whether a module can be used on any server. **Bot owner only** | `;gmod nsfw`
`;globalcommand` `;gcmd` | Enables or disables a command from use on all servers. **Bot owner only** | `;gcmd ` `;globalcommand` `;gcmd` | Toggles whether a command can be used on any server. **Bot owner only** | `;gcmd .stats`
###### [Back to ToC](#table-of-contents) ###### [Back to ToC](#table-of-contents)
@ -362,7 +362,7 @@ Commands and aliases | Description | Usage
`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin` `~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin`
`~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym` `~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
`~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj` `~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
`~chucknorris` `~cn` | Shows a random Chuck Norris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn` `~chucknorris` `~cn` | Shows a random Chuck Norris joke from <http://api.icndb.com/jokes/random/> | `~cn`
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke` `~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
`~magicitem` `~mi` | Shows a random magic item from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi` `~magicitem` `~mi` | Shows a random magic item from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist` `~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`

View File

@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Administration
var channel = msg.Channel as SocketTextChannel; var channel = msg.Channel as SocketTextChannel;
if (channel == null) if (channel == null)
return; return;
if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
await msg.DeleteAsync().ConfigureAwait(false); await msg.DeleteAsync().ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Administration
{ {
var guser = (IGuildUser)Context.User; var guser = (IGuildUser)Context.User;
var maxRole = guser.GetRoles().Max(x => x.Position); var maxRole = guser.GetRoles().Max(x => x.Position);
if (maxRole < role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)) if ((Context.User.Id != Context.Guild.OwnerId) && (maxRole < role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)))
return; return;
try try
{ {
@ -378,12 +378,14 @@ namespace NadekoBot.Modules.Administration
{ {
var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false); var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable(); var enumerable = (await Context.Channel.GetMessagesAsync().Flatten())
enumerable = enumerable.Where(x => x.Author.Id == user.Id); .Where(x => x.Author.Id == user.Id && DateTime.Now - x.CreatedAt < twoWeeks);
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
Context.Message.DeleteAfter(3); Context.Message.DeleteAfter(3);
} }
private TimeSpan twoWeeks => TimeSpan.FromDays(14);
// prune x // prune x
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
@ -396,7 +398,8 @@ namespace NadekoBot.Modules.Administration
return; return;
await Context.Message.DeleteAsync().ConfigureAwait(false); await Context.Message.DeleteAsync().ConfigureAwait(false);
int limit = (count < 100) ? count + 1 : 100; int limit = (count < 100) ? count + 1 : 100;
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false)); var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false))
.Where(x => DateTime.Now - x.CreatedAt < twoWeeks);
if (enumerable.FirstOrDefault()?.Id == Context.Message.Id) if (enumerable.FirstOrDefault()?.Id == Context.Message.Id)
enumerable = enumerable.Skip(1).ToArray(); enumerable = enumerable.Skip(1).ToArray();
else else
@ -419,7 +422,8 @@ namespace NadekoBot.Modules.Administration
count += 1; count += 1;
int limit = (count < 100) ? count : 100; int limit = (count < 100) ? count : 100;
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user); var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten())
.Where(m => m.Author == user && DateTime.Now - m.CreatedAt < twoWeeks);
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
Context.Message.DeleteAfter(3); Context.Message.DeleteAfter(3);
@ -434,7 +438,9 @@ namespace NadekoBot.Modules.Administration
foreach (var role in roles) foreach (var role in roles)
{ {
send += $"\n**{role.Name}**\n"; send += $"\n**{role.Name}**\n";
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Take(50).Select(u => u.Mention)); send += string.Join(", ", (await Context.Guild.GetUsersAsync())
.Where(u => u.GetRoles().Contains(role))
.Take(50).Select(u => u.Mention));
} }
while (send.Length > 2000) while (send.Length > 2000)

View File

@ -10,6 +10,8 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
namespace NadekoBot.Modules.Administration namespace NadekoBot.Modules.Administration
{ {
@ -35,30 +37,51 @@ namespace NadekoBot.Modules.Administration
= new ConcurrentDictionary<ulong, UserSpamStats>(); = new ConcurrentDictionary<ulong, UserSpamStats>();
} }
public class UserSpamStats public class UserSpamStats : IDisposable
{ {
public int Count { get; set; } public int Count => timers.Count;
public string LastMessage { get; set; } public string LastMessage { get; set; }
public UserSpamStats(string msg) private ConcurrentQueue<Timer> timers { get; }
{
Count = 1;
LastMessage = msg.ToUpperInvariant();
}
public UserSpamStats(IUserMessage msg)
{
LastMessage = msg.Content.ToUpperInvariant();
timers = new ConcurrentQueue<Timer>();
ApplyNextMessage(msg);
}
private readonly object applyLock = new object();
public void ApplyNextMessage(IUserMessage message) public void ApplyNextMessage(IUserMessage message)
{ {
var upperMsg = message.Content.ToUpperInvariant(); lock(applyLock){
if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any())) var upperMsg = message.Content.ToUpperInvariant();
{ if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any()))
LastMessage = upperMsg; {
Count = 0; LastMessage = upperMsg;
} //todo c#7
else Timer old;
{ while(timers.TryDequeue(out old))
Count++; old.Change(Timeout.Infinite, Timeout.Infinite);
}
var t = new Timer((_) => {
//todo c#7
Timer __;
if(timers.TryDequeue(out __))
__.Change(Timeout.Infinite, Timeout.Infinite);
}, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30));
timers.Enqueue(t);
} }
} }
public void Dispose()
{
//todo c#7
Timer old;
while(timers.TryDequeue(out old))
old.Change(Timeout.Infinite, Timeout.Infinite);
}
} }
[Group] [Group]
@ -112,7 +135,7 @@ namespace NadekoBot.Modules.Administration
})) }))
return; return;
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, (id) => new UserSpamStats(msg),
(id, old) => (id, old) =>
{ {
old.ApplyNextMessage(msg); return old; old.ApplyNextMessage(msg); return old;
@ -122,6 +145,7 @@ namespace NadekoBot.Modules.Administration
{ {
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
{ {
stats.Dispose();
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
@ -317,6 +341,7 @@ namespace NadekoBot.Modules.Administration
AntiSpamStats throwaway; AntiSpamStats throwaway;
if (_antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) if (_antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
{ {
throwaway.UserStats.ForEach(x => x.Value.Dispose());
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting) var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)

View File

@ -108,7 +108,6 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var roleModels = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToList(); var roleModels = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToList();
roleCnt = roleModels.Count;
msg.AppendLine(); msg.AppendLine();
foreach (var roleModel in roleModels) foreach (var roleModel in roleModels)
@ -116,11 +115,13 @@ namespace NadekoBot.Modules.Administration
var role = Context.Guild.Roles.FirstOrDefault(r => r.Id == roleModel.RoleId); var role = Context.Guild.Roles.FirstOrDefault(r => r.Id == roleModel.RoleId);
if (role == null) if (role == null)
{ {
toRemove.Add(roleModel);
uow.SelfAssignedRoles.Remove(roleModel); uow.SelfAssignedRoles.Remove(roleModel);
} }
else else
{ {
msg.Append($"**{role.Name}**, "); msg.Append($"**{role.Name}**, ");
roleCnt++;
} }
} }
foreach (var role in toRemove) foreach (var role in toRemove)

View File

@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Administration
await guild.AddBanAsync(user).ConfigureAwait(false); await guild.AddBanAsync(user).ConfigureAwait(false);
break; break;
case PunishmentAction.Softban: case PunishmentAction.Softban:
await guild.AddBanAsync(user).ConfigureAwait(false); await guild.AddBanAsync(user, 7).ConfigureAwait(false);
try try
{ {
await guild.RemoveBanAsync(user).ConfigureAwait(false); await guild.RemoveBanAsync(user).ConfigureAwait(false);
@ -214,25 +214,15 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var ps = uow.GuildConfigs.For(Context.Guild.Id).WarnPunishments; var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
var p = ps.FirstOrDefault(x => x.Count == number); ps.RemoveAll(x => x.Count == number);
if (p == null) ps.Add(new WarningPunishment()
{ {
ps.Add(new WarningPunishment() Count = number,
{ Punishment = punish,
Count = number, Time = time,
Punishment = punish, });
Time = time,
});
}
else
{
p.Count = number;
p.Punishment = punish;
p.Time = time;
uow._context.Update(p);
}
uow.Complete(); uow.Complete();
} }

View File

@ -173,6 +173,8 @@ namespace NadekoBot.Modules.Gambling
amount + CurrencySign); amount + CurrencySign);
if (w.Affinity?.UserId == Context.User.Id) if (w.Affinity?.UserId == Context.User.Id)
msg += "\n" + GetText("waifu_fulfilled", target, w.Price + CurrencySign); msg += "\n" + GetText("waifu_fulfilled", target, w.Price + CurrencySign);
else
msg = " " + msg;
await Context.Channel.SendConfirmAsync(Context.User.Mention + msg).ConfigureAwait(false); await Context.Channel.SendConfirmAsync(Context.User.Mention + msg).ConfigureAwait(false);
} }
@ -188,9 +190,15 @@ namespace NadekoBot.Modules.Gambling
private static readonly TimeSpan _divorceLimit = TimeSpan.FromHours(6); private static readonly TimeSpan _divorceLimit = TimeSpan.FromHours(6);
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Divorce([Remainder]IGuildUser target) [Priority(1)]
public Task Divorce([Remainder]IGuildUser target) => Divorce(target.Id);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[Priority(0)]
public async Task Divorce([Remainder]ulong targetId)
{ {
if (target.Id == Context.User.Id) if (targetId == Context.User.Id)
return; return;
DivorceResult result; DivorceResult result;
@ -199,7 +207,7 @@ namespace NadekoBot.Modules.Gambling
WaifuInfo w = null; WaifuInfo w = null;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
w = uow.Waifus.ByWaifuUserId(target.Id); w = uow.Waifus.ByWaifuUserId(targetId);
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id) if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id)
result = DivorceResult.NotYourWife; result = DivorceResult.NotYourWife;

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Games.Hangman
{ {
public class HangmanTermPool public class HangmanTermPool
{ {
const string termsPath = "data/hangman2.json"; const string termsPath = "data/hangman3.json";
public static IReadOnlyDictionary<string, HangmanObject[]> data { get; } public static IReadOnlyDictionary<string, HangmanObject[]> data { get; }
static HangmanTermPool() static HangmanTermPool()
{ {

View File

@ -82,9 +82,9 @@ namespace NadekoBot.Modules.Games
var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name]; var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name];
var toSend = dropAmount == 1 var toSend = dropAmount == 1
? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign) ? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign)
+ GetLocalText(channel, "pick_sn", prefix) + " " + GetLocalText(channel, "pick_sn", prefix)
: GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign) : GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign)
+ GetLocalText(channel, "pick_pl", prefix); + " " + GetLocalText(channel, "pick_pl", prefix);
var file = GetRandomCurrencyImage(); var file = GetRandomCurrencyImage();
using (var fileStream = file.Value.ToStream()) using (var fileStream = file.Value.ToStream())
{ {

View File

@ -26,7 +26,11 @@ namespace NadekoBot.Modules.Music.Classes
{ {
public SongInfo SongInfo { get; } public SongInfo SongInfo { get; }
public MusicPlayer MusicPlayer { get; set; } public MusicPlayer MusicPlayer { get; set; }
public string QueuerName { get; set; }
private string _queuerName;
public string QueuerName { get{
return Discord.Format.Sanitize(_queuerName);
} set { _queuerName = value; } }
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero; public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
public TimeSpan CurrentTime => TimeSpan.FromSeconds(BytesSent / (float)_frameBytes / (1000 / (float)_milliseconds)); public TimeSpan CurrentTime => TimeSpan.FromSeconds(BytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));

View File

@ -65,6 +65,9 @@ namespace NadekoBot.Modules.Permissions
private async Task Blacklist(AddRemove action, ulong id, BlacklistType type) private async Task Blacklist(AddRemove action, ulong id, BlacklistType type)
{ {
if(action == AddRemove.Add && NadekoBot.Credentials.OwnerIds.Contains(id))
return;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
if (action == AddRemove.Add) if (action == AddRemove.Add)

View File

@ -190,7 +190,7 @@ namespace NadekoBot.Modules.Permissions
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilteredWords)); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilteredWords));
removed = config.FilteredWords.RemoveWhere(fw => fw.Word == word); removed = config.FilteredWords.RemoveWhere(fw => fw.Word.Trim().ToLowerInvariant() == word);
if (removed == 0) if (removed == 0)
config.FilteredWords.Add(new Services.Database.Models.FilteredWord() { Word = word }); config.FilteredWords.Add(new Services.Database.Models.FilteredWord() { Word = word });

View File

@ -126,7 +126,7 @@ namespace NadekoBot.Modules.Utility
} }
await Context.Channel.EmbedAsync(new EmbedBuilder() await Context.Channel.EmbedAsync(new EmbedBuilder()
.WithTitle(GetText("activity_page", page)) .WithTitle(GetText("activity_page", page + 1))
.WithOkColor() .WithOkColor()
.WithFooter(efb => efb.WithText(GetText("activity_users_total", .WithFooter(efb => efb.WithText(GetText("activity_users_total",
NadekoBot.CommandHandler.UserMessagesSent.Count))) NadekoBot.CommandHandler.UserMessagesSent.Count)))

View File

@ -123,8 +123,19 @@ namespace NadekoBot.Modules.Utility
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)] [RequireUserPermission(GuildPermission.ManageMessages)]
[Priority(0)] [Priority(0)]
public Task Remind(ITextChannel channel, string timeStr, [Remainder] string message) => public async Task Remind(ITextChannel channel, string timeStr, [Remainder] string message)
RemindInternal(channel.Id, false, timeStr, message); {
var perms = ((IGuildUser)Context.User).GetPermissions((ITextChannel)channel);
if (!perms.SendMessages || !perms.ReadMessages)
{
await ReplyErrorLocalized("cant_read_or_send").ConfigureAwait(false);
return;
}
else
{
var _ = RemindInternal(channel.Id, false, timeStr, message).ConfigureAwait(false);
}
}
public async Task RemindInternal(ulong targetId, bool isPrivate, string timeStr, [Remainder] string message) public async Task RemindInternal(ulong targetId, bool isPrivate, string timeStr, [Remainder] string message)
{ {

View File

@ -503,7 +503,6 @@ namespace NadekoBot.Modules.Utility
await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Ping() public async Task Ping()
{ {
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();

View File

@ -418,7 +418,7 @@
<value>iamnot iamn</value> <value>iamnot iamn</value>
</data> </data>
<data name="iamnot_desc" xml:space="preserve"> <data name="iamnot_desc" xml:space="preserve">
<value>Removes a role to you that you choose. Role must be on a list of self-assignable roles.</value> <value>Removes a specified role from you. Role must be on a list of self-assignable roles.</value>
</data> </data>
<data name="iamnot_usage" xml:space="preserve"> <data name="iamnot_usage" xml:space="preserve">
<value>`{0}iamn Gamer`</value> <value>`{0}iamn Gamer`</value>
@ -2038,7 +2038,7 @@
<value>chucknorris cn</value> <value>chucknorris cn</value>
</data> </data>
<data name="chucknorris_desc" xml:space="preserve"> <data name="chucknorris_desc" xml:space="preserve">
<value>Shows a random Chuck Norris joke from &lt;http://tambal.azurewebsites.net/joke/random&gt;</value> <value>Shows a random Chuck Norris joke from &lt;http://api.icndb.com/jokes/random/&gt;</value>
</data> </data>
<data name="chucknorris_usage" xml:space="preserve"> <data name="chucknorris_usage" xml:space="preserve">
<value>`{0}cn`</value> <value>`{0}cn`</value>
@ -3388,7 +3388,7 @@
<value>shoprem shoprm</value> <value>shoprem shoprm</value>
</data> </data>
<data name="shopremove_desc" xml:space="preserve"> <data name="shopremove_desc" xml:space="preserve">
<value>Removes an item from the shop by its color.</value> <value>Removes an item from the shop by its ID.</value>
</data> </data>
<data name="shop_cmd" xml:space="preserve"> <data name="shop_cmd" xml:space="preserve">
<value>shop</value> <value>shop</value>
@ -3406,7 +3406,7 @@
<value>Toggles whether this role is displayed in the sidebar or not.</value> <value>Toggles whether this role is displayed in the sidebar or not.</value>
</data> </data>
<data name="rolehoist_usage" xml:space="preserve"> <data name="rolehoist_usage" xml:space="preserve">
<value>`{0}rh Guests` or `{0}rh "Space Wizards"</value> <value>`{0}rh Guests` or `{0}rh "Space Wizards"`</value>
</data> </data>
<data name="buy_cmd" xml:space="preserve"> <data name="buy_cmd" xml:space="preserve">
<value>buy</value> <value>buy</value>
@ -3442,19 +3442,19 @@
<value>globalcommand gcmd</value> <value>globalcommand gcmd</value>
</data> </data>
<data name="gcmd_desc" xml:space="preserve"> <data name="gcmd_desc" xml:space="preserve">
<value>Enables or disables a command from use on all servers.</value> <value>Toggles whether a command can be used on any server.</value>
</data> </data>
<data name="gcmd_usage" xml:space="preserve"> <data name="gcmd_usage" xml:space="preserve">
<value>`{0}gcmd `</value> <value>`{0}gcmd .stats`</value>
</data> </data>
<data name="gmod_cmd" xml:space="preserve"> <data name="gmod_cmd" xml:space="preserve">
<value>globalmodule gmod</value> <value>globalmodule gmod</value>
</data> </data>
<data name="gmod_desc" xml:space="preserve"> <data name="gmod_desc" xml:space="preserve">
<value>Enable or disable a module from use on all servers.</value> <value>Toggles whether a module can be used on any server.</value>
</data> </data>
<data name="gmod_usage" xml:space="preserve"> <data name="gmod_usage" xml:space="preserve">
<value>`{0}gmod nsfw disable`</value> <value>`{0}gmod nsfw`</value>
</data> </data>
<data name="lgp_cmd" xml:space="preserve"> <data name="lgp_cmd" xml:space="preserve">
<value>listglobalperms lgp</value> <value>listglobalperms lgp</value>

View File

@ -772,7 +772,7 @@
}, },
{ {
"Word": "Antigua and Barbuda", "Word": "Antigua and Barbuda",
"ImageUrl": "https://www.randomlists.com/img/national-flags/antigua-and-barbuda.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/antigua_and_barbuda.gif"
}, },
{ {
"Word": "Argentina", "Word": "Argentina",
@ -836,7 +836,7 @@
}, },
{ {
"Word": "Bosnia and Herzegovina", "Word": "Bosnia and Herzegovina",
"ImageUrl": "https://www.randomlists.com/img/national-flags/bosnia-and-herzegovina.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/bosnia_and_herzegovina.gif"
}, },
{ {
"Word": "Botswana", "Word": "Botswana",
@ -856,7 +856,7 @@
}, },
{ {
"Word": "Burkina Faso", "Word": "Burkina Faso",
"ImageUrl": "https://www.randomlists.com/img/national-flags/burkina-faso.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/burkina_faso.gif"
}, },
{ {
"Word": "Burma", "Word": "Burma",
@ -880,11 +880,11 @@
}, },
{ {
"Word": "Cape Verde", "Word": "Cape Verde",
"ImageUrl": "https://www.randomlists.com/img/national-flags/cape-verde.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/cape_verde.gif"
}, },
{ {
"Word": "Central African Republic", "Word": "Central African Republic",
"ImageUrl": "https://www.randomlists.com/img/national-flags/central-african-republic.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/central_african_republic.gif"
}, },
{ {
"Word": "Chad", "Word": "Chad",
@ -912,7 +912,7 @@
}, },
{ {
"Word": "Costa Rica", "Word": "Costa Rica",
"ImageUrl": "https://www.randomlists.com/img/national-flags/costa-rica.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/costa_rica.gif"
}, },
{ {
"Word": "Croatia", "Word": "Croatia",
@ -928,7 +928,7 @@
}, },
{ {
"Word": "Czech Republic", "Word": "Czech Republic",
"ImageUrl": "https://www.randomlists.com/img/national-flags/czech-republic.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/czech_republic.gif"
}, },
{ {
"Word": "Denmark", "Word": "Denmark",
@ -944,11 +944,11 @@
}, },
{ {
"Word": "Dominican Republic", "Word": "Dominican Republic",
"ImageUrl": "https://www.randomlists.com/img/national-flags/dominican-republic.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/dominican_republic.gif"
}, },
{ {
"Word": "East Timor", "Word": "East Timor",
"ImageUrl": "https://www.randomlists.com/img/national-flags/east-timor.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/east_timor.gif"
}, },
{ {
"Word": "Ecuador", "Word": "Ecuador",
@ -960,7 +960,7 @@
}, },
{ {
"Word": "El Salvador", "Word": "El Salvador",
"ImageUrl": "https://www.randomlists.com/img/national-flags/el-salvador.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/el_salvador.gif"
}, },
{ {
"Word": "England", "Word": "England",
@ -968,7 +968,7 @@
}, },
{ {
"Word": "Equatorial Guinea", "Word": "Equatorial Guinea",
"ImageUrl": "https://www.randomlists.com/img/national-flags/equatorial-guinea.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/equatorial_guinea.gif"
}, },
{ {
"Word": "Eritrea", "Word": "Eritrea",
@ -1032,7 +1032,7 @@
}, },
{ {
"Word": "Guinea-Bissau", "Word": "Guinea-Bissau",
"ImageUrl": "https://www.randomlists.com/img/national-flags/guinea-bissau.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/guinea_bissau.gif"
}, },
{ {
"Word": "Guyana", "Word": "Guyana",
@ -1048,7 +1048,7 @@
}, },
{ {
"Word": "Hong Kong", "Word": "Hong Kong",
"ImageUrl": "https://www.randomlists.com/img/national-flags/hong-kong.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/hong_kong.gif"
}, },
{ {
"Word": "Hungary", "Word": "Hungary",
@ -1080,7 +1080,7 @@
}, },
{ {
"Word": "Isle of Man", "Word": "Isle of Man",
"ImageUrl": "https://www.randomlists.com/img/national-flags/isle-of-man.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/isle_of_man.gif"
}, },
{ {
"Word": "Israel", "Word": "Israel",
@ -1116,11 +1116,11 @@
}, },
{ {
"Word": "North Korea", "Word": "North Korea",
"ImageUrl": "https://www.randomlists.com/img/national-flags/korea-north.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/korea_north.gif"
}, },
{ {
"Word": "South Korea", "Word": "South Korea",
"ImageUrl": "https://www.randomlists.com/img/national-flags/korea-south.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/korea_south.gif"
}, },
{ {
"Word": "Kosovo", "Word": "Kosovo",
@ -1204,7 +1204,7 @@
}, },
{ {
"Word": "Marshall Islands", "Word": "Marshall Islands",
"ImageUrl": "https://www.randomlists.com/img/national-flags/marshall-islands.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/marshall_islands.gif"
}, },
{ {
"Word": "Mauritania", "Word": "Mauritania",
@ -1264,7 +1264,7 @@
}, },
{ {
"Word": "New Zealand", "Word": "New Zealand",
"ImageUrl": "https://www.randomlists.com/img/national-flags/new-zealand.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/new_zealand.gif"
}, },
{ {
"Word": "Nicaragua", "Word": "Nicaragua",
@ -1300,7 +1300,7 @@
}, },
{ {
"Word": "Papua New Guinea", "Word": "Papua New Guinea",
"ImageUrl": "https://www.randomlists.com/img/national-flags/papua-new-guinea.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/papua_new_guinea.gif"
}, },
{ {
"Word": "Paraguay", "Word": "Paraguay",
@ -1324,7 +1324,7 @@
}, },
{ {
"Word": "Puerto Rico", "Word": "Puerto Rico",
"ImageUrl": "https://www.randomlists.com/img/national-flags/puerto-rico.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/puerto_rico.gif"
}, },
{ {
"Word": "Qatar", "Word": "Qatar",
@ -1344,15 +1344,15 @@
}, },
{ {
"Word": "Saint Kitts and Nevis", "Word": "Saint Kitts and Nevis",
"ImageUrl": "https://www.randomlists.com/img/national-flags/saint-kitts-and-nevis.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/saint_kitts_and_nevis.gif"
}, },
{ {
"Word": "Saint Lucia", "Word": "Saint Lucia",
"ImageUrl": "https://www.randomlists.com/img/national-flags/saint-lucia.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/saint_lucia.gif"
}, },
{ {
"Word": "Saint Vincent and the Grenadines", "Word": "Saint Vincent and the Grenadines",
"ImageUrl": "https://www.randomlists.com/img/national-flags/saint-vincent-and-the-grenadines.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/saint_vincent_and_the_grenadines.gif"
}, },
{ {
"Word": "Samoa", "Word": "Samoa",
@ -1360,11 +1360,11 @@
}, },
{ {
"Word": "San Marino", "Word": "San Marino",
"ImageUrl": "https://www.randomlists.com/img/national-flags/san-marino.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/san_marino.gif"
}, },
{ {
"Word": "Saudi Arabia", "Word": "Saudi Arabia",
"ImageUrl": "https://www.randomlists.com/img/national-flags/saudi-arabia.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/saudi_arabia.gif"
}, },
{ {
"Word": "Scotland", "Word": "Scotland",
@ -1384,7 +1384,7 @@
}, },
{ {
"Word": "Sierra Leone", "Word": "Sierra Leone",
"ImageUrl": "https://www.randomlists.com/img/national-flags/sierra-leone.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/sierra_leone.gif"
}, },
{ {
"Word": "Singapore", "Word": "Singapore",
@ -1400,7 +1400,7 @@
}, },
{ {
"Word": "Solomon Islands", "Word": "Solomon Islands",
"ImageUrl": "https://www.randomlists.com/img/national-flags/solomon-islands.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/solomon_islands.gif"
}, },
{ {
"Word": "Somalia", "Word": "Somalia",
@ -1408,7 +1408,7 @@
}, },
{ {
"Word": "South Africa", "Word": "South Africa",
"ImageUrl": "https://www.randomlists.com/img/national-flags/south-africa.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/south_africa.gif"
}, },
{ {
"Word": "Spain", "Word": "Spain",
@ -1416,7 +1416,7 @@
}, },
{ {
"Word": "Sri Lanka", "Word": "Sri Lanka",
"ImageUrl": "https://www.randomlists.com/img/national-flags/sri-lanka.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/sri_lanka.gif"
}, },
{ {
"Word": "Sudan", "Word": "Sudan",
@ -1468,7 +1468,7 @@
}, },
{ {
"Word": "Trinidad and Tobago", "Word": "Trinidad and Tobago",
"ImageUrl": "https://www.randomlists.com/img/national-flags/trinidad-and-tobago.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/trinidad_and_tobago.gif"
}, },
{ {
"Word": "Tunisia", "Word": "Tunisia",
@ -1496,15 +1496,15 @@
}, },
{ {
"Word": "United Arab Emirates", "Word": "United Arab Emirates",
"ImageUrl": "https://www.randomlists.com/img/national-flags/united-arab-emirates.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/united_arab_emirates.gif"
}, },
{ {
"Word": "United Kingdom", "Word": "United Kingdom",
"ImageUrl": "https://www.randomlists.com/img/national-flags/united-kingdom.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/united_kingdom.gif"
}, },
{ {
"Word": "United States of America", "Word": "United States of America",
"ImageUrl": "https://www.randomlists.com/img/national-flags/united-states-of-america.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/united_states_of_america.gif"
}, },
{ {
"Word": "Uruguay", "Word": "Uruguay",
@ -1524,7 +1524,7 @@
}, },
{ {
"Word": "Vatican City", "Word": "Vatican City",
"ImageUrl": "https://www.randomlists.com/img/national-flags/vatican-city.gif" "ImageUrl": "https://www.randomlists.com/img/national-flags/vatican_city.gif"
}, },
{ {
"Word": "Venezuela", "Word": "Venezuela",