From 45b696bab8319e21009ec568fff58fb5b8729fa6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 22 Sep 2017 06:59:57 +0200 Subject: [PATCH] support for rss and atoms feeds added. --- .../20170921185313_feeds.Designer.cs | 1985 +++++++++++++++++ .../Migrations/20170921185313_feeds.cs | 59 + .../NadekoSqliteContextModelSnapshot.cs | 42 +- .../Modules/Music/Services/MusicService.cs | 56 - .../Modules/Searches/FeedCommands.cs | 106 + .../Modules/Searches/Services/FeedsService.cs | 213 ++ src/NadekoBot/NadekoBot.csproj | 1 + src/NadekoBot/Properties/launchSettings.json | 4 + .../Services/Database/Models/FeedSub.cs | 23 + .../Services/Database/Models/GuildConfig.cs | 1 + .../Services/Database/NadekoContext.cs | 4 + .../Impl/GuildConfigRepository.cs | 2 + src/NadekoBot/Services/Impl/Localization.cs | 2 +- src/NadekoBot/_Extensions/StringExtensions.cs | 5 + .../_strings/ResponseStrings.en-US.json | 7 +- src/NadekoBot/data/command_strings.json | 21 + 16 files changed, 2469 insertions(+), 62 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170921185313_feeds.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170921185313_feeds.cs create mode 100644 src/NadekoBot/Modules/Searches/FeedCommands.cs create mode 100644 src/NadekoBot/Modules/Searches/Services/FeedsService.cs create mode 100644 src/NadekoBot/Services/Database/Models/FeedSub.cs diff --git a/src/NadekoBot/Migrations/20170921185313_feeds.Designer.cs b/src/NadekoBot/Migrations/20170921185313_feeds.Designer.cs new file mode 100644 index 00000000..86ee94cc --- /dev/null +++ b/src/NadekoBot/Migrations/20170921185313_feeds.Designer.cs @@ -0,0 +1,1985 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170921185313_feeds")] + partial class feeds + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.Property("MuteTime"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("BotConfigId1"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("BotConfigId1"); + + b.ToTable("BlockedCmdOrMdl"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyDropAmountMax"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("CustomReactionsStartWith"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("DefaultPrefix"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("PermissionVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.Property("XpMinutesTimeout") + .ValueGeneratedOnAdd() + .HasDefaultValue(5); + + b.Property("XpPerMessage") + .ValueGeneratedOnAdd() + .HasDefaultValue(3); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("DateAdded"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubApplicants", b => + { + b.Property("ClubId"); + + b.Property("UserId"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubApplicants"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubBans", b => + { + b.Property("ClubId"); + + b.Property("UserId"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubBans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Discrim"); + + b.Property("ImageUrl"); + + b.Property("MinimumLevelReq"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20); + + b.Property("OwnerId"); + + b.Property("Xp"); + + b.HasKey("Id"); + + b.HasAlternateKey("Name", "Discrim"); + + b.HasIndex("OwnerId") + .IsUnique(); + + b.ToTable("Clubs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("ContainsAnywhere"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("ClubId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("IsClubAdmin"); + + b.Property("LastLevelUp") + .ValueGeneratedOnAdd() + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local)); + + b.Property("LastXpGain"); + + b.Property("NotifyOnLevelUp"); + + b.Property("TotalXp"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.HasIndex("ClubId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("ItemType"); + + b.Property("XpSettingsId"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("ExcludedItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Url") + .IsRequired(); + + b.HasKey("Id"); + + b.HasAlternateKey("GuildConfigId", "Url"); + + b.ToTable("FeedSub"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GameVoiceChannel"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("Prefix"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerboseErrors"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.Property("StartTimeOfDay"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklitedTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Tag"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("NsfwBlacklitedTag"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("PatreonUserId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("StreamRoleSettingsId"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleBlacklistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddRoleId"); + + b.Property("DateAdded"); + + b.Property("Enabled"); + + b.Property("FromRoleId"); + + b.Property("GuildConfigId"); + + b.Property("Keyword"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("StreamRoleSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("StreamRoleSettingsId"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleWhitelistedUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AwardedXp"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("LastLevelUp") + .ValueGeneratedOnAdd() + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local)); + + b.Property("NotifyOnLevelUp"); + + b.Property("UserId"); + + b.Property("Xp"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "GuildId") + .IsUnique(); + + b.ToTable("UserXpStats"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Item"); + + b.Property("ItemEmoji"); + + b.Property("Price"); + + b.Property("WaifuInfoId"); + + b.HasKey("Id"); + + b.HasIndex("WaifuInfoId"); + + b.ToTable("WaifuItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Level"); + + b.Property("RoleId"); + + b.Property("XpSettingsId"); + + b.HasKey("Id"); + + b.HasAlternateKey("Level"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("XpRoleReward"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("NotifyMessage"); + + b.Property("ServerExcluded"); + + b.Property("XpRoleRewardExclusive"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("XpSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedCommands") + .HasForeignKey("BotConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedModules") + .HasForeignKey("BotConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubApplicants", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubBans", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClubInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClubInfo", "Club") + .WithMany("Users") + .HasForeignKey("ClubId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklitedTag", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("NsfwBlacklistedTags") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("NadekoBot.Services.Database.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b => + { + b.HasOne("NadekoBot.Services.Database.Models.XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("NadekoBot.Services.Database.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/NadekoBot/Migrations/20170921185313_feeds.cs b/src/NadekoBot/Migrations/20170921185313_feeds.cs new file mode 100644 index 00000000..b4cbc41b --- /dev/null +++ b/src/NadekoBot/Migrations/20170921185313_feeds.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace NadekoBot.Migrations +{ + public partial class feeds : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "FeedSub", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(type: "INTEGER", nullable: false), + DateAdded = table.Column(type: "TEXT", nullable: true), + GuildConfigId = table.Column(type: "INTEGER", nullable: false), + Url = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FeedSub", x => x.Id); + table.UniqueConstraint("AK_FeedSub_GuildConfigId_Url", x => new { x.GuildConfigId, x.Url }); + table.ForeignKey( + name: "FK_FeedSub_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FeedSub"); + + migrationBuilder.AlterColumn( + name: "LastLevelUp", + table: "UserXpStats", + nullable: false, + defaultValue: new DateTime(2017, 9, 15, 5, 48, 8, 665, DateTimeKind.Local), + oldClrType: typeof(DateTime), + oldType: "TEXT", + oldDefaultValue: new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local)); + + migrationBuilder.AlterColumn( + name: "LastLevelUp", + table: "DiscordUser", + nullable: false, + defaultValue: new DateTime(2017, 9, 15, 5, 48, 8, 660, DateTimeKind.Local), + oldClrType: typeof(DateTime), + oldType: "TEXT", + oldDefaultValue: new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local)); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index cb6b041e..37c56969 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -1,10 +1,13 @@ -using System; +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; +using System; namespace NadekoBot.Migrations { @@ -13,8 +16,9 @@ namespace NadekoBot.Migrations { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "1.1.1"); + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => { @@ -466,7 +470,7 @@ namespace NadekoBot.Migrations b.Property("LastLevelUp") .ValueGeneratedOnAdd() - .HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 660, DateTimeKind.Local)); + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local)); b.Property("LastXpGain"); @@ -546,6 +550,27 @@ namespace NadekoBot.Migrations b.ToTable("ExcludedItem"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Url") + .IsRequired(); + + b.HasKey("Id"); + + b.HasAlternateKey("GuildConfigId", "Url"); + + b.ToTable("FeedSub"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => { b.Property("Id") @@ -1366,7 +1391,7 @@ namespace NadekoBot.Migrations b.Property("LastLevelUp") .ValueGeneratedOnAdd() - .HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 665, DateTimeKind.Local)); + .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local)); b.Property("NotifyOnLevelUp"); @@ -1693,6 +1718,14 @@ namespace NadekoBot.Migrations .HasForeignKey("XpSettingsId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") @@ -1945,6 +1978,7 @@ namespace NadekoBot.Migrations .HasForeignKey("NadekoBot.Services.Database.Models.XpSettings", "GuildConfigId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/NadekoBot/Modules/Music/Services/MusicService.cs b/src/NadekoBot/Modules/Music/Services/MusicService.cs index 6b7fffc5..d0b00657 100644 --- a/src/NadekoBot/Modules/Music/Services/MusicService.cs +++ b/src/NadekoBot/Modules/Music/Services/MusicService.cs @@ -222,61 +222,5 @@ namespace NadekoBot.Modules.Music.Services if (MusicPlayers.TryRemove(id, out var mp)) await mp.Destroy(); } - - - - //public Task ResolveYoutubeSong(string query, string queuerName) - //{ - // _log.Info("Getting video"); - // //var (link, video) = await GetYoutubeVideo(query); - - // //if (video == null) // do something with this error - // //{ - // // _log.Info("Could not load any video elements based on the query."); - // // return null; - // //} - // ////var m = Regex.Match(query, @"\?t=(?\d*)"); - // ////int gotoTime = 0; - // ////if (m.Captures.Count > 0) - // //// int.TryParse(m.Groups["t"].ToString(), out gotoTime); - - // //_log.Info("Creating song info"); - // //var song = new SongInfo - // //{ - // // Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube" - // // Provider = "YouTube", - // // Uri = async () => { - // // var vid = await GetYoutubeVideo(query); - // // if (vid.Item2 == null) - // // throw new HttpRequestException(); - - // // return await vid.Item2.GetUriAsync(); - // // }, - // // Query = link, - // // ProviderType = MusicType.YouTube, - // // QueuerName = queuerName - // //}; - // return GetYoutubeVideo(query, queuerName); - //} - - //private async Task GetYoutubeVideo(string query, string queuerName) - //{ - - - // //if (string.IsNullOrWhiteSpace(link)) - // //{ - // // _log.Info("No song found."); - // // return (null, null); - // //} - // //_log.Info("Getting all videos"); - // //var allVideos = await Task.Run(async () => { try { return await _yt.GetAllVideosAsync(link).ConfigureAwait(false); } catch { return Enumerable.Empty(); } }).ConfigureAwait(false); - // //var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio); - // //var video = videos - // // .Where(v => v.AudioBitrate < 256) - // // .OrderByDescending(v => v.AudioBitrate) - // // .FirstOrDefault(); - - // //return (link, video); - //} } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/FeedCommands.cs b/src/NadekoBot/Modules/Searches/FeedCommands.cs new file mode 100644 index 00000000..38fe6be6 --- /dev/null +++ b/src/NadekoBot/Modules/Searches/FeedCommands.cs @@ -0,0 +1,106 @@ +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Microsoft.SyndicationFeed.Rss; +using NadekoBot.Common.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Modules.Searches.Services; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Xml; + +namespace NadekoBot.Modules.Searches +{ + public partial class Searches + { + [Group] + public class FeedCommands : NadekoSubmodule + { + private readonly DiscordSocketClient _client; + + public FeedCommands(DiscordSocketClient client) + { + _client = client; + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task Feed(string url, [Remainder] ITextChannel channel = null) + { + var success = Uri.TryCreate(url, UriKind.Absolute, out var uri) && + (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps); + if (success) + { + channel = channel ?? (ITextChannel)Context.Channel; + using (var xmlReader = XmlReader.Create(url, new XmlReaderSettings() { Async = true })) + { + var reader = new RssFeedReader(xmlReader); + try + { + await reader.Read(); + } + catch { success = false; } + } + + if (success) + { + success = _service.AddFeed(Context.Guild.Id, channel.Id, url); + if (success) + { + await ReplyConfirmLocalized("feed_added").ConfigureAwait(false); + return; + } + } + } + + await ReplyErrorLocalized("feed_not_valid").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task FeedRemove(int index) + { + if (_service.RemoveFeed(Context.Guild.Id, --index)) + { + await ReplyConfirmLocalized("feed_removed").ConfigureAwait(false); + } + else + await ReplyErrorLocalized("feed_out_of_range").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task FeedList() + { + var feeds = _service.GetFeeds(Context.Guild.Id); + + if (!feeds.Any()) + { + await Context.Channel.EmbedAsync(new EmbedBuilder() + .WithOkColor() + .WithDescription(GetText("feed_no_feed"))) + .ConfigureAwait(false); + return; + } + + await Context.Channel.SendPaginatedConfirmAsync(_client, 0, (cur) => + { + var embed = new EmbedBuilder() + .WithOkColor(); + var i = 0; + var fs = string.Join("\n", feeds.Skip(cur * 10) + .Take(10) + .Select(x => $"`{(cur * 10) + (++i)}.` <#{x.ChannelId}> {x.Url}")); + + return embed.WithDescription(fs); + + }, feeds.Count / 10); + } + } + } +} diff --git a/src/NadekoBot/Modules/Searches/Services/FeedsService.cs b/src/NadekoBot/Modules/Searches/Services/FeedsService.cs new file mode 100644 index 00000000..c0eae9d5 --- /dev/null +++ b/src/NadekoBot/Modules/Searches/Services/FeedsService.cs @@ -0,0 +1,213 @@ +using Discord; +using Microsoft.SyndicationFeed; +using Microsoft.SyndicationFeed.Rss; +using NadekoBot.Extensions; +using NadekoBot.Services; +using System; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml; +using System.Collections.Generic; +using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; +using System.Collections.Concurrent; +using Discord.WebSocket; + +namespace NadekoBot.Modules.Searches.Services +{ + public class FeedsService : INService + { + private readonly DbService _db; + private readonly ConcurrentDictionary> _subs; + private readonly DiscordSocketClient _client; + private readonly ConcurrentDictionary _lastPosts = + new ConcurrentDictionary(); + + public FeedsService(IEnumerable gcs, DbService db, DiscordSocketClient client) + { + _db = db; + + _subs = gcs.SelectMany(x => x.FeedSubs) + .GroupBy(x => x.Url) + .ToDictionary(x => x.Key, x => x.ToHashSet()) + .ToConcurrent(); + + _client = client; + + foreach (var kvp in _subs) + { + // to make sure rss feeds don't post right away, but + // only the updates from after the bot has started + _lastPosts.AddOrUpdate(kvp.Key, DateTime.UtcNow, (k, old) => DateTime.UtcNow); + } + + var _ = Task.Run(TrackFeeds); + } + + public async Task TrackFeeds() + { + while (true) + { + foreach (var kvp in _subs) + { + if (kvp.Value.Count == 0) + continue; + + DateTime lastTime; + if (!_lastPosts.TryGetValue(kvp.Key, out lastTime)) + lastTime = _lastPosts.AddOrUpdate(kvp.Key, DateTime.UtcNow, (k, old) => DateTime.UtcNow); + + var rssUrl = kvp.Key; + try + { + using (var xmlReader = XmlReader.Create(rssUrl, new XmlReaderSettings() { Async = true })) + { + var feedReader = new RssFeedReader(xmlReader); + + var embed = new EmbedBuilder() + .WithAuthor(kvp.Key) + .WithOkColor(); + + while (await feedReader.Read() && feedReader.ElementType != SyndicationElementType.Item) + { + switch (feedReader.ElementType) + { + case SyndicationElementType.Link: + var uri = await feedReader.ReadLink(); + embed.WithAuthor(kvp.Key, url: uri.Uri.AbsoluteUri); + break; + case SyndicationElementType.Content: + var content = await feedReader.ReadContent(); + break; + case SyndicationElementType.Category: + break; + case SyndicationElementType.Image: + ISyndicationImage image = await feedReader.ReadImage(); + embed.WithThumbnailUrl(image.Url.AbsoluteUri); + break; + default: + break; + } + } + + ISyndicationItem item = await feedReader.ReadItem(); + if (item.Published.UtcDateTime <= lastTime) + continue; + + var desc = item.Description.StripHTML(); + + lastTime = item.Published.UtcDateTime; + var title = string.IsNullOrWhiteSpace(item.Title) ? "-" : item.Title; + desc = Format.Code(item.Published.ToString()) + Environment.NewLine + desc; + var link = item.Links.FirstOrDefault(); + if (link != null) + desc = $"[link]({link.Uri}) " + desc; + + var img = item.Links.FirstOrDefault(x => x.RelationshipType == "enclosure")?.Uri.AbsoluteUri + ?? Regex.Match(item.Description, @"src=""(?.*?)""").Groups["src"].ToString(); + + if (!string.IsNullOrWhiteSpace(img) && Uri.IsWellFormedUriString(img, UriKind.Absolute)) + embed.WithImageUrl(img); + + embed.AddField(title, desc); + + //send the created embed to all subscribed channels + var sendTasks = kvp.Value + .Where(x => x.GuildConfig != null) + .Select(x => _client.GetGuild(x.GuildConfig.GuildId) + ?.GetTextChannel(x.ChannelId)) + .Where(x => x != null) + .Select(x => x.EmbedAsync(embed)); + + _lastPosts.AddOrUpdate(kvp.Key, item.Published.UtcDateTime, (k, old) => item.Published.UtcDateTime); + + await Task.WhenAll(sendTasks).ConfigureAwait(false); + } + } + catch (Exception ex) { Console.WriteLine(ex); } + } + + await Task.Delay(10000); + } + } + + public List GetFeeds(ulong guildId) + { + using (var uow = _db.UnitOfWork) + { + return uow.GuildConfigs.For(guildId, set => set.Include(x => x.FeedSubs)) + .FeedSubs + .OrderBy(x => x.Id) + .ToList(); + } + } + + public bool AddFeed(ulong guildId, ulong channelId, string rssFeed) + { + rssFeed.ThrowIfNull(nameof(rssFeed)); + + var fs = new FeedSub() + { + ChannelId = channelId, + Url = rssFeed.Trim().ToLowerInvariant(), + }; + + using (var uow = _db.UnitOfWork) + { + var gc = uow.GuildConfigs.For(guildId, set => set.Include(x => x.FeedSubs)); + + if (gc.FeedSubs.Contains(fs)) + { + return false; + } + else if (gc.FeedSubs.Count >= 10) + { + return false; + } + + gc.FeedSubs.Add(fs); + + //adding all, in case bot wasn't on this guild when it started + foreach (var f in gc.FeedSubs) + { + _subs.AddOrUpdate(f.Url, new HashSet(), (k, old) => + { + old.Add(f); + return old; + }); + } + + uow.Complete(); + } + + return true; + } + + public bool RemoveFeed(ulong guildId, int index) + { + if (index < 0) + return false; + + using (var uow = _db.UnitOfWork) + { + var items = uow.GuildConfigs.For(guildId, set => set.Include(x => x.FeedSubs)) + .FeedSubs + .OrderBy(x => x.Id) + .ToList(); + + if (items.Count <= index) + return false; + var toRemove = items[index]; + _subs.AddOrUpdate(toRemove.Url, new HashSet(), (key, old) => + { + old.Remove(toRemove); + return old; + }); + uow._context.Remove(toRemove); + uow.Complete(); + } + return true; + } + } +} diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index da1a1e22..e031284d 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -61,6 +61,7 @@ + diff --git a/src/NadekoBot/Properties/launchSettings.json b/src/NadekoBot/Properties/launchSettings.json index b532770a..ac657813 100644 --- a/src/NadekoBot/Properties/launchSettings.json +++ b/src/NadekoBot/Properties/launchSettings.json @@ -2,6 +2,10 @@ "profiles": { "NadekoBot": { "commandName": "Project" + }, + "Watch": { + "executablePath": "C:\\Program Files\\dotnet\\dotnet.exe", + "commandLineArgs": "watch run" } } } \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/FeedSub.cs b/src/NadekoBot/Services/Database/Models/FeedSub.cs new file mode 100644 index 00000000..aabf455e --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/FeedSub.cs @@ -0,0 +1,23 @@ +namespace NadekoBot.Services.Database.Models +{ + public class FeedSub : DbEntity + { + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public ulong ChannelId { get; set; } + public string Url { get; set; } + + public override int GetHashCode() + { + return Url.GetHashCode() ^ GuildConfigId.GetHashCode(); + } + + public override bool Equals(object obj) + { + return obj is FeedSub s + ? s.Url == Url && s.GuildConfigId == GuildConfigId + : false; + } + } +} diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 82cc8bdf..501b9a64 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -87,6 +87,7 @@ namespace NadekoBot.Services.Database.Models public StreamRoleSettings StreamRole { get; set; } public XpSettings XpSettings { get; set; } + public List FeedSubs { get; set; } = new List(); //public List ProtectionIgnoredChannels { get; set; } = new List(); } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 5142e8e5..373ab756 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -142,6 +142,9 @@ namespace NadekoBot.Services.Database .HasOne(x => x.GuildConfig) .WithOne(x => x.AntiRaidSetting); + modelBuilder.Entity() + .HasAlternateKey(x => new { x.GuildConfigId, x.Url }); + //modelBuilder.Entity() // .HasAlternateKey(c => new { c.ChannelId, c.ProtectionType }); @@ -304,6 +307,7 @@ namespace NadekoBot.Services.Database .WithOne(x => x.XpSettings); #endregion + //todo major bug #region XpRoleReward modelBuilder.Entity() .HasAlternateKey(x => x.Level); diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 720fd794..eac42399 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -44,6 +44,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.SlowmodeIgnoredUsers) .Include(gc => gc.AntiSpamSetting) .ThenInclude(x => x.IgnoredChannels) + .Include(gc => gc.FeedSubs) + .ThenInclude(x => x.GuildConfig) .Include(gc => gc.FollowedStreams) .Include(gc => gc.StreamRole) .Include(gc => gc.NsfwBlacklistedTags) diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index dc3829ce..8bc0d257 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Services.Impl public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; private static readonly Dictionary _commandData; - + static Localization() { _commandData = JsonConvert.DeserializeObject>( diff --git a/src/NadekoBot/_Extensions/StringExtensions.cs b/src/NadekoBot/_Extensions/StringExtensions.cs index fb083882..0b7adf65 100644 --- a/src/NadekoBot/_Extensions/StringExtensions.cs +++ b/src/NadekoBot/_Extensions/StringExtensions.cs @@ -9,6 +9,11 @@ namespace NadekoBot.Extensions { public static class StringExtensions { + public static string StripHTML(this string input) + { + return Regex.Replace(input, "<.*?>", String.Empty); + } + /// /// Easy use of fast, efficient case-insensitive Contains check with StringComparison Member Types /// CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index 80389b23..fe0a5ef3 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -872,5 +872,10 @@ "xp_club_admin_remove": "{0} is no longer club admin.", "xp_club_admin_error": "Error. You are either not the owner of the club, or that user is not in your club.", "nsfw_started": "Started. Reposting every {0}s.", - "nsfw_stopped": "Stopped reposting." + "nsfw_stopped": "Stopped reposting.", + "searches_feed_added": "Feed added.", + "searches_feed_not_valid": "Invalid link, or you're already following that feed on this server, or you've reached maximum number of feeds allowed.", + "searches_feed_out_of_range": "Index out of range.", + "searches_feed_removed": "Feed removed.", + "searches_feed_no_feed": "You haven't subscribed to any feeds on this server." } \ No newline at end of file diff --git a/src/NadekoBot/data/command_strings.json b/src/NadekoBot/data/command_strings.json index ca64fa24..1640acb0 100644 --- a/src/NadekoBot/data/command_strings.json +++ b/src/NadekoBot/data/command_strings.json @@ -2965,5 +2965,26 @@ "Usage": [ "{0}8ball" ] + }, + "feed": { + "cmd": "feed feedadd", + "desc": "Subscribes to a feed. Bot will post an update up to once every 10 seconds. You can have up to 10 feeds on one server. All feeds must have unique URLs.", + "usage": [ + "{0}feed https://www.rt.com/rss/" + ] + }, + "feedremove": { + "cmd": "feedremove feedrm feeddel", + "desc": "Stops tracking a feed on the given index. Use `{0}feeds` command to see a list of feeds and their indexes.", + "usage": [ + "{0}feedremove 3" + ] + }, + "feedlist": { + "cmd": "feeds feedlist", + "desc": "Shows the list of feeds you've subscribed to on this server.", + "usage": [ + "{0}feeds" + ] } } \ No newline at end of file