commit
ad5916fc19
16
README.md
16
README.md
@ -1,14 +1,12 @@
|
|||||||
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
||||||
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
||||||
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
||||||
# NadekoBot
|
[![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png)](http://nadekobot.xyz)
|
||||||
[![nadeko1](https://cdn.discordapp.com/attachments/155726317222887425/252095170676391936/A1.jpg)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
[![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
||||||
[![nadeko2](https://cdn.discordapp.com/attachments/155726317222887425/252095207514832896/A2.jpg)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
[![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
||||||
|
|
||||||
##For Update, Help and Guidlines
|
|
||||||
|
|
||||||
`Follow me on twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides.`
|
|
||||||
|
|
||||||
[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/155726317222887425/252192415673221122/discord_banner.JPG)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/155726317222887425/252192472849973250/read_the_docs_banner.JPG)](http://nadekobot.readthedocs.io/en/latest/)
|
|
||||||
|
|
||||||
|
##For Update, Help and Guidelines
|
||||||
|
|
||||||
|
| [![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) | [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) | [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/)
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Follow me on Twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides. |
|
23
src/NadekoBot/DataStructures/AsyncLazy.cs
Normal file
23
src/NadekoBot/DataStructures/AsyncLazy.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||||
|
{
|
||||||
|
public AsyncLazy(Func<T> valueFactory) :
|
||||||
|
base(() => Task.Factory.StartNew(valueFactory))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public AsyncLazy(Func<Task<T>> taskFactory) :
|
||||||
|
base(() => Task.Factory.StartNew(taskFactory).Unwrap())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1171
src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs
generated
Normal file
1171
src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
357
src/NadekoBot/Migrations/20170222162505_dateadded.cs
Normal file
357
src/NadekoBot/Migrations/20170222162505_dateadded.cs
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class dateadded : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuUpdates",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuInfo",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PokeGame",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SelfAssignableRoles",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Reminders",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "RaceAnimals",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Quotes",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlaylistSong",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlayingStatus",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Permission",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MutedUserId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MusicPlaylists",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ModulePrefixes",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "LogSettings",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredVoicePresenceCHannels",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredLogChannels",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildRepeater",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GCChannelId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FollowedStream",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilteredWord",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilterChannelId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "EightBallResponses",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Donators",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "DiscordUser",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CustomReactions",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CurrencyTransactions",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Currency",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ConversionUnits",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandPrice",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandCooldown",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashOfClans",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashCallers",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BotConfig",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BlacklistItem",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamSetting",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamIgnore",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiRaidSetting",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuUpdates");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuInfo");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PokeGame");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SelfAssignableRoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Reminders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "RaceAnimals");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Quotes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlaylistSong");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlayingStatus");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Permission");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MutedUserId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MusicPlaylists");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ModulePrefixes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "LogSettings");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredVoicePresenceCHannels");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredLogChannels");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildRepeater");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GCChannelId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FollowedStream");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilteredWord");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilterChannelId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "EightBallResponses");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Donators");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "DiscordUser");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CustomReactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CurrencyTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Currency");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ConversionUnits");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandCooldown");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashOfClans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashCallers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BotConfig");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BlacklistItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamSetting");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamIgnore");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiRaidSetting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Action");
|
b.Property<int>("Action");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId");
|
b.Property<int>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("Seconds");
|
b.Property<int>("Seconds");
|
||||||
@ -47,6 +49,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("AntiSpamSettingId");
|
b.HasIndex("AntiSpamSettingId");
|
||||||
@ -61,6 +65,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Action");
|
b.Property<int>("Action");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId");
|
b.Property<int>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("MessageThreshold");
|
b.Property<int>("MessageThreshold");
|
||||||
@ -80,6 +86,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("ItemId");
|
b.Property<ulong>("ItemId");
|
||||||
|
|
||||||
b.Property<int>("Type");
|
b.Property<int>("Type");
|
||||||
@ -120,6 +128,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("DMHelpString");
|
b.Property<string>("DMHelpString");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("ErrorColor");
|
b.Property<string>("ErrorColor");
|
||||||
|
|
||||||
b.Property<bool>("ForwardMessages");
|
b.Property<bool>("ForwardMessages");
|
||||||
@ -158,6 +168,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("ClashWarId");
|
b.Property<int>("ClashWarId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("SequenceNumber");
|
b.Property<int?>("SequenceNumber");
|
||||||
|
|
||||||
b.Property<int>("Stars");
|
b.Property<int>("Stars");
|
||||||
@ -178,6 +190,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("EnemyClan");
|
b.Property<string>("EnemyClan");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -200,6 +214,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("CommandName");
|
b.Property<string>("CommandName");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("Seconds");
|
b.Property<int>("Seconds");
|
||||||
@ -220,6 +236,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("CommandName");
|
b.Property<string>("CommandName");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("Price");
|
b.Property<int>("Price");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -237,6 +255,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("InternalTrigger");
|
b.Property<string>("InternalTrigger");
|
||||||
|
|
||||||
b.Property<decimal>("Modifier");
|
b.Property<decimal>("Modifier");
|
||||||
@ -255,6 +275,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<long>("Amount");
|
b.Property<long>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -272,6 +294,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<long>("Amount");
|
b.Property<long>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Reason");
|
b.Property<string>("Reason");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -286,6 +310,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong?>("GuildId");
|
b.Property<ulong?>("GuildId");
|
||||||
|
|
||||||
b.Property<bool>("IsRegex");
|
b.Property<bool>("IsRegex");
|
||||||
@ -308,6 +334,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("AvatarId");
|
b.Property<string>("AvatarId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Discriminator");
|
b.Property<string>("Discriminator");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -328,6 +356,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Amount");
|
b.Property<int>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -347,6 +377,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Text");
|
b.Property<string>("Text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -363,6 +395,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId1");
|
b.Property<int?>("GuildConfigId1");
|
||||||
@ -381,6 +415,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<string>("Word");
|
b.Property<string>("Word");
|
||||||
@ -399,6 +435,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -421,6 +459,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -455,6 +495,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<bool>("CleverbotEnabled");
|
b.Property<bool>("CleverbotEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<float>("DefaultMusicVolume");
|
b.Property<float>("DefaultMusicVolume");
|
||||||
|
|
||||||
b.Property<bool>("DeleteMessageOnCommand");
|
b.Property<bool>("DeleteMessageOnCommand");
|
||||||
@ -512,6 +554,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -534,6 +578,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("LogSettingId");
|
b.Property<int?>("LogSettingId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -550,6 +596,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("LogSettingId");
|
b.Property<int?>("LogSettingId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -578,6 +626,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong?>("ChannelUpdatedId");
|
b.Property<ulong?>("ChannelUpdatedId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<bool>("IsLogging");
|
b.Property<bool>("IsLogging");
|
||||||
|
|
||||||
b.Property<ulong?>("LogOtherId");
|
b.Property<ulong?>("LogOtherId");
|
||||||
@ -638,6 +688,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("ModuleName");
|
b.Property<string>("ModuleName");
|
||||||
|
|
||||||
b.Property<string>("Prefix");
|
b.Property<string>("Prefix");
|
||||||
@ -658,6 +710,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("AuthorId");
|
b.Property<ulong>("AuthorId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -670,6 +724,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -686,6 +742,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("NextId");
|
b.Property<int?>("NextId");
|
||||||
|
|
||||||
b.Property<int>("PrimaryTarget");
|
b.Property<int>("PrimaryTarget");
|
||||||
@ -713,6 +771,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Status");
|
b.Property<string>("Status");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -727,6 +787,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("MusicPlaylistId");
|
b.Property<int?>("MusicPlaylistId");
|
||||||
|
|
||||||
b.Property<string>("Provider");
|
b.Property<string>("Provider");
|
||||||
@ -756,6 +818,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<string>("AuthorName")
|
b.Property<string>("AuthorName")
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
|
|
||||||
b.Property<string>("Keyword")
|
b.Property<string>("Keyword")
|
||||||
@ -776,6 +840,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Icon");
|
b.Property<string>("Icon");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
@ -794,6 +860,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<bool>("IsPrivate");
|
b.Property<bool>("IsPrivate");
|
||||||
|
|
||||||
b.Property<string>("Message");
|
b.Property<string>("Message");
|
||||||
@ -814,6 +882,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
|
|
||||||
b.Property<ulong>("RoleId");
|
b.Property<ulong>("RoleId");
|
||||||
@ -831,6 +901,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
b.Property<string>("type");
|
b.Property<string>("type");
|
||||||
@ -852,6 +924,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("ClaimerId");
|
b.Property<int?>("ClaimerId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("Price");
|
b.Property<int>("Price");
|
||||||
|
|
||||||
b.Property<int>("WaifuId");
|
b.Property<int>("WaifuId");
|
||||||
@ -873,6 +947,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("NewId");
|
b.Property<int?>("NewId");
|
||||||
|
|
||||||
b.Property<int?>("OldId");
|
b.Property<int?>("OldId");
|
||||||
|
@ -16,7 +16,7 @@ using NLog;
|
|||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
[NadekoModule("Administration", ".")]
|
[NadekoModule("Administration", ".")]
|
||||||
public partial class Administration : NadekoModule
|
public partial class Administration : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
|
private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
|
||||||
|
|
||||||
@ -440,6 +440,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable();
|
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable();
|
||||||
enumerable = enumerable.Where(x => x.Author.Id == user.Id);
|
enumerable = enumerable.Where(x => x.Author.Id == user.Id);
|
||||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||||
|
Context.Message.DeleteAfter(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune x
|
// prune x
|
||||||
@ -451,7 +452,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
return;
|
return;
|
||||||
count += 1;
|
|
||||||
await Context.Message.DeleteAsync().ConfigureAwait(false);
|
await Context.Message.DeleteAsync().ConfigureAwait(false);
|
||||||
int limit = (count < 100) ? count : 100;
|
int limit = (count < 100) ? count : 100;
|
||||||
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false));
|
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false));
|
||||||
@ -474,6 +474,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
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);
|
||||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Context.Message.DeleteAfter(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -18,8 +18,14 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{"en-US", "English, United States" },
|
{"en-US", "English, United States"},
|
||||||
{"sr-cyrl-rs", "Serbian, Cyrillic" }
|
{"fr-FR", "French, France"},
|
||||||
|
{"ru-RU", "Russian, Russia"},
|
||||||
|
{"de-DE", "German, Germany"},
|
||||||
|
//{"nl-NL", "Dutch, Netherlands"},
|
||||||
|
//{"ja-JP", "Japanese, Japan"},
|
||||||
|
{"pt-BR", "Portuguese, Brazil"},
|
||||||
|
//{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"}
|
||||||
}.ToImmutableDictionary();
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -94,9 +100,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task LanguagesList()
|
public async Task LanguagesList()
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("lang_list",
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
string.Join("\n", supportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}")))
|
.WithTitle(GetText("lang_list", ""))
|
||||||
.ConfigureAwait(false);
|
.WithDescription(string.Join("\n",
|
||||||
|
supportedLocales.Select(x => $"{Format.Code(x.Key), -10} => {x.Value}"))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
|
embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
|
||||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}")
|
|
||||||
.WithThumbnailUrl(before.AvatarUrl)
|
.WithThumbnailUrl(before.AvatarUrl)
|
||||||
.WithImageUrl(after.AvatarUrl)
|
.WithImageUrl(after.AvatarUrl)
|
||||||
.WithFooter(fb => fb.WithText(currentTime))
|
.WithFooter(fb => fb.WithText(currentTime))
|
||||||
@ -530,7 +529,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
else if (afterVch == null)
|
else if (afterVch == null)
|
||||||
{
|
{
|
||||||
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
|
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
|
||||||
"👤" + Format.Code(prettyCurrentTime), "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||||
Format.Bold(beforeVch.Name ?? ""));
|
Format.Bold(beforeVch.Name ?? ""));
|
||||||
}
|
}
|
||||||
if (str != null)
|
if (str != null)
|
||||||
@ -705,17 +704,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name))
|
.WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name))
|
||||||
.WithDescription($"{msg.Author}")
|
.WithDescription(msg.Author.ToString())
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(currentTime));
|
.WithFooter(efb => efb.WithText(currentTime));
|
||||||
if (msg.Attachments.Any())
|
if (msg.Attachments.Any())
|
||||||
embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false));
|
embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false));
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,8 +753,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name))
|
.WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name))
|
||||||
.WithDescription(after.Author.ToString())
|
.WithDescription(after.Author.ToString())
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(currentTime));
|
.WithFooter(efb => efb.WithText(currentTime));
|
||||||
|
|
||||||
@ -988,7 +988,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task LogEvents()
|
public async Task LogEvents()
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("log_events", string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("log_events") + "\n" +
|
||||||
|
string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>()))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -1066,7 +1068,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public static class GuildExtensions
|
public static class GuildExtensions
|
||||||
{
|
{
|
||||||
public static string GetLogText(this IGuild guild, string key, params object[] replacements)
|
public static string GetLogText(this IGuild guild, string key, params object[] replacements)
|
||||||
=> NadekoModule.GetTextStatic(key,
|
=> NadekoTopLevelModule.GetTextStatic(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(guild),
|
NadekoBot.Localization.GetCultureInfo(guild),
|
||||||
typeof(Administration).Name.ToLowerInvariant(),
|
typeof(Administration).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
|
@ -72,23 +72,42 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
if (_forwardDMs && ownerChannels.Any())
|
if (_forwardDMs && ownerChannels.Any())
|
||||||
{
|
{
|
||||||
var title =
|
var title = GetTextStatic("dm_from",
|
||||||
GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo,
|
NadekoBot.Localization.DefaultCultureInfo,
|
||||||
typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})";
|
typeof(Administration).Name.ToLowerInvariant()) +
|
||||||
|
$" [{msg.Author}]({msg.Author.Id})";
|
||||||
|
|
||||||
|
var attachamentsTxt = GetTextStatic("attachments",
|
||||||
|
NadekoBot.Localization.DefaultCultureInfo,
|
||||||
|
typeof(Administration).Name.ToLowerInvariant());
|
||||||
|
|
||||||
|
var toSend = msg.Content;
|
||||||
|
|
||||||
|
if (msg.Attachments.Count > 0)
|
||||||
|
{
|
||||||
|
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" +
|
||||||
|
string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
||||||
|
}
|
||||||
|
|
||||||
if (_forwardDMsToAllOwners)
|
if (_forwardDMsToAllOwners)
|
||||||
{
|
{
|
||||||
await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
||||||
.Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false);
|
.Select(ch => ch.SendConfirmAsync(title, toSend))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var firstOwnerChannel = ownerChannels.First();
|
var firstOwnerChannel = ownerChannels.First();
|
||||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||||
try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); }
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,13 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.ClashOfClans
|
namespace NadekoBot.Modules.ClashOfClans
|
||||||
{
|
{
|
||||||
[NadekoModule("ClashOfClans", ",")]
|
[NadekoModule("ClashOfClans", ",")]
|
||||||
public class ClashOfClans : NadekoModule
|
public class ClashOfClans : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; }
|
||||||
|
|
||||||
private static Timer checkWarTimer { get; }
|
private static Timer checkWarTimer { get; }
|
||||||
|
|
||||||
@ -82,11 +80,9 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task CreateWar(int size, [Remainder] string enemyClan = null)
|
public async Task CreateWar(int size, [Remainder] string enemyClan = null)
|
||||||
{
|
{
|
||||||
if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
|
|
||||||
public static string Localize(this ClashWar cw, string key)
|
public static string Localize(this ClashWar cw, string key)
|
||||||
{
|
{
|
||||||
return NadekoModule.GetTextStatic(key,
|
return NadekoTopLevelModule.GetTextStatic(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId),
|
NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId),
|
||||||
typeof(ClashOfClans).Name.ToLowerInvariant());
|
typeof(ClashOfClans).Name.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ using NadekoBot.DataStructures;
|
|||||||
namespace NadekoBot.Modules.CustomReactions
|
namespace NadekoBot.Modules.CustomReactions
|
||||||
{
|
{
|
||||||
[NadekoModule("CustomReactions", ".")]
|
[NadekoModule("CustomReactions", ".")]
|
||||||
public class CustomReactions : NadekoModule
|
public class CustomReactions : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
||||||
public static CustomReaction[] GlobalReactions => _globalReactions;
|
public static CustomReaction[] GlobalReactions => _globalReactions;
|
||||||
|
@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix);
|
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix);
|
||||||
|
|
||||||
if (ar.Fail)
|
if (ar.Fail)
|
||||||
await Context.Channel.SendErrorAsync("🏁 `Failed starting a race. Another race is probably running.`").ConfigureAwait(false);
|
await ReplyErrorLocalized("race_failed_starting").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
AnimalRace ar;
|
AnimalRace ar;
|
||||||
if (!AnimalRaces.TryGetValue(Context.Guild.Id, out ar))
|
if (!AnimalRaces.TryGetValue(Context.Guild.Id, out ar))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No race exists on this server").ConfigureAwait(false);
|
await ReplyErrorLocalized("race_not_exist").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ar.JoinRace(Context.User as IGuildUser, amount);
|
await ar.JoinRace(Context.User as IGuildUser, amount);
|
||||||
@ -56,22 +56,22 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
public bool Fail { get; set; }
|
public bool Fail { get; set; }
|
||||||
|
|
||||||
public List<Participant> participants = new List<Participant>();
|
private readonly List<Participant> _participants = new List<Participant>();
|
||||||
private ulong serverId;
|
private readonly ulong _serverId;
|
||||||
private int messagesSinceGameStarted = 0;
|
private int _messagesSinceGameStarted;
|
||||||
private readonly string _prefix;
|
private readonly string _prefix;
|
||||||
|
|
||||||
private Logger _log { get; }
|
private readonly Logger _log;
|
||||||
|
|
||||||
public ITextChannel raceChannel { get; set; }
|
private readonly ITextChannel _raceChannel;
|
||||||
public bool Started { get; private set; } = false;
|
public bool Started { get; private set; }
|
||||||
|
|
||||||
public AnimalRace(ulong serverId, ITextChannel ch, string prefix)
|
public AnimalRace(ulong serverId, ITextChannel ch, string prefix)
|
||||||
{
|
{
|
||||||
this._prefix = prefix;
|
_prefix = prefix;
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
this.serverId = serverId;
|
_serverId = serverId;
|
||||||
this.raceChannel = ch;
|
_raceChannel = ch;
|
||||||
if (!AnimalRaces.TryAdd(serverId, this))
|
if (!AnimalRaces.TryAdd(serverId, this))
|
||||||
{
|
{
|
||||||
Fail = true;
|
Fail = true;
|
||||||
@ -90,8 +90,8 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"Starting in 20 seconds or when the room is full.",
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting"),
|
||||||
footer: $"Type {_prefix}jr to join the race.");
|
footer: GetText("animal_race_join_instr", _prefix));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -102,16 +102,16 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
cancelSource.Cancel();
|
cancelSource.Cancel();
|
||||||
if (t == fullgame)
|
if (t == fullgame)
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendConfirmAsync("Animal Race", "Full! Starting immediately."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_full") ); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else if (participants.Count > 1)
|
else if (_participants.Count > 1)
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendConfirmAsync("Animal Race", "Starting with " + participants.Count + " participants."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting_with_x", _participants.Count)); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendErrorAsync("Animal Race", "Failed to start since there was not enough participants."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_failed")); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
var p = participants.FirstOrDefault();
|
var p = _participants.FirstOrDefault();
|
||||||
|
|
||||||
if (p != null && p.AmountBet > 0)
|
if (p != null && p.AmountBet > 0)
|
||||||
await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, false).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, false).ConfigureAwait(false);
|
||||||
@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private void End()
|
private void End()
|
||||||
{
|
{
|
||||||
AnimalRace throwaway;
|
AnimalRace throwaway;
|
||||||
AnimalRaces.TryRemove(serverId, out throwaway);
|
AnimalRaces.TryRemove(_serverId, out throwaway);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartRace()
|
private async Task StartRace()
|
||||||
@ -136,21 +136,21 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
Participant winner = null;
|
Participant winner = null;
|
||||||
IUserMessage msg = null;
|
IUserMessage msg = null;
|
||||||
int place = 1;
|
var place = 1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
while (!participants.All(p => p.Total >= 60))
|
while (!_participants.All(p => p.Total >= 60))
|
||||||
{
|
{
|
||||||
//update the state
|
//update the state
|
||||||
participants.ForEach(p =>
|
_participants.ForEach(p =>
|
||||||
{
|
{
|
||||||
p.Total += 1 + rng.Next(0, 10);
|
p.Total += 1 + rng.Next(0, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
participants
|
_participants
|
||||||
.OrderByDescending(p => p.Total)
|
.OrderByDescending(p => p.Total)
|
||||||
.ForEach(p =>
|
.ForEach(p =>
|
||||||
{
|
{
|
||||||
@ -170,14 +170,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
//draw the state
|
//draw the state
|
||||||
|
|
||||||
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
||||||
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|
{String.Join("\n", _participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|
||||||
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
||||||
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
|
if (msg == null || _messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
|
||||||
{
|
{
|
||||||
if (msg != null)
|
if (msg != null)
|
||||||
try { await msg.DeleteAsync(); } catch { }
|
try { await msg.DeleteAsync(); } catch { }
|
||||||
messagesSinceGameStarted = 0;
|
_messagesSinceGameStarted = 0;
|
||||||
try { msg = await raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { msg = await _raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -187,22 +187,33 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
await Task.Delay(2500);
|
await Task.Delay(2500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (winner.AmountBet > 0)
|
if (winner != null)
|
||||||
{
|
{
|
||||||
var wonAmount = winner.AmountBet * (participants.Count - 1);
|
if (winner.AmountBet > 0)
|
||||||
|
{
|
||||||
|
var wonAmount = winner.AmountBet * (_participants.Count - 1);
|
||||||
|
|
||||||
await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true)
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{CurrencySign}!**").ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"),
|
||||||
else
|
Format.Bold(GetText("animal_race_won_money", winner.User.Mention,
|
||||||
{
|
winner.Animal, wonAmount + CurrencySign)))
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race!**").ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"),
|
||||||
|
Format.Bold(GetText("animal_race_won", winner.User.Mention, winner.Animal))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -212,9 +223,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var msg = imsg as SocketUserMessage;
|
var msg = imsg as SocketUserMessage;
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != raceChannel)
|
if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != _raceChannel)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
messagesSinceGameStarted++;
|
_messagesSinceGameStarted++;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,51 +239,66 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
public async Task JoinRace(IGuildUser u, int amount = 0)
|
public async Task JoinRace(IGuildUser u, int amount = 0)
|
||||||
{
|
{
|
||||||
var animal = "";
|
string animal;
|
||||||
if (!animals.TryDequeue(out animal))
|
if (!animals.TryDequeue(out animal))
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `There is no running race on this server.`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_no_race")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var p = new Participant(u, animal, amount);
|
var p = new Participant(u, animal, amount);
|
||||||
if (participants.Contains(p))
|
if (_participants.Contains(p))
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `You already joined this race.`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_already_in")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Started)
|
if (Started)
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `Race is already started`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_already_started")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false))
|
if (!await CurrencyHandler.RemoveCurrencyAsync(u, "BetRace", amount, false).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); } catch { }
|
await _raceChannel.SendErrorAsync(GetText("not_enough", CurrencySign)).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
participants.Add(p);
|
_participants.Add(p);
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{u.Mention} **joined as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {CurrencySign}!**" : "**"))
|
string confStr;
|
||||||
.ConfigureAwait(false);
|
if (amount > 0)
|
||||||
|
confStr = GetText("animal_race_join_bet", u.Mention, p.Animal, amount + CurrencySign);
|
||||||
|
else
|
||||||
|
confStr = GetText("animal_race_join", u.Mention, p.Animal);
|
||||||
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"), Format.Bold(confStr)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string text)
|
||||||
|
=> NadekoTopLevelModule.GetTextStatic(text,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild),
|
||||||
|
typeof(Gambling).Name.ToLowerInvariant());
|
||||||
|
|
||||||
|
private string GetText(string text, params object[] replacements)
|
||||||
|
=> NadekoTopLevelModule.GetTextStatic(text,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild),
|
||||||
|
typeof(Gambling).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Participant
|
public class Participant
|
||||||
{
|
{
|
||||||
public IGuildUser User { get; set; }
|
public IGuildUser User { get; }
|
||||||
public string Animal { get; set; }
|
public string Animal { get; }
|
||||||
public int AmountBet { get; set; }
|
public int AmountBet { get; }
|
||||||
|
|
||||||
public float Coeff { get; set; }
|
public float Coeff { get; set; }
|
||||||
public int Total { get; set; }
|
public int Total { get; set; }
|
||||||
|
|
||||||
public int Place { get; set; } = 0;
|
public int Place { get; set; }
|
||||||
|
|
||||||
public Participant(IGuildUser u, string a, int amount)
|
public Participant(IGuildUser u, string a, int amount)
|
||||||
{
|
{
|
||||||
this.User = u;
|
User = u;
|
||||||
this.Animal = a;
|
Animal = a;
|
||||||
this.AmountBet = amount;
|
AmountBet = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => User.GetHashCode();
|
public override int GetHashCode() => User.GetHashCode();
|
||||||
@ -288,23 +314,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var str = new string('‣', Total) + Animal;
|
var str = new string('‣', Total) + Animal;
|
||||||
if (Place == 0)
|
if (Place == 0)
|
||||||
return str;
|
return str;
|
||||||
if (Place == 1)
|
|
||||||
{
|
|
||||||
return str + "🏆";
|
|
||||||
}
|
|
||||||
else if (Place == 2)
|
|
||||||
{
|
|
||||||
return str + "`2nd`";
|
|
||||||
}
|
|
||||||
else if (Place == 3)
|
|
||||||
{
|
|
||||||
return str + "`3rd`";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return str + $"`{Place}th`";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
str += $"`#{Place}`";
|
||||||
|
|
||||||
|
if (Place == 1)
|
||||||
|
str += "🏆";
|
||||||
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case CurrencyEvent.FlowerReaction:
|
case CurrencyEvent.FlowerReaction:
|
||||||
await FlowerReactionEvent(Context).ConfigureAwait(false);
|
await FlowerReactionEvent(Context, arg).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
case CurrencyEvent.SneakyGameStatus:
|
case CurrencyEvent.SneakyGameStatus:
|
||||||
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
||||||
@ -115,23 +115,26 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return Task.Delay(0);
|
return Task.Delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task FlowerReactionEvent(CommandContext context)
|
public async Task FlowerReactionEvent(CommandContext context, int amount)
|
||||||
{
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
amount = 100;
|
||||||
|
|
||||||
var title = GetText("flowerreaction_title");
|
var title = GetText("flowerreaction_title");
|
||||||
var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(100.ToString()) + CurrencySign);
|
var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(amount.ToString()) + CurrencySign);
|
||||||
var footer = GetText("flowerreaction_footer", 24);
|
var footer = GetText("flowerreaction_footer", 24);
|
||||||
var msg = await context.Channel.SendConfirmAsync(title,
|
var msg = await context.Channel.SendConfirmAsync(title,
|
||||||
desc, footer: footer)
|
desc, footer: footer)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
await new FlowerReactionEvent().Start(msg, context);
|
await new FlowerReactionEvent().Start(msg, context, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class CurrencyEvent
|
public abstract class CurrencyEvent
|
||||||
{
|
{
|
||||||
public abstract Task Start(IUserMessage msg, CommandContext channel);
|
public abstract Task Start(IUserMessage msg, CommandContext channel, int amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FlowerReactionEvent : CurrencyEvent
|
public class FlowerReactionEvent : CurrencyEvent
|
||||||
@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Start(IUserMessage umsg, CommandContext context)
|
public override async Task Start(IUserMessage umsg, CommandContext context, int amount)
|
||||||
{
|
{
|
||||||
msg = umsg;
|
msg = umsg;
|
||||||
NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
|
NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
|
||||||
@ -193,7 +196,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _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))
|
||||||
{
|
{
|
||||||
await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false)
|
await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", amount, false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ImageSharp.Formats;
|
||||||
using Image = ImageSharp.Image;
|
using Image = ImageSharp.Image;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
@ -22,7 +23,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private Regex dndRegex { get; } = new Regex(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", RegexOptions.Compiled);
|
private Regex dndRegex { get; } = new Regex(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", RegexOptions.Compiled);
|
||||||
private Regex fudgeRegex { get; } = new Regex(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
private Regex fudgeRegex { get; } = new Regex(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
private readonly char[] fateRolls = new[] { '-', ' ', '+' };
|
private readonly char[] _fateRolls = { '-', ' ', '+' };
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Roll()
|
public async Task Roll()
|
||||||
@ -35,12 +36,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var imageStream = await Task.Run(() =>
|
var imageStream = await Task.Run(() =>
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
|
new[] { GetDice(num1), GetDice(num2) }.Merge().Save(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return ms;
|
return ms;
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(imageStream,
|
||||||
|
"dice.png",
|
||||||
|
Context.User.Mention + " " + GetText("dice_rolled", Format.Code(gen.ToString()))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RollOrderType
|
public enum RollOrderType
|
||||||
@ -82,7 +85,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (num < 1 || num > 30)
|
if (num < 1 || num > 30)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Invalid number specified. You can roll up to 1-30 dice at a time.").ConfigureAwait(false);
|
await ReplyErrorLocalized("dice_invalid_number", 1, 30).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +121,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
var bitmap = dice.Merge();
|
var bitmap = dice.Merge();
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
bitmap.SaveAsPng(ms);
|
bitmap.Save(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
await Context.Channel.SendFileAsync(ms, "dice.png", $"{Context.User.Mention} rolled {values.Count} {(values.Count == 1 ? "die" : "dice")}. Total: **{values.Sum()}** Average: **{(values.Sum() / (1.0f * values.Count)).ToString("N2")}**").ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(ms, "dice.png",
|
||||||
|
Context.User.Mention + " " +
|
||||||
|
GetText("dice_rolled_num", Format.Bold(values.Count.ToString())) +
|
||||||
|
" " + GetText("total_average",
|
||||||
|
Format.Bold(values.Sum().ToString()),
|
||||||
|
Format.Bold((values.Sum() / (1.0f * values.Count)).ToString("N2")))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternallDndRoll(string arg, bool ordered)
|
private async Task InternallDndRoll(string arg, bool ordered)
|
||||||
@ -138,9 +146,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
for (int i = 0; i < n1; i++)
|
for (int i = 0; i < n1; i++)
|
||||||
{
|
{
|
||||||
rolls.Add(fateRolls[rng.Next(0, fateRolls.Length)]);
|
rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]);
|
||||||
}
|
}
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} fate {(n1 == 1 ? "die" : "dice")}.")
|
var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " + GetText("dice_rolled_num", Format.Bold(n1.ToString())))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Result"))
|
.AddField(efb => efb.WithName(Format.Bold("Result"))
|
||||||
.WithValue(string.Join(" ", rolls.Select(c => Format.Code($"[{c}]")))));
|
.WithValue(string.Join(" ", rolls.Select(c => Format.Code($"[{c}]")))));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -164,7 +172,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sum = arr.Sum();
|
var sum = arr.Sum();
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}`")
|
var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " +GetText("dice_rolled_num", n1) + $"`1 - {n2}`")
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Rolls"))
|
.AddField(efb => efb.WithName(Format.Bold("Rolls"))
|
||||||
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))))
|
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Sum"))
|
.AddField(efb => efb.WithName(Format.Bold("Sum"))
|
||||||
@ -177,30 +185,26 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task NRoll([Remainder] string range)
|
public async Task NRoll([Remainder] string range)
|
||||||
{
|
{
|
||||||
try
|
int rolled;
|
||||||
|
if (range.Contains("-"))
|
||||||
{
|
{
|
||||||
int rolled;
|
var arr = range.Split('-')
|
||||||
if (range.Contains("-"))
|
.Take(2)
|
||||||
|
.Select(int.Parse)
|
||||||
|
.ToArray();
|
||||||
|
if (arr[0] > arr[1])
|
||||||
{
|
{
|
||||||
var arr = range.Split('-')
|
await ReplyErrorLocalized("second_larger_than_first").ConfigureAwait(false);
|
||||||
.Take(2)
|
return;
|
||||||
.Select(int.Parse)
|
|
||||||
.ToArray();
|
|
||||||
if (arr[0] > arr[1])
|
|
||||||
throw new ArgumentException("Second argument must be larger than the first one.");
|
|
||||||
rolled = new NadekoRandom().Next(arr[0], arr[1] + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
|
|
||||||
}
|
}
|
||||||
|
rolled = new NadekoRandom().Next(arr[0], arr[1] + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} rolled **{rolled}**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("dice_rolled", Format.Bold(rolled.ToString())).ConfigureAwait(false);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync($":anger: {ex.Message}").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Image GetDice(int num)
|
private Image GetDice(int num)
|
||||||
|
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
images.Add(new Image(stream));
|
images.Add(new Image(stream));
|
||||||
}
|
}
|
||||||
MemoryStream bitmapStream = new MemoryStream();
|
MemoryStream bitmapStream = new MemoryStream();
|
||||||
images.Merge().SaveAsPng(bitmapStream);
|
images.Merge().Save(bitmapStream);
|
||||||
bitmapStream.Position = 0;
|
bitmapStream.Position = 0;
|
||||||
var toSend = $"{Context.User.Mention}";
|
var toSend = $"{Context.User.Mention}";
|
||||||
if (cardObjects.Count == 5)
|
if (cardObjects.Count == 5)
|
||||||
|
@ -52,17 +52,22 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var imgs = new Image[count];
|
var imgs = new Image[count];
|
||||||
using (var heads = _images.Heads.ToStream())
|
for (var i = 0; i < count; i++)
|
||||||
using(var tails = _images.Tails.ToStream())
|
|
||||||
{
|
{
|
||||||
for (var i = 0; i < count; i++)
|
using (var heads = _images.Heads.ToStream())
|
||||||
|
using (var tails = _images.Tails.ToStream())
|
||||||
{
|
{
|
||||||
imgs[i] = rng.Next(0, 10) < 5 ?
|
if (rng.Next(0, 10) < 5)
|
||||||
new Image(heads) :
|
{
|
||||||
new Image(tails);
|
imgs[i] = new Image(heads);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imgs[i] = new Image(tails);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -105,7 +110,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier);
|
var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier);
|
||||||
str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign);
|
str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign);
|
||||||
await CurrencyHandler.AddCurrencyAsync(Context.User, GetText("betflip_gamble"), toWin, false).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using ImageSharp;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
@ -163,83 +164,43 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
var result = SlotMachine.Pull();
|
var result = SlotMachine.Pull();
|
||||||
int[] numbers = result.Numbers;
|
int[] numbers = result.Numbers;
|
||||||
using (var bgPixels = bgImage.Lock())
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
||||||
|
using (var randomImage = new ImageSharp.Image(file))
|
||||||
{
|
{
|
||||||
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
bgImage.DrawImage(randomImage, 100, default(Size), new Point(95 + 142 * i, 330));
|
||||||
{
|
|
||||||
var randomImage = new ImageSharp.Image(file);
|
|
||||||
using (var toAdd = randomImage.Lock())
|
|
||||||
{
|
|
||||||
for (int j = 0; j < toAdd.Width; j++)
|
|
||||||
{
|
|
||||||
for (int k = 0; k < toAdd.Height; k++)
|
|
||||||
{
|
|
||||||
var x = 95 + 142 * i + j;
|
|
||||||
int y = 330 + k;
|
|
||||||
var toSet = toAdd[j, k];
|
|
||||||
if (toSet.A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
bgPixels[x, y] = toAdd[j, k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var won = amount * result.Multiplier;
|
|
||||||
var printWon = won;
|
|
||||||
var n = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var digit = printWon % 10;
|
|
||||||
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
|
|
||||||
{
|
|
||||||
var img = new ImageSharp.Image(fs);
|
|
||||||
using (var pixels = img.Lock())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pixels.Width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < pixels.Height; j++)
|
|
||||||
{
|
|
||||||
if (pixels[i, j].A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
var x = 230 - n * 16 + i;
|
|
||||||
bgPixels[x, 462 + j] = pixels[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
} while ((printWon /= 10) != 0);
|
|
||||||
|
|
||||||
var printAmount = amount;
|
|
||||||
n = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var digit = printAmount % 10;
|
|
||||||
using (var fs = _images.SlotNumbers[digit].ToStream())
|
|
||||||
{
|
|
||||||
var img = new ImageSharp.Image(fs);
|
|
||||||
using (var pixels = img.Lock())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pixels.Width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < pixels.Height; j++)
|
|
||||||
{
|
|
||||||
if (pixels[i, j].A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
var x = 395 - n * 16 + i;
|
|
||||||
bgPixels[x, 462 + j] = pixels[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
} while ((printAmount /= 10) != 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var won = amount * result.Multiplier;
|
||||||
|
var printWon = won;
|
||||||
|
var n = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var digit = printWon % 10;
|
||||||
|
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
|
||||||
|
using (var img = new ImageSharp.Image(fs))
|
||||||
|
{
|
||||||
|
bgImage.DrawImage(img, 100, default(Size), new Point(230 - n * 16, 462));
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
} while ((printWon /= 10) != 0);
|
||||||
|
|
||||||
|
var printAmount = amount;
|
||||||
|
n = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var digit = printAmount % 10;
|
||||||
|
using (var fs = _images.SlotNumbers[digit].ToStream())
|
||||||
|
using (var img = new ImageSharp.Image(fs))
|
||||||
|
{
|
||||||
|
bgImage.DrawImage(img, 100, default(Size), new Point(395 - n * 16, 462));
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
} while ((printAmount /= 10) != 0);
|
||||||
|
|
||||||
var msg = GetText("better_luck");
|
var msg = GetText("better_luck");
|
||||||
if (result.Multiplier != 0)
|
if (result.Multiplier != 0)
|
||||||
{
|
{
|
||||||
|
@ -3,13 +3,11 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
@ -49,8 +47,8 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[Group]
|
[Group]
|
||||||
public class WaifuClaimCommands : NadekoSubmodule
|
public class WaifuClaimCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, DateTime> _divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
private static ConcurrentDictionary<ulong, DateTime> divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||||
private static ConcurrentDictionary<ulong, DateTime> _affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
private static ConcurrentDictionary<ulong, DateTime> affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||||
|
|
||||||
enum WaifuClaimResult
|
enum WaifuClaimResult
|
||||||
{
|
{
|
||||||
@ -65,20 +63,19 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (amount < 50)
|
if (amount < 50)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} No waifu is that cheap. You must pay at least 50{NadekoBot.BotConfig.CurrencySign} to get a waifu, even if their actual value is lower.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_isnt_cheap", 50 + CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.Id == Context.User.Id)
|
if (target.Id == Context.User.Id)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync(Context.User.Mention + " You can't claim yourself.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_yourself").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaifuClaimResult result = WaifuClaimResult.NotEnoughFunds;
|
WaifuClaimResult result;
|
||||||
int? oldPrice = null;
|
|
||||||
WaifuInfo w;
|
WaifuInfo w;
|
||||||
var isAffinity = false;
|
bool isAffinity;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
w = uow.Waifus.ByWaifuUserId(target.Id);
|
w = uow.Waifus.ByWaifuUserId(target.Id);
|
||||||
@ -120,7 +117,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var oldClaimer = w.Claimer;
|
var oldClaimer = w.Claimer;
|
||||||
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
||||||
oldPrice = w.Price;
|
|
||||||
w.Price = amount + (amount / 4);
|
w.Price = amount + (amount / 4);
|
||||||
result = WaifuClaimResult.Success;
|
result = WaifuClaimResult.Success;
|
||||||
|
|
||||||
@ -143,7 +139,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var oldClaimer = w.Claimer;
|
var oldClaimer = w.Claimer;
|
||||||
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
||||||
oldPrice = w.Price;
|
|
||||||
w.Price = amount;
|
w.Price = amount;
|
||||||
result = WaifuClaimResult.Success;
|
result = WaifuClaimResult.Success;
|
||||||
|
|
||||||
@ -165,22 +160,20 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (result == WaifuClaimResult.InsufficientAmount)
|
if (result == WaifuClaimResult.InsufficientAmount)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must pay {Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))} or more to claim that waifu!").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_enough", Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (result == WaifuClaimResult.NotEnoughFunds)
|
if (result == WaifuClaimResult.NotEnoughFunds)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} you don't have {amount}{NadekoBot.BotConfig.CurrencySign}!")
|
await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
return;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = $"{Context.User.Mention} claimed {target.Mention} as their waifu for {amount}{NadekoBot.BotConfig.CurrencySign}!";
|
|
||||||
if (w.Affinity?.UserId == Context.User.Id)
|
|
||||||
msg += $"\n🎉 Their love is fulfilled! 🎉\n**{target}'s** new value is {w.Price}{NadekoBot.BotConfig.CurrencySign}!";
|
|
||||||
await Context.Channel.SendConfirmAsync(msg)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
var msg = GetText("waifu_claimed",
|
||||||
|
Format.Bold(target.ToString()),
|
||||||
|
amount + CurrencySign);
|
||||||
|
if (w.Affinity?.UserId == Context.User.Id)
|
||||||
|
msg += "\n" + GetText("waifu_fulfilled", target, w.Price + CurrencySign);
|
||||||
|
await Context.Channel.SendConfirmAsync(Context.User.Mention + msg).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DivorceResult
|
public enum DivorceResult
|
||||||
@ -192,7 +185,7 @@ 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]IUser target)
|
public async Task Divorce([Remainder]IUser target)
|
||||||
@ -200,19 +193,19 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
if (target.Id == Context.User.Id)
|
if (target.Id == Context.User.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var result = DivorceResult.NotYourWife;
|
DivorceResult result;
|
||||||
TimeSpan difference = TimeSpan.Zero;
|
var difference = TimeSpan.Zero;
|
||||||
var amount = 0;
|
var amount = 0;
|
||||||
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(target.Id);
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
if (w == null || 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;
|
||||||
else if (_divorceCooldowns.AddOrUpdate(Context.User.Id,
|
else if (divorceCooldowns.AddOrUpdate(Context.User.Id,
|
||||||
now,
|
now,
|
||||||
(key, old) => ((difference = now.Subtract(old)) > DivorceLimit) ? now : old) != now)
|
(key, old) => ((difference = now.Subtract(old)) > _divorceLimit) ? now : old) != now)
|
||||||
{
|
{
|
||||||
result = DivorceResult.Cooldown;
|
result = DivorceResult.Cooldown;
|
||||||
}
|
}
|
||||||
@ -249,37 +242,39 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (result == DivorceResult.SucessWithPenalty)
|
if (result == DivorceResult.SucessWithPenalty)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who likes you. You heartless monster.\n{w.Waifu} received {amount}{NadekoBot.BotConfig.CurrencySign} as a compensation.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifu_divorced_like", Format.Bold(w.Waifu.ToString()), amount + CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (result == DivorceResult.Success)
|
else if (result == DivorceResult.Success)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who doesn't like you. You received {amount}{NadekoBot.BotConfig.CurrencySign} back.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifu_divorced_notlike", amount + CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (result == DivorceResult.NotYourWife)
|
else if (result == DivorceResult.NotYourWife)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} That waifu is not yours.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_yours").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var remaining = DivorceLimit.Subtract(difference);
|
var remaining = _divorceLimit.Subtract(difference);
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You divorced recently. You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** to divorce again.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_recent_divorce",
|
||||||
|
Format.Bold(((int)remaining.TotalHours).ToString()),
|
||||||
|
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly TimeSpan AffinityLimit = TimeSpan.FromMinutes(30);
|
private static readonly TimeSpan _affinityLimit = TimeSpan.FromMinutes(30);
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task WaifuClaimerAffinity([Remainder]IUser u = null)
|
public async Task WaifuClaimerAffinity([Remainder]IUser u = null)
|
||||||
{
|
{
|
||||||
if (u?.Id == Context.User.Id)
|
if (u?.Id == Context.User.Id)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} you can't set affinity to yourself, you egomaniac.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_egomaniac").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DiscordUser oldAff = null;
|
DiscordUser oldAff = null;
|
||||||
var sucess = false;
|
var sucess = false;
|
||||||
var cooldown = false;
|
var cooldown = false;
|
||||||
TimeSpan difference = TimeSpan.Zero;
|
var difference = TimeSpan.Zero;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var w = uow.Waifus.ByWaifuUserId(Context.User.Id);
|
var w = uow.Waifus.ByWaifuUserId(Context.User.Id);
|
||||||
@ -287,13 +282,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
if (w?.Affinity?.UserId == u?.Id)
|
if (w?.Affinity?.UserId == u?.Id)
|
||||||
{
|
{
|
||||||
sucess = false;
|
|
||||||
}
|
}
|
||||||
else if (_affinityCooldowns.AddOrUpdate(Context.User.Id,
|
else if (affinityCooldowns.AddOrUpdate(Context.User.Id,
|
||||||
now,
|
now,
|
||||||
(key, old) => ((difference = now.Subtract(old)) > AffinityLimit) ? now : old) != now)
|
(key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now)
|
||||||
{
|
{
|
||||||
sucess = false;
|
|
||||||
cooldown = true;
|
cooldown = true;
|
||||||
}
|
}
|
||||||
else if (w == null)
|
else if (w == null)
|
||||||
@ -338,19 +331,29 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (cooldown)
|
if (cooldown)
|
||||||
{
|
{
|
||||||
var remaining = AffinityLimit.Subtract(difference);
|
var remaining = _affinityLimit.Subtract(difference);
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** in order to change your affinity again.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_affinity_cooldown",
|
||||||
|
Format.Bold(((int)remaining.TotalHours).ToString()),
|
||||||
|
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} your affinity is already set to that waifu or you're trying to remove your affinity while not having one.").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyErrorLocalized("waifu_affinity_already").ConfigureAwait(false);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (u == null)
|
if (u == null)
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Reset", $"{Context.User.Mention} Your affinity is reset. You no longer have a person you like.").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_reset").ConfigureAwait(false);
|
||||||
|
}
|
||||||
else if (oldAff == null)
|
else if (oldAff == null)
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Set", $"{Context.User.Mention} wants to be {u.Mention}'s waifu. Aww <3").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_set", Format.Bold(u.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Changed", $"{Context.User.Mention} changed their affinity from {oldAff} to {u.Mention}.\n\n*This is morally questionable.*🤔").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_changed", Format.Bold(oldAff.ToString()), Format.Bold(u.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -365,19 +368,20 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (waifus.Count == 0)
|
if (waifus.Count == 0)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync("No waifus have been claimed yet.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifus_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithTitle("Top Waifus")
|
.WithTitle(GetText("waifus_top_waifus"))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
for (int i = 0; i < waifus.Count; i++)
|
for (var i = 0; i < waifus.Count; i++)
|
||||||
{
|
{
|
||||||
var w = waifus[i];
|
var w = waifus[i];
|
||||||
|
|
||||||
embed.AddField(efb => efb.WithName("#" + (i + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false));
|
var j = i;
|
||||||
|
embed.AddField(efb => efb.WithName("#" + (j + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -419,15 +423,18 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var claimInfo = GetClaimTitle(target.Id);
|
var claimInfo = GetClaimTitle(target.Id);
|
||||||
var affInfo = GetAffinityTitle(target.Id);
|
var affInfo = GetAffinityTitle(target.Id);
|
||||||
|
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
var nobody = GetText("nobody");
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
|
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
|
||||||
.AddField(efb => efb.WithName("Price").WithValue(w.Price.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("price")).WithValue(w.Price.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Claimed by").WithValue(w.Claimer?.ToString() ?? "No one").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("claimed_by")).WithValue(w.Claimer?.ToString() ?? nobody).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Likes").WithValue(w.Affinity?.ToString() ?? "Nobody").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Changes Of Heart").WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Divorces").WithValue(divorces.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("divorces")).WithValue(divorces.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? "Nobody" : string.Join("\n", claims.Select(x => x.Waifu))).WithIsInline(true));
|
.AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(40).Select(x => x.Waifu))).WithIsInline(true));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -447,13 +454,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private static WaifuProfileTitle GetClaimTitle(ulong userId)
|
private static WaifuProfileTitle GetClaimTitle(ulong userId)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
count = uow.Waifus.ByClaimerUserId(userId).Count;
|
count = uow.Waifus.ByClaimerUserId(userId).Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClaimTitles title = ClaimTitles.Lonely;
|
ClaimTitles title;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
title = ClaimTitles.Lonely;
|
title = ClaimTitles.Lonely;
|
||||||
else if (count == 1)
|
else if (count == 1)
|
||||||
@ -484,13 +491,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private static WaifuProfileTitle GetAffinityTitle(ulong userId)
|
private static WaifuProfileTitle GetAffinityTitle(ulong userId)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged);
|
count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
AffinityTitles title = AffinityTitles.Pure;
|
AffinityTitles title;
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
title = AffinityTitles.Pure;
|
title = AffinityTitles.Pure;
|
||||||
else if (count < 2)
|
else if (count < 2)
|
||||||
|
@ -12,7 +12,7 @@ using System.Collections.Generic;
|
|||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
{
|
{
|
||||||
[NadekoModule("Gambling", "$")]
|
[NadekoModule("Gambling", "$")]
|
||||||
public partial class Gambling : NadekoModule
|
public partial class Gambling : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static string CurrencyName { get; set; }
|
public static string CurrencyName { get; set; }
|
||||||
public static string CurrencyPluralName { get; set; }
|
public static string CurrencyPluralName { get; set; }
|
||||||
@ -49,8 +49,10 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Cash([Remainder] IUser user = null)
|
public async Task Cash([Remainder] IUser user = null)
|
||||||
{
|
{
|
||||||
user = user ?? Context.User;
|
if(user == null)
|
||||||
await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
await ConfirmLocalized("has", Format.Bold(Context.User.ToString()), $"{GetCurrency(Context.User.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -238,9 +240,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
(int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
(int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Console.WriteLine("started sending");
|
|
||||||
await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
|
||||||
Console.WriteLine("done sending");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class Acropobia : ModuleBase
|
public class Acropobia : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
||||||
@ -28,6 +28,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Acro(int time = 60)
|
public async Task Acro(int time = 60)
|
||||||
{
|
{
|
||||||
|
if (time < 10 || time > 120)
|
||||||
|
return;
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = new AcrophobiaGame(channel, time);
|
var game = new AcrophobiaGame(channel, time);
|
||||||
@ -45,7 +47,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia game is already running in this channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("acro_running").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,44 +61,44 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public class AcrophobiaGame
|
public class AcrophobiaGame
|
||||||
{
|
{
|
||||||
private readonly ITextChannel channel;
|
private readonly ITextChannel _channel;
|
||||||
private readonly int time;
|
private readonly int _time;
|
||||||
private readonly NadekoRandom rng;
|
private readonly NadekoRandom _rng;
|
||||||
private readonly ImmutableArray<char> startingLetters;
|
private readonly ImmutableArray<char> _startingLetters;
|
||||||
private readonly CancellationTokenSource source;
|
private readonly CancellationTokenSource _source;
|
||||||
private AcroPhase phase { get; set; } = AcroPhase.Submitting;
|
private AcroPhase phase { get; set; } = AcroPhase.Submitting;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, IGuildUser> submissions = new ConcurrentDictionary<string, IGuildUser>();
|
private readonly ConcurrentDictionary<string, IGuildUser> _submissions = new ConcurrentDictionary<string, IGuildUser>();
|
||||||
public IReadOnlyDictionary<string, IGuildUser> Submissions => submissions;
|
public IReadOnlyDictionary<string, IGuildUser> Submissions => _submissions;
|
||||||
|
|
||||||
private readonly ConcurrentHashSet<ulong> usersWhoSubmitted = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> _usersWhoSubmitted = new ConcurrentHashSet<ulong>();
|
||||||
private readonly ConcurrentHashSet<ulong> usersWhoVoted = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> _usersWhoVoted = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
private int spamCount = 0;
|
private int _spamCount;
|
||||||
|
|
||||||
//text, votes
|
//text, votes
|
||||||
private readonly ConcurrentDictionary<string, int> votes = new ConcurrentDictionary<string, int>();
|
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public AcrophobiaGame(ITextChannel channel, int time)
|
public AcrophobiaGame(ITextChannel channel, int time)
|
||||||
{
|
{
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
this.channel = channel;
|
_channel = channel;
|
||||||
this.time = time;
|
_time = time;
|
||||||
this.source = new CancellationTokenSource();
|
_source = new CancellationTokenSource();
|
||||||
|
|
||||||
this.rng = new NadekoRandom();
|
_rng = new NadekoRandom();
|
||||||
var wordCount = rng.Next(3, 6);
|
var wordCount = _rng.Next(3, 6);
|
||||||
|
|
||||||
var lettersArr = new char[wordCount];
|
var lettersArr = new char[wordCount];
|
||||||
|
|
||||||
for (int i = 0; i < wordCount; i++)
|
for (int i = 0; i < wordCount; i++)
|
||||||
{
|
{
|
||||||
var randChar = (char)rng.Next(65, 91);
|
var randChar = (char)_rng.Next(65, 91);
|
||||||
lettersArr[i] = randChar == 'X' ? (char)rng.Next(65, 88) : randChar;
|
lettersArr[i] = randChar == 'X' ? (char)_rng.Next(65, 88) : randChar;
|
||||||
}
|
}
|
||||||
startingLetters = lettersArr.ToImmutableArray();
|
_startingLetters = lettersArr.ToImmutableArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private EmbedBuilder GetEmbed()
|
private EmbedBuilder GetEmbed()
|
||||||
@ -104,19 +106,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
return phase == AcroPhase.Submitting
|
return phase == AcroPhase.Submitting
|
||||||
|
|
||||||
? new EmbedBuilder().WithOkColor()
|
? new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Acrophobia")
|
.WithTitle(GetText("acrophobia"))
|
||||||
.WithDescription($"Game started. Create a sentence with the following acronym: **{string.Join(".", startingLetters)}.**\n")
|
.WithDescription(GetText("acro_started", Format.Bold(string.Join(".", _startingLetters))))
|
||||||
.WithFooter(efb => efb.WithText("You have " + this.time + " seconds to make a submission."))
|
.WithFooter(efb => efb.WithText(GetText("acro_started_footer", _time)))
|
||||||
|
|
||||||
: new EmbedBuilder()
|
: new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("Acrophobia - Submissions Closed")
|
.WithTitle(GetText("acrophobia") + " - " + GetText("submissions_closed"))
|
||||||
.WithDescription($@"Acronym was **{string.Join(".", startingLetters)}.**
|
.WithDescription(GetText("acro_nym_was", Format.Bold(string.Join(".", _startingLetters)) + "\n" +
|
||||||
--
|
$@"--
|
||||||
{this.submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")}
|
{_submissions.Aggregate("",(agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")}
|
||||||
--")
|
--"))
|
||||||
.WithFooter(efb => efb.WithText("Vote by typing a number of the submission"));
|
.WithFooter(efb => efb.WithText(GetText("acro_vote")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run()
|
||||||
@ -125,10 +127,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
var embed = GetEmbed();
|
var embed = GetEmbed();
|
||||||
|
|
||||||
//SUBMISSIONS PHASE
|
//SUBMISSIONS PHASE
|
||||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
await _channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(time * 1000, source.Token).ConfigureAwait(false);
|
await Task.Delay(_time * 1000, _source.Token).ConfigureAwait(false);
|
||||||
phase = AcroPhase.Idle;
|
phase = AcroPhase.Idle;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -137,30 +139,32 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
//var i = 0;
|
//var i = 0;
|
||||||
if (submissions.Count == 0)
|
if (_submissions.Count == 0)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia", "Game ended with no submissions.");
|
await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_ended_no_sub"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (submissions.Count == 1)
|
if (_submissions.Count == 1)
|
||||||
{
|
{
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await _channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription($"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!")
|
.WithDescription(
|
||||||
.WithFooter(efb => efb.WithText(submissions.First().Key.ToLowerInvariant().ToTitleCase())))
|
GetText("acro_winner_only",
|
||||||
.ConfigureAwait(false);
|
Format.Bold(_submissions.First().Value.ToString())))
|
||||||
|
.WithFooter(efb => efb.WithText(_submissions.First().Key.ToLowerInvariant().ToTitleCase())))
|
||||||
|
.ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var submissionClosedEmbed = GetEmbed();
|
var submissionClosedEmbed = GetEmbed();
|
||||||
|
|
||||||
await channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false);
|
await _channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false);
|
||||||
|
|
||||||
//VOTING PHASE
|
//VOTING PHASE
|
||||||
this.phase = AcroPhase.Voting;
|
phase = AcroPhase.Voting;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//30 secondds for voting
|
//30 secondds for voting
|
||||||
await Task.Delay(30000, source.Token).ConfigureAwait(false);
|
await Task.Delay(30000, _source.Token).ConfigureAwait(false);
|
||||||
this.phase = AcroPhase.Idle;
|
phase = AcroPhase.Idle;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@ -174,10 +178,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var msg = arg as SocketUserMessage;
|
var msg = arg as SocketUserMessage;
|
||||||
if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id)
|
if (msg == null || msg.Author.IsBot || msg.Channel.Id != _channel.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
++spamCount;
|
++_spamCount;
|
||||||
|
|
||||||
var guildUser = (IGuildUser)msg.Author;
|
var guildUser = (IGuildUser)msg.Author;
|
||||||
|
|
||||||
@ -185,37 +189,39 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
if (phase == AcroPhase.Submitting)
|
if (phase == AcroPhase.Submitting)
|
||||||
{
|
{
|
||||||
if (spamCount > 10)
|
if (_spamCount > 10)
|
||||||
{
|
{
|
||||||
spamCount = 0;
|
_spamCount = 0;
|
||||||
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
var inputWords = input.Split(' '); //get all words
|
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
|
if (inputWords.Length != _startingLetters.Length) // number of words must be the same as the number of the starting letters
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < startingLetters.Length; i++)
|
for (int i = 0; i < _startingLetters.Length; i++)
|
||||||
{
|
{
|
||||||
var letter = startingLetters[i];
|
var letter = _startingLetters[i];
|
||||||
|
|
||||||
if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
|
if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!usersWhoSubmitted.Add(guildUser.Id))
|
if (!_usersWhoSubmitted.Add(guildUser.Id))
|
||||||
return;
|
return;
|
||||||
//try adding it to the list of answers
|
//try adding it to the list of answers
|
||||||
if (!submissions.TryAdd(input, guildUser))
|
if (!_submissions.TryAdd(input, guildUser))
|
||||||
{
|
{
|
||||||
usersWhoSubmitted.TryRemove(guildUser.Id);
|
_usersWhoSubmitted.TryRemove(guildUser.Id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// all good. valid input. answer recorded
|
// all good. valid input. answer recorded
|
||||||
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");
|
await _channel.SendConfirmAsync(GetText("acrophobia"),
|
||||||
|
GetText("acro_submit", guildUser.Mention,
|
||||||
|
_submissions.Count));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await msg.DeleteAsync();
|
await msg.DeleteAsync();
|
||||||
@ -227,14 +233,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
else if (phase == AcroPhase.Voting)
|
else if (phase == AcroPhase.Voting)
|
||||||
{
|
{
|
||||||
if (spamCount > 10)
|
if (_spamCount > 10)
|
||||||
{
|
{
|
||||||
spamCount = 0;
|
_spamCount = 0;
|
||||||
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
IGuildUser usr;
|
|
||||||
//if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
|
//if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
|
||||||
//{
|
//{
|
||||||
// if (!usersWhoVoted.Add(guildUser.Id))
|
// if (!usersWhoVoted.Add(guildUser.Id))
|
||||||
@ -246,17 +251,17 @@ namespace NadekoBot.Modules.Games
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
int num;
|
int num;
|
||||||
if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count)
|
if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count)
|
||||||
{
|
{
|
||||||
var kvp = submissions.Skip(num - 1).First();
|
var kvp = _submissions.Skip(num - 1).First();
|
||||||
usr = kvp.Value;
|
var usr = kvp.Value;
|
||||||
//can't vote for yourself, can't vote multiple times
|
//can't vote for yourself, can't vote multiple times
|
||||||
if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id))
|
if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id))
|
||||||
return;
|
return;
|
||||||
votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
|
_votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
|
||||||
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
|
await _channel.SendConfirmAsync(GetText("acrophobia"),
|
||||||
|
GetText("acro_vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false);
|
||||||
await msg.DeleteAsync().ConfigureAwait(false);
|
await msg.DeleteAsync().ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -269,27 +274,34 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public async Task End()
|
public async Task End()
|
||||||
{
|
{
|
||||||
if (!votes.Any())
|
if (!_votes.Any())
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia", "No votes cast. Game ended with no winner.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_no_votes_cast")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var table = votes.OrderByDescending(v => v.Value);
|
var table = _votes.OrderByDescending(v => v.Value);
|
||||||
var winner = table.First();
|
var winner = table.First();
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Acrophobia")
|
.WithTitle(GetText("acrophobia"))
|
||||||
.WithDescription($"Winner is {submissions[winner.Key].Mention} with {winner.Value} points.\n")
|
.WithDescription(GetText("acro_winner", Format.Bold(_submissions[winner.Key].ToString()),
|
||||||
|
Format.Bold(winner.Value.ToString())))
|
||||||
.WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase()));
|
.WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase()));
|
||||||
|
|
||||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
await _channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureStopped()
|
public void EnsureStopped()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= PotentialAcro;
|
NadekoBot.Client.MessageReceived -= PotentialAcro;
|
||||||
if (!source.IsCancellationRequested)
|
if (!_source.IsCancellationRequested)
|
||||||
source.Cancel();
|
_source.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements)
|
||||||
|
=> GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_channel.Guild),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,11 +17,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CleverBotCommands : ModuleBase
|
public class CleverBotCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Logger _log { get; }
|
private new static Logger _log { get; }
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; } = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>();
|
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; }
|
||||||
|
|
||||||
static CleverBotCommands()
|
static CleverBotCommands()
|
||||||
{
|
{
|
||||||
@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Disabled cleverbot on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cleverbot_disabled").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cleverbot_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,9 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.Modules.Games.Commands.Hangman;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games.Commands.Hangman
|
namespace NadekoBot.Modules.Games.Hangman
|
||||||
{
|
{
|
||||||
public class HangmanTermPool
|
public class HangmanTermPool
|
||||||
{
|
{
|
||||||
@ -70,7 +71,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
return $" {c}";
|
return $" {c}";
|
||||||
|
|
||||||
c = char.ToUpperInvariant(c);
|
c = char.ToUpperInvariant(c);
|
||||||
return Guesses.Contains(c) ? $" {c}" : " _";
|
return Guesses.Contains(c) ? $" {c}" : " ◯";
|
||||||
})) + "`";
|
})) + "`";
|
||||||
|
|
||||||
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
||||||
@ -145,7 +146,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
++Errors;
|
++Errors;
|
||||||
if (Errors < MaxErrors)
|
if (Errors < MaxErrors)
|
||||||
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
@ -158,7 +159,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
{
|
{
|
||||||
if (GuessedAll)
|
if (GuessedAll)
|
||||||
{
|
{
|
||||||
try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
|
try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -166,7 +167,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@ -177,7 +178,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
++Errors;
|
++Errors;
|
||||||
if (Errors < MaxErrors)
|
if (Errors < MaxErrors)
|
||||||
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
|
@ -1,36 +1,25 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Commands.Hangman;
|
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.Modules.Games.Hangman;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class HangmanCommands : ModuleBase
|
public class HangmanCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Logger _log { get; }
|
|
||||||
|
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
||||||
private static string typesStr { get; } = "";
|
|
||||||
|
|
||||||
static HangmanCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
typesStr =
|
|
||||||
string.Format("`List of \"{0}hangman\" term types:`\n", NadekoBot.ModulePrefixes[typeof(Games).Name]) + String.Join(", ", HangmanTermPool.data.Keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Hangmanlist()
|
public async Task Hangmanlist()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(typesStr);
|
await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + string.Join(", ", HangmanTermPool.data.Keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -40,11 +29,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Hangman game already running on this channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("hangman_running").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hm.OnEnded += (g) =>
|
hm.OnEnded += g =>
|
||||||
{
|
{
|
||||||
HangmanGame throwaway;
|
HangmanGame throwaway;
|
||||||
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
||||||
@ -55,14 +44,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { }
|
try { await Context.Channel.SendErrorAsync(GetText("hangman_start_errored") + " " + ex.Message).ConfigureAwait(false); } catch { }
|
||||||
HangmanGame throwaway;
|
HangmanGame throwaway;
|
||||||
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
||||||
throwaway.Dispose();
|
throwaway.Dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman());
|
await Context.Channel.SendConfirmAsync(GetText("hangman_game_started"), hm.ScrambledWord + "\n" + hm.GetHangman());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
@ -31,7 +28,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class PlantPickCommands : NadekoSubmodule
|
public class PlantPickCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentHashSet<ulong> generationChannels { get; } = new ConcurrentHashSet<ulong>();
|
private static ConcurrentHashSet<ulong> generationChannels { get; }
|
||||||
//channelid/message
|
//channelid/message
|
||||||
private static ConcurrentDictionary<ulong, List<IUserMessage>> plantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
private static ConcurrentDictionary<ulong, List<IUserMessage>> plantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
||||||
//channelId/last generation
|
//channelId/last generation
|
||||||
@ -82,25 +79,17 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (dropAmount > 0)
|
if (dropAmount > 0)
|
||||||
{
|
{
|
||||||
var msgs = new IUserMessage[dropAmount];
|
var msgs = new IUserMessage[dropAmount];
|
||||||
|
var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name];
|
||||||
string firstPart;
|
var toSend = dropAmount == 1
|
||||||
if (dropAmount == 1)
|
? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign, prefix)
|
||||||
{
|
: GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign, prefix);
|
||||||
firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!";
|
|
||||||
}
|
|
||||||
var file = GetRandomCurrencyImage();
|
var file = GetRandomCurrencyImage();
|
||||||
using (var fileStream = file.Value.ToStream())
|
using (var fileStream = file.Value.ToStream())
|
||||||
{
|
{
|
||||||
var sent = await channel.SendFileAsync(
|
var sent = await channel.SendFileAsync(
|
||||||
fileStream,
|
fileStream,
|
||||||
file.Key,
|
file.Key,
|
||||||
string.Format("❗ {0} Pick it up by typing `{1}pick`", firstPart,
|
toSend).ConfigureAwait(false);
|
||||||
NadekoBot.ModulePrefixes[typeof(Games).Name]))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
msgs[0] = sent;
|
msgs[0] = sent;
|
||||||
}
|
}
|
||||||
@ -117,6 +106,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetLocalText(ITextChannel channel, string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Pick()
|
public async Task Pick()
|
||||||
@ -135,7 +130,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
||||||
|
|
||||||
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
|
||||||
var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false);
|
var msg = await ReplyConfirmLocalized("picked", msgs.Count + NadekoBot.BotConfig.CurrencySign)
|
||||||
|
.ConfigureAwait(false);
|
||||||
msg.DeleteAfter(10);
|
msg.DeleteAfter(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,14 +145,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
||||||
if (!removed)
|
if (!removed)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_enough", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgData = GetRandomCurrencyImage();
|
var imgData = GetRandomCurrencyImage();
|
||||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
|
||||||
|
|
||||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {Prefix}pick";
|
//todo upload all currency images to transfer.sh and use that one as cdn
|
||||||
|
//and then
|
||||||
|
|
||||||
|
var msgToSend = GetText("planted",
|
||||||
|
Format.Bold(Context.User.ToString()),
|
||||||
|
amount + NadekoBot.BotConfig.CurrencySign,
|
||||||
|
Prefix);
|
||||||
|
|
||||||
IUserMessage msg;
|
IUserMessage msg;
|
||||||
using (var toSend = imgData.Value.ToStream())
|
using (var toSend = imgData.Value.ToStream())
|
||||||
@ -203,11 +204,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Currency generation enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("curgen_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Currency generation disabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,10 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
@ -16,7 +14,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class PollCommands : ModuleBase
|
public class PollCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||||
|
|
||||||
@ -24,20 +22,20 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task Poll([Remainder] string arg = null)
|
public Task Poll([Remainder] string arg = null)
|
||||||
=> InternalStartPoll(arg, isPublic: false);
|
=> InternalStartPoll(arg, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task PublicPoll([Remainder] string arg = null)
|
public Task PublicPoll([Remainder] string arg = null)
|
||||||
=> InternalStartPoll(arg, isPublic: true);
|
=> InternalStartPoll(arg, true);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task PollStats()
|
public async Task PollStats()
|
||||||
{
|
{
|
||||||
Games.Poll poll;
|
Poll poll;
|
||||||
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -48,8 +46,6 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
|
|
||||||
return;
|
|
||||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
||||||
return;
|
return;
|
||||||
var data = arg.Split(';');
|
var data = arg.Split(';');
|
||||||
@ -80,27 +76,25 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public class Poll
|
public class Poll
|
||||||
{
|
{
|
||||||
private readonly IUserMessage originalMessage;
|
private readonly IUserMessage _originalMessage;
|
||||||
private readonly IGuild guild;
|
private readonly IGuild _guild;
|
||||||
private string[] Answers { get; }
|
private string[] answers { get; }
|
||||||
private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
|
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
|
||||||
private readonly string question;
|
private readonly string _question;
|
||||||
private DateTime started;
|
|
||||||
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
|
|
||||||
public bool IsPublic { get; }
|
public bool IsPublic { get; }
|
||||||
|
|
||||||
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
||||||
{
|
{
|
||||||
this.originalMessage = umsg;
|
_originalMessage = umsg;
|
||||||
this.guild = ((ITextChannel)umsg.Channel).Guild;
|
_guild = ((ITextChannel)umsg.Channel).Guild;
|
||||||
this.question = question;
|
_question = question;
|
||||||
this.Answers = enumerable as string[] ?? enumerable.ToArray();
|
answers = enumerable as string[] ?? enumerable.ToArray();
|
||||||
this.IsPublic = isPublic;
|
IsPublic = isPublic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbedBuilder GetStats(string title)
|
public EmbedBuilder GetStats(string title)
|
||||||
{
|
{
|
||||||
var results = participants.GroupBy(kvp => kvp.Value)
|
var results = _participants.GroupBy(kvp => kvp.Value)
|
||||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||||
.OrderByDescending(kvp => kvp.Value)
|
.OrderByDescending(kvp => kvp.Value)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@ -108,7 +102,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var eb = new EmbedBuilder().WithTitle(title);
|
var eb = new EmbedBuilder().WithTitle(title);
|
||||||
|
|
||||||
var sb = new StringBuilder()
|
var sb = new StringBuilder()
|
||||||
.AppendLine(Format.Bold(question))
|
.AppendLine(Format.Bold(_question))
|
||||||
.AppendLine();
|
.AppendLine();
|
||||||
|
|
||||||
var totalVotesCast = 0;
|
var totalVotesCast = 0;
|
||||||
@ -121,7 +115,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
for (int i = 0; i < results.Length; i++)
|
for (int i = 0; i < results.Length; i++)
|
||||||
{
|
{
|
||||||
var result = results[i];
|
var result = results[i];
|
||||||
sb.AppendLine($"`{i + 1}.` {Format.Bold(Answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes.");
|
sb.AppendLine($"`{i + 1}.` {Format.Bold(answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes.");
|
||||||
totalVotesCast += result.Value;
|
totalVotesCast += result.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,22 +129,21 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public async Task StartPoll()
|
public async Task StartPoll()
|
||||||
{
|
{
|
||||||
started = DateTime.Now;
|
|
||||||
NadekoBot.Client.MessageReceived += Vote;
|
NadekoBot.Client.MessageReceived += Vote;
|
||||||
var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
|
var msgToSend = $"📃**{_originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{_question}**\n";
|
||||||
var num = 1;
|
var num = 1;
|
||||||
msgToSend = Answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||||
if (!IsPublic)
|
if (!IsPublic)
|
||||||
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
||||||
else
|
else
|
||||||
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
|
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
|
||||||
await originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
|
await _originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopPoll()
|
public async Task StopPoll()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= Vote;
|
NadekoBot.Client.MessageReceived -= Vote;
|
||||||
await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Vote(SocketMessage imsg)
|
private async Task Vote(SocketMessage imsg)
|
||||||
@ -166,14 +159,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
int vote;
|
int vote;
|
||||||
if (!int.TryParse(imsg.Content, out vote))
|
if (!int.TryParse(imsg.Content, out vote))
|
||||||
return;
|
return;
|
||||||
if (vote < 1 || vote > Answers.Length)
|
if (vote < 1 || vote > answers.Length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IMessageChannel ch;
|
IMessageChannel ch;
|
||||||
if (IsPublic)
|
if (IsPublic)
|
||||||
{
|
{
|
||||||
//if public, channel must be the same the poll started in
|
//if public, channel must be the same the poll started in
|
||||||
if (originalMessage.Channel.Id != imsg.Channel.Id)
|
if (_originalMessage.Channel.Id != imsg.Channel.Id)
|
||||||
return;
|
return;
|
||||||
ch = imsg.Channel;
|
ch = imsg.Channel;
|
||||||
}
|
}
|
||||||
@ -184,13 +177,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// user must be a member of the guild this poll is in
|
// user must be a member of the guild this poll is in
|
||||||
var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
|
var guildUsers = await _guild.GetUsersAsync().ConfigureAwait(false);
|
||||||
if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
|
if (guildUsers.All(u => u.Id != imsg.Author.Id))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//user can vote only once
|
//user can vote only once
|
||||||
if (participants.TryAdd(msg.Author.Id, vote))
|
if (_participants.TryAdd(msg.Author.Id, vote))
|
||||||
{
|
{
|
||||||
if (!IsPublic)
|
if (!IsPublic)
|
||||||
{
|
{
|
||||||
|
@ -147,7 +147,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class SpeedTypingCommands : ModuleBase
|
public class SpeedTypingCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
||||||
|
|
||||||
|
@ -4,9 +4,7 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -15,21 +13,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
//todo timeout
|
|
||||||
[Group]
|
[Group]
|
||||||
public class TicTacToeCommands : ModuleBase
|
public class TicTacToeCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//channelId/game
|
//channelId/game
|
||||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
||||||
private readonly Logger _log;
|
|
||||||
|
|
||||||
public TicTacToeCommands()
|
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1);
|
|
||||||
private readonly object tttLockObj = new object();
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -37,7 +27,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
await sem.WaitAsync(1000);
|
await _sem.WaitAsync(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TicTacToe game;
|
TicTacToe game;
|
||||||
@ -51,7 +41,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
game = new TicTacToe(channel, (IGuildUser)Context.User);
|
game = new TicTacToe(channel, (IGuildUser)Context.User);
|
||||||
_games.Add(channel.Id, game);
|
_games.Add(channel.Id, game);
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Created a TicTacToe game.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
||||||
|
|
||||||
game.OnEnded += (g) =>
|
game.OnEnded += (g) =>
|
||||||
{
|
{
|
||||||
@ -60,7 +50,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
sem.Release();
|
_sem.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,46 +65,49 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly ITextChannel _channel;
|
private readonly ITextChannel _channel;
|
||||||
private readonly Logger _log;
|
|
||||||
private readonly IGuildUser[] _users;
|
private readonly IGuildUser[] _users;
|
||||||
private readonly int?[,] _state;
|
private readonly int?[,] _state;
|
||||||
private Phase _phase;
|
private Phase _phase;
|
||||||
int curUserIndex = 0;
|
private int _curUserIndex;
|
||||||
private readonly SemaphoreSlim moveLock;
|
private readonly SemaphoreSlim _moveLock;
|
||||||
|
|
||||||
private IGuildUser _winner = null;
|
private IGuildUser _winner;
|
||||||
|
|
||||||
private readonly string[] numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
private readonly string[] _numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
||||||
|
|
||||||
public Action<TicTacToe> OnEnded;
|
public Action<TicTacToe> OnEnded;
|
||||||
|
|
||||||
private IUserMessage previousMessage = null;
|
private IUserMessage _previousMessage;
|
||||||
private Timer timeoutTimer;
|
private Timer _timeoutTimer;
|
||||||
|
|
||||||
public TicTacToe(ITextChannel channel, IGuildUser firstUser)
|
public TicTacToe(ITextChannel channel, IGuildUser firstUser)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_users = new IGuildUser[2] { firstUser, null };
|
_users = new[] { firstUser, null };
|
||||||
_state = new int?[3, 3] {
|
_state = new int?[,] {
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
};
|
};
|
||||||
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
_log.Warn($"User {firstUser} created a TicTacToe game.");
|
|
||||||
_phase = Phase.Starting;
|
_phase = Phase.Starting;
|
||||||
moveLock = new SemaphoreSlim(1, 1);
|
_moveLock = new SemaphoreSlim(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
public string GetState()
|
public string GetState()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (int i = 0; i < _state.GetLength(0); i++)
|
for (var i = 0; i < _state.GetLength(0); i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < _state.GetLength(1); j++)
|
for (var j = 0; j < _state.GetLength(1); j++)
|
||||||
{
|
{
|
||||||
sb.Append(_state[i, j] == null ? numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
sb.Append(_state[i, j] == null ? _numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
||||||
if (j < _state.GetLength(1) - 1)
|
if (j < _state.GetLength(1) - 1)
|
||||||
sb.Append("┃");
|
sb.Append("┃");
|
||||||
}
|
}
|
||||||
@ -130,7 +123,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithDescription(Environment.NewLine + GetState())
|
.WithDescription(Environment.NewLine + GetState())
|
||||||
.WithAuthor(eab => eab.WithName($"{_users[0]} vs {_users[1]}"));
|
.WithAuthor(eab => eab.WithName(GetText("vs", _users[0], _users[1])));
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(title))
|
if (!string.IsNullOrWhiteSpace(title))
|
||||||
embed.WithTitle(title);
|
embed.WithTitle(title);
|
||||||
@ -138,12 +131,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (_winner == null)
|
if (_winner == null)
|
||||||
{
|
{
|
||||||
if (_phase == Phase.Ended)
|
if (_phase == Phase.Ended)
|
||||||
embed.WithFooter(efb => efb.WithText($"No moves left!"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves")));
|
||||||
else
|
else
|
||||||
embed.WithFooter(efb => efb.WithText($"{_users[curUserIndex]}'s move"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_users_move", _users[_curUserIndex])));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
embed.WithFooter(efb => efb.WithText($"{_winner} Won!"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner)));
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
}
|
}
|
||||||
@ -169,23 +162,22 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
if (_phase == Phase.Started || _phase == Phase.Ended)
|
if (_phase == Phase.Started || _phase == Phase.Ended)
|
||||||
{
|
{
|
||||||
await _channel.SendErrorAsync(user.Mention + " TicTacToe Game is already running in this channel.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_already_running")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (_users[0] == user)
|
else if (_users[0] == user)
|
||||||
{
|
{
|
||||||
await _channel.SendErrorAsync(user.Mention + " You can't play against yourself.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_against_yourself")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_users[1] = user;
|
_users[1] = user;
|
||||||
_log.Warn($"User {user} joined a TicTacToe game.");
|
|
||||||
|
|
||||||
_phase = Phase.Started;
|
_phase = Phase.Started;
|
||||||
|
|
||||||
timeoutTimer = new Timer(async (_) =>
|
_timeoutTimer = new Timer(async (_) =>
|
||||||
{
|
{
|
||||||
await moveLock.WaitAsync();
|
await _moveLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_phase == Phase.Ended)
|
if (_phase == Phase.Ended)
|
||||||
@ -194,12 +186,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
if (_users[1] != null)
|
if (_users[1] != null)
|
||||||
{
|
{
|
||||||
_winner = _users[curUserIndex ^= 1];
|
_winner = _users[_curUserIndex ^= 1];
|
||||||
var del = previousMessage?.DeleteAsync();
|
var del = _previousMessage?.DeleteAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false);
|
await _channel.EmbedAsync(GetEmbed(GetText("ttt_time_expired"))).ConfigureAwait(false);
|
||||||
await del.ConfigureAwait(false);
|
if (del != null)
|
||||||
|
await del.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
@ -209,21 +202,21 @@ namespace NadekoBot.Modules.Games
|
|||||||
catch { }
|
catch { }
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
moveLock.Release();
|
_moveLock.Release();
|
||||||
}
|
}
|
||||||
}, null, 15000, Timeout.Infinite);
|
}, null, 15000, Timeout.Infinite);
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
|
|
||||||
previousMessage = await _channel.EmbedAsync(GetEmbed("Game Started")).ConfigureAwait(false);
|
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsDraw()
|
private bool IsDraw()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (var i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 3; j++)
|
for (var j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
if (_state[i, j] == null)
|
if (_state[i, j] == null)
|
||||||
return false;
|
return false;
|
||||||
@ -236,10 +229,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await moveLock.WaitAsync().ConfigureAwait(false);
|
await _moveLock.WaitAsync().ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var curUser = _users[curUserIndex];
|
var curUser = _users[_curUserIndex];
|
||||||
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -249,53 +242,53 @@ namespace NadekoBot.Modules.Games
|
|||||||
index <= 9 &&
|
index <= 9 &&
|
||||||
_state[index / 3, index % 3] == null)
|
_state[index / 3, index % 3] == null)
|
||||||
{
|
{
|
||||||
_state[index / 3, index % 3] = curUserIndex;
|
_state[index / 3, index % 3] = _curUserIndex;
|
||||||
|
|
||||||
// i'm lazy
|
// i'm lazy
|
||||||
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
||||||
{
|
{
|
||||||
_state[index / 3, 0] = curUserIndex + 2;
|
_state[index / 3, 0] = _curUserIndex + 2;
|
||||||
_state[index / 3, 1] = curUserIndex + 2;
|
_state[index / 3, 1] = _curUserIndex + 2;
|
||||||
_state[index / 3, 2] = curUserIndex + 2;
|
_state[index / 3, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
||||||
{
|
{
|
||||||
_state[0, index % 3] = curUserIndex + 2;
|
_state[0, index % 3] = _curUserIndex + 2;
|
||||||
_state[1, index % 3] = curUserIndex + 2;
|
_state[1, index % 3] = _curUserIndex + 2;
|
||||||
_state[2, index % 3] = curUserIndex + 2;
|
_state[2, index % 3] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
else if (_curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
||||||
{
|
{
|
||||||
_state[0, 0] = curUserIndex + 2;
|
_state[0, 0] = _curUserIndex + 2;
|
||||||
_state[1, 1] = curUserIndex + 2;
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
_state[2, 2] = curUserIndex + 2;
|
_state[2, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
else if (_curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
||||||
{
|
{
|
||||||
_state[0, 2] = curUserIndex + 2;
|
_state[0, 2] = _curUserIndex + 2;
|
||||||
_state[1, 1] = curUserIndex + 2;
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
_state[2, 0] = curUserIndex + 2;
|
_state[2, 0] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
string reason = "";
|
var reason = "";
|
||||||
|
|
||||||
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
||||||
{
|
{
|
||||||
reason = "Matched three!";
|
reason = GetText("ttt_matched_three");
|
||||||
_winner = _users[curUserIndex];
|
_winner = _users[_curUserIndex];
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
else if (IsDraw())
|
else if (IsDraw())
|
||||||
{
|
{
|
||||||
reason = "A draw!";
|
reason = GetText("ttt_a_draw");
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
@ -304,19 +297,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
var sendstate = Task.Run(async () =>
|
var sendstate = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var del1 = msg.DeleteAsync();
|
var del1 = msg.DeleteAsync();
|
||||||
var del2 = previousMessage?.DeleteAsync();
|
var del2 = _previousMessage?.DeleteAsync();
|
||||||
try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
||||||
try { await del1; } catch { }
|
try { await del1; } catch { }
|
||||||
try { if (del2 != null) await del2; } catch { }
|
try { if (del2 != null) await del2; } catch { }
|
||||||
});
|
});
|
||||||
curUserIndex ^= 1;
|
_curUserIndex ^= 1;
|
||||||
|
|
||||||
timeoutTimer.Change(15000, Timeout.Infinite);
|
_timeoutTimer.Change(15000, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
moveLock.Release();
|
_moveLock.Release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,36 +17,42 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
public class TriviaGame
|
public class TriviaGame
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
||||||
private Logger _log { get; }
|
private readonly Logger _log;
|
||||||
|
|
||||||
public IGuild guild { get; }
|
public IGuild Guild { get; }
|
||||||
public ITextChannel channel { get; }
|
public ITextChannel Channel { get; }
|
||||||
|
|
||||||
private int QuestionDurationMiliseconds { get; } = 30000;
|
private int questionDurationMiliseconds { get; } = 30000;
|
||||||
private int HintTimeoutMiliseconds { get; } = 6000;
|
private int hintTimeoutMiliseconds { get; } = 6000;
|
||||||
public bool ShowHints { get; } = true;
|
public bool ShowHints { get; }
|
||||||
private CancellationTokenSource triviaCancelSource { get; set; }
|
private CancellationTokenSource triviaCancelSource { get; set; }
|
||||||
|
|
||||||
public TriviaQuestion CurrentQuestion { get; private set; }
|
public TriviaQuestion CurrentQuestion { get; private set; }
|
||||||
public HashSet<TriviaQuestion> oldQuestions { get; } = new HashSet<TriviaQuestion>();
|
public HashSet<TriviaQuestion> OldQuestions { get; } = new HashSet<TriviaQuestion>();
|
||||||
|
|
||||||
public ConcurrentDictionary<IGuildUser, int> Users { get; } = new ConcurrentDictionary<IGuildUser, int>();
|
public ConcurrentDictionary<IGuildUser, int> Users { get; } = new ConcurrentDictionary<IGuildUser, int>();
|
||||||
|
|
||||||
public bool GameActive { get; private set; } = false;
|
public bool GameActive { get; private set; }
|
||||||
public bool ShouldStopGame { get; private set; }
|
public bool ShouldStopGame { get; private set; }
|
||||||
|
|
||||||
public int WinRequirement { get; } = 10;
|
public int WinRequirement { get; }
|
||||||
|
|
||||||
public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq)
|
public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq)
|
||||||
{
|
{
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
this.ShowHints = showHints;
|
ShowHints = showHints;
|
||||||
this.guild = guild;
|
Guild = guild;
|
||||||
this.channel = channel;
|
Channel = channel;
|
||||||
this.WinRequirement = winReq;
|
WinRequirement = winReq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(Channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
public async Task StartGame()
|
public async Task StartGame()
|
||||||
{
|
{
|
||||||
while (!ShouldStopGame)
|
while (!ShouldStopGame)
|
||||||
@ -55,26 +61,24 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
triviaCancelSource = new CancellationTokenSource();
|
triviaCancelSource = new CancellationTokenSource();
|
||||||
|
|
||||||
// load question
|
// load question
|
||||||
CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions);
|
CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions);
|
||||||
if (CurrentQuestion == null ||
|
if (string.IsNullOrWhiteSpace(CurrentQuestion?.Answer) || string.IsNullOrWhiteSpace(CurrentQuestion.Question))
|
||||||
string.IsNullOrWhiteSpace(CurrentQuestion.Answer) ||
|
|
||||||
string.IsNullOrWhiteSpace(CurrentQuestion.Question))
|
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Trivia Game", "Failed loading a question.").ConfigureAwait(false);
|
await Channel.SendErrorAsync(GetText("trivia_game"), GetText("failed_loading_question")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
oldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again
|
OldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again
|
||||||
|
|
||||||
EmbedBuilder questionEmbed;
|
EmbedBuilder questionEmbed;
|
||||||
IUserMessage questionMessage;
|
IUserMessage questionMessage;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
questionEmbed = new EmbedBuilder().WithOkColor()
|
questionEmbed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Trivia Game")
|
.WithTitle(GetText("trivia_game"))
|
||||||
.AddField(eab => eab.WithName("Category").WithValue(CurrentQuestion.Category))
|
.AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category))
|
||||||
.AddField(eab => eab.WithName("Question").WithValue(CurrentQuestion.Question));
|
.AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question));
|
||||||
|
|
||||||
questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
|
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
|
||||||
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
|
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
|
||||||
@ -99,7 +103,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//hint
|
//hint
|
||||||
await Task.Delay(HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
await Task.Delay(hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
||||||
if (ShowHints)
|
if (ShowHints)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -113,7 +117,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
|
||||||
//timeout
|
//timeout
|
||||||
await Task.Delay(QuestionDurationMiliseconds - HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
await Task.Delay(questionDurationMiliseconds - hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException) { } //means someone guessed the answer
|
catch (TaskCanceledException) { } //means someone guessed the answer
|
||||||
@ -124,7 +128,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
||||||
}
|
}
|
||||||
if (!triviaCancelSource.IsCancellationRequested)
|
if (!triviaCancelSource.IsCancellationRequested)
|
||||||
try { await channel.SendErrorAsync("Trivia Game", $"**Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { await Channel.SendErrorAsync(GetText("trivia_game"), GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
await Task.Delay(2000).ConfigureAwait(false);
|
await Task.Delay(2000).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +137,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
|
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Trivia Game Ended"))
|
.WithAuthor(eab => eab.WithName("Trivia Game Ended"))
|
||||||
.WithTitle("Final Results")
|
.WithTitle("Final Results")
|
||||||
.WithDescription(GetLeaderboard())).ConfigureAwait(false);
|
.WithDescription(GetLeaderboard())).ConfigureAwait(false);
|
||||||
@ -144,7 +148,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
var old = ShouldStopGame;
|
var old = ShouldStopGame;
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
if (!old)
|
if (!old)
|
||||||
try { await channel.SendConfirmAsync("Trivia Game", "Stopping after this question.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { await Channel.SendConfirmAsync(GetText("trivia_game"), GetText("trivia_stopping")).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PotentialGuess(SocketMessage imsg)
|
private async Task PotentialGuess(SocketMessage imsg)
|
||||||
@ -155,11 +159,9 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var umsg = imsg as SocketUserMessage;
|
var umsg = imsg as SocketUserMessage;
|
||||||
if (umsg == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var textChannel = umsg.Channel as ITextChannel;
|
var textChannel = umsg?.Channel as ITextChannel;
|
||||||
if (textChannel == null || textChannel.Guild != guild)
|
if (textChannel == null || textChannel.Guild != Guild)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var guildUser = (IGuildUser)umsg.Author;
|
var guildUser = (IGuildUser)umsg.Author;
|
||||||
@ -182,13 +184,24 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
if (Users[guildUser] == WinRequirement)
|
if (Users[guildUser] == WinRequirement)
|
||||||
{
|
{
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
try { await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await Channel.SendConfirmAsync(GetText("trivia_game"),
|
||||||
|
GetText("trivia_win",
|
||||||
|
guildUser.Mention,
|
||||||
|
Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
var reward = NadekoBot.BotConfig.TriviaCurrencyReward;
|
var reward = NadekoBot.BotConfig.TriviaCurrencyReward;
|
||||||
if (reward > 0)
|
if (reward > 0)
|
||||||
await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
|
await Channel.SendConfirmAsync(GetText("trivia_game"),
|
||||||
|
GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
@ -197,13 +210,13 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
public string GetLeaderboard()
|
public string GetLeaderboard()
|
||||||
{
|
{
|
||||||
if (Users.Count == 0)
|
if (Users.Count == 0)
|
||||||
return "No results.";
|
return GetText("no_results");
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
foreach (var kvp in Users.OrderByDescending(kvp => kvp.Value))
|
foreach (var kvp in Users.OrderByDescending(kvp => kvp.Value))
|
||||||
{
|
{
|
||||||
sb.AppendLine($"**{kvp.Key.Username}** has {kvp.Value} points".ToString().SnPl(kvp.Value));
|
sb.AppendLine(GetText("trivia_points", Format.Bold(kvp.Key.ToString()), kvp.Value).SnPl(kvp.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
@ -3,9 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Trivia;
|
using NadekoBot.Modules.Games.Trivia;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +12,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class TriviaCommands : ModuleBase
|
public class TriviaCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||||
|
|
||||||
@ -31,7 +29,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
var showHints = !additionalArgs.Contains("nohint");
|
var showHints = !additionalArgs.Contains("nohint");
|
||||||
|
|
||||||
TriviaGame trivia = new TriviaGame(channel.Guild, channel, showHints, winReq);
|
var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq);
|
||||||
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -45,8 +43,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
await Context.Channel.SendErrorAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false);
|
await Context.Channel.SendErrorAsync(GetText("trivia_already_running") + "\n" + trivia.CurrentQuestion)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -58,11 +57,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
TriviaGame trivia;
|
TriviaGame trivia;
|
||||||
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Leaderboard", trivia.GetLeaderboard()).ConfigureAwait(false);
|
await channel.SendConfirmAsync(GetText("leaderboard"), trivia.GetLeaderboard()).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("trivia_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -78,7 +77,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("trivia_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,29 @@ using NadekoBot.Services;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using System.Net.Http;
|
||||||
|
using ImageSharp;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
[NadekoModule("Games", ">")]
|
[NadekoModule("Games", ">")]
|
||||||
public partial class Games : NadekoModule
|
public partial class Games : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray();
|
private static readonly ImmutableArray<string> _8BallResponses = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray();
|
||||||
|
|
||||||
|
private static readonly Timer _t = new Timer((_) =>
|
||||||
|
{
|
||||||
|
_girlRatings.Clear();
|
||||||
|
|
||||||
|
}, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1));
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Choose([Remainder] string list = null)
|
public async Task Choose([Remainder] string list = null)
|
||||||
@ -21,7 +34,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (string.IsNullOrWhiteSpace(list))
|
if (string.IsNullOrWhiteSpace(list))
|
||||||
return;
|
return;
|
||||||
var listArr = list.Split(';');
|
var listArr = list.Split(';');
|
||||||
if (listArr.Count() < 2)
|
if (listArr.Length < 2)
|
||||||
return;
|
return;
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
|
||||||
@ -34,21 +47,24 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||||
.AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false))
|
.AddField(efb => efb.WithName("❓ " + GetText("question") ).WithValue(question).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
.AddField(efb => efb.WithName("🎱 " + GetText("8ball")).WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Rps(string input)
|
public async Task Rps(string input)
|
||||||
{
|
{
|
||||||
Func<int,string> GetRPSPick = (p) =>
|
Func<int,string> getRpsPick = (p) =>
|
||||||
{
|
{
|
||||||
if (p == 0)
|
switch (p)
|
||||||
return "🚀";
|
{
|
||||||
else if (p == 1)
|
case 0:
|
||||||
return "📎";
|
return "🚀";
|
||||||
else
|
case 1:
|
||||||
return "✂️";
|
return "📎";
|
||||||
|
default:
|
||||||
|
return "✂️";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int pick;
|
int pick;
|
||||||
@ -72,19 +88,176 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var nadekoPick = new NadekoRandom().Next(0, 3);
|
var nadekoPick = new NadekoRandom().Next(0, 3);
|
||||||
var msg = "";
|
string msg;
|
||||||
if (pick == nadekoPick)
|
if (pick == nadekoPick)
|
||||||
msg = $"It's a draw! Both picked {GetRPSPick(pick)}";
|
msg = GetText("rps_draw", getRpsPick(pick));
|
||||||
else if ((pick == 0 && nadekoPick == 1) ||
|
else if ((pick == 0 && nadekoPick == 1) ||
|
||||||
(pick == 1 && nadekoPick == 2) ||
|
(pick == 1 && nadekoPick == 2) ||
|
||||||
(pick == 2 && nadekoPick == 0))
|
(pick == 2 && nadekoPick == 0))
|
||||||
msg = $"{NadekoBot.Client.CurrentUser.Mention} won! {GetRPSPick(nadekoPick)} beats {GetRPSPick(pick)}";
|
msg = GetText("rps_win", NadekoBot.Client.CurrentUser.Mention,
|
||||||
|
getRpsPick(nadekoPick), getRpsPick(pick));
|
||||||
else
|
else
|
||||||
msg = $"{Context.User.Mention} won! {GetRPSPick(pick)} beats {GetRPSPick(nadekoPick)}";
|
msg = GetText("rps_win", Context.User.Mention, getRpsPick(pick),
|
||||||
|
getRpsPick(nadekoPick));
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<ulong, GirlRating> _girlRatings = new ConcurrentDictionary<ulong, GirlRating>();
|
||||||
|
|
||||||
|
public class GirlRating
|
||||||
|
{
|
||||||
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public double Crazy { get; }
|
||||||
|
public double Hot { get; }
|
||||||
|
public int Roll { get; }
|
||||||
|
public string Advice { get; }
|
||||||
|
public AsyncLazy<string> Url { get; }
|
||||||
|
|
||||||
|
public GirlRating(double crazy, double hot, int roll, string advice)
|
||||||
|
{
|
||||||
|
Crazy = crazy;
|
||||||
|
Hot = hot;
|
||||||
|
Roll = roll;
|
||||||
|
Advice = advice; // convenient to have it here, even though atm there are only few different ones.
|
||||||
|
|
||||||
|
Url = new AsyncLazy<string>(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(NadekoBot.Images.WifeMatrix.ToArray(), false))
|
||||||
|
using (var img = new ImageSharp.Image(ms))
|
||||||
|
{
|
||||||
|
const int minx = 35;
|
||||||
|
const int miny = 385;
|
||||||
|
const int length = 345;
|
||||||
|
|
||||||
|
var pointx = (int)(minx + length * (Hot / 10));
|
||||||
|
var pointy = (int)(miny - length * ((Crazy - 4) / 6));
|
||||||
|
|
||||||
|
using (var pointMs = new MemoryStream(NadekoBot.Images.RategirlDot.ToArray(), false))
|
||||||
|
using (var pointImg = new ImageSharp.Image(pointMs))
|
||||||
|
{
|
||||||
|
img.DrawImage(pointImg, 100, default(Size), new Point(pointx - 10, pointy - 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
string url;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
using (var imgStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
img.Save(imgStream);
|
||||||
|
var byteContent = new ByteArrayContent(imgStream.ToArray());
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
|
||||||
|
var reponse = await http.PutAsync("https://transfer.sh/img.png", byteContent);
|
||||||
|
url = await reponse.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task RateGirl(IGuildUser usr)
|
||||||
|
{
|
||||||
|
var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl);
|
||||||
|
var img = await gr.Url;
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle("Girl Rating For " + usr)
|
||||||
|
.AddField(efb => efb.WithName("Hot").WithValue(gr.Hot.ToString("F2")).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("Crazy").WithValue(gr.Crazy.ToString("F2")).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("Advice").WithValue(gr.Advice).WithIsInline(false))
|
||||||
|
.WithImageUrl(img)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double NextDouble(double x, double y)
|
||||||
|
{
|
||||||
|
var rng = new Random();
|
||||||
|
return rng.NextDouble() * (y - x) + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GirlRating GetGirl(ulong uid)
|
||||||
|
{
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
var roll = rng.Next(1, 1001);
|
||||||
|
|
||||||
|
if ((uid == 185968432783687681 ||
|
||||||
|
uid == 265642040950390784) && roll >= 900)
|
||||||
|
roll = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
double hot;
|
||||||
|
double crazy;
|
||||||
|
string advice;
|
||||||
|
if (roll < 500)
|
||||||
|
{
|
||||||
|
hot = NextDouble(0, 5);
|
||||||
|
crazy = NextDouble(4, 10);
|
||||||
|
advice =
|
||||||
|
"This is your NO-GO ZONE. We do not hang around, and date, and marry women who are atleast, in our mind, a 5. " +
|
||||||
|
"So, this is your no-go zone. You don't go here. You just rule this out. Life is better this way, that's the way it is.";
|
||||||
|
}
|
||||||
|
else if (roll < 750)
|
||||||
|
{
|
||||||
|
hot = NextDouble(5, 8);
|
||||||
|
crazy = NextDouble(4, .6 * hot + 4);
|
||||||
|
advice = "Above a 5, and to about an 8, and below the crazy line - this is your FUN ZONE. You can " +
|
||||||
|
"hang around here, and meet these girls and spend time with them. Keep in mind, while you're " +
|
||||||
|
"in the fun zone, you want to move OUT of the fun zone to a more permanent location. " +
|
||||||
|
"These girls are most of the time not crazy.";
|
||||||
|
}
|
||||||
|
else if (roll < 900)
|
||||||
|
{
|
||||||
|
hot = NextDouble(5, 10);
|
||||||
|
crazy = NextDouble(.61 * hot + 4, 10);
|
||||||
|
advice = "Above the crazy line - it's the DANGER ZONE. This is redheads, strippers, anyone named Tiffany, " +
|
||||||
|
"hairdressers... This is where your car gets keyed, you get bunny in the pot, your tires get slashed, " +
|
||||||
|
"and you wind up in jail.";
|
||||||
|
}
|
||||||
|
else if (roll < 951)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(7, .6 * hot + 4);
|
||||||
|
advice = "Below the crazy line, above an 8 hot, but still about 7 crazy. This is your DATE ZONE. " +
|
||||||
|
"You can stay in the date zone indefinitely. These are the girls you introduce to your friends and your family. " +
|
||||||
|
"They're good looking, and they're reasonably not crazy most of the time. You can stay here indefinitely.";
|
||||||
|
}
|
||||||
|
else if (roll < 990)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(5, 7);
|
||||||
|
advice = "Above an 8 hot, and between about 7 and a 5 crazy - this is WIFE ZONE. You you meet this girl, you should consider long-term " +
|
||||||
|
"relationship. Rare.";
|
||||||
|
}
|
||||||
|
else if (roll < 999)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(2, 3.99d);
|
||||||
|
advice = "You've met a girl she's above 8 hot, and not crazy at all (below 4)... totally cool?" +
|
||||||
|
" You should be careful. That's a dude. It's a tranny.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(4, 5);
|
||||||
|
advice = "Below 5 crazy, and above 8 hot, this is the UNICORN ZONE, these things don't exist." +
|
||||||
|
"If you find a unicorn, please capture it safely, keep it alive, we'd like to study it, " +
|
||||||
|
"and maybe look at how to replicate that.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GirlRating(crazy, hot, roll, advice);
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Linux(string guhnoo, string loonix)
|
public async Task Linux(string guhnoo, string loonix)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ using System.Collections.Generic;
|
|||||||
namespace NadekoBot.Modules.Help
|
namespace NadekoBot.Modules.Help
|
||||||
{
|
{
|
||||||
[NadekoModule("Help", "-")]
|
[NadekoModule("Help", "-")]
|
||||||
public class Help : NadekoModule
|
public class Help : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static string helpString { get; } = NadekoBot.BotConfig.HelpString;
|
private static string helpString { get; } = NadekoBot.BotConfig.HelpString;
|
||||||
public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]);
|
public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]);
|
||||||
|
@ -77,10 +77,10 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
public IVoiceChannel PlaybackVoiceChannel { get; private set; }
|
public IVoiceChannel PlaybackVoiceChannel { get; private set; }
|
||||||
public ITextChannel OutputTextChannel { get; set; }
|
public ITextChannel OutputTextChannel { get; set; }
|
||||||
|
|
||||||
private bool destroyed { get; set; } = false;
|
private bool destroyed { get; set; }
|
||||||
public bool RepeatSong { get; private set; } = false;
|
public bool RepeatSong { get; private set; }
|
||||||
public bool RepeatPlaylist { get; private set; } = false;
|
public bool RepeatPlaylist { get; private set; }
|
||||||
public bool Autoplay { get; set; } = false;
|
public bool Autoplay { get; set; }
|
||||||
public uint MaxQueueSize { get; set; } = 0;
|
public uint MaxQueueSize { get; set; } = 0;
|
||||||
|
|
||||||
private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
|
private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
|
||||||
|
@ -5,12 +5,9 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using VideoLibrary;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Modules.Music.Classes
|
||||||
@ -32,22 +29,22 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
public string QueuerName { get; set; }
|
public string QueuerName { get; set; }
|
||||||
|
|
||||||
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
||||||
public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / (1000 / milliseconds));
|
public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));
|
||||||
|
|
||||||
const int milliseconds = 20;
|
private const int _milliseconds = 20;
|
||||||
const int samplesPerFrame = (48000 / 1000) * milliseconds;
|
private const int _samplesPerFrame = (48000 / 1000) * _milliseconds;
|
||||||
const int frameBytes = 3840; //16-bit, 2 channels
|
private const int _frameBytes = 3840; //16-bit, 2 channels
|
||||||
|
|
||||||
private ulong bytesSent { get; set; } = 0;
|
private ulong bytesSent { get; set; }
|
||||||
|
|
||||||
//pwetty
|
//pwetty
|
||||||
|
|
||||||
public string PrettyProvider =>
|
public string PrettyProvider =>
|
||||||
$"{(SongInfo.Provider ?? "No Provider")}";
|
$"{(SongInfo.Provider ?? "???")}";
|
||||||
|
|
||||||
public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime;
|
public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime;
|
||||||
|
|
||||||
public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({songUrl})**";
|
public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({SongUrl})**";
|
||||||
|
|
||||||
public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}";
|
public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}";
|
||||||
|
|
||||||
@ -65,22 +62,19 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string PrettyTotalTime {
|
public string PrettyTotalTime {
|
||||||
get {
|
get
|
||||||
|
{
|
||||||
if (TotalTime == TimeSpan.Zero)
|
if (TotalTime == TimeSpan.Zero)
|
||||||
return "(?)";
|
return "(?)";
|
||||||
else if (TotalTime == TimeSpan.MaxValue)
|
if (TotalTime == TimeSpan.MaxValue)
|
||||||
return "∞";
|
return "∞";
|
||||||
else
|
var time = TotalTime.ToString(@"mm\:ss");
|
||||||
{
|
var hrs = (int)TotalTime.TotalHours;
|
||||||
var time = TotalTime.ToString(@"mm\:ss");
|
|
||||||
var hrs = (int)TotalTime.TotalHours;
|
|
||||||
|
|
||||||
if (hrs > 0)
|
if (hrs > 0)
|
||||||
return hrs + ":" + time;
|
return hrs + ":" + time;
|
||||||
else
|
return time;
|
||||||
return time;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,13 +83,13 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
switch (SongInfo.ProviderType)
|
switch (SongInfo.ProviderType)
|
||||||
{
|
{
|
||||||
case MusicType.Radio:
|
case MusicType.Radio:
|
||||||
return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
|
return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
|
||||||
case MusicType.Normal:
|
case MusicType.Normal:
|
||||||
//todo have videoid in songinfo from the start
|
//todo have videoid in songinfo from the start
|
||||||
var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
|
var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
|
||||||
return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
|
return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
|
||||||
case MusicType.Local:
|
case MusicType.Local:
|
||||||
return $"https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links
|
return "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links
|
||||||
case MusicType.Soundcloud:
|
case MusicType.Soundcloud:
|
||||||
return SongInfo.AlbumArt;
|
return SongInfo.AlbumArt;
|
||||||
default:
|
default:
|
||||||
@ -104,7 +98,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string songUrl {
|
public string SongUrl {
|
||||||
get {
|
get {
|
||||||
switch (SongInfo.ProviderType)
|
switch (SongInfo.ProviderType)
|
||||||
{
|
{
|
||||||
@ -122,36 +116,32 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int skipTo = 0;
|
public int SkipTo { get; set; }
|
||||||
public int SkipTo {
|
|
||||||
get { return skipTo; }
|
|
||||||
set {
|
|
||||||
skipTo = value;
|
|
||||||
bytesSent = (ulong)skipTo * 3840 * 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public Song(SongInfo songInfo)
|
public Song(SongInfo songInfo)
|
||||||
{
|
{
|
||||||
this.SongInfo = songInfo;
|
SongInfo = songInfo;
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Song Clone()
|
public Song Clone()
|
||||||
{
|
{
|
||||||
var s = new Song(SongInfo);
|
var s = new Song(SongInfo)
|
||||||
s.MusicPlayer = MusicPlayer;
|
{
|
||||||
s.QueuerName = QueuerName;
|
MusicPlayer = MusicPlayer,
|
||||||
|
QueuerName = QueuerName
|
||||||
|
};
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
bytesSent = (ulong) SkipTo * 3840 * 50;
|
||||||
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
||||||
|
|
||||||
SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo, frameBytes * 100);
|
var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
|
||||||
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -200,22 +190,22 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
var outStream = voiceClient.CreatePCMStream(960);
|
var outStream = voiceClient.CreatePCMStream(960);
|
||||||
|
|
||||||
int nextTime = Environment.TickCount + milliseconds;
|
int nextTime = Environment.TickCount + _milliseconds;
|
||||||
|
|
||||||
byte[] buffer = new byte[frameBytes];
|
byte[] buffer = new byte[_frameBytes];
|
||||||
while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason
|
while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason
|
||||||
!(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime
|
!(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
|
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
|
||||||
var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||||
//await inStream.CopyToAsync(voiceClient.OutputStream);
|
//await inStream.CopyToAsync(voiceClient.OutputStream);
|
||||||
if (read < frameBytes)
|
if (read < _frameBytes)
|
||||||
_log.Debug("read {0}", read);
|
_log.Debug("read {0}", read);
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
bytesSent += (ulong)read;
|
bytesSent += (ulong)read;
|
||||||
}
|
}
|
||||||
if (read < frameBytes)
|
if (read < _frameBytes)
|
||||||
{
|
{
|
||||||
if (read == 0)
|
if (read == 0)
|
||||||
{
|
{
|
||||||
@ -231,12 +221,12 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
_log.Warn("Slow connection has disrupted music, waiting a bit for buffer");
|
_log.Warn("Slow connection has disrupted music, waiting a bit for buffer");
|
||||||
|
|
||||||
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
|
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Task.Delay(100, cancelToken).ConfigureAwait(false);
|
await Task.Delay(100, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -245,16 +235,16 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
else
|
else
|
||||||
attempt = 0;
|
attempt = 0;
|
||||||
|
|
||||||
while (this.MusicPlayer.Paused)
|
while (MusicPlayer.Paused)
|
||||||
{
|
{
|
||||||
await Task.Delay(200, cancelToken).ConfigureAwait(false);
|
await Task.Delay(200, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
|
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
|
||||||
if (read != frameBytes) continue;
|
if (read != _frameBytes) continue;
|
||||||
nextTime = unchecked(nextTime + milliseconds);
|
nextTime = unchecked(nextTime + _milliseconds);
|
||||||
int delayMillis = unchecked(nextTime - Environment.TickCount);
|
int delayMillis = unchecked(nextTime - Environment.TickCount);
|
||||||
if (delayMillis > 0)
|
if (delayMillis > 0)
|
||||||
await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false);
|
await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false);
|
||||||
@ -264,8 +254,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await bufferTask;
|
await bufferTask;
|
||||||
if (inStream != null)
|
inStream.Dispose();
|
||||||
inStream.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,25 +268,20 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
//aidiakapi ftw
|
//aidiakapi ftw
|
||||||
public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume)
|
public static unsafe byte[] AdjustVolume(byte[] audioSamples, float volume)
|
||||||
{
|
{
|
||||||
Contract.Requires(audioSamples != null);
|
|
||||||
Contract.Requires(audioSamples.Length % 2 == 0);
|
|
||||||
Contract.Requires(volume >= 0f && volume <= 1f);
|
|
||||||
Contract.Assert(BitConverter.IsLittleEndian);
|
|
||||||
|
|
||||||
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
|
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
|
||||||
|
|
||||||
// 16-bit precision for the multiplication
|
// 16-bit precision for the multiplication
|
||||||
int volumeFixed = (int)Math.Round(volume * 65536d);
|
var volumeFixed = (int)Math.Round(volume * 65536d);
|
||||||
|
|
||||||
int count = audioSamples.Length / 2;
|
var count = audioSamples.Length / 2;
|
||||||
|
|
||||||
fixed (byte* srcBytes = audioSamples)
|
fixed (byte* srcBytes = audioSamples)
|
||||||
{
|
{
|
||||||
short* src = (short*)srcBytes;
|
var src = (short*)srcBytes;
|
||||||
|
|
||||||
for (int i = count; i != 0; i--, src++)
|
for (var i = count; i != 0; i--, src++)
|
||||||
*src = (short)(((*src) * volumeFixed) >> 16);
|
*src = (short)(((*src) * volumeFixed) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,14 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
using VideoLibrary;
|
using VideoLibrary;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Modules.Music.Classes
|
||||||
{
|
{
|
||||||
public static class SongHandler
|
public static class SongHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
|
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
@ -106,7 +108,8 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed resolving the link.{ex.Message}");
|
_log.Warn($"Failed resolving the link.{ex.Message}");
|
||||||
|
_log.Warn(ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +140,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .pls:\n{file}");
|
_log.Warn($"Failed reading .pls:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +159,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .m3u:\n{file}");
|
_log.Warn($"Failed reading .m3u:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .asx:\n{file}");
|
_log.Warn($"Failed reading .asx:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +195,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .xspf:\n{file}");
|
_log.Warn($"Failed reading .xspf:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,13 @@ using System.Net.Http;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music
|
namespace NadekoBot.Modules.Music
|
||||||
{
|
{
|
||||||
[NadekoModule("Music", "!!")]
|
[NadekoModule("Music", "!!")]
|
||||||
[DontAutoLoad]
|
[DontAutoLoad]
|
||||||
public partial class Music : NadekoModule
|
public class Music : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
||||||
|
|
||||||
@ -78,7 +77,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +155,14 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
var val = musicPlayer.FairPlay = !musicPlayer.FairPlay;
|
var val = musicPlayer.FairPlay = !musicPlayer.FairPlay;
|
||||||
|
|
||||||
await channel.SendConfirmAsync("Fair play " + (val ? "enabled" : "disabled") + ".").ConfigureAwait(false);
|
if (val)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("fp_enabled").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("fp_disabled").ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -182,57 +191,56 @@ namespace NadekoBot.Modules.Music
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ListQueue(int page = 1)
|
public async Task ListQueue(int page = 1)
|
||||||
{
|
{
|
||||||
|
Song currentSong;
|
||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer) ||
|
||||||
|
(currentSong = musicPlayer?.CurrentSong) == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_player").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (page <= 0)
|
if (page <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var currentSong = musicPlayer.CurrentSong;
|
|
||||||
if (currentSong == null)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
const int itemsPerPage = 10;
|
const int itemsPerPage = 10;
|
||||||
|
|
||||||
var total = musicPlayer.TotalPlaytime;
|
var total = musicPlayer.TotalPlaytime;
|
||||||
var totalStr = total == TimeSpan.MaxValue ? "∞" : $"{(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s";
|
var totalStr = total == TimeSpan.MaxValue ? "∞" : GetText("time_format",
|
||||||
|
(int) total.TotalHours,
|
||||||
|
total.Minutes,
|
||||||
|
total.Seconds);
|
||||||
var maxPlaytime = musicPlayer.MaxPlaytimeSeconds;
|
var maxPlaytime = musicPlayer.MaxPlaytimeSeconds;
|
||||||
var lastPage = musicPlayer.Playlist.Count / itemsPerPage;
|
var lastPage = musicPlayer.Playlist.Count / itemsPerPage;
|
||||||
Func<int, EmbedBuilder> printAction = (curPage) =>
|
Func<int, EmbedBuilder> printAction = curPage =>
|
||||||
{
|
{
|
||||||
int startAt = itemsPerPage * (curPage - 1);
|
var startAt = itemsPerPage * (curPage - 1);
|
||||||
var number = 0 + startAt;
|
var number = 0 + startAt;
|
||||||
var desc = string.Join("\n", musicPlayer.Playlist
|
var desc = string.Join("\n", musicPlayer.Playlist
|
||||||
.Skip(startAt)
|
.Skip(startAt)
|
||||||
.Take(itemsPerPage)
|
.Take(itemsPerPage)
|
||||||
.Select(v => $"`{++number}.` {v.PrettyFullName}"));
|
.Select(v => $"`{++number}.` {v.PrettyFullName}"));
|
||||||
|
|
||||||
if (currentSong != null)
|
desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc;
|
||||||
desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc;
|
|
||||||
|
|
||||||
if (musicPlayer.RepeatSong)
|
if (musicPlayer.RepeatSong)
|
||||||
desc = "🔂 Repeating Current Song\n\n" + desc;
|
desc = "🔂 " + GetText("repeating_cur_song") +"\n\n" + desc;
|
||||||
else if (musicPlayer.RepeatPlaylist)
|
else if (musicPlayer.RepeatPlaylist)
|
||||||
desc = "🔁 Repeating Playlist\n\n" + desc;
|
desc = "🔁 " + GetText("repeating_playlist")+"\n\n" + desc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}")
|
.WithAuthor(eab => eab.WithName(GetText("player_queue", curPage, lastPage + 1))
|
||||||
.WithMusicIcon())
|
.WithMusicIcon())
|
||||||
.WithDescription(desc)
|
.WithDescription(desc)
|
||||||
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
||||||
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " +
|
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " +
|
||||||
(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit")))
|
(musicPlayer.FairPlay
|
||||||
|
? "✔️" + GetText("fairplay")
|
||||||
|
: "✖️" + GetText("fairplay")) + " | " +
|
||||||
|
(maxPlaytime == 0 ? "unlimited" : GetText("play_limit", maxPlaytime))))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
@ -253,7 +261,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Now Playing").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("now_playing")).WithMusicIcon())
|
||||||
.WithDescription(currentSong.PrettyName)
|
.WithDescription(currentSong.PrettyName)
|
||||||
.WithThumbnailUrl(currentSong.Thumbnail)
|
.WithThumbnailUrl(currentSong.Thumbnail)
|
||||||
.WithFooter(ef => ef.WithText(musicPlayer.PrettyVolume + " | " + currentSong.PrettyFullTime + $" | {currentSong.PrettyProvider} | {currentSong.QueuerName}"));
|
.WithFooter(ef => ef.WithText(musicPlayer.PrettyVolume + " | " + currentSong.PrettyFullTime + $" | {currentSong.PrettyProvider} | {currentSong.QueuerName}"));
|
||||||
@ -270,21 +278,22 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||||
return;
|
return;
|
||||||
if (val < 0)
|
if (val < 0 || val > 100)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
var volume = musicPlayer.SetVolume(val);
|
var volume = musicPlayer.SetVolume(val);
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Volume set to {volume}%").ConfigureAwait(false);
|
await ReplyConfirmLocalized("volume_set", volume).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Defvol([Remainder] int val)
|
public async Task Defvol([Remainder] int val)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if (val < 0 || val > 100)
|
if (val < 0 || val > 100)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Volume number invalid. Must be between 0 and 100").ConfigureAwait(false);
|
await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
@ -292,7 +301,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f;
|
uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f;
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Default volume set to {val}%").ConfigureAwait(false);
|
await ReplyConfirmLocalized("defvol_set", val).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -306,13 +315,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||||
return;
|
return;
|
||||||
if (musicPlayer.Playlist.Count < 2)
|
if (musicPlayer.Playlist.Count < 2)
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayer.Shuffle();
|
musicPlayer.Shuffle();
|
||||||
await Context.Channel.SendConfirmAsync("🎵 Songs shuffled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("songs_shuffled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -325,29 +331,31 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
|
var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
|
||||||
if (plId == null)
|
if (plId == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No search results for that query.");
|
await ReplyErrorLocalized("no_search_results").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var ids = await NadekoBot.Google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false);
|
var ids = await NadekoBot.Google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false);
|
||||||
if (!ids.Any())
|
if (!ids.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"🎵 Failed to find any songs.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_search_results").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var count = ids.Count();
|
var count = ids.Count();
|
||||||
|
|
||||||
var msg = await Context.Channel.SendMessageAsync($"🎵 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false);
|
var msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue",
|
||||||
|
Format.Bold(count.ToString())))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var cancelSource = new CancellationTokenSource();
|
var cancelSource = new CancellationTokenSource();
|
||||||
|
|
||||||
var gusr = (IGuildUser)Context.User;
|
var gusr = (IGuildUser)Context.User;
|
||||||
|
//todo use grouping
|
||||||
while (ids.Any() && !cancelSource.IsCancellationRequested)
|
while (ids.Any() && !cancelSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var tasks = Task.WhenAll(ids.Take(5).Select(async id =>
|
var tasks = Task.WhenAll(ids.Take(5).Select(async id =>
|
||||||
@ -366,7 +374,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
ids = ids.Skip(5);
|
ids = ids.Skip(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
await msg.ModifyAsync(m => m.Content = "✅ Playlist queue complete.").ConfigureAwait(false);
|
await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -392,7 +400,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mp.AddSong(new Song(new Classes.SongInfo
|
mp.AddSong(new Song(new SongInfo
|
||||||
{
|
{
|
||||||
Title = svideo.FullName,
|
Title = svideo.FullName,
|
||||||
Provider = "SoundCloud",
|
Provider = "SoundCloud",
|
||||||
@ -434,20 +442,20 @@ namespace NadekoBot.Modules.Music
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("dir_queue_complete").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Radio(string radio_link)
|
public async Task Radio(string radioLink)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining it.").ConfigureAwait(false);
|
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false);
|
await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radioLink, musicType: MusicType.Radio).ConfigureAwait(false);
|
||||||
if ((await Context.Guild.GetCurrentUserAsync()).GetPermissions((IGuildChannel)Context.Channel).ManageMessages)
|
if ((await Context.Guild.GetCurrentUserAsync()).GetPermissions((IGuildChannel)Context.Channel).ManageMessages)
|
||||||
{
|
{
|
||||||
Context.Message.DeleteAfter(10);
|
Context.Message.DeleteAfter(10);
|
||||||
@ -504,20 +512,20 @@ namespace NadekoBot.Modules.Music
|
|||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return;
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return;
|
||||||
musicPlayer.ClearQueue();
|
musicPlayer.ClearQueue();
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Queue cleared!").ConfigureAwait(false);
|
await ReplyConfirmLocalized("queue_cleared").ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task MoveSong([Remainder] string fromto)
|
public async Task MoveSong([Remainder] string fromto)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(fromto))
|
||||||
|
return;
|
||||||
|
|
||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
fromto = fromto?.Trim();
|
fromto = fromto?.Trim();
|
||||||
var fromtoArr = fromto.Split('>');
|
var fromtoArr = fromto.Split('>');
|
||||||
|
|
||||||
@ -530,7 +538,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
|
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
|
||||||
n1 > playlist.Count || n2 > playlist.Count)
|
n1 > playlist.Count || n2 > playlist.Count)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Invalid input.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invalid_input").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,10 +549,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
|
.WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
|
||||||
.WithUrl($"{s.SongInfo.Query}")
|
.WithUrl(s.SongUrl)
|
||||||
.WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
|
.WithAuthor(eab => eab.WithName(GetText("song_moved")).WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
|
||||||
.AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("from_position")).WithValue($"#{n1}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("to_position")).WithValue($"#{n2}").WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -562,7 +570,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
musicPlayer.MaxQueueSize = size;
|
musicPlayer.MaxQueueSize = size;
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}.");
|
|
||||||
|
if(size == 0)
|
||||||
|
await ReplyConfirmLocalized("max_queue_unlimited").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("max_queue_x", size).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -578,9 +590,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
musicPlayer.MaxPlaytimeSeconds = seconds;
|
musicPlayer.MaxPlaytimeSeconds = seconds;
|
||||||
if (seconds == 0)
|
if (seconds == 0)
|
||||||
await channel.SendConfirmAsync($"🎵 Max playtime has no limit now.");
|
await ReplyConfirmLocalized("max_playtime_none").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await channel.SendConfirmAsync($"🎵 Max playtime set to {seconds} seconds.");
|
await ReplyConfirmLocalized("max_playtime_set", seconds).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -599,11 +611,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (currentValue)
|
if (currentValue)
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 Repeating track"))
|
.WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 " + GetText("repeating_track")))
|
||||||
.WithDescription(currentSong.PrettyName)
|
.WithDescription(currentSong.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(currentSong.PrettyInfo))).ConfigureAwait(false);
|
.WithFooter(ef => ef.WithText(currentSong.PrettyInfo))).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync($"🔂 Current track repeat stopped.")
|
await Context.Channel.SendConfirmAsync("🔂 " + GetText("repeating_track_stopped"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +628,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
return;
|
return;
|
||||||
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
||||||
await Context.Channel.SendConfirmAsync($"🔁 Repeat playlist {(currentValue ? "**enabled**." : "**disabled**.")}").ConfigureAwait(false);
|
if(currentValue)
|
||||||
|
await ReplyConfirmLocalized("rpl_enabled").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("rpl_disabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -653,7 +668,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(($"🎵 Saved playlist as **{name}**, ID: {playlist.Id}.")).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("playlist_saved"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("name")).WithValue(name))
|
||||||
|
.AddField(efb => efb.WithName(GetText("id")).WithValue(playlist.Id.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -668,11 +686,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
|
|
||||||
if (mpl == null)
|
if (mpl == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Can't find playlist with that ID.").ConfigureAwait(false);
|
await ReplyErrorLocalized("playlist_id_not_found").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IUserMessage msg = null;
|
IUserMessage msg = null;
|
||||||
try { msg = await Context.Channel.SendMessageAsync($"🎶 Attempting to load **{mpl.Songs.Count}** songs...").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue", Format.Bold(mpl.Songs.Count.ToString()))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
foreach (var item in mpl.Songs)
|
foreach (var item in mpl.Songs)
|
||||||
{
|
{
|
||||||
var usr = (IGuildUser)Context.User;
|
var usr = (IGuildUser)Context.User;
|
||||||
@ -684,15 +702,13 @@ namespace NadekoBot.Modules.Music
|
|||||||
catch { break; }
|
catch { break; }
|
||||||
}
|
}
|
||||||
if (msg != null)
|
if (msg != null)
|
||||||
await msg.ModifyAsync(m => m.Content = $"✅ Done loading playlist **{mpl.Name}**.").ConfigureAwait(false);
|
await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Playlists([Remainder] int num = 1)
|
public async Task Playlists([Remainder] int num = 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if (num <= 0)
|
if (num <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -704,8 +720,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("playlists_page", num)).WithMusicIcon())
|
||||||
.WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by *{r.Author}* ({r.Songs.Count} songs)")))
|
.WithDescription(string.Join("\n", playlists.Select(r =>
|
||||||
|
GetText("playlists", "#" + r.Id, r.Name, r.Author, r.Songs.Count))))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -715,13 +732,12 @@ namespace NadekoBot.Modules.Music
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task DeletePlaylist([Remainder] int id)
|
public async Task DeletePlaylist([Remainder] int id)
|
||||||
{
|
{
|
||||||
bool success = false;
|
var success = false;
|
||||||
MusicPlaylist pl = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
pl = uow.MusicPlaylists.Get(id);
|
var pl = uow.MusicPlaylists.Get(id);
|
||||||
|
|
||||||
if (pl != null)
|
if (pl != null)
|
||||||
{
|
{
|
||||||
@ -731,15 +747,13 @@ namespace NadekoBot.Modules.Music
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
success = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
await Context.Channel.SendErrorAsync("Failed to delete that playlist. It either doesn't exist, or you are not its author.").ConfigureAwait(false);
|
await ReplyErrorLocalized("playlist_delete_fail").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("🗑 Playlist successfully **deleted**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("playlist_deleted").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -779,7 +793,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (seconds.Length == 1)
|
if (seconds.Length == 1)
|
||||||
seconds = "0" + seconds;
|
seconds = "0" + seconds;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"Skipped to `{minutes}:{seconds}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("skipped_to", minutes, seconds).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -791,9 +805,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!musicPlayer.ToggleAutoplay())
|
if (!musicPlayer.ToggleAutoplay())
|
||||||
await Context.Channel.SendConfirmAsync("❌ Autoplay disabled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autoplay_disabled").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autoplay_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -804,29 +818,29 @@ namespace NadekoBot.Modules.Music
|
|||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_player").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel;
|
musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("set_music_channel").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
public async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||||
{
|
{
|
||||||
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
||||||
{
|
{
|
||||||
if (!silent)
|
if (!silent)
|
||||||
await textCh.SendErrorAsync($"💢 You need to be in a voice channel on this server.").ConfigureAwait(false);
|
await textCh.SendErrorAsync(GetText("must_be_in_voice")).ConfigureAwait(false);
|
||||||
throw new ArgumentNullException(nameof(voiceCh));
|
throw new ArgumentNullException(nameof(voiceCh));
|
||||||
}
|
}
|
||||||
if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
|
if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
|
||||||
throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
|
throw new ArgumentException("Invalid song query.", nameof(query));
|
||||||
|
|
||||||
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server =>
|
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server =>
|
||||||
{
|
{
|
||||||
float vol = 1;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
float vol;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
|
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
|
||||||
@ -843,7 +857,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("finished_song")).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -861,17 +875,23 @@ namespace NadekoBot.Modules.Music
|
|||||||
textCh,
|
textCh,
|
||||||
voiceCh,
|
voiceCh,
|
||||||
relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)],
|
relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)],
|
||||||
true,
|
true).ConfigureAwait(false);
|
||||||
musicType).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mp.OnStarted += async (player, song) =>
|
mp.OnStarted += async (player, song) =>
|
||||||
{
|
{
|
||||||
try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); }
|
||||||
var sender = player as MusicPlayer;
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
var sender = player;
|
||||||
if (sender == null)
|
if (sender == null)
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
@ -879,12 +899,15 @@ namespace NadekoBot.Modules.Music
|
|||||||
playingMessage?.DeleteAfter(0);
|
playingMessage?.DeleteAfter(0);
|
||||||
|
|
||||||
playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("playing_song")).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
mp.OnPauseChanged += async (paused) =>
|
mp.OnPauseChanged += async (paused) =>
|
||||||
{
|
{
|
||||||
@ -892,13 +915,16 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
IUserMessage msg;
|
IUserMessage msg;
|
||||||
if (paused)
|
if (paused)
|
||||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("paused")).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("resumed")).ConfigureAwait(false);
|
||||||
|
|
||||||
msg?.DeleteAfter(10);
|
msg?.DeleteAfter(10);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mp.SongRemoved += async (song, index) =>
|
mp.SongRemoved += async (song, index) =>
|
||||||
@ -906,7 +932,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName("Removed song #" + (index + 1)).WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("removed_song") + " #" + (index + 1)).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
||||||
.WithErrorColor();
|
.WithErrorColor();
|
||||||
@ -914,7 +940,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return mp;
|
return mp;
|
||||||
});
|
});
|
||||||
@ -931,7 +960,14 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
catch (PlaylistFullException)
|
catch (PlaylistFullException)
|
||||||
{
|
{
|
||||||
try { await textCh.SendConfirmAsync($"🎵 Queue is full at **{musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}**."); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await textCh.SendConfirmAsync(GetText("queue_full", musicPlayer.MaxQueueSize));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
if (!silent)
|
if (!silent)
|
||||||
@ -940,15 +976,17 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
//var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
|
//var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
|
||||||
var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Queued Song #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("queued_song") + " #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon())
|
||||||
.WithDescription($"{resolvedSong.PrettyName}\nQueue ")
|
.WithDescription($"{resolvedSong.PrettyName}\n{GetText("queue")} ")
|
||||||
.WithThumbnailUrl(resolvedSong.Thumbnail)
|
.WithThumbnailUrl(resolvedSong.Thumbnail)
|
||||||
.WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider)))
|
.WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (queuedMessage != null)
|
queuedMessage?.DeleteAfter(10);
|
||||||
queuedMessage.DeleteAfter(10);
|
|
||||||
}
|
}
|
||||||
catch { } // if queued message sending fails, don't attempt to delete it
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
} // if queued message sending fails, don't attempt to delete it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -17,11 +15,11 @@ using System.Collections.Concurrent;
|
|||||||
namespace NadekoBot.Modules.NSFW
|
namespace NadekoBot.Modules.NSFW
|
||||||
{
|
{
|
||||||
[NadekoModule("NSFW", "~")]
|
[NadekoModule("NSFW", "~")]
|
||||||
public class NSFW : NadekoModule
|
public class NSFW : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> AutoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private static readonly ConcurrentHashSet<ulong> HentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||||
{
|
{
|
||||||
@ -72,7 +70,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
if (interval == 0)
|
if (interval == 0)
|
||||||
{
|
{
|
||||||
if (!AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||||
|
|
||||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||||
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
||||||
@ -99,7 +97,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
}, null, interval * 1000, interval * 1000);
|
}, null, interval * 1000, interval * 1000);
|
||||||
|
|
||||||
AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
_autoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
||||||
{
|
{
|
||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
return t;
|
return t;
|
||||||
@ -114,7 +112,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task HentaiBomb([Remainder] string tag = null)
|
public async Task HentaiBomb([Remainder] string tag = null)
|
||||||
{
|
{
|
||||||
if (!HentaiBombBlacklist.Add(Context.User.Id))
|
if (!_hentaiBombBlacklist.Add(Context.User.Id))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -138,17 +136,17 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
HentaiBombBlacklist.TryRemove(Context.User.Id);
|
_hentaiBombBlacklist.TryRemove(Context.User.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Yandere([Remainder] string tag = null)
|
public Task Yandere([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere);
|
=> InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Konachan([Remainder] string tag = null)
|
public Task Konachan([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan);
|
=> InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task E621([Remainder] string tag = null)
|
public async Task E621([Remainder] string tag = null)
|
||||||
@ -169,7 +167,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Rule34([Remainder] string tag = null)
|
public Task Rule34([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34);
|
=> InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Danbooru([Remainder] string tag = null)
|
public async Task Danbooru([Remainder] string tag = null)
|
||||||
@ -212,7 +210,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Gelbooru([Remainder] string tag = null)
|
public Task Gelbooru([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru);
|
=> InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Cp()
|
public async Task Cp()
|
||||||
@ -289,5 +287,22 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
public static Task<string> GetGelbooruImageLink(string tag) =>
|
public static Task<string> GetGelbooruImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
|
public async Task InternalDapiCommand(IUserMessage umsg, string tag, Searches.Searches.DapiSearchType type)
|
||||||
|
{
|
||||||
|
var channel = umsg.Channel;
|
||||||
|
|
||||||
|
tag = tag?.Trim() ?? "";
|
||||||
|
|
||||||
|
var url = await Searches.Searches.InternalDapiSearch(tag, type).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (url == null)
|
||||||
|
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
||||||
|
else
|
||||||
|
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithDescription(umsg.Author.Mention + " " + tag)
|
||||||
|
.WithImageUrl(url)
|
||||||
|
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules
|
namespace NadekoBot.Modules
|
||||||
{
|
{
|
||||||
public abstract class NadekoModule : ModuleBase
|
public abstract class NadekoTopLevelModule : ModuleBase
|
||||||
{
|
{
|
||||||
protected readonly Logger _log;
|
protected readonly Logger _log;
|
||||||
protected CultureInfo _cultureInfo;
|
protected CultureInfo _cultureInfo;
|
||||||
@ -17,7 +17,7 @@ namespace NadekoBot.Modules
|
|||||||
public readonly string ModuleTypeName;
|
public readonly string ModuleTypeName;
|
||||||
public readonly string LowerModuleTypeName;
|
public readonly string LowerModuleTypeName;
|
||||||
|
|
||||||
protected NadekoModule(bool isTopLevelModule = true)
|
protected NadekoTopLevelModule(bool isTopLevelModule = true)
|
||||||
{
|
{
|
||||||
//if it's top level module
|
//if it's top level module
|
||||||
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
||||||
@ -69,7 +69,7 @@ namespace NadekoBot.Modules
|
|||||||
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
||||||
text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
return "I cant tell if you command is executed, because there was an error printing out the response. Key '" +
|
return "I can't tell you is the command executed, because there was an error printing out the response. Key '" +
|
||||||
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
@ -120,7 +120,7 @@ namespace NadekoBot.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class NadekoSubmodule : NadekoModule
|
public abstract class NadekoSubmodule : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
protected NadekoSubmodule() : base(false)
|
protected NadekoSubmodule() : base(false)
|
||||||
{
|
{
|
||||||
|
@ -21,11 +21,11 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class BlacklistCommands : ModuleBase
|
public class BlacklistCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; }
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; }
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; }
|
||||||
|
|
||||||
static BlacklistCommands()
|
static BlacklistCommands()
|
||||||
{
|
{
|
||||||
@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BlacklistType.Channel:
|
case BlacklistType.Channel:
|
||||||
var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.channel.Id == id);
|
var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.Channel.Id == id);
|
||||||
Games.Games.TriviaCommands.RunningTrivias.TryRemove(item.Key, out tg);
|
Games.Games.TriviaCommands.RunningTrivias.TryRemove(item.Key, out tg);
|
||||||
if (tg != null)
|
if (tg != null)
|
||||||
{
|
{
|
||||||
@ -124,16 +124,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
break;
|
break;
|
||||||
case BlacklistType.User:
|
case BlacklistType.User:
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(action == AddRemove.Add)
|
if(action == AddRemove.Add)
|
||||||
await Context.Channel.SendConfirmAsync($"Blacklisted a `{type}` with id `{id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("blacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync($"Unblacklisted a `{type}` with id `{id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("unblacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,15 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class CmdCdsCommands : ModuleBase
|
public class CmdCdsCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> commandCooldowns { get; }
|
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns { get; }
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> activeCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
|
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> activeCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
|
||||||
|
|
||||||
static CmdCdsCommands()
|
static CmdCdsCommands()
|
||||||
{
|
{
|
||||||
var configs = NadekoBot.AllGuildConfigs;
|
var configs = NadekoBot.AllGuildConfigs;
|
||||||
commandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
|
CommandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
|
||||||
}
|
}
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -38,14 +38,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
if (secs < 0 || secs > 3600)
|
if (secs < 0 || secs > 3600)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Invalid second parameter. (Must be a number between 0 and 3600)").ConfigureAwait(false);
|
await ReplyErrorLocalized("invalid_second_param_between", 0, 3600).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
|
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
|
||||||
var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
|
|
||||||
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||||
localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||||
@ -65,13 +65,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
||||||
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
||||||
await channel.SendConfirmAsync($"🚮 Command **{command.Aliases.First()}** has no coooldown now and all existing cooldowns have been cleared.")
|
await ReplyConfirmLocalized("cmdcd_cleared",
|
||||||
.ConfigureAwait(false);
|
Format.Bold(command.Aliases.First())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync($"✅ Command **{command.Aliases.First()}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.")
|
await ReplyConfirmLocalized("cmdcd_add",
|
||||||
.ConfigureAwait(false);
|
Format.Bold(command.Aliases.First()),
|
||||||
|
Format.Bold(secs.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +81,19 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public async Task AllCmdCooldowns()
|
public async Task AllCmdCooldowns()
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
|
|
||||||
if (!localSet.Any())
|
if (!localSet.Any())
|
||||||
await channel.SendConfirmAsync("ℹ️ `No command cooldowns set.`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cmdcd_none").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + " secs"), s => $"{s,-30}", 2).ConfigureAwait(false);
|
await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + GetText("sec")), s => $"{s,-30}", 2).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user)
|
public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user)
|
||||||
{
|
{
|
||||||
if (guild == null)
|
if (guild == null)
|
||||||
return false;
|
return false;
|
||||||
var cmdcds = CmdCdsCommands.commandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var cmdcds = CmdCdsCommands.CommandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
CommandCooldown cdRule;
|
CommandCooldown cdRule;
|
||||||
if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null)
|
if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public partial class Permissions
|
public partial class Permissions
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CommandCostCommands : ModuleBase
|
public class CommandCostCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, int> _commandCosts = new ConcurrentDictionary<string, int>();
|
private static readonly ConcurrentDictionary<string, int> _commandCosts = new ConcurrentDictionary<string, int>();
|
||||||
public static IReadOnlyDictionary<string, int> CommandCosts => _commandCosts;
|
public static IReadOnlyDictionary<string, int> CommandCosts => _commandCosts;
|
||||||
@ -29,29 +29,29 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
// x => x.Cost));
|
// x => x.Cost));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task CmdCosts(int page = 1)
|
//public async Task CmdCosts(int page = 1)
|
||||||
{
|
//{
|
||||||
var prices = _commandCosts.ToList();
|
// var prices = _commandCosts.ToList();
|
||||||
|
|
||||||
if (!prices.Any())
|
// if (!prices.Any())
|
||||||
{
|
// {
|
||||||
await Context.Channel.SendConfirmAsync("No costs set.").ConfigureAwait(false);
|
// await Context.Channel.SendConfirmAsync(GetText("no_costs")).ConfigureAwait(false);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => {
|
// await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => {
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
// var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Command Costs");
|
// .WithTitle(GetText("command_costs"));
|
||||||
var current = prices.Skip((curPage - 1) * 9)
|
// var current = prices.Skip((curPage - 1) * 9)
|
||||||
.Take(9);
|
// .Take(9);
|
||||||
foreach (var price in current)
|
// foreach (var price in current)
|
||||||
{
|
// {
|
||||||
embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true));
|
// embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true));
|
||||||
}
|
// }
|
||||||
return embed;
|
// return embed;
|
||||||
}, prices.Count / 9).ConfigureAwait(false);
|
// }, prices.Count / 9).ConfigureAwait(false);
|
||||||
}
|
//}
|
||||||
|
|
||||||
//[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
//public async Task CommandCost(int cost, CommandInfo cmd)
|
//public async Task CommandCost(int cost, CommandInfo cmd)
|
||||||
|
@ -13,13 +13,13 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public partial class Permissions
|
public partial class Permissions
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class FilterCommands : ModuleBase
|
public class FilterCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentHashSet<ulong> InviteFilteringChannels { get; }
|
public static ConcurrentHashSet<ulong> InviteFilteringChannels { get; }
|
||||||
public static ConcurrentHashSet<ulong> InviteFilteringServers { get; }
|
public static ConcurrentHashSet<ulong> InviteFilteringServers { get; }
|
||||||
|
|
||||||
//serverid, filteredwords
|
//serverid, filteredwords
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<string>> ServerFilteredWords { get; }
|
private static ConcurrentDictionary<ulong, ConcurrentHashSet<string>> serverFilteredWords { get; }
|
||||||
|
|
||||||
public static ConcurrentHashSet<ulong> WordFilteringChannels { get; }
|
public static ConcurrentHashSet<ulong> WordFilteringChannels { get; }
|
||||||
public static ConcurrentHashSet<ulong> WordFilteringServers { get; }
|
public static ConcurrentHashSet<ulong> WordFilteringServers { get; }
|
||||||
@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
ConcurrentHashSet<string> words = new ConcurrentHashSet<string>();
|
ConcurrentHashSet<string> words = new ConcurrentHashSet<string>();
|
||||||
if(WordFilteringChannels.Contains(channelId))
|
if(WordFilteringChannels.Contains(channelId))
|
||||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
serverFilteredWords.TryGetValue(guildId, out words);
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
var words = new ConcurrentHashSet<string>();
|
var words = new ConcurrentHashSet<string>();
|
||||||
if(WordFilteringServers.Contains(guildId))
|
if(WordFilteringServers.Contains(guildId))
|
||||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
serverFilteredWords.TryGetValue(guildId, out words);
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
|
var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
|
||||||
|
|
||||||
ServerFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
|
serverFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
|
||||||
|
|
||||||
var serverFiltering = guildConfigs.Where(gc => gc.FilterWords);
|
var serverFiltering = guildConfigs.Where(gc => gc.FilterWords);
|
||||||
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
||||||
@ -74,12 +74,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
InviteFilteringServers.Add(channel.Guild.Id);
|
InviteFilteringServers.Add(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering enabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_server_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InviteFilteringServers.TryRemove(channel.Guild.Id);
|
InviteFilteringServers.TryRemove(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering disabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_server_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,12 +107,11 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
InviteFilteringChannels.Add(channel.Id);
|
InviteFilteringChannels.Add(channel.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_channel_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InviteFilteringChannels.TryRemove(channel.Id);
|
await ReplyConfirmLocalized("invite_filter_channel_off").ConfigureAwait(false);
|
||||||
await channel.SendConfirmAsync("Invite filtering disabled on this channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,12 +132,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
WordFilteringServers.Add(channel.Guild.Id);
|
WordFilteringServers.Add(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering enabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_server_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WordFilteringServers.TryRemove(channel.Guild.Id);
|
WordFilteringServers.TryRemove(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering disabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_server_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,12 +165,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
WordFilteringChannels.Add(channel.Id);
|
WordFilteringChannels.Add(channel.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_channel_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WordFilteringChannels.TryRemove(channel.Id);
|
WordFilteringChannels.TryRemove(channel.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering disabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_channel_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,19 +198,17 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredWords = ServerFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<string>());
|
var filteredWords = serverFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<string>());
|
||||||
|
|
||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
filteredWords.Add(word);
|
filteredWords.Add(word);
|
||||||
await channel.SendConfirmAsync($"Word `{word}` successfully added to the list of filtered words.")
|
await ReplyConfirmLocalized("filter_word_add", Format.Code(word)).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filteredWords.TryRemove(word);
|
filteredWords.TryRemove(word);
|
||||||
await channel.SendConfirmAsync($"Word `{word}` removed from the list of filtered words.")
|
await ReplyConfirmLocalized("filter_word_remove", Format.Code(word)).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,9 +219,9 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
ConcurrentHashSet<string> filteredWords;
|
ConcurrentHashSet<string> filteredWords;
|
||||||
ServerFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords);
|
serverFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords);
|
||||||
|
|
||||||
await channel.SendConfirmAsync($"List of filtered words", string.Join("\n", filteredWords))
|
await channel.SendConfirmAsync(GetText("filter_word_list"), string.Join("\n", filteredWords))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ using NLog;
|
|||||||
namespace NadekoBot.Modules.Permissions
|
namespace NadekoBot.Modules.Permissions
|
||||||
{
|
{
|
||||||
[NadekoModule("Permissions", ";")]
|
[NadekoModule("Permissions", ";")]
|
||||||
public partial class Permissions : NadekoModule
|
public partial class Permissions : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public class PermissionCache
|
public class PermissionCache
|
||||||
{
|
{
|
||||||
@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
static Permissions()
|
static Permissions()
|
||||||
{
|
{
|
||||||
var _log = LogManager.GetCurrentClassLogger();
|
var log = LogManager.GetCurrentClassLogger();
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -65,8 +65,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.Verbose = config.VerbosePermissions; return old; });
|
}, (id, old) => { old.Verbose = config.VerbosePermissions; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
if (action.Value)
|
||||||
await Context.Channel.SendConfirmAsync("ℹ️ I will " + (action.Value ? "now" : "no longer") + " show permission warnings.").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("verbose_true").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("verbose_false").ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -81,22 +87,20 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
if (role == null)
|
if (role == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"ℹ️ Current permission role is **{config.PermissionRole}**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("permrole", Format.Bold(config.PermissionRole)).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
config.PermissionRole = role.Name.Trim();
|
||||||
config.PermissionRole = role.Name.Trim();
|
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
{
|
||||||
{
|
PermRole = config.PermissionRole,
|
||||||
PermRole = config.PermissionRole,
|
RootPermission = Permission.GetDefaultRoot(),
|
||||||
RootPermission = Permission.GetDefaultRoot(),
|
Verbose = config.VerbosePermissions
|
||||||
Verbose = config.VerbosePermissions
|
}, (id, old) => { old.PermRole = role.Name.Trim(); return old; });
|
||||||
}, (id, old) => { old.PermRole = role.Name.Trim(); return old; });
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"Users now require **{role.Name}** role in order to edit permissions.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("permrole_changed", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -105,12 +109,18 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
if (page < 1 || page > 4)
|
if (page < 1 || page > 4)
|
||||||
return;
|
return;
|
||||||
string toSend = "";
|
string toSend;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var perms = uow.GuildConfigs.PermissionsFor(Context.Guild.Id).RootPermission;
|
var perms = uow.GuildConfigs.PermissionsFor(Context.Guild.Id).RootPermission;
|
||||||
var i = 1 + 20 * (page - 1);
|
var i = 1 + 20 * (page - 1);
|
||||||
toSend = Format.Code($"📄 Permissions page {page}") + "\n\n" + String.Join("\n", perms.AsEnumerable().Skip((page - 1) * 20).Take(20).Select(p => $"`{(i++)}.` {(p.Next == null ? Format.Bold(p.GetCommand((SocketGuild)Context.Guild) + " [uneditable]") : (p.GetCommand((SocketGuild)Context.Guild)))}"));
|
toSend = Format.Bold(GetText("page", page)) + "\n\n" + string.Join("\n",
|
||||||
|
perms.AsEnumerable()
|
||||||
|
.Skip((page - 1) * 20)
|
||||||
|
.Take(20)
|
||||||
|
.Select(
|
||||||
|
p =>
|
||||||
|
$"`{(i++)}.` {(p.Next == null ? Format.Bold(p.GetCommand((SocketGuild) Context.Guild) + $" [{GetText("uneditable")}]") : (p.GetCommand((SocketGuild) Context.Guild)))}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
||||||
@ -132,7 +142,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
p = perms;
|
p = perms;
|
||||||
config.RootPermission = perms.Next;
|
config.RootPermission = perms.Next;
|
||||||
@ -155,12 +165,13 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
uow2._context.Remove<Permission>(p);
|
uow2._context.Remove<Permission>(p);
|
||||||
uow2._context.SaveChanges();
|
uow2._context.SaveChanges();
|
||||||
}
|
}
|
||||||
|
await ReplyConfirmLocalized("removed",
|
||||||
await Context.Channel.SendConfirmAsync($"✅ {Context.User.Mention} removed permission **{p.GetCommand((SocketGuild)Context.Guild)}** from position #{index + 1}.").ConfigureAwait(false);
|
index+1,
|
||||||
|
Format.Code(p.GetCommand((SocketGuild)Context.Guild))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException)
|
catch (IndexOutOfRangeException)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("❗️`No command on that index found.`").ConfigureAwait(false);
|
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +191,6 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id);
|
var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id);
|
||||||
var perms = config.RootPermission;
|
var perms = config.RootPermission;
|
||||||
var root = perms;
|
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var fromFound = false;
|
var fromFound = false;
|
||||||
var toFound = false;
|
var toFound = false;
|
||||||
@ -207,13 +217,13 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
if (!fromFound)
|
if (!fromFound)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++from}`").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found", ++from).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!toFound)
|
if (!toFound)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++to}`").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found", ++to).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +240,6 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
next.Previous = pre;
|
next.Previous = pre;
|
||||||
if (from == 0)
|
if (from == 0)
|
||||||
{
|
{
|
||||||
root = next;
|
|
||||||
}
|
}
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
//Inserting
|
//Inserting
|
||||||
@ -263,14 +272,18 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"`Moved permission:` \"{fromPerm.GetCommand((SocketGuild)Context.Guild)}\" `from #{++from} to #{++to}.`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("moved_permission",
|
||||||
|
Format.Code(fromPerm.GetCommand((SocketGuild) Context.Guild)),
|
||||||
|
++from,
|
||||||
|
++to)
|
||||||
|
.ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException)
|
catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendErrorAsync("`Invalid index(es) specified.`").ConfigureAwait(false);
|
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -297,7 +310,19 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command on this server.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_enable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_disable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -323,7 +348,19 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of **`{module.Name}`** module on this server.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_enable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -349,7 +386,21 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{user}` user.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_enable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_disable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -375,7 +426,21 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{user}` user.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_enable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -404,7 +469,21 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{role}` role.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_enable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_disable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -433,39 +512,62 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{role}` role.").ConfigureAwait(false);
|
|
||||||
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_enable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl)
|
public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl)
|
||||||
{
|
{
|
||||||
try
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
var newPerm = new Permission
|
||||||
{
|
{
|
||||||
var newPerm = new Permission
|
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||||
{
|
PrimaryTargetId = chnl.Id,
|
||||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
SecondaryTarget = SecondaryPermissionType.Command,
|
||||||
PrimaryTargetId = chnl.Id,
|
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
||||||
SecondaryTarget = SecondaryPermissionType.Command,
|
State = action.Value,
|
||||||
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
};
|
||||||
State = action.Value,
|
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
||||||
};
|
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
{
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
PermRole = config.PermissionRole,
|
||||||
{
|
RootPermission = config.RootPermission,
|
||||||
PermRole = config.PermissionRole,
|
Verbose = config.VerbosePermissions
|
||||||
RootPermission = config.RootPermission,
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
Verbose = config.VerbosePermissions
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
|
||||||
_log.Error(ex);
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_enable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_disable",
|
||||||
|
Format.Code(command.Aliases.First()),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -491,7 +593,21 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_enable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -517,7 +633,17 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("acm_enable",
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("acm_disable",
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -546,7 +672,17 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{role}` role.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("arm_enable",
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("arm_disable",
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -572,7 +708,17 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{user}` user.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("aum_enable",
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("aum_disable",
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -609,7 +755,15 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` on this server.").ConfigureAwait(false);
|
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("asm_enable").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("asm_disable").ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ using System.Collections.Concurrent;
|
|||||||
namespace NadekoBot.Modules.Pokemon
|
namespace NadekoBot.Modules.Pokemon
|
||||||
{
|
{
|
||||||
[NadekoModule("Pokemon", ">")]
|
[NadekoModule("Pokemon", ">")]
|
||||||
public class Pokemon : NadekoModule
|
public class Pokemon : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
||||||
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom.Html;
|
using AngleSharp.Dom.Html;
|
||||||
using AngleSharp.Extensions;
|
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
@ -8,7 +7,6 @@ using NadekoBot.Extensions;
|
|||||||
using NadekoBot.Modules.Searches.Models;
|
using NadekoBot.Modules.Searches.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -21,37 +19,37 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class AnimeSearchCommands : ModuleBase
|
public class AnimeSearchCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Timer anilistTokenRefresher { get; }
|
private static readonly Timer anilistTokenRefresher;
|
||||||
private static Logger _log { get; }
|
|
||||||
private static string anilistToken { get; set; }
|
private static string anilistToken { get; set; }
|
||||||
|
|
||||||
static AnimeSearchCommands()
|
static AnimeSearchCommands()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
anilistTokenRefresher = new Timer(async (state) =>
|
anilistTokenRefresher = new Timer(async (state) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var headers = new Dictionary<string, string> {
|
var headers = new Dictionary<string, string>
|
||||||
{"grant_type", "client_credentials"},
|
{
|
||||||
{"client_id", "kwoth-w0ki9"},
|
{"grant_type", "client_credentials"},
|
||||||
{"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
|
{"client_id", "kwoth-w0ki9"},
|
||||||
};
|
{"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
|
||||||
|
};
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.AddFakeHeaders();
|
//http.AddFakeHeaders();
|
||||||
|
http.DefaultRequestHeaders.Clear();
|
||||||
var formContent = new FormUrlEncodedContent(headers);
|
var formContent = new FormUrlEncodedContent(headers);
|
||||||
var response = await http.PostAsync("http://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false);
|
var response = await http.PostAsync("https://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false);
|
||||||
var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
anilistToken = JObject.Parse(stringContent)["access_token"].ToString();
|
anilistToken = JObject.Parse(stringContent)["access_token"].ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
_log.Error(ex);
|
// ignored
|
||||||
}
|
}
|
||||||
}, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
|
}, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
|
||||||
}
|
}
|
||||||
@ -75,7 +73,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc");
|
var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc");
|
||||||
|
|
||||||
var favAnime = "No favorite anime yet";
|
var favAnime = GetText("anime_no_fav");
|
||||||
if (favorites[0].QuerySelector("p") == null)
|
if (favorites[0].QuerySelector("p") == null)
|
||||||
favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
|
favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
|
||||||
.Shuffle()
|
.Shuffle()
|
||||||
@ -106,14 +104,14 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle($"{name}'s MAL profile")
|
.WithTitle(GetText("mal_profile", name))
|
||||||
.AddField(efb => efb.WithName("💚 Watching").WithValue(stats[0]).WithIsInline(true))
|
.AddField(efb => efb.WithName("💚 " + GetText("watching")).WithValue(stats[0]).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("💙 Completed").WithValue(stats[1]).WithIsInline(true));
|
.AddField(efb => efb.WithName("💙 " + GetText("completed")).WithValue(stats[1]).WithIsInline(true));
|
||||||
if (info.Count < 3)
|
if (info.Count < 3)
|
||||||
embed.AddField(efb => efb.WithName("💛 On-Hold").WithValue(stats[2]).WithIsInline(true));
|
embed.AddField(efb => efb.WithName("💛 " + GetText("on_hold")).WithValue(stats[2]).WithIsInline(true));
|
||||||
embed
|
embed
|
||||||
.AddField(efb => efb.WithName("💔 Dropped").WithValue(stats[3]).WithIsInline(true))
|
.AddField(efb => efb.WithName("💔 " + GetText("dropped")).WithValue(stats[3]).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("⚪ Plan to watch").WithValue(stats[4]).WithIsInline(true))
|
.AddField(efb => efb.WithName("⚪ " + GetText("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[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("📊 " + 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[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true))
|
||||||
@ -126,7 +124,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithDescription($@"
|
.WithDescription($@"
|
||||||
** https://myanimelist.net/animelist/{ name } **
|
** https://myanimelist.net/animelist/{ name } **
|
||||||
|
|
||||||
**Top 3 Favorite Anime:**
|
**{GetText("top_3_fav_anime")}**
|
||||||
{favAnime}"
|
{favAnime}"
|
||||||
|
|
||||||
//**[Manga List](https://myanimelist.net/mangalist/{name})**
|
//**[Manga List](https://myanimelist.net/mangalist/{name})**
|
||||||
@ -176,7 +174,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (animeData == null)
|
if (animeData == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed finding that animu.").ConfigureAwait(false);
|
await ReplyErrorLocalized("failed_finding_anime").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,10 +183,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithTitle(animeData.title_english)
|
.WithTitle(animeData.title_english)
|
||||||
.WithUrl(animeData.Link)
|
.WithUrl(animeData.Link)
|
||||||
.WithImageUrl(animeData.image_url_lge)
|
.WithImageUrl(animeData.image_url_lge)
|
||||||
.AddField(efb => efb.WithName("Episodes").WithValue(animeData.total_episodes.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("episodes")).WithValue(animeData.total_episodes.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Status").WithValue(animeData.AiringStatus.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("status")).WithValue(animeData.AiringStatus.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Genres").WithValue(String.Join(", ", animeData.Genres)).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", animeData.Genres)).WithIsInline(true))
|
||||||
.WithFooter(efb => efb.WithText("Score: " + animeData.average_score + " / 100"));
|
.WithFooter(efb => efb.WithText(GetText("score") + " " + animeData.average_score + " / 100"));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +201,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (mangaData == null)
|
if (mangaData == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed finding that mango.").ConfigureAwait(false);
|
await ReplyErrorLocalized("failed_finding_manga").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,10 +210,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithTitle(mangaData.title_english)
|
.WithTitle(mangaData.title_english)
|
||||||
.WithUrl(mangaData.Link)
|
.WithUrl(mangaData.Link)
|
||||||
.WithImageUrl(mangaData.image_url_lge)
|
.WithImageUrl(mangaData.image_url_lge)
|
||||||
.AddField(efb => efb.WithName("Episodes").WithValue(mangaData.total_chapters.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("chapters")).WithValue(mangaData.total_chapters.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Status").WithValue(mangaData.publishing_status.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("status")).WithValue(mangaData.publishing_status.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Genres").WithValue(String.Join(", ", mangaData.Genres)).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", mangaData.Genres)).WithIsInline(true))
|
||||||
.WithFooter(efb => efb.WithText("Score: " + mangaData.average_score + " / 100"));
|
.WithFooter(efb => efb.WithText(GetText("score") + " " + mangaData.average_score + " / 100"));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using System;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -13,7 +14,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public static GoogleTranslator Instance = _instance ?? (_instance = new GoogleTranslator());
|
public static GoogleTranslator Instance = _instance ?? (_instance = new GoogleTranslator());
|
||||||
|
|
||||||
public IEnumerable<string> Languages => _languageDictionary.Keys.OrderBy(x => x);
|
public IEnumerable<string> Languages => _languageDictionary.Keys.OrderBy(x => x);
|
||||||
private Dictionary<string, string> _languageDictionary;
|
private readonly Dictionary<string, string> _languageDictionary;
|
||||||
|
|
||||||
static GoogleTranslator() { }
|
static GoogleTranslator() { }
|
||||||
private GoogleTranslator() {
|
private GoogleTranslator() {
|
||||||
@ -153,13 +154,18 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
public async Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage)
|
public async Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage)
|
||||||
{
|
{
|
||||||
string text = string.Empty;
|
string text;
|
||||||
|
|
||||||
string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
if(!_languageDictionary.ContainsKey(sourceLanguage) ||
|
||||||
|
!_languageDictionary.ContainsKey(targetLanguage))
|
||||||
|
throw new ArgumentException();
|
||||||
|
|
||||||
|
|
||||||
|
var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
||||||
ConvertToLanguageCode(sourceLanguage),
|
ConvertToLanguageCode(sourceLanguage),
|
||||||
ConvertToLanguageCode(targetLanguage),
|
ConvertToLanguageCode(targetLanguage),
|
||||||
WebUtility.UrlEncode(sourceText));
|
WebUtility.UrlEncode(sourceText));
|
||||||
using (HttpClient http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
||||||
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||||
@ -170,7 +176,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
private string ConvertToLanguageCode(string language)
|
private string ConvertToLanguageCode(string language)
|
||||||
{
|
{
|
||||||
string mode = string.Empty;
|
string mode;
|
||||||
_languageDictionary.TryGetValue(language, out mode);
|
_languageDictionary.TryGetValue(language, out mode);
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using Newtonsoft.Json;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -18,11 +17,11 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class JokeCommands : ModuleBase
|
public class JokeCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static List<WoWJoke> wowJokes { get; } = new List<WoWJoke>();
|
private static List<WoWJoke> wowJokes { get; } = new List<WoWJoke>();
|
||||||
private static List<MagicItem> magicItems { get; } = new List<MagicItem>();
|
private static List<MagicItem> magicItems { get; } = new List<MagicItem>();
|
||||||
private static Logger _log { get; }
|
private new static readonly Logger _log;
|
||||||
|
|
||||||
static JokeCommands()
|
static JokeCommands()
|
||||||
{
|
{
|
||||||
@ -78,7 +77,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
if (!wowJokes.Any())
|
if (!wowJokes.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Jokes not loaded.").ConfigureAwait(false);
|
await ReplyErrorLocalized("jokes_not_loaded").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var joke = wowJokes[new NadekoRandom().Next(0, wowJokes.Count)];
|
var joke = wowJokes[new NadekoRandom().Next(0, wowJokes.Count)];
|
||||||
@ -90,7 +89,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
if (!wowJokes.Any())
|
if (!wowJokes.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("MagicItems not loaded.").ConfigureAwait(false);
|
await ReplyErrorLocalized("magicitems_not_loaded").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var item = magicItems[new NadekoRandom().Next(0, magicItems.Count)];
|
var item = magicItems[new NadekoRandom().Next(0, magicItems.Count)];
|
||||||
|
@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Lolban()
|
public async Task Lolban()
|
||||||
{
|
{
|
||||||
var showCount = 8;
|
const int showCount = 8;
|
||||||
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
|
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -44,19 +44,20 @@ namespace NadekoBot.Modules.Searches
|
|||||||
$"limit={showCount}")
|
$"limit={showCount}")
|
||||||
.ConfigureAwait(false))["data"] as JArray;
|
.ConfigureAwait(false))["data"] as JArray;
|
||||||
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList();
|
||||||
var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline($"{dataList.Count} most banned champions"));
|
var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline(GetText("x_most_banned_champs",dataList.Count)));
|
||||||
for (var i = 0; i < dataList.Count; i++)
|
foreach (var champ in dataList)
|
||||||
{
|
{
|
||||||
var champ = dataList[i];
|
var champ1 = champ;
|
||||||
eb.AddField(efb => efb.WithName(champ["name"].ToString()).WithValue(champ["general"]["banRate"] + "%").WithIsInline(true));
|
eb.AddField(efb => efb.WithName(champ1["name"].ToString()).WithValue(champ1["general"]["banRate"] + "%").WithIsInline(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(eb, Format.Italics(trashTalk[new NadekoRandom().Next(0, trashTalk.Length)])).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(eb, Format.Italics(trashTalk[new NadekoRandom().Next(0, trashTalk.Length)])).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendMessageAsync("Something went wrong.").ConfigureAwait(false);
|
_log.Warn(ex);
|
||||||
|
await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,79 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[Group]
|
||||||
public async Task Memelist()
|
public class MemegenCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
HttpClientHandler handler = new HttpClientHandler();
|
private static readonly ImmutableDictionary<char, string> _map = new Dictionary<char, string>()
|
||||||
|
|
||||||
handler.AllowAutoRedirect = false;
|
|
||||||
|
|
||||||
using (var http = new HttpClient(handler))
|
|
||||||
{
|
{
|
||||||
var rawJson = await http.GetStringAsync("https://memegen.link/api/templates/").ConfigureAwait(false);
|
{'?', "~q"},
|
||||||
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawJson)
|
{'%', "~p"},
|
||||||
.Select(kvp => Path.GetFileName(kvp.Value));
|
{'#', "~h"},
|
||||||
|
{'/', "~s"},
|
||||||
|
{' ', "-"},
|
||||||
|
{'-', "--"},
|
||||||
|
{'_', "__"},
|
||||||
|
{'"', "''"}
|
||||||
|
|
||||||
await Context.Channel.SendTableAsync(data, x => $"{x,-17}", 3).ConfigureAwait(false);
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
public async Task Memelist()
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using (var http = new HttpClient(handler))
|
||||||
|
{
|
||||||
|
var rawJson = await http.GetStringAsync("https://memegen.link/api/templates/").ConfigureAwait(false);
|
||||||
|
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawJson)
|
||||||
|
.Select(kvp => Path.GetFileName(kvp.Value));
|
||||||
|
|
||||||
|
await Context.Channel.SendTableAsync(data, x => $"{x,-17}", 3).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Memegen(string meme, string topText, string botText)
|
public async Task Memegen(string meme, string topText, string botText)
|
||||||
{
|
{
|
||||||
var top = Uri.EscapeDataString(topText.Replace(' ', '-'));
|
var top = Replace(topText);
|
||||||
var bot = Uri.EscapeDataString(botText.Replace(' ', '-'));
|
var bot = Replace(botText);
|
||||||
await Context.Channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg")
|
await Context.Channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Replace(string input)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var c in input)
|
||||||
|
{
|
||||||
|
string tmp;
|
||||||
|
if (_map.TryGetValue(c, out tmp))
|
||||||
|
sb.Append(tmp);
|
||||||
|
else
|
||||||
|
sb.Append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,22 +33,23 @@ namespace NadekoBot.Modules.Searches.Models
|
|||||||
public string[] Evos { get; set; }
|
public string[] Evos { get; set; }
|
||||||
public string[] EggGroups { get; set; }
|
public string[] EggGroups { get; set; }
|
||||||
|
|
||||||
public override string ToString() => $@"`Name:` {Species}
|
// public override string ToString() => $@"`Name:` {Species}
|
||||||
`Types:` {string.Join(", ", Types)}
|
//`Types:` {string.Join(", ", Types)}
|
||||||
`Stats:` {BaseStats}
|
//`Stats:` {BaseStats}
|
||||||
`Height:` {HeightM,4}m `Weight:` {WeightKg}kg
|
//`Height:` {HeightM,4}m `Weight:` {WeightKg}kg
|
||||||
`Abilities:` {string.Join(", ", Abilities.Values)}";
|
//`Abilities:` {string.Join(", ", Abilities.Values)}";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SearchPokemonAbility
|
public class SearchPokemonAbility
|
||||||
{
|
{
|
||||||
public string Desc { get; set; }
|
public string Desc { get; set; }
|
||||||
|
public string ShortDesc { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public float Rating { get; set; }
|
public float Rating { get; set; }
|
||||||
|
|
||||||
public override string ToString() => $@"`Name:` : {Name}
|
// public override string ToString() => $@"`Name:` : {Name}
|
||||||
`Rating:` {Rating}
|
//`Rating:` {Rating}
|
||||||
`Description:` {Desc}";
|
//`Description:` {Desc}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -16,21 +15,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class OsuCommands : ModuleBase
|
public class OsuCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Logger _log { get; }
|
|
||||||
|
|
||||||
static OsuCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
}
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Osu(string usr, [Remainder] string mode = null)
|
public async Task Osu(string usr, [Remainder] string mode = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(usr))
|
if (string.IsNullOrWhiteSpace(usr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (HttpClient http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -42,15 +35,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
http.AddFakeHeaders();
|
http.AddFakeHeaders();
|
||||||
var res = await http.GetStreamAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ usr }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}")).ConfigureAwait(false);
|
var res = await http.GetStreamAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ usr }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}")).ConfigureAwait(false);
|
||||||
|
|
||||||
MemoryStream ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
res.CopyTo(ms);
|
res.CopyTo(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
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);
|
await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **{GetText("profile_link")}** <https://new.ppy.sh/u/{Uri.EscapeDataString(usr)}>\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed retrieving osu signature.").ConfigureAwait(false);
|
await ReplyErrorLocalized("osu_failed").ConfigureAwait(false);
|
||||||
_log.Warn(ex, "Osu command failed");
|
_log.Warn(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +53,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("An osu! API key is required.").ConfigureAwait(false);
|
await ReplyErrorLocalized("osu_api_key").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +68,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&{mapId}";
|
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&{mapId}";
|
||||||
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0];
|
var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0];
|
||||||
var sb = new System.Text.StringBuilder();
|
var sb = new System.Text.StringBuilder();
|
||||||
var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2);
|
var starRating = Math.Round(double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2);
|
||||||
var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss");
|
var time = TimeSpan.FromSeconds(double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss");
|
||||||
sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}");
|
sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}");
|
||||||
sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}");
|
sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}");
|
||||||
await Context.Channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
||||||
@ -84,8 +77,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Something went wrong.");
|
await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false);
|
||||||
_log.Warn(ex, "Osub command failed");
|
_log.Warn(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,54 +114,53 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&b={item["beatmap_id"]}";
|
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&b={item["beatmap_id"]}";
|
||||||
var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0];
|
var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0];
|
||||||
var pp = Math.Round(Double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2);
|
var pp = Math.Round(double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2);
|
||||||
var acc = CalculateAcc(item, m);
|
var acc = CalculateAcc(item, m);
|
||||||
var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}"));
|
var mods = ResolveMods(int.Parse($"{item["enabled_mods"]}"));
|
||||||
if (mods != "+")
|
sb.AppendLine(mods != "+"
|
||||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | **{mods,-10}** | /b/{item["beatmap_id"]}");
|
? $"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | **{mods,-10}** | /b/{item["beatmap_id"]}"
|
||||||
else
|
: $"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | /b/{item["beatmap_id"]}");
|
||||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | /b/{item["beatmap_id"]}");
|
|
||||||
}
|
}
|
||||||
sb.Append("```");
|
sb.Append("```");
|
||||||
await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Something went wrong.");
|
await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false);
|
||||||
_log.Warn(ex, "Osu5 command failed");
|
_log.Warn(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://osu.ppy.sh/wiki/Accuracy
|
//https://osu.ppy.sh/wiki/Accuracy
|
||||||
private static Double CalculateAcc(JToken play, int mode)
|
private static double CalculateAcc(JToken play, int mode)
|
||||||
{
|
{
|
||||||
if (mode == 0)
|
if (mode == 0)
|
||||||
{
|
{
|
||||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["count300"]}") * 300;
|
var hitPoints = double.Parse($"{play["count50"]}") * 50 + double.Parse($"{play["count100"]}") * 100 + double.Parse($"{play["count300"]}") * 300;
|
||||||
var totalHits = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countmiss"]}");
|
var totalHits = double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countmiss"]}");
|
||||||
totalHits *= 300;
|
totalHits *= 300;
|
||||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||||
}
|
}
|
||||||
else if (mode == 1)
|
else if (mode == 1)
|
||||||
{
|
{
|
||||||
var hitPoints = Double.Parse($"{play["countmiss"]}") * 0 + Double.Parse($"{play["count100"]}") * 0.5 + Double.Parse($"{play["count300"]}") * 1;
|
var hitPoints = double.Parse($"{play["countmiss"]}") * 0 + double.Parse($"{play["count100"]}") * 0.5 + double.Parse($"{play["count300"]}") * 1;
|
||||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
var totalHits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}");
|
||||||
hitPoints *= 300;
|
hitPoints *= 300;
|
||||||
totalHits *= 300;
|
totalHits *= 300;
|
||||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||||
}
|
}
|
||||||
else if (mode == 2)
|
else if (mode == 2)
|
||||||
{
|
{
|
||||||
var fruitsCaught = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
var fruitsCaught = double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}");
|
||||||
var totalFruits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countkatu"]}");
|
var totalFruits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countkatu"]}");
|
||||||
return Math.Round(fruitsCaught / totalFruits * 100, 2);
|
return Math.Round(fruitsCaught / totalFruits * 100, 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["countkatu"]}") * 200 + (Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}")) * 300;
|
var hitPoints = double.Parse($"{play["count50"]}") * 50 + double.Parse($"{play["count100"]}") * 100 + double.Parse($"{play["countkatu"]}") * 200 + (double.Parse($"{play["count300"]}") + double.Parse($"{play["countgeki"]}")) * 300;
|
||||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["countkatu"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}");
|
var totalHits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["countkatu"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countgeki"]}");
|
||||||
totalHits *= 300;
|
totalHits *= 300;
|
||||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||||
}
|
}
|
||||||
@ -176,10 +168,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
private static string ResolveMap(string mapLink)
|
private static string ResolveMap(string mapLink)
|
||||||
{
|
{
|
||||||
Match s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink);
|
var s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||||
Match b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink);
|
var b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||||
Match p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink);
|
var p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||||
Match m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink);
|
var m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink);
|
||||||
if (s.Success)
|
if (s.Success)
|
||||||
{
|
{
|
||||||
var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3);
|
var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3);
|
||||||
|
@ -4,7 +4,6 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Searches.Models;
|
using NadekoBot.Modules.Searches.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -14,13 +13,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class OverwatchCommands : ModuleBase
|
public class OverwatchCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private readonly Logger _log;
|
|
||||||
public OverwatchCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
}
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Overwatch(string region, [Remainder] string query = null)
|
public async Task Overwatch(string region, [Remainder] string query = null)
|
||||||
{
|
{
|
||||||
@ -34,9 +28,9 @@ namespace NadekoBot.Modules.Searches
|
|||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
var model = await GetProfile(region, battletag);
|
var model = await GetProfile(region, battletag);
|
||||||
|
|
||||||
var rankimg = $"{model.Competitive.rank_img}";
|
var rankimg = model.Competitive.rank_img;
|
||||||
var rank = $"{model.Competitive.rank}";
|
var rank = model.Competitive.rank;
|
||||||
//var competitiveplay = $"{model.Games.Competitive.played}";
|
|
||||||
if (string.IsNullOrWhiteSpace(rank))
|
if (string.IsNullOrWhiteSpace(rank))
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
@ -44,10 +38,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
|
.WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
|
||||||
.WithIconUrl($"{model.avatar}"))
|
.WithIconUrl($"{model.avatar}"))
|
||||||
.WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png")
|
.WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png")
|
||||||
.AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_rank")).WithValue("0").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -58,22 +52,21 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
|
.WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
|
||||||
.WithIconUrl($"{model.avatar}"))
|
.WithIconUrl($"{model.avatar}"))
|
||||||
.WithThumbnailUrl(rankimg)
|
.WithThumbnailUrl(rankimg)
|
||||||
.AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_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(GetText("compet_losses")).WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(rank).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Playtime.competitive}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Found no user! Please check the **Region** and **BattleTag** before trying again.");
|
await ReplyErrorLocalized("ow_user_not_found").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task<OverwatchApiModel.OverwatchPlayer.Data> GetProfile(string region, string battletag)
|
public async Task<OverwatchApiModel.OverwatchPlayer.Data> GetProfile(string region, string battletag)
|
||||||
@ -82,8 +75,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile");
|
var url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile");
|
||||||
var model = JsonConvert.DeserializeObject<OverwatchApiModel.OverwatchPlayer>(Url);
|
var model = JsonConvert.DeserializeObject<OverwatchApiModel.OverwatchPlayer>(url);
|
||||||
return model.data;
|
return model.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,9 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class PlaceCommands : ModuleBase
|
public class PlaceCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static string typesStr { get; } =
|
private static string typesStr { get; } = string.Join(", ", Enum.GetNames(typeof(PlaceType)));
|
||||||
string.Format("`List of \"{0}place\" tags:`\n", NadekoBot.ModulePrefixes[typeof(Searches).Name]) + String.Join(", ", Enum.GetNames(typeof(PlaceType)));
|
|
||||||
|
|
||||||
public enum PlaceType
|
public enum PlaceType
|
||||||
{
|
{
|
||||||
@ -30,14 +29,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Placelist()
|
public async Task Placelist()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(typesStr)
|
await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.ModulePrefixes[typeof(Searches).Name]),
|
||||||
|
typesStr)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Place(PlaceType placeType, uint width = 0, uint height = 0)
|
public async Task Place(PlaceType placeType, uint width = 0, uint height = 0)
|
||||||
{
|
{
|
||||||
string url = "";
|
var url = "";
|
||||||
switch (placeType)
|
switch (placeType)
|
||||||
{
|
{
|
||||||
case PlaceType.Cage:
|
case PlaceType.Cage:
|
||||||
|
@ -6,7 +6,6 @@ using NadekoBot.Modules.Searches.Models;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -16,7 +15,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class PokemonSearchCommands : ModuleBase
|
public class PokemonSearchCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Dictionary<string, SearchPokemon> pokemons { get; } = new Dictionary<string, SearchPokemon>();
|
private static Dictionary<string, SearchPokemon> pokemons { get; } = new Dictionary<string, SearchPokemon>();
|
||||||
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities { get; } = new Dictionary<string, SearchPokemonAbility>();
|
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities { get; } = new Dictionary<string, SearchPokemonAbility>();
|
||||||
@ -24,7 +23,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public const string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json";
|
public const string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json";
|
||||||
|
|
||||||
public const string PokemonListFile = "data/pokemon/pokemon_list7.json";
|
public const string PokemonListFile = "data/pokemon/pokemon_list7.json";
|
||||||
private static Logger _log { get; }
|
private new static readonly Logger _log;
|
||||||
|
|
||||||
static PokemonSearchCommands()
|
static PokemonSearchCommands()
|
||||||
{
|
{
|
||||||
@ -57,14 +56,13 @@ namespace NadekoBot.Modules.Searches
|
|||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(kvp.Key.ToTitleCase())
|
.WithTitle(kvp.Key.ToTitleCase())
|
||||||
.WithDescription(p.BaseStats.ToString())
|
.WithDescription(p.BaseStats.ToString())
|
||||||
.AddField(efb => efb.WithName("Types").WithValue(string.Join(",\n", p.Types)).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("types")).WithValue(string.Join(",\n", p.Types)).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Height/Weight").WithValue($"{p.HeightM}m/{p.WeightKg}kg").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("height_weight")).WithValue(GetText("height_weight_val", p.HeightM, p.WeightKg)).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Abilitities").WithValue(string.Join(",\n", p.Abilities.Select(a => a.Value))).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("abilities")).WithValue(string.Join(",\n", p.Abilities.Select(a => a.Value))).WithIsInline(true)));
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendErrorAsync("No pokemon found.");
|
await ReplyErrorLocalized("pokemon_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -79,13 +77,16 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(kvp.Value.Name)
|
.WithTitle(kvp.Value.Name)
|
||||||
.WithDescription(kvp.Value.Desc)
|
.WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc)
|
||||||
.AddField(efb => efb.WithName("Rating").WithValue(kvp.Value.Rating.ToString()).WithIsInline(true))
|
? kvp.Value.ShortDesc
|
||||||
|
: kvp.Value.Desc)
|
||||||
|
.AddField(efb => efb.WithName(GetText("rating"))
|
||||||
|
.WithValue(kvp.Value.Rating.ToString(_cultureInfo)).WithIsInline(true))
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendErrorAsync("No ability found.");
|
await ReplyErrorLocalized("pokemon_ability_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,7 @@ using System.Net.Http;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
@ -65,23 +63,19 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class StreamNotificationCommands : ModuleBase
|
public class StreamNotificationCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Timer checkTimer { get; }
|
private static readonly Timer _checkTimer;
|
||||||
private static ConcurrentDictionary<string, StreamStatus> oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
private static readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
||||||
private static ConcurrentDictionary<string, StreamStatus> cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
|
||||||
private static Logger _log { get; }
|
|
||||||
|
|
||||||
private static bool FirstPass { get; set; } = true;
|
private static bool firstPass { get; set; } = true;
|
||||||
|
|
||||||
static StreamNotificationCommands()
|
static StreamNotificationCommands()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_checkTimer = new Timer(async (state) =>
|
||||||
|
|
||||||
checkTimer = new Timer(async (state) =>
|
|
||||||
{
|
{
|
||||||
oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(cachedStatuses);
|
var oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(_cachedStatuses);
|
||||||
cachedStatuses.Clear();
|
_cachedStatuses.Clear();
|
||||||
IEnumerable<FollowedStream> streams;
|
IEnumerable<FollowedStream> streams;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
@ -93,7 +87,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
|
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
|
||||||
if (FirstPass)
|
if (firstPass)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -108,7 +102,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false);
|
await channel.EmbedAsync(fs.GetEmbed(newStatus, channel.Guild.Id)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -122,7 +116,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FirstPass = false;
|
firstPass = false;
|
||||||
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
|
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +128,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
case FollowedStream.FollowedStreamType.Hitbox:
|
case FollowedStream.FollowedStreamType.Hitbox:
|
||||||
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
|
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
|
||||||
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
|
if (checkCache && _cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||||
return result;
|
return result;
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
@ -149,11 +143,11 @@ namespace NadekoBot.Modules.Searches
|
|||||||
ApiLink = hitboxUrl,
|
ApiLink = hitboxUrl,
|
||||||
Views = hbData.Views
|
Views = hbData.Views
|
||||||
};
|
};
|
||||||
cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
|
_cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
|
||||||
return result;
|
return result;
|
||||||
case FollowedStream.FollowedStreamType.Twitch:
|
case FollowedStream.FollowedStreamType.Twitch:
|
||||||
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
|
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
|
||||||
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
|
if (checkCache && _cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||||
return result;
|
return result;
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
@ -170,11 +164,11 @@ namespace NadekoBot.Modules.Searches
|
|||||||
ApiLink = twitchUrl,
|
ApiLink = twitchUrl,
|
||||||
Views = twData.Stream?.Viewers.ToString() ?? "0"
|
Views = twData.Stream?.Viewers.ToString() ?? "0"
|
||||||
};
|
};
|
||||||
cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
|
_cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
|
||||||
return result;
|
return result;
|
||||||
case FollowedStream.FollowedStreamType.Beam:
|
case FollowedStream.FollowedStreamType.Beam:
|
||||||
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
|
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
|
||||||
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
|
if (checkCache && _cachedStatuses.TryGetValue(beamUrl, out result))
|
||||||
return result;
|
return result;
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
@ -190,7 +184,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
ApiLink = beamUrl,
|
ApiLink = beamUrl,
|
||||||
Views = bmData.ViewersCurrent.ToString()
|
Views = bmData.ViewersCurrent.ToString()
|
||||||
};
|
};
|
||||||
cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
|
_cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
|
||||||
return result;
|
return result;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -234,17 +228,21 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (!streams.Any())
|
if (!streams.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync("You are not following any streams on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("streams_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = string.Join("\n", await Task.WhenAll(streams.Select(async snc =>
|
var text = string.Join("\n", await Task.WhenAll(streams.Select(async snc =>
|
||||||
{
|
{
|
||||||
var ch = await Context.Guild.GetTextChannelAsync(snc.ChannelId);
|
var ch = await Context.Guild.GetTextChannelAsync(snc.ChannelId);
|
||||||
return $"`{snc.Username}`'s stream on **{(ch)?.Name}** channel. 【`{snc.Type.ToString()}`】";
|
return string.Format("{0}'s stream on {1} channel. 【{2}】",
|
||||||
|
Format.Code(snc.Username),
|
||||||
|
Format.Bold(ch?.Name ?? "deleted-channel"),
|
||||||
|
Format.Code(snc.Type.ToString()));
|
||||||
})));
|
})));
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"You are following **{streams.Count()}** streams on this server.\n\n" + text).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("streams_following", streams.Count()) + "\n\n" + text)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -271,10 +269,13 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
if (!removed)
|
if (!removed)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No such stream.").ConfigureAwait(false);
|
await ReplyErrorLocalized("stream_no").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"Removed `{username}`'s stream ({type}) from notifications.").ConfigureAwait(false);
|
|
||||||
|
await ReplyConfirmLocalized("stream_removed",
|
||||||
|
Format.Code(username),
|
||||||
|
type).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -293,20 +294,24 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}));
|
}));
|
||||||
if (streamStatus.IsLive)
|
if (streamStatus.IsLive)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"Streamer {username} is online with {streamStatus.Views} viewers.");
|
await ReplyConfirmLocalized("streamer_online",
|
||||||
|
username,
|
||||||
|
streamStatus.Views)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"Streamer {username} is offline.");
|
await ReplyConfirmLocalized("streamer_offline",
|
||||||
|
username).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No channel found.");
|
await ReplyErrorLocalized("no_channel_found").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type)
|
private async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type)
|
||||||
{
|
{
|
||||||
username = username.ToLowerInvariant().Trim();
|
username = username.ToLowerInvariant().Trim();
|
||||||
var fs = new FollowedStream
|
var fs = new FollowedStream
|
||||||
@ -324,7 +329,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Stream probably doesn't exist.").ConfigureAwait(false);
|
await ReplyErrorLocalized("stream_not_exist").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,24 +340,24 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.Add(fs);
|
.Add(fs);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await channel.EmbedAsync(fs.GetEmbed(status), $"🆗 I will notify this channel when status changes.").ConfigureAwait(false);
|
await channel.EmbedAsync(fs.GetEmbed(status, Context.Guild.Id), GetText("stream_tracked")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FollowedStreamExtensions
|
public static class FollowedStreamExtensions
|
||||||
{
|
{
|
||||||
public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status)
|
public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status, ulong guildId)
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder().WithTitle(fs.Username)
|
var embed = new EmbedBuilder().WithTitle(fs.Username)
|
||||||
.WithUrl(fs.GetLink())
|
.WithUrl(fs.GetLink())
|
||||||
.AddField(efb => efb.WithName("Status")
|
.AddField(efb => efb.WithName(fs.GetText("status"))
|
||||||
.WithValue(status.IsLive ? "Online" : "Offline")
|
.WithValue(status.IsLive ? "Online" : "Offline")
|
||||||
.WithIsInline(true))
|
.WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Viewers")
|
.AddField(efb => efb.WithName(fs.GetText("viewers"))
|
||||||
.WithValue(status.IsLive ? status.Views : "-")
|
.WithValue(status.IsLive ? status.Views : "-")
|
||||||
.WithIsInline(true))
|
.WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Platform")
|
.AddField(efb => efb.WithName(fs.GetText("platform"))
|
||||||
.WithValue(fs.Type.ToString())
|
.WithValue(fs.Type.ToString())
|
||||||
.WithIsInline(true))
|
.WithIsInline(true))
|
||||||
.WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor);
|
.WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor);
|
||||||
@ -360,15 +365,21 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return embed;
|
return embed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetLink(this FollowedStream fs) {
|
public static string GetText(this FollowedStream fs, string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(fs.GuildId),
|
||||||
|
typeof(Searches).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
|
public static string GetLink(this FollowedStream fs)
|
||||||
|
{
|
||||||
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
|
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
|
||||||
return $"http://www.hitbox.tv/{fs.Username}/";
|
return $"http://www.hitbox.tv/{fs.Username}/";
|
||||||
else if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
|
if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
|
||||||
return $"http://www.twitch.tv/{fs.Username}/";
|
return $"http://www.twitch.tv/{fs.Username}/";
|
||||||
else if (fs.Type == FollowedStream.FollowedStreamType.Beam)
|
if (fs.Type == FollowedStream.FollowedStreamType.Beam)
|
||||||
return $"https://beam.pro/{fs.Username}/";
|
return $"https://beam.pro/{fs.Username}/";
|
||||||
else
|
return "??";
|
||||||
return "??";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class TranslateCommands : ModuleBase
|
public class TranslateCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, bool> TranslatedChannels { get; } = new ConcurrentDictionary<ulong, bool>();
|
private static ConcurrentDictionary<ulong, bool> translatedChannels { get; } = new ConcurrentDictionary<ulong, bool>();
|
||||||
private static ConcurrentDictionary<UserChannelPair, string> UserLanguages { get; } = new ConcurrentDictionary<UserChannelPair, string>();
|
private static ConcurrentDictionary<UserChannelPair, string> userLanguages { get; } = new ConcurrentDictionary<UserChannelPair, string>();
|
||||||
|
|
||||||
static TranslateCommands()
|
static TranslateCommands()
|
||||||
{
|
{
|
||||||
@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool autoDelete;
|
bool autoDelete;
|
||||||
if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete))
|
if (!translatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete))
|
||||||
return;
|
return;
|
||||||
var key = new UserChannelPair()
|
var key = new UserChannelPair()
|
||||||
{
|
{
|
||||||
@ -44,10 +44,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
};
|
};
|
||||||
|
|
||||||
string langs;
|
string langs;
|
||||||
if (!UserLanguages.TryGetValue(key, out langs))
|
if (!userLanguages.TryGetValue(key, out langs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore), true)
|
var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (autoDelete)
|
if (autoDelete)
|
||||||
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
@ -64,21 +64,21 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
var translation = await TranslateInternal(langs, text);
|
var translation = await TranslateInternal(langs, text);
|
||||||
await Context.Channel.SendConfirmAsync("Translation " + langs, translation).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("translation") + " " + langs, translation).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Bad input format, or something went wrong...").ConfigureAwait(false);
|
await ReplyErrorLocalized("bad_input_format").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> TranslateInternal(string langs, [Remainder] string text = null, bool silent = false)
|
private static async Task<string> TranslateInternal(string langs, [Remainder] string text = null)
|
||||||
{
|
{
|
||||||
var langarr = langs.ToLowerInvariant().Split('>');
|
var langarr = langs.ToLowerInvariant().Split('>');
|
||||||
if (langarr.Length != 2)
|
if (langarr.Length != 2)
|
||||||
throw new ArgumentException();
|
throw new ArgumentException();
|
||||||
string from = langarr[0];
|
var from = langarr[0];
|
||||||
string to = langarr[1];
|
var to = langarr[1];
|
||||||
text = text?.Trim();
|
text = text?.Trim();
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
throw new ArgumentException();
|
throw new ArgumentException();
|
||||||
@ -101,20 +101,20 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (autoDelete == AutoDeleteAutoTranslate.Del)
|
if (autoDelete == AutoDeleteAutoTranslate.Del)
|
||||||
{
|
{
|
||||||
TranslatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true);
|
translatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true);
|
||||||
try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel. User messages will be auto-deleted.").ConfigureAwait(false); } catch { }
|
await ReplyConfirmLocalized("atl_ad_started").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool throwaway;
|
bool throwaway;
|
||||||
if (TranslatedChannels.TryRemove(channel.Id, out throwaway))
|
if (translatedChannels.TryRemove(channel.Id, out throwaway))
|
||||||
{
|
{
|
||||||
try { await channel.SendConfirmAsync("Stopped automatic translation of messages on this channel.").ConfigureAwait(false); } catch { }
|
await ReplyConfirmLocalized("atl_stopped").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (TranslatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del))
|
if (translatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del))
|
||||||
{
|
{
|
||||||
try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel.").ConfigureAwait(false); } catch { }
|
await ReplyConfirmLocalized("atl_started").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +130,8 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(langs))
|
if (string.IsNullOrWhiteSpace(langs))
|
||||||
{
|
{
|
||||||
if (UserLanguages.TryRemove(ucp, out langs))
|
if (userLanguages.TryRemove(ucp, out langs))
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention}'s auto-translate language has been removed.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_removed").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,20 +143,20 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
|
if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
|
||||||
{
|
{
|
||||||
try { await Context.Channel.SendErrorAsync("Invalid source and/or target language.").ConfigureAwait(false); } catch { }
|
await ReplyErrorLocalized("invalid_lang").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
userLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"Your auto-translate language has been set to {from}>{to}").ConfigureAwait(false);
|
await ReplyConfirmLocalized("atl_set", from, to).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Translangs()
|
public async Task Translangs()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", columns: 3);
|
await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public partial class Searches
|
public partial class Searches
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class XkcdCommands : ModuleBase
|
public class XkcdCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private const string xkcdUrl = "https://xkcd.com";
|
private const string _xkcdUrl = "https://xkcd.com";
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
@ -24,9 +24,9 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var res = await http.GetStringAsync($"{xkcdUrl}/info.0.json").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"{_xkcdUrl}/info.0.json").ConfigureAwait(false);
|
||||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||||
var sent = await Context.Channel.SendMessageAsync($"{Context.User.Mention} " + comic.ToString())
|
var sent = await Context.Channel.SendMessageAsync($"{Context.User.Mention} " + comic)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
await Task.Delay(10000).ConfigureAwait(false);
|
await Task.Delay(10000).ConfigureAwait(false);
|
||||||
@ -47,14 +47,14 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"{_xkcdUrl}/{num}/info.0.json").ConfigureAwait(false);
|
||||||
|
|
||||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||||
var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||||
.WithImageUrl(comic.ImageLink)
|
.WithImageUrl(comic.ImageLink)
|
||||||
.WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico"))
|
.WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{_xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico"))
|
||||||
.AddField(efb => efb.WithName("Comic#").WithValue(comic.Num.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("comic_number")).WithValue(comic.Num.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Date").WithValue($"{comic.Month}/{comic.Year}").WithIsInline(true));
|
.AddField(efb => efb.WithName(GetText("date")).WithValue($"{comic.Month}/{comic.Year}").WithIsInline(true));
|
||||||
var sent = await Context.Channel.EmbedAsync(embed)
|
var sent = await Context.Channel.EmbedAsync(embed)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
@ -75,9 +75,6 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[JsonProperty("img")]
|
[JsonProperty("img")]
|
||||||
public string ImageLink { get; set; }
|
public string ImageLink { get; set; }
|
||||||
public string Alt { get; set; }
|
public string Alt { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
=> $"`Comic:` #{Num} `Title:` {Title} `Date:` {Month}/{Year}\n{ImageLink}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
@ -8,27 +7,26 @@ using System.Text;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Attributes;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NadekoBot.Modules.Searches.Models;
|
using NadekoBot.Modules.Searches.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using ImageSharp;
|
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NadekoBot.Modules.Searches.Commands.OMDB;
|
using NadekoBot.Modules.Searches.Commands.OMDB;
|
||||||
using NadekoBot.Modules.Searches.Commands.Models;
|
using NadekoBot.Modules.Searches.Commands.Models;
|
||||||
using AngleSharp.Parser.Html;
|
|
||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom.Html;
|
using AngleSharp.Dom.Html;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using Configuration = AngleSharp.Configuration;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using Discord.Commands;
|
||||||
|
using ImageSharp.Processing.Processors;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches
|
namespace NadekoBot.Modules.Searches
|
||||||
{
|
{
|
||||||
[NadekoModule("Searches", "~")]
|
[NadekoModule("Searches", "~")]
|
||||||
public partial class Searches : NadekoModule
|
public partial class Searches : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Weather([Remainder] string query)
|
public async Task Weather([Remainder] string query)
|
||||||
@ -43,15 +41,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var data = JsonConvert.DeserializeObject<WeatherData>(response);
|
var data = JsonConvert.DeserializeObject<WeatherData>(response);
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.AddField(fb => fb.WithName("🌍 **Location**").WithValue(data.name + ", " + data.sys.country).WithIsInline(true))
|
.AddField(fb => fb.WithName("🌍 " + GetText("location")).WithValue(data.name + ", " + data.sys.country).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("📏 **Lat,Long**").WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true))
|
.AddField(fb => fb.WithName("📏 " + GetText("latlong")).WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("☁ **Condition**").WithValue(String.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true))
|
.AddField(fb => fb.WithName("☁ " + GetText("condition")).WithValue(string.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("😓 **Humidity**").WithValue($"{data.main.humidity}%").WithIsInline(true))
|
.AddField(fb => fb.WithName("😓 " + GetText("humidity")).WithValue($"{data.main.humidity}%").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("💨 **Wind Speed**").WithValue(data.wind.speed + " km/h").WithIsInline(true))
|
.AddField(fb => fb.WithName("💨 " + GetText("wind_speed")).WithValue(data.wind.speed + " km/h").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("🌡 **Temperature**").WithValue(data.main.temp + "°C").WithIsInline(true))
|
.AddField(fb => fb.WithName("🌡 " + GetText("temperature")).WithValue(data.main.temp + "°C").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("🔆 **Min - Max**").WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true))
|
.AddField(fb => fb.WithName("🔆 " + GetText("min_max")).WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("🌄 **Sunrise (utc)**").WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true))
|
.AddField(fb => fb.WithName("🌄 " + GetText("sunrise")).WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("🌇 **Sunset (utc)**").WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true))
|
.AddField(fb => fb.WithName("🌇 " + GetText("sunset")).WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true))
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithFooter(efb => efb.WithText("Powered by http://openweathermap.org"));
|
.WithFooter(efb => efb.WithText("Powered by http://openweathermap.org"));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -60,17 +58,15 @@ namespace NadekoBot.Modules.Searches
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Youtube([Remainder] string query = null)
|
public async Task Youtube([Remainder] string query = null)
|
||||||
{
|
{
|
||||||
if (!(await ValidateQuery(Context.Channel, query).ConfigureAwait(false))) return;
|
if (!await ValidateQuery(Context.Channel, query).ConfigureAwait(false)) return;
|
||||||
var result = (await NadekoBot.Google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault();
|
var result = (await NadekoBot.Google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault();
|
||||||
if (string.IsNullOrWhiteSpace(result))
|
if (string.IsNullOrWhiteSpace(result))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No results found for that query.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_results").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(result).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(result).ConfigureAwait(false);
|
||||||
|
|
||||||
//await Context.Channel.EmbedAsync(new Discord.API.Embed() { Video = new Discord.API.EmbedVideo() { Url = result.Replace("watch?v=", "embed/") }, Color = NadekoBot.OkColor }).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -82,7 +78,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var movie = await OmdbProvider.FindMovie(query);
|
var movie = await OmdbProvider.FindMovie(query);
|
||||||
if (movie == null)
|
if (movie == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed to find that movie.").ConfigureAwait(false);
|
await ReplyErrorLocalized("imdb_fail").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Context.Channel.EmbedAsync(movie.GetEmbed()).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(movie.GetEmbed()).ConfigureAwait(false);
|
||||||
@ -94,7 +90,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
var res = JObject.Parse(await http.GetStringAsync("http://www.random.cat/meow").ConfigureAwait(false));
|
var res = JObject.Parse(await http.GetStringAsync("http://www.random.cat/meow").ConfigureAwait(false));
|
||||||
await Context.Channel.SendMessageAsync(res["file"].ToString()).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(Uri.EscapeUriString(res["file"].ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,12 +118,12 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false);
|
var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false);
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
||||||
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
||||||
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
||||||
.WithDescription(res.Link)
|
.WithDescription(res.Link)
|
||||||
.WithImageUrl(res.Link)
|
.WithImageUrl(res.Link)
|
||||||
.WithTitle(Context.User.Mention);
|
.WithTitle(Context.User.ToString());
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -157,7 +153,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
||||||
.WithDescription(source)
|
.WithDescription(source)
|
||||||
.WithImageUrl(source)
|
.WithImageUrl(source)
|
||||||
.WithTitle(Context.User.Mention);
|
.WithTitle(Context.User.ToString());
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,12 +170,12 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
|
var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
||||||
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
||||||
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
||||||
.WithDescription(res.Link)
|
.WithDescription(res.Link)
|
||||||
.WithImageUrl(res.Link)
|
.WithImageUrl(res.Link)
|
||||||
.WithTitle(Context.User.Mention);
|
.WithTitle(Context.User.ToString());
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -205,12 +201,12 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50))
|
||||||
.WithUrl(fullQueryLink)
|
.WithUrl(fullQueryLink)
|
||||||
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
.WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?"))
|
||||||
.WithDescription(source)
|
.WithDescription(source)
|
||||||
.WithImageUrl(source)
|
.WithImageUrl(source)
|
||||||
.WithTitle(Context.User.Mention);
|
.WithTitle(Context.User.ToString());
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,13 +231,14 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
if (shortened == arg)
|
if (shortened == arg)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed to shorten that url.").ConfigureAwait(false);
|
await ReplyErrorLocalized("shorten_fail").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||||
.AddField(efb => efb.WithName("Original Url")
|
.AddField(efb => efb.WithName(GetText("original_url"))
|
||||||
.WithValue($"<{arg}>"))
|
.WithValue($"<{arg}>"))
|
||||||
.AddField(efb => efb.WithName("Short Url")
|
.AddField(efb => efb.WithName(GetText("short_url"))
|
||||||
.WithValue($"<{shortened}>")))
|
.WithValue($"<{shortened}>")))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -273,7 +270,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
var results = elems.Select<IElement, GoogleSearchResult?>(elem =>
|
var results = elems.Select<IElement, GoogleSearchResult?>(elem =>
|
||||||
{
|
{
|
||||||
var aTag = (elem.Children.FirstOrDefault().Children.FirstOrDefault() as IHtmlAnchorElement); // <h3> -> <a>
|
var aTag = (elem.Children.FirstOrDefault()?.Children.FirstOrDefault() as IHtmlAnchorElement); // <h3> -> <a>
|
||||||
var href = aTag?.Href;
|
var href = aTag?.Href;
|
||||||
var name = aTag?.TextContent;
|
var name = aTag?.TextContent;
|
||||||
if (href == null || name == null)
|
if (href == null || name == null)
|
||||||
@ -289,35 +286,31 @@ namespace NadekoBot.Modules.Searches
|
|||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Search For: " + terms.TrimTo(50))
|
.WithAuthor(eab => eab.WithName(GetText("search_for") + " " + terms.TrimTo(50))
|
||||||
.WithUrl(fullQueryLink)
|
.WithUrl(fullQueryLink)
|
||||||
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
||||||
.WithTitle(Context.User.Mention)
|
.WithTitle(Context.User.ToString())
|
||||||
.WithFooter(efb => efb.WithText(totalResults));
|
.WithFooter(efb => efb.WithText(totalResults));
|
||||||
|
|
||||||
var desc = await Task.WhenAll(results.Select(async res =>
|
var desc = await Task.WhenAll(results.Select(async res =>
|
||||||
$"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n"))
|
$"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
await Context.Channel.EmbedAsync(embed.WithDescription(String.Concat(desc))).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed.WithDescription(string.Concat(desc))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task MagicTheGathering([Remainder] string name = null)
|
public async Task MagicTheGathering([Remainder] string name)
|
||||||
{
|
{
|
||||||
var arg = name;
|
var arg = name;
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("Please enter a card name to search for.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
string response = "";
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
response = await http.GetStringAsync($"https://api.deckbrew.com/mtg/cards?name={Uri.EscapeUriString(arg)}")
|
var response = await http.GetStringAsync($"https://api.deckbrew.com/mtg/cards?name={Uri.EscapeUriString(arg)}")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var items = JArray.Parse(response).ToArray();
|
var items = JArray.Parse(response).ToArray();
|
||||||
@ -327,50 +320,46 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString());
|
var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString());
|
||||||
var cost = item["cost"].ToString();
|
var cost = item["cost"].ToString();
|
||||||
var desc = item["text"].ToString();
|
var desc = item["text"].ToString();
|
||||||
var types = String.Join(",\n", item["types"].ToObject<string[]>());
|
var types = string.Join(",\n", item["types"].ToObject<string[]>());
|
||||||
var img = item["editions"][0]["image_url"].ToString();
|
var img = item["editions"][0]["image_url"].ToString();
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle(item["name"].ToString())
|
.WithTitle(item["name"].ToString())
|
||||||
.WithDescription(desc)
|
.WithDescription(desc)
|
||||||
.WithImageUrl(img)
|
.WithImageUrl(img)
|
||||||
.AddField(efb => efb.WithName("Store Url").WithValue(storeUrl).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("store_url")).WithValue(storeUrl).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Cost").WithValue(cost).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("cost")).WithValue(cost).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Types").WithValue(types).WithIsInline(true));
|
.AddField(efb => efb.WithName(GetText("types")).WithValue(types).WithIsInline(true));
|
||||||
//.AddField(efb => efb.WithName("Store Url").WithValue(await NadekoBot.Google.ShortenUrl(items[0]["store_url"].ToString())).WithIsInline(true));
|
//.AddField(efb => efb.WithName("Store Url").WithValue(await NadekoBot.Google.ShortenUrl(items[0]["store_url"].ToString())).WithIsInline(true));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Error could not find the card '{arg}'.").ConfigureAwait(false);
|
await ReplyErrorLocalized("card_not_found").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Hearthstone([Remainder] string name = null)
|
public async Task Hearthstone([Remainder] string name)
|
||||||
{
|
{
|
||||||
var arg = name;
|
var arg = name;
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("Please enter a card name to search for.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
string response = "";
|
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||||
response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}")
|
var response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}")
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var items = JArray.Parse(response).Shuffle().ToList();
|
var items = JArray.Parse(response).Shuffle().ToList();
|
||||||
@ -393,17 +382,17 @@ namespace NadekoBot.Modules.Searches
|
|||||||
string msg = null;
|
string msg = null;
|
||||||
if (items.Count > 4)
|
if (items.Count > 4)
|
||||||
{
|
{
|
||||||
msg = "⚠ Found over 4 images. Showing random 4.";
|
msg = GetText("hs_over_x", 4);
|
||||||
}
|
}
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
await Task.Run(() => images.AsEnumerable().Merge().SaveAsPng(ms));
|
await Task.Run(() => images.AsEnumerable().Merge().Save(ms));
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Error occured.").ConfigureAwait(false);
|
|
||||||
_log.Error(ex);
|
_log.Error(ex);
|
||||||
|
await ReplyErrorLocalized("error_occured").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,23 +402,20 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var arg = query;
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("Please enter a sentence.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||||
http.DefaultRequestHeaders.Add("Accept", "text/plain");
|
http.DefaultRequestHeaders.Add("Accept", "text/plain");
|
||||||
var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(arg)}").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(query)}").ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
@ -441,7 +427,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed to yodify your sentence.").ConfigureAwait(false);
|
await ReplyErrorLocalized("yodify_error").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,22 +437,19 @@ namespace NadekoBot.Modules.Searches
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var arg = query;
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("Please enter a search term.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("Accept", "application/json");
|
http.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||||
var res = await http.GetStringAsync($"http://api.urbandictionary.com/v0/define?term={Uri.EscapeUriString(arg)}").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"http://api.urbandictionary.com/v0/define?term={Uri.EscapeUriString(query)}").ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var items = JObject.Parse(res);
|
var items = JObject.Parse(res);
|
||||||
@ -482,7 +465,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed finding a definition for that term.").ConfigureAwait(false);
|
await ReplyErrorLocalized("ud_error").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,39 +492,36 @@ namespace NadekoBot.Modules.Searches
|
|||||||
definition = ((JArray)JToken.Parse(sense.Definition.ToString())).First.ToString();
|
definition = ((JArray)JToken.Parse(sense.Definition.ToString())).First.ToString();
|
||||||
|
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Define: " + word)
|
.WithTitle(GetText("define") + " " + word)
|
||||||
.WithDescription(definition)
|
.WithDescription(definition)
|
||||||
.WithFooter(efb => efb.WithText(sense.Gramatical_info?.type));
|
.WithFooter(efb => efb.WithText(sense.Gramatical_info?.type));
|
||||||
|
|
||||||
if (sense.Examples != null)
|
if (sense.Examples != null)
|
||||||
embed.AddField(efb => efb.WithName("Example").WithValue(sense.Examples.First().text));
|
embed.AddField(efb => efb.WithName(GetText("example")).WithValue(sense.Examples.First().text));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Hashtag([Remainder] string query = null)
|
public async Task Hashtag([Remainder] string query)
|
||||||
{
|
{
|
||||||
var arg = query;
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("Please enter a search term.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false);
|
await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
var res = "";
|
string res;
|
||||||
using (var http = new HttpClient())
|
using (var http = new HttpClient())
|
||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey);
|
||||||
res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(arg)}.json").ConfigureAwait(false);
|
res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(query)}.json").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -560,7 +540,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Failed finding a definition for that tag.").ConfigureAwait(false);
|
await ReplyErrorLocalized("hashtag_error").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +554,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var fact = JObject.Parse(response)["facts"][0].ToString();
|
var fact = JObject.Parse(response)["facts"][0].ToString();
|
||||||
await Context.Channel.SendConfirmAsync("🐈fact", fact).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("🐈" + GetText("catfact"), fact).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,7 +591,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var result = await http.GetStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query));
|
var result = await http.GetStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query));
|
||||||
var data = JsonConvert.DeserializeObject<WikipediaApiModel>(result);
|
var data = JsonConvert.DeserializeObject<WikipediaApiModel>(result);
|
||||||
if (data.Query.Pages[0].Missing)
|
if (data.Query.Pages[0].Missing)
|
||||||
await Context.Channel.SendErrorAsync("That page could not be found.").ConfigureAwait(false);
|
await ReplyErrorLocalized("wiki_page_not_found").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -625,28 +605,21 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return;
|
return;
|
||||||
var img = new ImageSharp.Image(50, 50);
|
var img = new ImageSharp.Image(50, 50);
|
||||||
|
|
||||||
img.BackgroundColor(new ImageSharp.Color(color));
|
img.ApplyProcessor(new BackgroundColorProcessor<ImageSharp.Color>(ImageSharp.Color.FromHex(color)), img.Bounds);
|
||||||
|
|
||||||
await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); ;
|
await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Videocall([Remainder] params IUser[] users)
|
public async Task Videocall(params IUser[] users)
|
||||||
{
|
{
|
||||||
try
|
var allUsrs = users.Append(Context.User);
|
||||||
|
var allUsrsArray = allUsrs.ToArray();
|
||||||
|
var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Username[0].ToString()));
|
||||||
|
str += new NadekoRandom().Next();
|
||||||
|
foreach (var usr in allUsrsArray)
|
||||||
{
|
{
|
||||||
var allUsrs = users.Append(Context.User);
|
await (await usr.CreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false);
|
||||||
var allUsrsArray = allUsrs.ToArray();
|
|
||||||
var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Username[0].ToString()));
|
|
||||||
str += new NadekoRandom().Next();
|
|
||||||
foreach (var usr in allUsrsArray)
|
|
||||||
{
|
|
||||||
await (await (usr as IGuildUser).CreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Error(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,11 +639,11 @@ namespace NadekoBot.Modules.Searches
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Wikia(string target, [Remainder] string query = null)
|
public async Task Wikia(string target, [Remainder] string query)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(query))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Please enter a target wikia, followed by search query.").ConfigureAwait(false);
|
await ReplyErrorLocalized("wikia_input_error").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
@ -682,90 +655,87 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var res = await http.GetStringAsync($"http://www.{Uri.EscapeUriString(target)}.wikia.com/api/v1/Search/List?query={Uri.EscapeUriString(query)}&limit=25&minArticleQuality=10&batch=1&namespaces=0%2C14").ConfigureAwait(false);
|
var res = await http.GetStringAsync($"http://www.{Uri.EscapeUriString(target)}.wikia.com/api/v1/Search/List?query={Uri.EscapeUriString(query)}&limit=25&minArticleQuality=10&batch=1&namespaces=0%2C14").ConfigureAwait(false);
|
||||||
var items = JObject.Parse(res);
|
var items = JObject.Parse(res);
|
||||||
var found = items["items"][0];
|
var found = items["items"][0];
|
||||||
var response = $@"`Title:` {found["title"].ToString()}
|
var response = $@"`{GetText("title")}` {found["title"]}
|
||||||
`Quality:` {found["quality"]}
|
`{GetText("quality")}` {found["quality"]}
|
||||||
`URL:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}";
|
`{GetText("url")}:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}";
|
||||||
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Failed finding `{query}`.").ConfigureAwait(false);
|
await ReplyErrorLocalized("wikia_error").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task MCPing([Remainder] string query = null)
|
//public async Task MCPing([Remainder] string query2 = null)
|
||||||
{
|
//{
|
||||||
var arg = query;
|
// var query = query2;
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
// if (string.IsNullOrWhiteSpace(query))
|
||||||
{
|
// return;
|
||||||
await Context.Channel.SendErrorAsync("💢 Please enter a `ip:port`.").ConfigureAwait(false);
|
// await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
return;
|
// using (var http = new HttpClient())
|
||||||
}
|
// {
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
// http.DefaultRequestHeaders.Clear();
|
||||||
using (var http = new HttpClient())
|
// var ip = query.Split(':')[0];
|
||||||
{
|
// var port = query.Split(':')[1];
|
||||||
http.DefaultRequestHeaders.Clear();
|
// var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false);
|
||||||
string ip = arg.Split(':')[0];
|
// try
|
||||||
string port = arg.Split(':')[1];
|
// {
|
||||||
var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false);
|
// var items = JObject.Parse(res);
|
||||||
try
|
// var sb = new StringBuilder();
|
||||||
{
|
// var ping = (int)Math.Ceiling(double.Parse(items["latency"].ToString()));
|
||||||
var items = JObject.Parse(res);
|
// sb.AppendLine($"`Server:` {query}");
|
||||||
var sb = new StringBuilder();
|
// sb.AppendLine($"`Version:` {items["version"]["name"]} / Protocol {items["version"]["protocol"]}");
|
||||||
int ping = (int)Math.Ceiling(Double.Parse(items["latency"].ToString()));
|
// sb.AppendLine($"`Description:` {items["description"]}");
|
||||||
sb.AppendLine($"`Server:` {arg}");
|
// sb.AppendLine($"`Online Players:` {items["players"]["online"]}/{items["players"]["max"]}");
|
||||||
sb.AppendLine($"`Version:` {items["version"]["name"].ToString()} / Protocol {items["version"]["protocol"].ToString()}");
|
// sb.Append($"`Latency:` {ping}");
|
||||||
sb.AppendLine($"`Description:` {items["description"].ToString()}");
|
// await Context.Channel.SendMessageAsync(sb.ToString());
|
||||||
sb.AppendLine($"`Online Players:` {items["players"]["online"].ToString()}/{items["players"]["max"].ToString()}");
|
// }
|
||||||
sb.Append($"`Latency:` {ping}");
|
// catch
|
||||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
// {
|
||||||
}
|
// await Context.Channel.SendErrorAsync($"Failed finding `{query}`.").ConfigureAwait(false);
|
||||||
catch
|
// }
|
||||||
{
|
// }
|
||||||
await Context.Channel.SendErrorAsync($"Failed finding `{arg}`.").ConfigureAwait(false);
|
//}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task MCQ([Remainder] string query = null)
|
//public async Task MCQ([Remainder] string query = null)
|
||||||
{
|
//{
|
||||||
var arg = query;
|
// var arg = query;
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
// if (string.IsNullOrWhiteSpace(arg))
|
||||||
{
|
// {
|
||||||
await Context.Channel.SendErrorAsync("Please enter `ip:port`.").ConfigureAwait(false);
|
// await Context.Channel.SendErrorAsync("Please enter `ip:port`.").ConfigureAwait(false);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
// await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
using (var http = new HttpClient())
|
// using (var http = new HttpClient())
|
||||||
{
|
// {
|
||||||
http.DefaultRequestHeaders.Clear();
|
// http.DefaultRequestHeaders.Clear();
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
string ip = arg.Split(':')[0];
|
// var ip = arg.Split(':')[0];
|
||||||
string port = arg.Split(':')[1];
|
// var port = arg.Split(':')[1];
|
||||||
var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false);
|
// var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false);
|
||||||
var items = JObject.Parse(res);
|
// var items = JObject.Parse(res);
|
||||||
var sb = new StringBuilder();
|
// var sb = new StringBuilder();
|
||||||
sb.AppendLine($"`Server:` {arg.ToString()} 〘Status: {items["status"]}〙");
|
// sb.AppendLine($"`Server:` {arg} 〘Status: {items["status"]}〙");
|
||||||
sb.AppendLine($"`Player List (First 5):`");
|
// sb.AppendLine("`Player List (First 5):`");
|
||||||
foreach (var item in items["Playerlist"].Take(5))
|
// foreach (var item in items["Playerlist"].Take(5))
|
||||||
{
|
// {
|
||||||
sb.AppendLine($"〔:rosette: {item}〕");
|
// sb.AppendLine($"〔:rosette: {item}〕");
|
||||||
}
|
// }
|
||||||
sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}");
|
// sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}");
|
||||||
sb.AppendLine($"`Plugins:` {items["Plugins"]}");
|
// sb.AppendLine($"`Plugins:` {items["Plugins"]}");
|
||||||
sb.Append($"`Version:` {items["Version"]}");
|
// sb.Append($"`Version:` {items["Version"]}");
|
||||||
await Context.Channel.SendMessageAsync(sb.ToString());
|
// await Context.Channel.SendMessageAsync(sb.ToString());
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
await Context.Channel.SendErrorAsync($"Failed finding server `{arg}`.").ConfigureAwait(false);
|
// await Context.Channel.SendErrorAsync($"Failed finding server `{arg}`.").ConfigureAwait(false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
public enum DapiSearchType
|
public enum DapiSearchType
|
||||||
{
|
{
|
||||||
@ -776,7 +746,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
Yandere
|
Yandere
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type)
|
public async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type)
|
||||||
{
|
{
|
||||||
var channel = umsg.Channel;
|
var channel = umsg.Channel;
|
||||||
|
|
||||||
@ -785,7 +755,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
var url = await InternalDapiSearch(tag, type).ConfigureAwait(false);
|
var url = await InternalDapiSearch(tag, type).ConfigureAwait(false);
|
||||||
|
|
||||||
if (url == null)
|
if (url == null)
|
||||||
await channel.SendErrorAsync(umsg.Author.Mention + " No results.");
|
await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results"));
|
||||||
else
|
else
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription(umsg.Author.Mention + " " + tag)
|
.WithDescription(umsg.Author.Mention + " " + tag)
|
||||||
@ -796,7 +766,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
public static async Task<string> InternalDapiSearch(string tag, DapiSearchType type)
|
public static async Task<string> InternalDapiSearch(string tag, DapiSearchType type)
|
||||||
{
|
{
|
||||||
tag = tag?.Replace(" ", "_");
|
tag = tag?.Replace(" ", "_");
|
||||||
string website = "";
|
var website = "";
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case DapiSearchType.Safebooru:
|
case DapiSearchType.Safebooru:
|
||||||
@ -841,10 +811,10 @@ namespace NadekoBot.Modules.Searches
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static async Task<bool> ValidateQuery(IMessageChannel ch, string query)
|
public async Task<bool> ValidateQuery(IMessageChannel ch, string query)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(query.Trim())) return true;
|
if (!string.IsNullOrWhiteSpace(query)) return true;
|
||||||
await ch.SendErrorAsync("Please specify search parameters.").ConfigureAwait(false);
|
await ch.SendErrorAsync(GetText("specify_search_params")).ConfigureAwait(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CalcCommands : ModuleBase
|
public class CalcCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Calculate([Remainder] string expression)
|
public async Task Calculate([Remainder] string expression)
|
||||||
@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
expr.EvaluateParameter += Expr_EvaluateParameter;
|
expr.EvaluateParameter += Expr_EvaluateParameter;
|
||||||
var result = expr.Evaluate();
|
var result = expr.Evaluate();
|
||||||
if (expr.Error == null)
|
if (expr.Error == null)
|
||||||
await Context.Channel.SendConfirmAsync("Result", $"{result}");
|
await Context.Channel.SendConfirmAsync("⚙ " + GetText("result"), result.ToString());
|
||||||
else
|
else
|
||||||
await Context.Channel.SendErrorAsync($"⚙ Error", expr.Error);
|
await Context.Channel.SendErrorAsync("⚙ " + GetText("error"), expr.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Expr_EvaluateParameter(string name, NCalc.ParameterArgs args)
|
private static void Expr_EvaluateParameter(string name, NCalc.ParameterArgs args)
|
||||||
@ -42,29 +42,26 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task CalcOps()
|
public async Task CalcOps()
|
||||||
{
|
{
|
||||||
var selection = typeof(Math).GetTypeInfo().GetMethods().Except(typeof(object).GetTypeInfo().GetMethods()).Distinct(new MethodInfoEqualityComparer()).Select(x =>
|
var selection = typeof(Math).GetTypeInfo()
|
||||||
{
|
.GetMethods()
|
||||||
return x.Name;
|
.Distinct(new MethodInfoEqualityComparer())
|
||||||
})
|
.Select(x => x.Name)
|
||||||
.Except(new[] { "ToString",
|
.Except(new[]
|
||||||
"Equals",
|
{
|
||||||
"GetHashCode",
|
"ToString",
|
||||||
"GetType"});
|
"Equals",
|
||||||
await Context.Channel.SendConfirmAsync("Available functions in calc", string.Join(", ", selection));
|
"GetHashCode",
|
||||||
|
"GetType"
|
||||||
|
});
|
||||||
|
await Context.Channel.SendConfirmAsync(GetText("utility_calcops", Prefix), string.Join(", ", selection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MethodInfoEqualityComparer : IEqualityComparer<MethodInfo>
|
private class MethodInfoEqualityComparer : IEqualityComparer<MethodInfo>
|
||||||
{
|
{
|
||||||
public bool Equals(MethodInfo x, MethodInfo y) => x.Name == y.Name;
|
public bool Equals(MethodInfo x, MethodInfo y) => x.Name == y.Name;
|
||||||
|
|
||||||
public int GetHashCode(MethodInfo obj) => obj.Name.GetHashCode();
|
public int GetHashCode(MethodInfo obj) => obj.Name.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionContext
|
|
||||||
{
|
|
||||||
public double Pi { get; set; } = Math.PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,8 +3,6 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NLog;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -14,12 +12,11 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CrossServerTextChannel : ModuleBase
|
public class CrossServerTextChannel : NadekoSubmodule
|
||||||
{
|
{
|
||||||
static CrossServerTextChannel()
|
static CrossServerTextChannel()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
NadekoBot.Client.MessageReceived += async imsg =>
|
||||||
NadekoBot.Client.MessageReceived += async (imsg) =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -37,23 +34,32 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var set = subscriber.Value;
|
var set = subscriber.Value;
|
||||||
if (!set.Contains(channel))
|
if (!set.Contains(channel))
|
||||||
continue;
|
continue;
|
||||||
foreach (var chan in set.Except(new[] { channel }))
|
foreach (var chan in set.Except(new[] {channel}))
|
||||||
{
|
{
|
||||||
try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try
|
||||||
|
{
|
||||||
|
await chan.SendMessageAsync(GetMessage(channel, (IGuildUser) msg.Author,
|
||||||
|
msg)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch
|
||||||
_log.Warn(ex);
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) =>
|
private static string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) =>
|
||||||
$"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
|
$"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
|
||||||
|
|
||||||
public static readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers = new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
public static readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
|
||||||
private static Logger _log { get; }
|
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -64,8 +70,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var set = new ConcurrentHashSet<ITextChannel>();
|
var set = new ConcurrentHashSet<ITextChannel>();
|
||||||
if (Subscribers.TryAdd(token, set))
|
if (Subscribers.TryAdd(token, set))
|
||||||
{
|
{
|
||||||
set.Add((ITextChannel)Context.Channel);
|
set.Add((ITextChannel) Context.Channel);
|
||||||
await ((IGuildUser)Context.User).SendConfirmAsync("This is your CSC token", token.ToString()).ConfigureAwait(false);
|
await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString())
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +84,8 @@ namespace NadekoBot.Modules.Utility
|
|||||||
ConcurrentHashSet<ITextChannel> set;
|
ConcurrentHashSet<ITextChannel> set;
|
||||||
if (!Subscribers.TryGetValue(token, out set))
|
if (!Subscribers.TryGetValue(token, out set))
|
||||||
return;
|
return;
|
||||||
set.Add((ITextChannel)Context.Channel);
|
set.Add((ITextChannel) Context.Channel);
|
||||||
await Context.Channel.SendConfirmAsync("Joined cross server channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("csc_join").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -88,9 +95,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
foreach (var subscriber in Subscribers)
|
foreach (var subscriber in Subscribers)
|
||||||
{
|
{
|
||||||
subscriber.Value.TryRemove((ITextChannel)Context.Channel);
|
subscriber.Value.TryRemove((ITextChannel) Context.Channel);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendMessageAsync("Left cross server channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("csc_leave").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class InfoCommands : ModuleBase
|
public class InfoCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (string.IsNullOrWhiteSpace(guildName))
|
if (string.IsNullOrWhiteSpace(guildName))
|
||||||
guild = channel.Guild;
|
guild = channel.Guild;
|
||||||
else
|
else
|
||||||
guild = NadekoBot.Client.GetGuilds().Where(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant()).FirstOrDefault();
|
guild = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant());
|
||||||
if (guild == null)
|
if (guild == null)
|
||||||
return;
|
return;
|
||||||
var ownername = await guild.GetUserAsync(guild.OwnerId);
|
var ownername = await guild.GetUserAsync(guild.OwnerId);
|
||||||
@ -37,22 +37,22 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (string.IsNullOrWhiteSpace(features))
|
if (string.IsNullOrWhiteSpace(features))
|
||||||
features = "-";
|
features = "-";
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName("Server Info"))
|
.WithAuthor(eab => eab.WithName(GetText("server_info")))
|
||||||
.WithTitle(guild.Name)
|
.WithTitle(guild.Name)
|
||||||
.AddField(fb => fb.WithName("**ID**").WithValue(guild.Id.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("id")).WithValue(guild.Id.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Owner**").WithValue(ownername.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("owner")).WithValue(ownername.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Members**").WithValue(users.Count.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("members")).WithValue(users.Count.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Text Channels**").WithValue(textchn.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("text_channels")).WithValue(textchn.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("voice_channels")).WithValue(voicechn.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("region")).WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("roles")).WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Features**").WithValue(features).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true))
|
||||||
.WithImageUrl(guild.IconUrl)
|
.WithImageUrl(guild.IconUrl)
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
if (guild.Emojis.Any())
|
if (guild.Emojis.Any())
|
||||||
{
|
{
|
||||||
embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emojis.Count})").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||||
}
|
}
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -69,9 +69,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithTitle(ch.Name)
|
.WithTitle(ch.Name)
|
||||||
.WithDescription(ch.Topic?.SanitizeMentions())
|
.WithDescription(ch.Topic?.SanitizeMentions())
|
||||||
.AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("id")).WithValue(ch.Id.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("users")).WithValue(usercount.ToString()).WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -86,15 +86,15 @@ namespace NadekoBot.Modules.Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.AddField(fb => fb.WithName("**Name**").WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true));
|
.AddField(fb => fb.WithName(GetText("name")).WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true));
|
||||||
if (!string.IsNullOrWhiteSpace(user.Nickname))
|
if (!string.IsNullOrWhiteSpace(user.Nickname))
|
||||||
{
|
{
|
||||||
embed.AddField(fb => fb.WithName("**Nickname**").WithValue(user.Nickname).WithIsInline(true));
|
embed.AddField(fb => fb.WithName(GetText("nickname")).WithValue(user.Nickname).WithIsInline(true));
|
||||||
}
|
}
|
||||||
embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true))
|
embed.AddField(fb => fb.WithName(GetText("id")).WithValue(user.Id.ToString()).WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "unavail."}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("joined_server")).WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "?"}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("joined_discord")).WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("roles")).WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
|
|
||||||
if (user.AvatarId != null)
|
if (user.AvatarId != null)
|
||||||
@ -119,12 +119,17 @@ namespace NadekoBot.Modules.Utility
|
|||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage))
|
foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage))
|
||||||
{
|
{
|
||||||
str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total");
|
str.AppendLine(GetText("activity_line",
|
||||||
|
++startCount,
|
||||||
|
Format.Bold(kvp.Key.ToString()),
|
||||||
|
kvp.Value / NadekoBot.Stats.GetUptime().TotalSeconds, kvp.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}")
|
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
||||||
|
.WithTitle(GetText("activity_page", page))
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total."))
|
.WithFooter(efb => efb.WithText(GetText("activity_users_total",
|
||||||
|
NadekoBot.CommandHandler.UserMessagesSent.Count)))
|
||||||
.WithDescription(str.ToString()));
|
.WithDescription(str.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,45 +5,47 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class RepeatCommands : ModuleBase
|
public class RepeatCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//guildid/RepeatRunners
|
//guildid/RepeatRunners
|
||||||
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> repeaters { get; }
|
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
|
||||||
|
|
||||||
|
private static bool _ready;
|
||||||
|
|
||||||
public class RepeatRunner
|
public class RepeatRunner
|
||||||
{
|
{
|
||||||
private Logger _log { get; }
|
private readonly Logger _log;
|
||||||
|
|
||||||
private CancellationTokenSource source { get; set; }
|
private CancellationTokenSource source { get; set; }
|
||||||
private CancellationToken token { get; set; }
|
private CancellationToken token { get; set; }
|
||||||
public Repeater Repeater { get; }
|
public Repeater Repeater { get; }
|
||||||
public ITextChannel Channel { get; }
|
public SocketGuild Guild { get; }
|
||||||
|
public ITextChannel Channel { get; private set; }
|
||||||
|
|
||||||
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
|
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
this.Repeater = repeater;
|
Repeater = repeater;
|
||||||
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId);
|
Channel = channel;
|
||||||
if (Channel == null)
|
|
||||||
return;
|
Guild = NadekoBot.Client.GetGuild(repeater.GuildId);
|
||||||
Task.Run(Run);
|
if(Guild!=null)
|
||||||
|
Task.Run(Run);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -64,10 +66,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
if (oldMsg != null)
|
if (oldMsg != null)
|
||||||
try { await oldMsg.DeleteAsync(); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await oldMsg.DeleteAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
if (Channel == null)
|
||||||
|
Channel = Guild.GetTextChannel(Repeater.ChannelId);
|
||||||
|
|
||||||
|
if (Channel != null)
|
||||||
|
oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
@ -85,7 +98,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) { }
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
@ -101,22 +116,23 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}";
|
return
|
||||||
|
$"{Channel.Mention} | {(int) Repeater.Interval.TotalHours}:{Repeater.Interval:mm} | {Repeater.Message.TrimTo(33)}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RepeatCommands()
|
static RepeatCommands()
|
||||||
{
|
{
|
||||||
var _log = LogManager.GetCurrentClassLogger();
|
var _ = Task.Run(async () =>
|
||||||
var sw = Stopwatch.StartNew();
|
{
|
||||||
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
|
Repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
|
||||||
.ToDictionary(gc => gc.GuildId,
|
.ToDictionary(gc => gc.GuildId,
|
||||||
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr))
|
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters
|
||||||
.Where(gr => gr.Channel != null))));
|
.Select(gr => new RepeatRunner(gr))
|
||||||
|
.Where(x => x.Guild != null))));
|
||||||
sw.Stop();
|
_ready = true;
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -124,11 +140,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task RepeatInvoke(int index)
|
public async Task RepeatInvoke(int index)
|
||||||
{
|
{
|
||||||
|
if (!_ready)
|
||||||
|
return;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
ConcurrentQueue<RepeatRunner> rep;
|
ConcurrentQueue<RepeatRunner> rep;
|
||||||
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
|
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false);
|
await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +154,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
if (index >= repList.Count)
|
if (index >= repList.Count)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
|
await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var repeater = repList[index].Repeater;
|
var repeater = repList[index].Repeater;
|
||||||
@ -151,19 +169,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task RepeatRemove(int index)
|
public async Task RepeatRemove(int index)
|
||||||
{
|
{
|
||||||
|
if (!_ready)
|
||||||
|
return;
|
||||||
if (index < 1)
|
if (index < 1)
|
||||||
return;
|
return;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
|
|
||||||
ConcurrentQueue<RepeatRunner> rep;
|
ConcurrentQueue<RepeatRunner> rep;
|
||||||
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
|
if (!Repeaters.TryGetValue(Context.Guild.Id, out rep))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var repeaterList = rep.ToList();
|
var repeaterList = rep.ToList();
|
||||||
|
|
||||||
if (index >= repeaterList.Count)
|
if (index >= repeaterList.Count)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
|
await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,8 +199,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
|
if (Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
|
||||||
await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("message_repeater"),
|
||||||
|
GetText("repeater_stopped", index + 1) + $"\n\n{repeater}").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -189,6 +210,8 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task Repeat(int minutes, [Remainder] string message)
|
public async Task Repeat(int minutes, [Remainder] string message)
|
||||||
{
|
{
|
||||||
|
if (!_ready)
|
||||||
|
return;
|
||||||
if (minutes < 1 || minutes > 10080)
|
if (minutes < 1 || minutes > 10080)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -214,15 +237,20 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel);
|
var rep = new RepeatRunner(toAdd, (ITextChannel) Context.Channel);
|
||||||
|
|
||||||
repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] { rep }), (key, old) =>
|
Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] {rep}), (key, old) =>
|
||||||
{
|
{
|
||||||
old.Enqueue(rep);
|
old.Enqueue(rep);
|
||||||
return old;
|
return old;
|
||||||
});
|
});
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(
|
||||||
|
"🔁 " + GetText("repeater",
|
||||||
|
Format.Bold(rep.Repeater.Message),
|
||||||
|
Format.Bold(rep.Repeater.Interval.Days.ToString()),
|
||||||
|
Format.Bold(rep.Repeater.Interval.Hours.ToString()),
|
||||||
|
Format.Bold(rep.Repeater.Interval.Minutes.ToString()))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -230,27 +258,33 @@ namespace NadekoBot.Modules.Utility
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task RepeatList()
|
public async Task RepeatList()
|
||||||
{
|
{
|
||||||
|
if (!_ready)
|
||||||
|
return;
|
||||||
ConcurrentQueue<RepeatRunner> repRunners;
|
ConcurrentQueue<RepeatRunner> repRunners;
|
||||||
if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners))
|
if (!Repeaters.TryGetValue(Context.Guild.Id, out repRunners))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var replist = repRunners.ToList();
|
var replist = repRunners.ToList();
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < replist.Count; i++)
|
for (var i = 0; i < replist.Count; i++)
|
||||||
{
|
{
|
||||||
var rep = replist[i];
|
var rep = replist[i];
|
||||||
|
|
||||||
sb.AppendLine($"`{i + 1}.` {rep.ToString()}");
|
sb.AppendLine($"`{i + 1}.` {rep}");
|
||||||
}
|
}
|
||||||
|
var desc = sb.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(desc))
|
||||||
|
desc = GetText("no_active_repeaters");
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("List Of Repeaters")
|
.WithTitle(GetText("list_of_repeaters"))
|
||||||
.WithDescription(sb.ToString()))
|
.WithDescription(desc))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class QuoteCommands : ModuleBase
|
public class QuoteCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -32,10 +33,11 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (quotes.Any())
|
if (quotes.Any())
|
||||||
await Context.Channel.SendConfirmAsync($"💬 **Page {page + 1} of quotes:**\n```xl\n" + String.Join("\n", quotes.Select((q) => $"{q.Keyword,-20} by {q.AuthorName}")) + "\n```")
|
await Context.Channel.SendConfirmAsync(GetText("quotes_page", page + 1),
|
||||||
|
string.Join("\n", quotes.Select(q => $"{q.Keyword,-20} by {q.AuthorName}")))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendErrorAsync("No quotes on this page.").ConfigureAwait(false);
|
await ReplyErrorLocalized("quotes_page_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -56,9 +58,41 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (quote == null)
|
if (quote == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
CREmbed crembed;
|
||||||
|
if (CREmbed.TryParse(quote.Text, out crembed))
|
||||||
|
{
|
||||||
|
try { await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn("Sending CREmbed failed");
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions());
|
await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task SearchQuote(string keyword, [Remainder] string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text))
|
||||||
|
return;
|
||||||
|
|
||||||
|
keyword = keyword.ToUpperInvariant();
|
||||||
|
|
||||||
|
Quote keywordquote;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
keywordquote = await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keywordquote == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await Context.Channel.SendMessageAsync("💬 " + keyword + ": " + keywordquote.Text.SanitizeMentions());
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task AddQuote(string keyword, [Remainder] string text)
|
public async Task AddQuote(string keyword, [Remainder] string text)
|
||||||
@ -80,7 +114,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
});
|
});
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync("✅ Quote added.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("quote_added").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -102,7 +136,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (qs == null || !qs.Any())
|
if (qs == null || !qs.Any())
|
||||||
{
|
{
|
||||||
sucess = false;
|
sucess = false;
|
||||||
response = "No quotes found which you can remove.";
|
response = GetText("quotes_remove_none");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -111,7 +145,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
uow.Quotes.Remove(q);
|
uow.Quotes.Remove(q);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
sucess = true;
|
sucess = true;
|
||||||
response = "🗑 **Deleted a random quote.**";
|
response = GetText("quote_deleted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(sucess)
|
if(sucess)
|
||||||
@ -139,7 +173,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"🗑 **Deleted all quotes** with **{keyword}** keyword.");
|
await ReplyConfirmLocalized("quotes_deleted", Format.Bold(keyword)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,21 +17,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class RemindCommands : ModuleBase
|
public class RemindCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
readonly Regex _regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
||||||
Regex regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
|
|
||||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||||
|
|
||||||
private static string RemindMessageFormat { get; }
|
private static string remindMessageFormat { get; }
|
||||||
|
|
||||||
private static IDictionary<string, Func<Reminder, string>> replacements = new Dictionary<string, Func<Reminder, string>>
|
private static readonly IDictionary<string, Func<Reminder, string>> _replacements = new Dictionary<string, Func<Reminder, string>>
|
||||||
{
|
{
|
||||||
{ "%message%" , (r) => r.Message },
|
{ "%message%" , (r) => r.Message },
|
||||||
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
{ "%user%", (r) => $"<@!{r.UserId}>" },
|
||||||
{ "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
{ "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"}
|
||||||
};
|
};
|
||||||
private static Logger _log { get; }
|
|
||||||
|
private new static readonly Logger _log;
|
||||||
|
|
||||||
static RemindCommands()
|
static RemindCommands()
|
||||||
{
|
{
|
||||||
@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
reminders = uow.Reminders.GetAll().ToList();
|
reminders = uow.Reminders.GetAll().ToList();
|
||||||
}
|
}
|
||||||
RemindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat;
|
remindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat;
|
||||||
|
|
||||||
foreach (var r in reminders)
|
foreach (var r in reminders)
|
||||||
{
|
{
|
||||||
@ -58,10 +58,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (time.TotalMilliseconds > int.MaxValue)
|
if (time.TotalMilliseconds > int.MaxValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Task.Delay(time);
|
await Task.Delay(time).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IMessageChannel ch = null;
|
IMessageChannel ch;
|
||||||
if (r.IsPrivate)
|
if (r.IsPrivate)
|
||||||
{
|
{
|
||||||
ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false);
|
ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false);
|
||||||
@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
await ch.SendMessageAsync(
|
await ch.SendMessageAsync(
|
||||||
replacements.Aggregate(RemindMessageFormat,
|
_replacements.Aggregate(remindMessageFormat,
|
||||||
(cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
(cur, replace) => cur.Replace(replace.Key, replace.Value(r)))
|
||||||
.SanitizeMentions()
|
.SanitizeMentions()
|
||||||
).ConfigureAwait(false); //it works trust me
|
).ConfigureAwait(false); //it works trust me
|
||||||
@ -119,27 +119,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
if (ch == null)
|
var m = _regex.Match(timeStr);
|
||||||
{
|
|
||||||
await channel.SendErrorAsync($"{Context.User.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var m = regex.Match(timeStr);
|
|
||||||
|
|
||||||
if (m.Length == 0)
|
if (m.Length == 0)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Not a valid time format. Type `-h .remind`").ConfigureAwait(false);
|
await ReplyErrorLocalized("remind_invalid_format").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string output = "";
|
string output = "";
|
||||||
var namesAndValues = new Dictionary<string, int>();
|
var namesAndValues = new Dictionary<string, int>();
|
||||||
|
|
||||||
foreach (var groupName in regex.GetGroupNames())
|
foreach (var groupName in _regex.GetGroupNames())
|
||||||
{
|
{
|
||||||
if (groupName == "0") continue;
|
if (groupName == "0") continue;
|
||||||
int value = 0;
|
int value;
|
||||||
int.TryParse(m.Groups[groupName].Value, out value);
|
int.TryParse(m.Groups[groupName].Value, out value);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(m.Groups[groupName].Value))
|
if (string.IsNullOrEmpty(m.Groups[groupName].Value))
|
||||||
@ -147,7 +141,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
namesAndValues[groupName] = 0;
|
namesAndValues[groupName] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (value < 1 ||
|
if (value < 1 ||
|
||||||
(groupName == "months" && value > 1) ||
|
(groupName == "months" && value > 1) ||
|
||||||
(groupName == "weeks" && value > 4) ||
|
(groupName == "weeks" && value > 4) ||
|
||||||
(groupName == "days" && value >= 7) ||
|
(groupName == "days" && value >= 7) ||
|
||||||
@ -157,8 +151,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await channel.SendErrorAsync($"Invalid {groupName} value.").ConfigureAwait(false);
|
await channel.SendErrorAsync($"Invalid {groupName} value.").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
namesAndValues[groupName] = value;
|
||||||
namesAndValues[groupName] = value;
|
|
||||||
output += m.Groups[groupName].Value + " " + groupName + " ";
|
output += m.Groups[groupName].Value + " " + groupName + " ";
|
||||||
}
|
}
|
||||||
var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] +
|
var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] +
|
||||||
@ -184,17 +177,26 @@ namespace NadekoBot.Modules.Utility
|
|||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
try { await channel.SendConfirmAsync($"⏰ I will remind **\"{(ch is ITextChannel ? ((ITextChannel)ch).Name : Context.User.Username)}\"** to **\"{message.SanitizeMentions()}\"** in **{output}** `({time:d.M.yyyy.} at {time:HH:mm})`").ConfigureAwait(false); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await channel.SendConfirmAsync(
|
||||||
|
"⏰ " + GetText("remind",
|
||||||
|
Format.Bold(ch is ITextChannel ? ((ITextChannel) ch).Name : Context.User.Username),
|
||||||
|
Format.Bold(message.SanitizeMentions()),
|
||||||
|
Format.Bold(output),
|
||||||
|
time, time)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
await StartReminder(rem);
|
await StartReminder(rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task RemindTemplate([Remainder] string arg)
|
public async Task RemindTemplate([Remainder] string arg)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(arg))
|
if (string.IsNullOrWhiteSpace(arg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -203,7 +205,8 @@ namespace NadekoBot.Modules.Utility
|
|||||||
uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim();
|
uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim();
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await channel.SendConfirmAsync("🆗 New remind template set.");
|
|
||||||
|
await ReplyConfirmLocalized("remind_template").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ using Newtonsoft.Json;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -21,12 +20,12 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public partial class Utility
|
public partial class Utility
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class UnitConverterCommands : ModuleBase
|
public class UnitConverterCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
public static List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
||||||
private static Logger _log { get; }
|
private new static readonly Logger _log;
|
||||||
private static Timer _timer;
|
private static Timer _timer;
|
||||||
private static TimeSpan updateInterval = new TimeSpan(12, 0, 0);
|
private static readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0);
|
||||||
|
|
||||||
static UnitConverterCommands()
|
static UnitConverterCommands()
|
||||||
{
|
{
|
||||||
@ -55,7 +54,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
_log.Warn("Could not load units: " + e.Message);
|
_log.Warn("Could not load units: " + e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_timer = new Timer(async (obj) => await UpdateCurrency(), null, (int)updateInterval.TotalMilliseconds, (int)updateInterval.TotalMilliseconds);
|
_timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UpdateCurrency()
|
public static async Task UpdateCurrency()
|
||||||
@ -93,15 +92,34 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_log.Warn("Failed updating currency.");
|
_log.Warn("Failed updating currency. Ignore this.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
//[RequireContext(ContextType.Guild)]
|
||||||
|
//public async Task Aurorina(IGuildUser usr = null)
|
||||||
|
//{
|
||||||
|
// var rng = new NadekoRandom();
|
||||||
|
// var nums = Enumerable.Range(48, 10)
|
||||||
|
// .Concat(Enumerable.Range(65, 26))
|
||||||
|
// .Concat(Enumerable.Range(97, 26))
|
||||||
|
// .Concat(new[] {45, 46, 95})
|
||||||
|
// .ToArray();
|
||||||
|
|
||||||
|
// var token = String.Concat(new int[59]
|
||||||
|
// .Select(x => (char) nums[rng.Next(0, nums.Length)]));
|
||||||
|
// if (usr == null)
|
||||||
|
// await Context.Channel.SendConfirmAsync(token).ConfigureAwait(false);
|
||||||
|
// else
|
||||||
|
// await Context.Channel.SendConfirmAsync($"Token of user {usr} is `{token}`").ConfigureAwait(false);
|
||||||
|
//}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ConvertList()
|
public async Task ConvertList()
|
||||||
{
|
{
|
||||||
var res = Units.GroupBy(x => x.UnitType)
|
var res = Units.GroupBy(x => x.UnitType)
|
||||||
.Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__")
|
.Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist"))
|
||||||
.WithColor(NadekoBot.OkColor),
|
.WithColor(NadekoBot.OkColor),
|
||||||
(embed, g) => embed.AddField(efb =>
|
(embed, g) => embed.AddField(efb =>
|
||||||
efb.WithName(g.Key.ToTitleCase())
|
efb.WithName(g.Key.ToTitleCase())
|
||||||
@ -116,12 +134,12 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var targetUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
|
var targetUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
|
||||||
if (originUnit == null || targetUnit == null)
|
if (originUnit == null || targetUnit == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: units not found", origin, target));
|
await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (originUnit.UnitType != targetUnit.UnitType)
|
if (originUnit.UnitType != targetUnit.UnitType)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: types of unit are not equal", originUnit.Triggers.First(), targetUnit.Triggers.First()));
|
await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
decimal res;
|
decimal res;
|
||||||
@ -150,8 +168,6 @@ namespace NadekoBot.Modules.Utility
|
|||||||
case "F":
|
case "F":
|
||||||
res = res * (9m / 5m) - 459.67m;
|
res = res * (9m / 5m) - 459.67m;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -165,7 +181,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
}
|
}
|
||||||
res = Math.Round(res, 4);
|
res = Math.Round(res, 4);
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(string.Format("{0} {1} is equal to {2} {3}", value, (originUnit.Triggers.First() + "s").SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2)));
|
await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using NadekoBot.Services.Impl;
|
using NadekoBot.Services.Impl;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -21,7 +20,7 @@ using NadekoBot.Services;
|
|||||||
namespace NadekoBot.Modules.Utility
|
namespace NadekoBot.Modules.Utility
|
||||||
{
|
{
|
||||||
[NadekoModule("Utility", ".")]
|
[NadekoModule("Utility", ".")]
|
||||||
public partial class Utility : NadekoModule
|
public partial class Utility : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, Timer> rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
private static ConcurrentDictionary<ulong, Timer> rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||||
|
|
||||||
@ -118,14 +117,14 @@ namespace NadekoBot.Modules.Utility
|
|||||||
if (rotatingRoleColors.TryRemove(role.Id, out t))
|
if (rotatingRoleColors.TryRemove(role.Id, out t))
|
||||||
{
|
{
|
||||||
t.Change(Timeout.Infinite, Timeout.Infinite);
|
t.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
await channel.SendConfirmAsync($"Stopped rotating colors for the **{role.Name}** role").ConfigureAwait(false);
|
await ReplyConfirmLocalized("rrc_stop", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hexColors = hexes.Select(hex =>
|
var hexColors = hexes.Select(hex =>
|
||||||
{
|
{
|
||||||
try { return (ImageSharp.Color?)new ImageSharp.Color(hex.Replace("#", "")); } catch { return null; }
|
try { return (ImageSharp.Color?)ImageSharp.Color.FromHex(hex.Replace("#", "")); } catch { return null; }
|
||||||
})
|
})
|
||||||
.Where(c => c != null)
|
.Where(c => c != null)
|
||||||
.Select(c => c.Value)
|
.Select(c => c.Value)
|
||||||
@ -133,7 +132,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
if (!hexColors.Any())
|
if (!hexColors.Any())
|
||||||
{
|
{
|
||||||
await channel.SendMessageAsync("No colors are in the correct format. Use `#00ff00` for example.").ConfigureAwait(false);
|
await ReplyErrorLocalized("rrc_no_colors").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,8 +162,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
|
await channel.SendFileAsync(images, "magicalgirl.jpg", GetText("rrc_start", Format.Bold(role.Name))).ConfigureAwait(false);
|
||||||
await channel.SendFileAsync(images, "magicalgirl.jpg", $"Rotating **{role.Name}** role's color.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -181,14 +179,14 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.WithAuthor(eab => eab.WithIconUrl("https://togethertube.com/assets/img/favicons/favicon-32x32.png")
|
.WithAuthor(eab => eab.WithIconUrl("https://togethertube.com/assets/img/favicons/favicon-32x32.png")
|
||||||
.WithName("Together Tube")
|
.WithName("Together Tube")
|
||||||
.WithUrl("https://togethertube.com/"))
|
.WithUrl("https://togethertube.com/"))
|
||||||
.WithDescription($"{Context.User.Mention} Here is your room link:\n{target}"));
|
.WithDescription(Context.User.Mention + " " + GetText("togtub_room_link") + "\n" + target));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task WhosPlaying([Remainder] string game = null)
|
public async Task WhosPlaying([Remainder] string game)
|
||||||
{
|
{
|
||||||
game = game.Trim().ToUpperInvariant();
|
game = game?.Trim().ToUpperInvariant();
|
||||||
if (string.IsNullOrWhiteSpace(game))
|
if (string.IsNullOrWhiteSpace(game))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -208,7 +206,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (arr.Length == 0)
|
if (arr.Length == 0)
|
||||||
await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false);
|
await ReplyErrorLocalized("nobody_playing_game").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2)
|
await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2)
|
||||||
@ -219,26 +217,24 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task InRole([Remainder] string roles)
|
public async Task InRole(params IRole[] roles)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(roles))
|
if (roles.Length == 0)
|
||||||
return;
|
return;
|
||||||
var arg = roles.Split(',').Select(r => r.Trim().ToUpperInvariant());
|
var send = "ℹ️ " + Format.Bold(GetText("inrole_list"));
|
||||||
string send = "ℹ️ **Here is a list of users in those roles:**";
|
var usrs = (await Context.Guild.GetUsersAsync()).ToArray();
|
||||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@EVERYONE" && str != "EVERYONE"))
|
foreach (var role in roles.Where(r => r.Id != Context.Guild.Id))
|
||||||
{
|
{
|
||||||
var role = Context.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleStr).FirstOrDefault();
|
|
||||||
if (role == null) continue;
|
|
||||||
send += $"```css\n[{role.Name}]\n";
|
send += $"```css\n[{role.Name}]\n";
|
||||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString()));
|
send += string.Join(", ", usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString()));
|
||||||
send += $"\n```";
|
send += "\n```";
|
||||||
}
|
}
|
||||||
var usr = Context.User as IGuildUser;
|
var usr = (IGuildUser)Context.User;
|
||||||
while (send.Length > 2000)
|
while (send.Length > 2000)
|
||||||
{
|
{
|
||||||
if (!usr.GetPermissions((ITextChannel)Context.Channel).ManageMessages)
|
if (!usr.GetPermissions((ITextChannel)Context.Channel).ManageMessages)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"⚠️ {usr.Mention} **you are not allowed to use this command on roles with a lot of users in them to prevent abuse.**").ConfigureAwait(false);
|
await ReplyErrorLocalized("inrole_not_allowed").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var curstr = send.Substring(0, 2000);
|
var curstr = send.Substring(0, 2000);
|
||||||
@ -255,15 +251,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public async Task CheckMyPerms()
|
public async Task CheckMyPerms()
|
||||||
{
|
{
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder("```http\n");
|
StringBuilder builder = new StringBuilder();
|
||||||
var user = Context.User as IGuildUser;
|
var user = (IGuildUser) Context.User;
|
||||||
var perms = user.GetPermissions((ITextChannel)Context.Channel);
|
var perms = user.GetPermissions((ITextChannel)Context.Channel);
|
||||||
foreach (var p in perms.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
foreach (var p in perms.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
||||||
{
|
{
|
||||||
builder.AppendLine($"{p.Name} : {p.GetValue(perms, null).ToString()}");
|
builder.AppendLine($"{p.Name} : {p.GetValue(perms, null)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Append("```");
|
|
||||||
await Context.Channel.SendConfirmAsync(builder.ToString());
|
await Context.Channel.SendConfirmAsync(builder.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,20 +266,23 @@ namespace NadekoBot.Modules.Utility
|
|||||||
public async Task UserId(IGuildUser target = null)
|
public async Task UserId(IGuildUser target = null)
|
||||||
{
|
{
|
||||||
var usr = target ?? Context.User;
|
var usr = target ?? Context.User;
|
||||||
await Context.Channel.SendConfirmAsync($"🆔 of the user **{ usr.Username }** is `{ usr.Id }`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("userid", "🆔", Format.Bold(usr.ToString()),
|
||||||
|
Format.Code(usr.Id.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task ChannelId()
|
public async Task ChannelId()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"🆔 of this channel is `{Context.Channel.Id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("channelid", "🆔", Format.Code(Context.Channel.Id.ToString()))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ServerId()
|
public async Task ServerId()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"🆔 of this server is `{Context.Guild.Id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("serverid", "🆔", Format.Code(Context.Guild.Id.ToString()))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -295,33 +292,36 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
var guild = channel.Guild;
|
var guild = channel.Guild;
|
||||||
|
|
||||||
const int RolesPerPage = 20;
|
const int rolesPerPage = 20;
|
||||||
|
|
||||||
if (page < 1 || page > 100)
|
if (page < 1 || page > 100)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
var roles = target.GetRoles().Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage);
|
var roles = target.GetRoles().Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray();
|
||||||
if (!roles.Any())
|
if (!roles.Any())
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync($"⚔ **Page #{page} of roles for {target.Username}**", $"```css\n• " + string.Join("\n• ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false);
|
|
||||||
|
await channel.SendConfirmAsync(GetText("roles_page", page, Format.Bold(target.ToString())),
|
||||||
|
"\n• " + string.Join("\n• ", (IEnumerable<IRole>)roles).SanitizeMentions()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage);
|
var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray();
|
||||||
if (!roles.Any())
|
if (!roles.Any())
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync($"⚔ **Page #{page} of all roles on this server:**", $"```css\n• " + string.Join("\n• ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false);
|
await channel.SendConfirmAsync(GetText("roles_all_page", page),
|
||||||
|
"\n• " + string.Join("\n• ", (IEnumerable<IRole>)roles).SanitizeMentions()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,9 +340,9 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
var topic = channel.Topic;
|
var topic = channel.Topic;
|
||||||
if (string.IsNullOrWhiteSpace(topic))
|
if (string.IsNullOrWhiteSpace(topic))
|
||||||
await Context.Channel.SendErrorAsync("No topic set.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_topic_set").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("channel_topic"), topic).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -363,11 +363,13 @@ namespace NadekoBot.Modules.Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var status = string.Join(", ", NadekoBot.Client.Shards.GroupBy(x => x.ConnectionState)
|
var status = string.Join(", ", NadekoBot.Client.Shards.GroupBy(x => x.ConnectionState)
|
||||||
.Select(x => $"{x.Count()} shards {x.Key}")
|
.Select(x => $"{x.Count()} {x.Key}")
|
||||||
.ToArray());
|
.ToArray());
|
||||||
|
|
||||||
var allShardStrings = NadekoBot.Client.Shards
|
var allShardStrings = NadekoBot.Client.Shards
|
||||||
.Select(x => $"Shard **#{x.ShardId.ToString()}** is in {Format.Bold(x.ConnectionState.ToString())} state with {Format.Bold(x.Guilds.Count.ToString())} servers")
|
.Select(x =>
|
||||||
|
GetText("shard_stats_txt", x.ShardId.ToString(),
|
||||||
|
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString())))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|
||||||
@ -378,10 +380,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25));
|
var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(str))
|
if (string.IsNullOrWhiteSpace(str))
|
||||||
str = "No shards on this page.";
|
str = GetText("no_shards_on_page");
|
||||||
|
|
||||||
return new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.WithAuthor(a => a.WithName("Shard Stats"))
|
.WithAuthor(a => a.WithName(GetText("shard_stats")))
|
||||||
.WithTitle(status)
|
.WithTitle(status)
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithDescription(str);
|
.WithDescription(str);
|
||||||
@ -393,7 +395,7 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
var shardId = NadekoBot.Client.GetShardIdFor(guildid);
|
var shardId = NadekoBot.Client.GetShardIdFor(guildid);
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"ShardId for **{guildid}** with {NadekoBot.Client.Shards.Count} total shards", shardId.ToString()).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -410,17 +412,21 @@ namespace NadekoBot.Modules.Utility
|
|||||||
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}")
|
||||||
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
|
.WithUrl("http://nadekobot.readthedocs.io/en/latest/")
|
||||||
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
.WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg"))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Author")).WithValue(stats.Author).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("author")).WithValue(stats.Author).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Bot ID")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("botid")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Shard")).WithValue($"#{shardId}, {NadekoBot.Client.Shards.Count} total").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {NadekoBot.Client.Shards.Count}").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("owner_ids")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("presence")).WithValue(
|
||||||
|
GetText("presence_txt",
|
||||||
|
NadekoBot.Client.GetGuildCount(), stats.TextChannels, stats.VoiceChannels)).WithIsInline(true))
|
||||||
#if !GLOBAL_NADEKO
|
#if !GLOBAL_NADEKO
|
||||||
.WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued."))
|
.WithFooter(efb => efb.WithText(GetText("stats_songs",
|
||||||
|
Music.Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
|
||||||
|
Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count))))
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -430,10 +436,10 @@ namespace NadekoBot.Modules.Utility
|
|||||||
{
|
{
|
||||||
var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emoji)t.Value);
|
var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emoji)t.Value);
|
||||||
|
|
||||||
var result = string.Join("\n", tags.Select(m => $"**Name:** {m} **Link:** {m.Url}"));
|
var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url)));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(result))
|
if (string.IsNullOrWhiteSpace(result))
|
||||||
await Context.Channel.SendErrorAsync("No special emojis found.");
|
await ReplyErrorLocalized("showemojis_none").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendMessageAsync(result).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(result).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -451,13 +457,15 @@ namespace NadekoBot.Modules.Utility
|
|||||||
|
|
||||||
if (!guilds.Any())
|
if (!guilds.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No servers found on that page.").ConfigureAwait(false);
|
await ReplyErrorLocalized("listservers_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithOkColor(),
|
await Context.Channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithOkColor(),
|
||||||
(embed, g) => embed.AddField(efb => efb.WithName(g.Name)
|
(embed, g) => embed.AddField(efb => efb.WithName(g.Name)
|
||||||
.WithValue($"```css\nID: {g.Id}\nMembers: {g.Users.Count}\nOwnerID: {g.OwnerId} ```")
|
.WithValue(
|
||||||
|
GetText("listservers", g.Id, g.Users.Count,
|
||||||
|
g.OwnerId))
|
||||||
.WithIsInline(false))))
|
.WithIsInline(false))))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,9 @@ namespace NadekoBot
|
|||||||
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
||||||
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.PngFormat());
|
||||||
|
//ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.JpegFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RunAsync(params string[] args)
|
public async Task RunAsync(params string[] args)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgambling_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgambling_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgames_005Ccommands/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgames_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cpermissions_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Csearches_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cutility_005Ccommands/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
64
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
64
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -501,7 +501,7 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders..
|
/// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string antispam_desc {
|
public static string antispam_desc {
|
||||||
get {
|
get {
|
||||||
@ -717,7 +717,7 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to `{0}atl en>fr`.
|
/// Looks up a localized string similar to Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string autotranslang_desc {
|
public static string autotranslang_desc {
|
||||||
get {
|
get {
|
||||||
@ -726,7 +726,7 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value..
|
/// Looks up a localized string similar to `{0}atl en>fr`.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string autotranslang_usage {
|
public static string autotranslang_usage {
|
||||||
get {
|
get {
|
||||||
@ -3552,7 +3552,7 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission..
|
/// Looks up a localized string similar to Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string inrole_desc {
|
public static string inrole_desc {
|
||||||
get {
|
get {
|
||||||
@ -3561,7 +3561,7 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to `{0}inrole Role`.
|
/// Looks up a localized string similar to `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3`.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string inrole_usage {
|
public static string inrole_usage {
|
||||||
get {
|
get {
|
||||||
@ -5729,6 +5729,33 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to rategirl.
|
||||||
|
/// </summary>
|
||||||
|
public static string rategirl_cmd {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("rategirl_cmd", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart..
|
||||||
|
/// </summary>
|
||||||
|
public static string rategirl_desc {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("rategirl_desc", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to `{0}rategirl @SomeGurl`.
|
||||||
|
/// </summary>
|
||||||
|
public static string rategirl_usage {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("rategirl_usage", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to reloadimages.
|
/// Looks up a localized string similar to reloadimages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -6674,6 +6701,33 @@ namespace NadekoBot.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to qsearch.
|
||||||
|
/// </summary>
|
||||||
|
public static string searchquote_cmd {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("searchquote_cmd", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Shows a random quote for a keyword that contains any text specified in the search..
|
||||||
|
/// </summary>
|
||||||
|
public static string searchquote_desc {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("searchquote_desc", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to `{0}qsearch keyword text`.
|
||||||
|
/// </summary>
|
||||||
|
public static string searchquote_usage {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("searchquote_usage", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to send.
|
/// Looks up a localized string similar to send.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
2171
src/NadekoBot/Resources/CommandStrings.ja-JP.resx
Normal file
2171
src/NadekoBot/Resources/CommandStrings.ja-JP.resx
Normal file
File diff suppressed because it is too large
Load Diff
2169
src/NadekoBot/Resources/CommandStrings.nl-NL.resx
Normal file
2169
src/NadekoBot/Resources/CommandStrings.nl-NL.resx
Normal file
File diff suppressed because it is too large
Load Diff
@ -841,10 +841,10 @@
|
|||||||
<value>inrole</value>
|
<value>inrole</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="inrole_desc" xml:space="preserve">
|
<data name="inrole_desc" xml:space="preserve">
|
||||||
<value>Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission.</value>
|
<value>Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="inrole_usage" xml:space="preserve">
|
<data name="inrole_usage" xml:space="preserve">
|
||||||
<value>`{0}inrole Role`</value>
|
<value>`{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="checkmyperms_cmd" xml:space="preserve">
|
<data name="checkmyperms_cmd" xml:space="preserve">
|
||||||
<value>checkmyperms</value>
|
<value>checkmyperms</value>
|
||||||
@ -1143,6 +1143,15 @@
|
|||||||
<data name="showquote_usage" xml:space="preserve">
|
<data name="showquote_usage" xml:space="preserve">
|
||||||
<value>`{0}.. abc`</value>
|
<value>`{0}.. abc`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="searchquote_cmd" xml:space="preserve">
|
||||||
|
<value>qsearch</value>
|
||||||
|
</data>
|
||||||
|
<data name="searchquote_desc" xml:space="preserve">
|
||||||
|
<value>Shows a random quote for a keyword that contains any text specified in the search.</value>
|
||||||
|
</data>
|
||||||
|
<data name="searchquote_usage" xml:space="preserve">
|
||||||
|
<value>`{0}qsearch keyword text`</value>
|
||||||
|
</data>
|
||||||
<data name="deletequote_cmd" xml:space="preserve">
|
<data name="deletequote_cmd" xml:space="preserve">
|
||||||
<value>deletequote delq</value>
|
<value>deletequote delq</value>
|
||||||
</data>
|
</data>
|
||||||
@ -2434,7 +2443,7 @@
|
|||||||
<value>antispam</value>
|
<value>antispam</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="antispam_desc" xml:space="preserve">
|
<data name="antispam_desc" xml:space="preserve">
|
||||||
<value>Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders.</value>
|
<value>Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="antispam_usage" xml:space="preserve">
|
<data name="antispam_usage" xml:space="preserve">
|
||||||
<value>`{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban`</value>
|
<value>`{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban`</value>
|
||||||
@ -2560,10 +2569,10 @@
|
|||||||
<value>autotranslang atl</value>
|
<value>autotranslang atl</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="autotranslang_desc" xml:space="preserve">
|
<data name="autotranslang_desc" xml:space="preserve">
|
||||||
<value>`{0}atl en>fr`</value>
|
<value>Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="autotranslang_usage" xml:space="preserve">
|
<data name="autotranslang_usage" xml:space="preserve">
|
||||||
<value>Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value.</value>
|
<value>`{0}atl en>fr`</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="autotranslate_cmd" xml:space="preserve">
|
<data name="autotranslate_cmd" xml:space="preserve">
|
||||||
<value>autotrans at</value>
|
<value>autotrans at</value>
|
||||||
@ -3132,4 +3141,13 @@
|
|||||||
<data name="languageslist_usage" xml:space="preserve">
|
<data name="languageslist_usage" xml:space="preserve">
|
||||||
<value>`{0}langli`</value>
|
<value>`{0}langli`</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="rategirl_cmd" xml:space="preserve">
|
||||||
|
<value>rategirl</value>
|
||||||
|
</data>
|
||||||
|
<data name="rategirl_desc" xml:space="preserve">
|
||||||
|
<value>Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart.</value>
|
||||||
|
</data>
|
||||||
|
<data name="rategirl_usage" xml:space="preserve">
|
||||||
|
<value>`{0}rategirl @SomeGurl`</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
3393
src/NadekoBot/Resources/ResponseStrings.Designer.cs
generated
3393
src/NadekoBot/Resources/ResponseStrings.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
2191
src/NadekoBot/Resources/ResponseStrings.de-DE.resx
Normal file
2191
src/NadekoBot/Resources/ResponseStrings.de-DE.resx
Normal file
File diff suppressed because it is too large
Load Diff
2203
src/NadekoBot/Resources/ResponseStrings.fr-FR.resx
Normal file
2203
src/NadekoBot/Resources/ResponseStrings.fr-FR.resx
Normal file
File diff suppressed because it is too large
Load Diff
2203
src/NadekoBot/Resources/ResponseStrings.fr-fr.resx
Normal file
2203
src/NadekoBot/Resources/ResponseStrings.fr-fr.resx
Normal file
File diff suppressed because it is too large
Load Diff
2191
src/NadekoBot/Resources/ResponseStrings.pt-BR.resx
Normal file
2191
src/NadekoBot/Resources/ResponseStrings.pt-BR.resx
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2189
src/NadekoBot/Resources/ResponseStrings.ru-RU.resx
Normal file
2189
src/NadekoBot/Resources/ResponseStrings.ru-RU.resx
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,9 +5,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System.Diagnostics;
|
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using NadekoBot.Modules.Permissions;
|
using NadekoBot.Modules.Permissions;
|
||||||
using Discord.Net;
|
using Discord.Net;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
@ -22,7 +20,7 @@ using NadekoBot.DataStructures;
|
|||||||
|
|
||||||
namespace NadekoBot.Services
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
public class IGuildUserComparer : IEqualityComparer<IGuildUser>
|
public class GuildUserComparer : IEqualityComparer<IGuildUser>
|
||||||
{
|
{
|
||||||
public bool Equals(IGuildUser x, IGuildUser y) => x.Id == y.Id;
|
public bool Equals(IGuildUser x, IGuildUser y) => x.Id == y.Id;
|
||||||
|
|
||||||
@ -40,7 +38,7 @@ namespace NadekoBot.Services
|
|||||||
private readonly CommandService _commandService;
|
private readonly CommandService _commandService;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
private List<IDMChannel> ownerChannels { get; set; }
|
private List<IDMChannel> ownerChannels { get; set; } = new List<IDMChannel>();
|
||||||
|
|
||||||
public event Func<SocketUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
|
public event Func<SocketUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
|
||||||
|
|
||||||
@ -48,7 +46,7 @@ namespace NadekoBot.Services
|
|||||||
public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
|
public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
|
||||||
|
|
||||||
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||||
private Timer clearUsersOnShortCooldown { get; }
|
private readonly Timer _clearUsersOnShortCooldown;
|
||||||
|
|
||||||
public CommandHandler(DiscordShardedClient client, CommandService commandService)
|
public CommandHandler(DiscordShardedClient client, CommandService commandService)
|
||||||
{
|
{
|
||||||
@ -56,26 +54,62 @@ namespace NadekoBot.Services
|
|||||||
_commandService = commandService;
|
_commandService = commandService;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
clearUsersOnShortCooldown = new Timer((_) =>
|
_clearUsersOnShortCooldown = new Timer(_ =>
|
||||||
{
|
{
|
||||||
UsersOnShortCooldown.Clear();
|
UsersOnShortCooldown.Clear();
|
||||||
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
||||||
}
|
}
|
||||||
public async Task StartHandling()
|
public Task StartHandling()
|
||||||
{
|
{
|
||||||
ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users)
|
var _ = Task.Run(async () =>
|
||||||
.Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id))
|
{
|
||||||
.Distinct(new IGuildUserComparer())
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
.Select(async u => { try { return await u.CreateDMChannelAsync(); } catch { return null; } })))
|
ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users)
|
||||||
.Where(ch => ch != null)
|
.Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id))
|
||||||
.ToList();
|
.Distinct(new GuildUserComparer())
|
||||||
|
.Select(async u =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await u.CreateDMChannelAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
.Where(ch => ch != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (!ownerChannels.Any())
|
if (!ownerChannels.Any())
|
||||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||||
else
|
else
|
||||||
_log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels.");
|
_log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels.");
|
||||||
|
});
|
||||||
|
|
||||||
_client.MessageReceived += MessageReceivedHandler;
|
_client.MessageReceived += MessageReceivedHandler;
|
||||||
|
_client.MessageUpdated += (oldmsg, newMsg) =>
|
||||||
|
{
|
||||||
|
var ignore = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var usrMsg = newMsg as SocketUserMessage;
|
||||||
|
var guild = (usrMsg?.Channel as ITextChannel)?.Guild;
|
||||||
|
|
||||||
|
if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||||
|
await WordFiltered(guild, usrMsg).ConfigureAwait(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild)
|
private async Task<bool> TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild)
|
||||||
@ -100,11 +134,12 @@ namespace NadekoBot.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) =>
|
private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) =>
|
||||||
|
usrMsg.Author?.Id == 193022505026453504 || // he requested to be blacklisted from self-hosted bots
|
||||||
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||||
|
|
||||||
const float oneThousandth = 1.0f / 1000;
|
private const float _oneThousandth = 1.0f / 1000;
|
||||||
private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total)
|
private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total)
|
||||||
{
|
{
|
||||||
_log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" +
|
_log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" +
|
||||||
@ -116,10 +151,10 @@ namespace NadekoBot.Services
|
|||||||
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
|
||||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||||
usrMsg.Content, // {3}
|
usrMsg.Content, // {3}
|
||||||
exec1 * oneThousandth, // {4}
|
exec1 * _oneThousandth, // {4}
|
||||||
exec2 * oneThousandth, // {5}
|
exec2 * _oneThousandth, // {5}
|
||||||
exec3 * oneThousandth, // {6}
|
exec3 * _oneThousandth, // {6}
|
||||||
total * oneThousandth // {7}
|
total * _oneThousandth // {7}
|
||||||
);
|
);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@ -137,10 +172,10 @@ namespace NadekoBot.Services
|
|||||||
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
|
||||||
usrMsg.Content,// {3}
|
usrMsg.Content,// {3}
|
||||||
exec.Result.ErrorReason, // {4}
|
exec.Result.ErrorReason, // {4}
|
||||||
exec1 * oneThousandth, // {5}
|
exec1 * _oneThousandth, // {5}
|
||||||
exec2 * oneThousandth, // {6}
|
exec2 * _oneThousandth, // {6}
|
||||||
exec3 * oneThousandth, // {7}
|
exec3 * _oneThousandth, // {7}
|
||||||
total * oneThousandth // {8}
|
total * _oneThousandth // {8}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +241,8 @@ namespace NadekoBot.Services
|
|||||||
if (usrMsg == null) //has to be an user message, not system/other messages.
|
if (usrMsg == null) //has to be an user message, not system/other messages.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (usrMsg.Author.Id == 193022505026453504)
|
||||||
|
return;
|
||||||
#if !GLOBAL_NADEKO
|
#if !GLOBAL_NADEKO
|
||||||
// track how many messagges each user is sending
|
// track how many messagges each user is sending
|
||||||
UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
||||||
@ -390,10 +427,10 @@ namespace NadekoBot.Services
|
|||||||
// Bot will ignore commands which are ran more often than what specified by
|
// Bot will ignore commands which are ran more often than what specified by
|
||||||
// GlobalCommandsCooldown constant (miliseconds)
|
// GlobalCommandsCooldown constant (miliseconds)
|
||||||
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
|
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
|
||||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"You are on a global cooldown."));
|
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."));
|
||||||
|
|
||||||
if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
|
if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
|
||||||
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on a cooldown for you."));
|
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "That command is on a cooldown for you."));
|
||||||
|
|
||||||
return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, dependencyMap));
|
return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, dependencyMap));
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ namespace NadekoBot.Services.Database.Models
|
|||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public DateTime DateAdded { get; } = DateTime.UtcNow;
|
public DateTime? DateAdded { get; set; } = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ namespace NadekoBot.Services.Database.Repositories
|
|||||||
{
|
{
|
||||||
IEnumerable<Quote> GetAllQuotesByKeyword(ulong guildId, string keyword);
|
IEnumerable<Quote> GetAllQuotesByKeyword(ulong guildId, string keyword);
|
||||||
Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword);
|
Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword);
|
||||||
|
Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text);
|
||||||
IEnumerable<Quote> GetGroup(ulong guildId, int skip, int take);
|
IEnumerable<Quote> GetGroup(ulong guildId, int skip, int take);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
|||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rng.Next()).FirstOrDefaultAsync();
|
return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rng.Next()).FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
public Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text)
|
||||||
|
{
|
||||||
|
var rngk = new NadekoRandom();
|
||||||
|
return _set.Where(q => q.Text.Contains(text) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ namespace NadekoBot.Services
|
|||||||
ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; }
|
ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; }
|
||||||
ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; }
|
ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; }
|
||||||
|
|
||||||
|
ImmutableArray<byte> WifeMatrix { get; }
|
||||||
|
ImmutableArray<byte> RategirlDot { get; }
|
||||||
|
|
||||||
Task<TimeSpan> Reload();
|
Task<TimeSpan> Reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,5 @@ namespace NadekoBot.Services
|
|||||||
public interface IStatsService
|
public interface IStatsService
|
||||||
{
|
{
|
||||||
Task<string> Print();
|
Task<string> Print();
|
||||||
Task Reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
using NadekoBot.DataStructures;
|
using NLog;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Impl
|
namespace NadekoBot.Services.Impl
|
||||||
@ -16,23 +13,26 @@ namespace NadekoBot.Services.Impl
|
|||||||
{
|
{
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
private const string basePath = "data/images/";
|
private const string _basePath = "data/images/";
|
||||||
|
|
||||||
private const string headsPath = basePath + "coins/heads.png";
|
private const string _headsPath = _basePath + "coins/heads.png";
|
||||||
private const string tailsPath = basePath + "coins/tails.png";
|
private const string _tailsPath = _basePath + "coins/tails.png";
|
||||||
|
|
||||||
private const string currencyImagesPath = basePath + "currency";
|
private const string _currencyImagesPath = _basePath + "currency";
|
||||||
private const string diceImagesPath = basePath + "dice";
|
private const string _diceImagesPath = _basePath + "dice";
|
||||||
|
|
||||||
private const string slotBackgroundPath = basePath + "slots/background.png";
|
private const string _slotBackgroundPath = _basePath + "slots/background.png";
|
||||||
private const string slotNumbersPath = basePath + "slots/numbers/";
|
private const string _slotNumbersPath = _basePath + "slots/numbers/";
|
||||||
private const string slotEmojisPath = basePath + "slots/emojis/";
|
private const string _slotEmojisPath = _basePath + "slots/emojis/";
|
||||||
|
|
||||||
|
private const string _wifeMatrixPath = _basePath + "rategirl/wifematrix.png";
|
||||||
|
private const string _rategirlDot = _basePath + "rategirl/dot.png";
|
||||||
|
|
||||||
|
|
||||||
public ImmutableArray<byte> Heads { get; private set; }
|
public ImmutableArray<byte> Heads { get; private set; }
|
||||||
public ImmutableArray<byte> Tails { get; private set; }
|
public ImmutableArray<byte> Tails { get; private set; }
|
||||||
|
|
||||||
//todo C#7
|
//todo C#7 tuples
|
||||||
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; private set; }
|
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; private set; }
|
||||||
|
|
||||||
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; private set; }
|
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; private set; }
|
||||||
@ -41,6 +41,9 @@ namespace NadekoBot.Services.Impl
|
|||||||
public ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; private set; }
|
public ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; private set; }
|
||||||
public ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; private set; }
|
public ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; private set; }
|
||||||
|
|
||||||
|
public ImmutableArray<byte> WifeMatrix { get; private set; }
|
||||||
|
public ImmutableArray<byte> RategirlDot { get; private set; }
|
||||||
|
|
||||||
private ImagesService()
|
private ImagesService()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
@ -59,33 +62,36 @@ namespace NadekoBot.Services.Impl
|
|||||||
{
|
{
|
||||||
_log.Info("Loading images...");
|
_log.Info("Loading images...");
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
Heads = File.ReadAllBytes(headsPath).ToImmutableArray();
|
Heads = File.ReadAllBytes(_headsPath).ToImmutableArray();
|
||||||
Tails = File.ReadAllBytes(tailsPath).ToImmutableArray();
|
Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray();
|
||||||
|
|
||||||
Currency = Directory.GetFiles(currencyImagesPath)
|
Currency = Directory.GetFiles(_currencyImagesPath)
|
||||||
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(
|
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(
|
||||||
Path.GetFileName(x),
|
Path.GetFileName(x),
|
||||||
File.ReadAllBytes(x).ToImmutableArray()))
|
File.ReadAllBytes(x).ToImmutableArray()))
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
Dice = Directory.GetFiles(diceImagesPath)
|
Dice = Directory.GetFiles(_diceImagesPath)
|
||||||
.OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x)))
|
.OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x)))
|
||||||
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(x,
|
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(x,
|
||||||
File.ReadAllBytes(x).ToImmutableArray()))
|
File.ReadAllBytes(x).ToImmutableArray()))
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
SlotBackground = File.ReadAllBytes(slotBackgroundPath).ToImmutableArray();
|
SlotBackground = File.ReadAllBytes(_slotBackgroundPath).ToImmutableArray();
|
||||||
|
|
||||||
SlotNumbers = Directory.GetFiles(slotNumbersPath)
|
SlotNumbers = Directory.GetFiles(_slotNumbersPath)
|
||||||
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
||||||
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
SlotEmojis = Directory.GetFiles(slotEmojisPath)
|
SlotEmojis = Directory.GetFiles(_slotEmojisPath)
|
||||||
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
|
||||||
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray();
|
||||||
|
RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray();
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!");
|
_log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!");
|
||||||
return sw.Elapsed;
|
return sw.Elapsed;
|
||||||
|
@ -3,6 +3,7 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -12,75 +13,108 @@ namespace NadekoBot.Services.Impl
|
|||||||
{
|
{
|
||||||
public class StatsService : IStatsService
|
public class StatsService : IStatsService
|
||||||
{
|
{
|
||||||
private DiscordShardedClient client;
|
private readonly DiscordShardedClient _client;
|
||||||
private DateTime started;
|
private readonly DateTime _started;
|
||||||
|
|
||||||
public const string BotVersion = "1.1.8-alpha";
|
public const string BotVersion = "1.2";
|
||||||
|
|
||||||
public string Author => "Kwoth#2560";
|
public string Author => "Kwoth#2560";
|
||||||
public string Library => "Discord.Net";
|
public string Library => "Discord.Net";
|
||||||
public int MessageCounter { get; private set; } = 0;
|
|
||||||
public int CommandsRan { get; private set; } = 0;
|
|
||||||
public string Heap =>
|
public string Heap =>
|
||||||
Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString();
|
Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString(CultureInfo.InvariantCulture);
|
||||||
public double MessagesPerSecond => MessageCounter / GetUptime().TotalSeconds;
|
public double MessagesPerSecond => MessageCounter / GetUptime().TotalSeconds;
|
||||||
private int _textChannels = 0;
|
|
||||||
public int TextChannels => _textChannels;
|
|
||||||
private int _voiceChannels = 0;
|
|
||||||
public int VoiceChannels => _voiceChannels;
|
|
||||||
|
|
||||||
Timer carbonitexTimer { get; }
|
private long _textChannels;
|
||||||
|
public long TextChannels => Interlocked.Read(ref _textChannels);
|
||||||
|
private long _voiceChannels;
|
||||||
|
public long VoiceChannels => Interlocked.Read(ref _voiceChannels);
|
||||||
|
private long _messageCounter;
|
||||||
|
public long MessageCounter => Interlocked.Read(ref _messageCounter);
|
||||||
|
private long _commandsRan;
|
||||||
|
public long CommandsRan => Interlocked.Read(ref _commandsRan);
|
||||||
|
|
||||||
|
private Timer carbonitexTimer { get; }
|
||||||
|
|
||||||
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler)
|
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler)
|
||||||
{
|
{
|
||||||
|
|
||||||
this.client = client;
|
_client = client;
|
||||||
|
|
||||||
Reset();
|
_started = DateTime.Now;
|
||||||
this.client.MessageReceived += _ => Task.FromResult(MessageCounter++);
|
_client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter));
|
||||||
cmdHandler.CommandExecuted += (_, e) => Task.FromResult(CommandsRan++);
|
cmdHandler.CommandExecuted += (_, e) => Task.FromResult(Interlocked.Increment(ref _commandsRan));
|
||||||
|
|
||||||
this.client.ChannelCreated += (c) =>
|
_client.ChannelCreated += (c) =>
|
||||||
{
|
{
|
||||||
if (c is ITextChannel)
|
if (c is ITextChannel)
|
||||||
++_textChannels;
|
Interlocked.Increment(ref _textChannels);
|
||||||
else if (c is IVoiceChannel)
|
else if (c is IVoiceChannel)
|
||||||
++_voiceChannels;
|
Interlocked.Increment(ref _voiceChannels);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.ChannelDestroyed += (c) =>
|
_client.ChannelDestroyed += (c) =>
|
||||||
{
|
{
|
||||||
if (c is ITextChannel)
|
if (c is ITextChannel)
|
||||||
--_textChannels;
|
Interlocked.Decrement(ref _textChannels);
|
||||||
else if (c is IVoiceChannel)
|
else if (c is IVoiceChannel)
|
||||||
--_voiceChannels;
|
Interlocked.Decrement(ref _voiceChannels);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.JoinedGuild += (g) =>
|
_client.GuildAvailable += (g) =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
var _ = Task.Run(() =>
|
||||||
var vc = g.Channels.Count - tc;
|
{
|
||||||
_textChannels += tc;
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
_voiceChannels += vc;
|
var vc = g.Channels.Count - tc;
|
||||||
|
Interlocked.Add(ref _textChannels, tc);
|
||||||
|
Interlocked.Add(ref _voiceChannels, vc);
|
||||||
|
});
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.LeftGuild += (g) =>
|
_client.JoinedGuild += (g) =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
var _ = Task.Run(() =>
|
||||||
var vc = g.Channels.Count - tc;
|
{
|
||||||
_textChannels -= tc;
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
_voiceChannels -= vc;
|
var vc = g.Channels.Count - tc;
|
||||||
|
Interlocked.Add(ref _textChannels, tc);
|
||||||
|
Interlocked.Add(ref _voiceChannels, vc);
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
_client.GuildUnavailable += (g) =>
|
||||||
|
{
|
||||||
|
var _ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
|
var vc = g.Channels.Count - tc;
|
||||||
|
Interlocked.Add(ref _textChannels, -tc);
|
||||||
|
Interlocked.Add(ref _voiceChannels, -vc);
|
||||||
|
});
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.carbonitexTimer = new Timer(async (state) =>
|
_client.LeftGuild += (g) =>
|
||||||
|
{
|
||||||
|
var _ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
|
var vc = g.Channels.Count - tc;
|
||||||
|
Interlocked.Add(ref _textChannels, -tc);
|
||||||
|
Interlocked.Add(ref _voiceChannels, -vc);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
carbonitexTimer = new Timer(async (state) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||||
return;
|
return;
|
||||||
@ -90,7 +124,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
{
|
{
|
||||||
using (var content = new FormUrlEncodedContent(
|
using (var content = new FormUrlEncodedContent(
|
||||||
new Dictionary<string, string> {
|
new Dictionary<string, string> {
|
||||||
{ "servercount", this.client.GetGuildCount().ToString() },
|
{ "servercount", _client.GetGuildCount().ToString() },
|
||||||
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
||||||
{
|
{
|
||||||
content.Headers.Clear();
|
content.Headers.Clear();
|
||||||
@ -98,7 +132,7 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -109,34 +143,27 @@ namespace NadekoBot.Services.Impl
|
|||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
var guilds = this.client.GetGuilds().ToArray();
|
var guilds = _client.GetGuilds().ToArray();
|
||||||
_textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
|
_textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
|
||||||
_voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
|
_voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string> Print()
|
public Task<string> Print()
|
||||||
{
|
{
|
||||||
var curUser = client.CurrentUser;
|
var curUser = _client.CurrentUser;
|
||||||
return Task.FromResult($@"
|
return Task.FromResult($@"
|
||||||
Author: [{Author}] | Library: [{Library}]
|
Author: [{Author}] | Library: [{Library}]
|
||||||
Bot Version: [{BotVersion}]
|
Bot Version: [{BotVersion}]
|
||||||
Bot ID: {curUser.Id}
|
Bot ID: {curUser.Id}
|
||||||
Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
|
Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
|
||||||
Uptime: {GetUptimeString()}
|
Uptime: {GetUptimeString()}
|
||||||
Servers: {client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
Servers: {_client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||||
Commands Ran this session: {CommandsRan}
|
Commands Ran this session: {CommandsRan}
|
||||||
Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]");
|
Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Reset()
|
|
||||||
{
|
|
||||||
MessageCounter = 0;
|
|
||||||
started = DateTime.Now;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSpan GetUptime() =>
|
public TimeSpan GetUptime() =>
|
||||||
DateTime.Now - started;
|
DateTime.Now - _started;
|
||||||
|
|
||||||
public string GetUptimeString(string separator = ", ")
|
public string GetUptimeString(string separator = ", ")
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,11 @@ namespace NadekoBot.Extensions
|
|||||||
private const string arrow_right = "➡";
|
private const string arrow_right = "➡";
|
||||||
|
|
||||||
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
|
||||||
=> new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
|
{
|
||||||
|
var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// danny kamisama
|
/// danny kamisama
|
||||||
@ -398,22 +402,15 @@ namespace NadekoBot.Extensions
|
|||||||
|
|
||||||
public static ImageSharp.Image Merge(this IEnumerable<ImageSharp.Image> images)
|
public static ImageSharp.Image Merge(this IEnumerable<ImageSharp.Image> images)
|
||||||
{
|
{
|
||||||
var imgList = images.ToList();
|
var imgs = images.ToArray();
|
||||||
|
|
||||||
var canvas = new ImageSharp.Image(imgList.Sum(img => img.Width), imgList.Max(img => img.Height));
|
var canvas = new ImageSharp.Image(imgs.Sum(img => img.Width), imgs.Max(img => img.Height));
|
||||||
|
|
||||||
var canvasPixels = canvas.Lock();
|
var xOffset = 0;
|
||||||
int offsetX = 0;
|
for (int i = 0; i < imgs.Length; i++)
|
||||||
foreach (var img in imgList.Select(img => img.Lock()))
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < img.Width; i++)
|
canvas.DrawImage(imgs[i], 100, default(Size), new Point(xOffset, 0));
|
||||||
{
|
xOffset += imgs[i].Bounds.Width;
|
||||||
for (int j = 0; j < img.Height; j++)
|
|
||||||
{
|
|
||||||
canvasPixels[i + offsetX, j] = img[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offsetX += img.Width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
@ -422,7 +419,7 @@ namespace NadekoBot.Extensions
|
|||||||
public static Stream ToStream(this ImageSharp.Image img)
|
public static Stream ToStream(this ImageSharp.Image img)
|
||||||
{
|
{
|
||||||
var imageStream = new MemoryStream();
|
var imageStream = new MemoryStream();
|
||||||
img.SaveAsPng(imageStream);
|
img.Save(imageStream);
|
||||||
imageStream.Position = 0;
|
imageStream.Position = 0;
|
||||||
return imageStream;
|
return imageStream;
|
||||||
}
|
}
|
||||||
|
BIN
src/NadekoBot/data/images/rategirl/dot - Copy.png
Normal file
BIN
src/NadekoBot/data/images/rategirl/dot - Copy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 886 B |
BIN
src/NadekoBot/data/images/rategirl/dot.png
Normal file
BIN
src/NadekoBot/data/images/rategirl/dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 565 B |
BIN
src/NadekoBot/data/images/rategirl/wifematrix.png
Normal file
BIN
src/NadekoBot/data/images/rategirl/wifematrix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -23,7 +23,12 @@
|
|||||||
"Google.Apis.Urlshortener.v1": "1.19.0.138",
|
"Google.Apis.Urlshortener.v1": "1.19.0.138",
|
||||||
"Google.Apis.YouTube.v3": "1.20.0.701",
|
"Google.Apis.YouTube.v3": "1.20.0.701",
|
||||||
"Google.Apis.Customsearch.v1": "1.20.0.466",
|
"Google.Apis.Customsearch.v1": "1.20.0.466",
|
||||||
"ImageSharp": "1.0.0-alpha-000079",
|
"ImageSharp": "1.0.0-alpha2-*",
|
||||||
|
"ImageSharp.Processing": "1.0.0-alpha2-*",
|
||||||
|
"ImageSharp.Formats.Png": "1.0.0-alpha2-*",
|
||||||
|
"ImageSharp.Formats.Jpeg": "1.0.0-alpha2-*",
|
||||||
|
"ImageSharp.Drawing": "1.0.0-alpha2-*",
|
||||||
|
"ImageSharp.Drawing.Paths": "1.0.0-alpha2-*",
|
||||||
"Microsoft.EntityFrameworkCore": "1.1.0",
|
"Microsoft.EntityFrameworkCore": "1.1.0",
|
||||||
"Microsoft.EntityFrameworkCore.Design": "1.1.0",
|
"Microsoft.EntityFrameworkCore.Design": "1.1.0",
|
||||||
"Microsoft.EntityFrameworkCore.Sqlite": "1.1.0",
|
"Microsoft.EntityFrameworkCore.Sqlite": "1.1.0",
|
||||||
@ -39,7 +44,6 @@
|
|||||||
},
|
},
|
||||||
"Newtonsoft.Json": "9.0.2-beta1",
|
"Newtonsoft.Json": "9.0.2-beta1",
|
||||||
"NLog": "5.0.0-beta03",
|
"NLog": "5.0.0-beta03",
|
||||||
"System.Diagnostics.Contracts": "4.3.0",
|
|
||||||
"System.Xml.XPath": "4.3.0",
|
"System.Xml.XPath": "4.3.0",
|
||||||
"Discord.Net.Commands": {
|
"Discord.Net.Commands": {
|
||||||
"target": "project",
|
"target": "project",
|
||||||
|
Loading…
Reference in New Issue
Block a user