From 77e43071b941420c1da50857213072a31aa55118 Mon Sep 17 00:00:00 2001 From: Wilson Biggs Date: Thu, 7 Dec 2023 19:26:44 -0500 Subject: [PATCH 1/3] First pass adding redbot support --- src/FMBot.Bot/Builders/GuildSettingBuilder.cs | 39 + src/FMBot.Bot/Handlers/CommandHandler.cs | 2 +- src/FMBot.Bot/Models/Modals/SettingModals.cs | 9 + src/FMBot.Bot/Models/MusicBot/MusicBot.cs | 8 +- src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs | 49 + .../Resources/InteractionConstants.cs | 3 + src/FMBot.Bot/Services/Guild/GuildService.cs | 26 +- src/FMBot.Bot/Services/TimerService.cs | 6 +- .../GuildSettingSlashCommands.cs | 30 + src/FMBot.Domain/Enums/GuildSetting.cs | 4 +- src/FMBot.Persistence.Domain/Models/Guild.cs | 2 + .../20231207235943_AddRedBotName.Designer.cs | 2296 +++++++++++++++++ .../20231207235943_AddRedBotName.cs | 28 + .../Migrations/FMBotDbContextModelSnapshot.cs | 6 +- 14 files changed, 2500 insertions(+), 8 deletions(-) create mode 100644 src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs create mode 100644 src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.Designer.cs create mode 100644 src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.cs diff --git a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs index 5ae3c3772..c89ace14c 100644 --- a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs +++ b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs @@ -170,6 +170,8 @@ public async Task GetGuildSettings(ContextModel context, GuildPer response.Embed.AddField("Missing server-wide permissions", serverPermission.ToString()); } + response.Embed.AddField("Red bot name", guild.RedBotName ?? "N/A"); + var guildSettings = new SelectMenuBuilder() .WithPlaceholder("Select setting you want to change") .WithCustomId(InteractionConstants.GuildSetting) @@ -952,4 +954,41 @@ public async Task ToggleChannelCommand(ContextModel context, ulon return response; } + + public async Task SetRedBotName(ContextModel context, IUser lastModifier = null) + { + var response = new ResponseModel + { + ResponseType = ResponseType.Embed, + }; + + response.Embed.WithTitle("Set Red bot name"); + response.Embed.WithColor(DiscordConstants.InformationColorBlue); + + var description = new StringBuilder(); + var guild = await this._guildService.GetGuildAsync(context.DiscordGuild.Id); + + var redBotName = guild.RedBotName; + + description.AppendLine(); + description.AppendLine($"Current name: `{redBotName ?? "N/A"}`"); + description.AppendLine(); + description.AppendLine("Your Red bot instance's name must start with, or be the same as, the name you enter."); + description.AppendLine(); + + var components = new ComponentBuilder(); + + components.WithButton("Set Red bot name", InteractionConstants.SetRedBotName, style: ButtonStyle.Primary); + + response.Embed.WithDescription(description.ToString()); + + if (lastModifier != null) + { + response.Embed.WithFooter($"Last modified by {lastModifier.Username}"); + } + + response.Components = components; + + return response; + } } diff --git a/src/FMBot.Bot/Handlers/CommandHandler.cs b/src/FMBot.Bot/Handlers/CommandHandler.cs index a7ac51156..df927894c 100644 --- a/src/FMBot.Bot/Handlers/CommandHandler.cs +++ b/src/FMBot.Bot/Handlers/CommandHandler.cs @@ -144,7 +144,7 @@ private async Task TryScrobbling(SocketUserMessage msg, ICommandContext context) { foreach (var musicBot in MusicBot.SupportedBots) { - if (musicBot.IsAuthor(msg.Author)) + if (await musicBot.IsAuthor(msg.Author, context, this._guildService)) { await this._musicBotService.Scrobble(musicBot, msg, context); break; diff --git a/src/FMBot.Bot/Models/Modals/SettingModals.cs b/src/FMBot.Bot/Models/Modals/SettingModals.cs index eee0ae5e8..04a22fe93 100644 --- a/src/FMBot.Bot/Models/Modals/SettingModals.cs +++ b/src/FMBot.Bot/Models/Modals/SettingModals.cs @@ -92,3 +92,12 @@ public class AddDisabledGuildCommandModal : IModal [ModalTextInput("command", placeholder: "whoknows", minLength: 1, maxLength: 40)] public string Command { get; set; } } + +public class SetRedBotNameModal : IModal +{ + public string Title => "Set Red bot name"; + + [InputLabel("Enter new bot name")] + [ModalTextInput("red_bot_name", minLength: 1, maxLength: 15)] + public string NewBotName { get; set; } +} diff --git a/src/FMBot.Bot/Models/MusicBot/MusicBot.cs b/src/FMBot.Bot/Models/MusicBot/MusicBot.cs index 8f4895d76..67512901e 100644 --- a/src/FMBot.Bot/Models/MusicBot/MusicBot.cs +++ b/src/FMBot.Bot/Models/MusicBot/MusicBot.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Discord; +using Discord.Commands; using Discord.WebSocket; +using FMBot.Bot.Services.Guild; namespace FMBot.Bot.Models.MusicBot; @@ -16,7 +19,8 @@ public abstract class MusicBot { new JockieMusicBot(), new CakeyBotMusicBot(), - new SoundCloudMusicBot() + new SoundCloudMusicBot(), + new RedMusicBot() }; protected MusicBot(string name, bool possiblyIncludesLinks = true, bool skipUploaderName = false) @@ -26,7 +30,7 @@ protected MusicBot(string name, bool possiblyIncludesLinks = true, bool skipUplo this.SkipUploaderName = skipUploaderName; } - public bool IsAuthor(SocketUser user) + public virtual async Task IsAuthor(SocketUser user, ICommandContext context, GuildService guildService) { return user?.Username?.StartsWith(this.Name, StringComparison.OrdinalIgnoreCase) ?? false; } diff --git a/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs b/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs new file mode 100644 index 000000000..68d4bfbf9 --- /dev/null +++ b/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using FMBot.Bot.Services.Guild; + +namespace FMBot.Bot.Models.MusicBot; + +internal class RedMusicBot : MusicBot +{ + public RedMusicBot() : base("Red", true, true) + { + } + + public override bool ShouldIgnoreMessage(IUserMessage msg) + { + // Bot sends only single embed per request + if (msg.Embeds.Count != 1) + { + return true; + } + + var targetEmbed = msg.Embeds.First(); + + return targetEmbed.Title == null || + !targetEmbed.Title.Contains("Now Playing") || + string.IsNullOrEmpty(targetEmbed.Description); + } + + public override string GetTrackQuery(IUserMessage msg) + { + return msg.Embeds.First().Description; + } + + public override async Task IsAuthor(SocketUser user, ICommandContext context, GuildService guildService) + { + var guild = await guildService.GetGuildAsync(context.Guild.Id); + string redBotName = guild.RedBotName; + + if (redBotName != null) + { + return user?.Username?.StartsWith(redBotName, StringComparison.OrdinalIgnoreCase) ?? false; + } + + return false; + } +} diff --git a/src/FMBot.Bot/Resources/InteractionConstants.cs b/src/FMBot.Bot/Resources/InteractionConstants.cs index 62a09daa0..a2b511b5c 100644 --- a/src/FMBot.Bot/Resources/InteractionConstants.cs +++ b/src/FMBot.Bot/Resources/InteractionConstants.cs @@ -126,6 +126,9 @@ public static class ToggleCommand public const string ToggleGuildCommandRemoveModal = "toggle-guild-command-modal-remove"; } + public const string SetRedBotName = "set-red-bot-name"; + public const string SetRedBotNameModal = "set-red-bot-name-modal"; + public const string WhoKnowsRolePicker = "whoknows-role-picker"; public const string WhoKnowsAlbumRolePicker = "whoknows-album-role-picker"; public const string WhoKnowsTrackRolePicker = "whoknows-track-role-picker"; diff --git a/src/FMBot.Bot/Services/Guild/GuildService.cs b/src/FMBot.Bot/Services/Guild/GuildService.cs index e4a595d59..ee3f0fd70 100644 --- a/src/FMBot.Bot/Services/Guild/GuildService.cs +++ b/src/FMBot.Bot/Services/Guild/GuildService.cs @@ -254,7 +254,7 @@ public static (FilterStats Stats, IDictionary FilteredGuildU users = users .Where(w => w.Value.Roles != null && !guild.BlockedRoles.Any(a => w.Value.Roles.Contains(a))) - .ToDictionary(i => i.Key, i => i.Value); + .ToDictionary(i => i.Key, i => i.Value); stats.BlockedRolesFiltered = preFilterCount - users.Count; } @@ -1263,4 +1263,28 @@ public async Task UpdateGuildUserLastMessageDate(IGuildUser discordGuildUser, in Log.Error(e, $"Exception in {nameof(UpdateGuildUserLastMessageDate)}"); } } + + public async Task SetGuildRedBotNameAsync(IGuild discordGuild, string? botName) + { + await using var db = await this._contextFactory.CreateDbContextAsync(); + var existingGuild = await db.Guilds + .AsQueryable() + .FirstOrDefaultAsync(f => f.DiscordGuildId == discordGuild.Id); + + if (existingGuild == null) + { + return false; + } + + existingGuild.Name = discordGuild.Name; + existingGuild.RedBotName = botName; + + db.Entry(existingGuild).State = EntityState.Modified; + + await db.SaveChangesAsync(); + + await RemoveGuildFromCache(discordGuild.Id); + + return true; + } } diff --git a/src/FMBot.Bot/Services/TimerService.cs b/src/FMBot.Bot/Services/TimerService.cs index 8efaf82ac..674942e6b 100644 --- a/src/FMBot.Bot/Services/TimerService.cs +++ b/src/FMBot.Bot/Services/TimerService.cs @@ -88,9 +88,11 @@ public void QueueJobs() Log.Information($"RecurringJob: Adding {nameof(ClearUserCache)}"); RecurringJob.AddOrUpdate(nameof(ClearUserCache), () => ClearUserCache(), "30 */2 * * *"); + Log.Information($"Bot Settings: {ConfigData.Data.Shards}"); + if (this._botSettings.LastFm.UserIndexFrequencyInDays != null && this._botSettings.LastFm.UserIndexFrequencyInDays != 0 && - ConfigData.Data.Shards.MainInstance == true) + ConfigData.Data.Shards?.MainInstance == true) { Log.Information($"RecurringJob: Adding {nameof(AddUsersToIndexQueue)}"); RecurringJob.AddOrUpdate(nameof(AddUsersToIndexQueue), () => AddUsersToIndexQueue(), "0 8 * * *"); @@ -102,7 +104,7 @@ public void QueueJobs() if (this._botSettings.LastFm.UserUpdateFrequencyInHours != null && this._botSettings.LastFm.UserUpdateFrequencyInHours != 0 && - ConfigData.Data.Shards.MainInstance == true) + ConfigData.Data.Shards?.MainInstance == true) { Log.Information($"RecurringJob: Adding {nameof(AddUsersToUpdateQueue)}"); RecurringJob.AddOrUpdate(nameof(AddUsersToUpdateQueue), () => AddUsersToUpdateQueue(), "0 * * * *"); diff --git a/src/FMBot.Bot/SlashCommands/GuildSettingSlashCommands.cs b/src/FMBot.Bot/SlashCommands/GuildSettingSlashCommands.cs index b46b8737d..ee30b15cf 100644 --- a/src/FMBot.Bot/SlashCommands/GuildSettingSlashCommands.cs +++ b/src/FMBot.Bot/SlashCommands/GuildSettingSlashCommands.cs @@ -242,6 +242,12 @@ public async Task GetGuildSetting(string[] inputs) await this.Context.SendResponse(this.Interactivity, response, ephemeral: false); } break; + case GuildSetting.RedBotName: + { + response = await this._guildSettingBuilder.SetRedBotName(new ContextModel(this.Context)); + await this.Context.SendResponse(this.Interactivity, response, ephemeral: false); + } + break; default: throw new ArgumentOutOfRangeException(); } @@ -789,4 +795,28 @@ public async Task ClearDisabledChannelCommand() await this.Context.UpdateInteractionEmbed(response); } + + [ComponentInteraction(InteractionConstants.SetRedBotName)] + [ServerStaffOnly] + public async Task SetRedBotName() + { + var message = (this.Context.Interaction as SocketMessageComponent)?.Message; + + if (message == null) + { + return; + } + + await this.Context.Interaction.RespondWithModalAsync($"{InteractionConstants.SetRedBotNameModal}-{message.Id}"); + } + + [ModalInteraction($"{InteractionConstants.SetRedBotNameModal}-*")] + [ServerStaffOnly] + public async Task SetRedBotName(string messageId, SetRedBotNameModal modal) + { + await this._guildService.SetGuildRedBotNameAsync(this.Context.Guild, modal.NewBotName); + + var response = await this._guildSettingBuilder.SetRedBotName(new ContextModel(this.Context), this.Context.User); + await this.Context.UpdateMessageEmbed(response, messageId); + } } diff --git a/src/FMBot.Domain/Enums/GuildSetting.cs b/src/FMBot.Domain/Enums/GuildSetting.cs index b928d5581..12694f741 100644 --- a/src/FMBot.Domain/Enums/GuildSetting.cs +++ b/src/FMBot.Domain/Enums/GuildSetting.cs @@ -29,7 +29,9 @@ public enum GuildSetting [Option("Disabled channel commands", "Toggle commands or the bot per channel")] DisabledCommands = 30, - [Option("Disabled server commands", "Toggle commands server-wide")] DisabledGuildCommands = 31, + + [Option("Red bot name", "Name of Red bot instance for music bot scrobbling")] + RedBotName = 40, } diff --git a/src/FMBot.Persistence.Domain/Models/Guild.cs b/src/FMBot.Persistence.Domain/Models/Guild.cs index d9027df01..52dcb818f 100644 --- a/src/FMBot.Persistence.Domain/Models/Guild.cs +++ b/src/FMBot.Persistence.Domain/Models/Guild.cs @@ -60,4 +60,6 @@ public class Guild public ICollection Webhooks { get; set; } public ulong? WhoKnowsWhitelistRoleId { get; set; } + + public string? RedBotName { get; set; } } diff --git a/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.Designer.cs b/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.Designer.cs new file mode 100644 index 000000000..8fda49f23 --- /dev/null +++ b/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.Designer.cs @@ -0,0 +1,2296 @@ +// +using System; +using System.Collections.Generic; +using FMBot.Persistence.EntityFrameWork; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FMBot.Persistence.EntityFrameWork.Migrations +{ + [DbContext(typeof(FMBotDbContext))] + [Migration("20231207235943_AddRedBotName")] + partial class AddRedBotName + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "citext"); + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "pg_trgm"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.AiGeneration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateGenerated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_generated"); + + b.Property("Model") + .HasColumnType("text") + .HasColumnName("model"); + + b.Property("Output") + .HasColumnType("text") + .HasColumnName("output"); + + b.Property("Prompt") + .HasColumnType("text") + .HasColumnName("prompt"); + + b.Property("TargetedUserId") + .HasColumnType("integer") + .HasColumnName("targeted_user_id"); + + b.Property("TotalTokens") + .HasColumnType("integer") + .HasColumnName("total_tokens"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_ai_generations"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_ai_generations_user_id"); + + b.ToTable("ai_generations", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.AiPrompt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Language") + .HasColumnType("text") + .HasColumnName("language"); + + b.Property("Prompt") + .HasColumnType("text") + .HasColumnName("prompt"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("Version") + .HasColumnType("integer") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_ai_prompts"); + + b.ToTable("ai_prompts", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Album", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("Label") + .HasColumnType("text") + .HasColumnName("label"); + + b.Property("LastFmDescription") + .HasColumnType("text") + .HasColumnName("last_fm_description"); + + b.Property("LastFmUrl") + .HasColumnType("text") + .HasColumnName("last_fm_url"); + + b.Property("LastfmDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("lastfm_date"); + + b.Property("LastfmImageUrl") + .HasColumnType("text") + .HasColumnName("lastfm_image_url"); + + b.Property("Mbid") + .HasColumnType("uuid") + .HasColumnName("mbid"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Popularity") + .HasColumnType("integer") + .HasColumnName("popularity"); + + b.Property("ReleaseDate") + .HasColumnType("text") + .HasColumnName("release_date"); + + b.Property("ReleaseDatePrecision") + .HasColumnType("text") + .HasColumnName("release_date_precision"); + + b.Property("SpotifyId") + .HasColumnType("text") + .HasColumnName("spotify_id"); + + b.Property("SpotifyImageDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("spotify_image_date"); + + b.Property("SpotifyImageUrl") + .HasColumnType("text") + .HasColumnName("spotify_image_url"); + + b.HasKey("Id") + .HasName("pk_albums"); + + b.HasIndex("ArtistId") + .HasDatabaseName("ix_albums_artist_id"); + + b.ToTable("albums", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Artist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CountryCode") + .HasColumnType("text") + .HasColumnName("country_code"); + + b.Property("Disambiguation") + .HasColumnType("text") + .HasColumnName("disambiguation"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_date"); + + b.Property("Gender") + .HasColumnType("text") + .HasColumnName("gender"); + + b.Property("LastFmDescription") + .HasColumnType("text") + .HasColumnName("last_fm_description"); + + b.Property("LastFmUrl") + .HasColumnType("text") + .HasColumnName("last_fm_url"); + + b.Property("LastfmDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("lastfm_date"); + + b.Property("Location") + .HasColumnType("text") + .HasColumnName("location"); + + b.Property("Mbid") + .HasColumnType("uuid") + .HasColumnName("mbid"); + + b.Property("MusicBrainzDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("music_brainz_date"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Popularity") + .HasColumnType("integer") + .HasColumnName("popularity"); + + b.Property("SpotifyId") + .HasColumnType("text") + .HasColumnName("spotify_id"); + + b.Property("SpotifyImageDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("spotify_image_date"); + + b.Property("SpotifyImageUrl") + .HasColumnType("text") + .HasColumnName("spotify_image_url"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_date"); + + b.Property("Type") + .HasColumnType("text") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_artists"); + + b.ToTable("artists", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.ArtistAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Alias") + .HasColumnType("text") + .HasColumnName("alias"); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("CorrectsInScrobbles") + .HasColumnType("boolean") + .HasColumnName("corrects_in_scrobbles"); + + b.Property("Options") + .HasColumnType("integer") + .HasColumnName("options"); + + b.HasKey("Id") + .HasName("pk_artist_aliases"); + + b.HasIndex("ArtistId") + .HasDatabaseName("ix_artist_aliases_artist_id"); + + b.ToTable("artist_aliases", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.ArtistGenre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_artist_genres"); + + b.HasIndex("ArtistId") + .HasDatabaseName("ix_artist_genres_artist_id"); + + b.ToTable("artist_genres", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.BottedUser", b => + { + b.Property("BottedUserId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("botted_user_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BottedUserId")); + + b.Property("BanActive") + .HasColumnType("boolean") + .HasColumnName("ban_active"); + + b.Property("LastFmRegistered") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_fm_registered"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("UserNameLastFM") + .HasColumnType("text") + .HasColumnName("user_name_last_fm"); + + b.HasKey("BottedUserId") + .HasName("pk_botted_users"); + + b.ToTable("botted_users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.BottedUserReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ProcessedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("processed_at"); + + b.Property("ProcessedByDiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("processed_by_discord_user_id"); + + b.Property("ProvidedNote") + .HasColumnType("text") + .HasColumnName("provided_note"); + + b.Property("ReportStatus") + .HasColumnType("integer") + .HasColumnName("report_status"); + + b.Property("ReportedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("reported_at"); + + b.Property("ReportedByDiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("reported_by_discord_user_id"); + + b.Property("UserNameLastFM") + .HasColumnType("text") + .HasColumnName("user_name_last_fm"); + + b.HasKey("Id") + .HasName("pk_botted_user_report"); + + b.ToTable("botted_user_report", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.CensoredMusic", b => + { + b.Property("CensoredMusicId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("censored_music_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("CensoredMusicId")); + + b.Property("AlbumName") + .HasColumnType("text") + .HasColumnName("album_name"); + + b.Property("AlternativeCoverUrl") + .HasColumnType("text") + .HasColumnName("alternative_cover_url"); + + b.Property("Artist") + .HasColumnType("boolean") + .HasColumnName("artist"); + + b.Property("ArtistName") + .HasColumnType("text") + .HasColumnName("artist_name"); + + b.Property("CensorType") + .HasColumnType("bigint") + .HasColumnName("censor_type"); + + b.Property("FeaturedBanOnly") + .HasColumnType("boolean") + .HasColumnName("featured_ban_only"); + + b.Property("SafeForCommands") + .HasColumnType("boolean") + .HasColumnName("safe_for_commands"); + + b.Property("SafeForFeatured") + .HasColumnType("boolean") + .HasColumnName("safe_for_featured"); + + b.Property("TimesCensored") + .HasColumnType("integer") + .HasColumnName("times_censored"); + + b.HasKey("CensoredMusicId") + .HasName("pk_censored_music"); + + b.ToTable("censored_music", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.CensoredMusicReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlbumId") + .HasColumnType("integer") + .HasColumnName("album_id"); + + b.Property("AlbumName") + .HasColumnType("text") + .HasColumnName("album_name"); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("ArtistName") + .HasColumnType("text") + .HasColumnName("artist_name"); + + b.Property("IsArtist") + .HasColumnType("boolean") + .HasColumnName("is_artist"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("processed_at"); + + b.Property("ProcessedByDiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("processed_by_discord_user_id"); + + b.Property("ProvidedNote") + .HasColumnType("text") + .HasColumnName("provided_note"); + + b.Property("ReportStatus") + .HasColumnType("integer") + .HasColumnName("report_status"); + + b.Property("ReportedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("reported_at"); + + b.Property("ReportedByDiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("reported_by_discord_user_id"); + + b.HasKey("Id") + .HasName("pk_censored_music_report"); + + b.HasIndex("AlbumId") + .HasDatabaseName("ix_censored_music_report_album_id"); + + b.HasIndex("ArtistId") + .HasDatabaseName("ix_censored_music_report_artist_id"); + + b.ToTable("censored_music_report", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Channel", b => + { + b.Property("ChannelId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("channel_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ChannelId")); + + b.Property("BotDisabled") + .HasColumnType("boolean") + .HasColumnName("bot_disabled"); + + b.Property("DisabledCommands") + .HasColumnType("text") + .HasColumnName("disabled_commands"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_channel_id"); + + b.Property("FmCooldown") + .HasColumnType("integer") + .HasColumnName("fm_cooldown"); + + b.Property("FmEmbedType") + .HasColumnType("integer") + .HasColumnName("fm_embed_type"); + + b.Property("GuildId") + .HasColumnType("integer") + .HasColumnName("guild_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("ChannelId") + .HasName("pk_channels"); + + b.HasIndex("DiscordChannelId") + .HasDatabaseName("ix_channels_discord_channel_id"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_channels_guild_id"); + + b.ToTable("channels", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsFormatDescriptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("citext") + .HasColumnName("description"); + + b.Property("ReleaseId") + .HasColumnType("integer") + .HasColumnName("release_id"); + + b.HasKey("Id") + .HasName("pk_discogs_format_descriptions"); + + b.HasIndex("ReleaseId") + .HasDatabaseName("ix_discogs_format_descriptions_release_id"); + + b.ToTable("discogs_format_descriptions", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsGenre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("citext") + .HasColumnName("description"); + + b.Property("ReleaseId") + .HasColumnType("integer") + .HasColumnName("release_id"); + + b.HasKey("Id") + .HasName("pk_discogs_genre"); + + b.HasIndex("ReleaseId") + .HasDatabaseName("ix_discogs_genre_release_id"); + + b.ToTable("discogs_genre", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsRelease", b => + { + b.Property("DiscogsId") + .HasColumnType("integer") + .HasColumnName("discogs_id"); + + b.Property("AlbumId") + .HasColumnType("integer") + .HasColumnName("album_id"); + + b.Property("Artist") + .HasColumnType("citext") + .HasColumnName("artist"); + + b.Property("ArtistDiscogsId") + .HasColumnType("integer") + .HasColumnName("artist_discogs_id"); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("CoverUrl") + .HasColumnType("text") + .HasColumnName("cover_url"); + + b.Property("FeaturingArtist") + .HasColumnType("citext") + .HasColumnName("featuring_artist"); + + b.Property("FeaturingArtistDiscogsId") + .HasColumnType("integer") + .HasColumnName("featuring_artist_discogs_id"); + + b.Property("FeaturingArtistId") + .HasColumnType("integer") + .HasColumnName("featuring_artist_id"); + + b.Property("FeaturingArtistJoin") + .HasColumnType("text") + .HasColumnName("featuring_artist_join"); + + b.Property("Format") + .HasColumnType("citext") + .HasColumnName("format"); + + b.Property("FormatText") + .HasColumnType("text") + .HasColumnName("format_text"); + + b.Property("Label") + .HasColumnType("citext") + .HasColumnName("label"); + + b.Property("LowestPrice") + .HasColumnType("numeric") + .HasColumnName("lowest_price"); + + b.Property("MasterId") + .HasColumnType("integer") + .HasColumnName("master_id"); + + b.Property("SecondLabel") + .HasColumnType("text") + .HasColumnName("second_label"); + + b.Property("Title") + .HasColumnType("citext") + .HasColumnName("title"); + + b.Property("Year") + .HasColumnType("integer") + .HasColumnName("year"); + + b.HasKey("DiscogsId") + .HasName("pk_discogs_releases"); + + b.ToTable("discogs_releases", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsStyle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("citext") + .HasColumnName("description"); + + b.Property("ReleaseId") + .HasColumnType("integer") + .HasColumnName("release_id"); + + b.HasKey("Id") + .HasName("pk_discogs_style"); + + b.HasIndex("ReleaseId") + .HasDatabaseName("ix_discogs_style_release_id"); + + b.ToTable("discogs_style", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.FeaturedLog", b => + { + b.Property("FeaturedLogId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("featured_log_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("FeaturedLogId")); + + b.Property("AlbumName") + .HasColumnType("citext") + .HasColumnName("album_name"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("BotType") + .HasColumnType("integer") + .HasColumnName("bot_type"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_time"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("FeaturedMode") + .HasColumnType("integer") + .HasColumnName("featured_mode"); + + b.Property("HasFeatured") + .HasColumnType("boolean") + .HasColumnName("has_featured"); + + b.Property("ImageUrl") + .HasColumnType("text") + .HasColumnName("image_url"); + + b.Property("NoUpdate") + .HasColumnType("boolean") + .HasColumnName("no_update"); + + b.Property("SupporterDay") + .HasColumnType("boolean") + .HasColumnName("supporter_day"); + + b.Property("TrackName") + .HasColumnType("citext") + .HasColumnName("track_name"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("FeaturedLogId") + .HasName("pk_featured_logs"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_featured_logs_user_id"); + + b.ToTable("featured_logs", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Friend", b => + { + b.Property("FriendId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("friend_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("FriendId")); + + b.Property("FriendUserId") + .HasColumnType("integer") + .HasColumnName("friend_user_id"); + + b.Property("LastFMUserName") + .HasColumnType("text") + .HasColumnName("last_fm_user_name"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("FriendId") + .HasName("pk_friends"); + + b.HasIndex("FriendUserId") + .HasDatabaseName("ix_friends_friend_user_id"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_friends_user_id"); + + b.ToTable("friends", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.GlobalFilteredUser", b => + { + b.Property("GlobalFilteredUserId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("global_filtered_user_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("GlobalFilteredUserId")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("OccurrenceEnd") + .HasColumnType("timestamp with time zone") + .HasColumnName("occurrence_end"); + + b.Property("OccurrenceStart") + .HasColumnType("timestamp with time zone") + .HasColumnName("occurrence_start"); + + b.Property("Reason") + .HasColumnType("integer") + .HasColumnName("reason"); + + b.Property("ReasonAmount") + .HasColumnType("integer") + .HasColumnName("reason_amount"); + + b.Property("RegisteredLastFm") + .HasColumnType("timestamp with time zone") + .HasColumnName("registered_last_fm"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("UserNameLastFm") + .HasColumnType("text") + .HasColumnName("user_name_last_fm"); + + b.HasKey("GlobalFilteredUserId") + .HasName("pk_global_filtered_users"); + + b.ToTable("global_filtered_users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Guild", b => + { + b.Property("GuildId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("guild_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("GuildId")); + + b.Property("ActivityThresholdDays") + .HasColumnType("integer") + .HasColumnName("activity_threshold_days"); + + b.Property("AllowedRoles") + .HasColumnType("numeric(20,0)[]") + .HasColumnName("allowed_roles"); + + b.Property("AutomaticCrownSeeder") + .HasColumnType("integer") + .HasColumnName("automatic_crown_seeder"); + + b.Property("BlockedRoles") + .HasColumnType("numeric(20,0)[]") + .HasColumnName("blocked_roles"); + + b.Property("BotManagementRoles") + .HasColumnType("numeric(20,0)[]") + .HasColumnName("bot_management_roles"); + + b.Property("CrownsActivityThresholdDays") + .HasColumnType("integer") + .HasColumnName("crowns_activity_threshold_days"); + + b.Property("CrownsDisabled") + .HasColumnType("boolean") + .HasColumnName("crowns_disabled"); + + b.Property("CrownsMinimumPlaycountThreshold") + .HasColumnType("integer") + .HasColumnName("crowns_minimum_playcount_threshold"); + + b.Property("CustomLogo") + .HasColumnType("text") + .HasColumnName("custom_logo"); + + b.Property("DisableSupporterMessages") + .HasColumnType("boolean") + .HasColumnName("disable_supporter_messages"); + + b.Property("DisabledCommands") + .HasColumnType("text") + .HasColumnName("disabled_commands"); + + b.Property("DiscordGuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_guild_id"); + + b.Property("EmoteReactions") + .HasColumnType("text") + .HasColumnName("emote_reactions"); + + b.Property("FilterRoles") + .HasColumnType("numeric(20,0)[]") + .HasColumnName("filter_roles"); + + b.Property("FmEmbedType") + .HasColumnType("integer") + .HasColumnName("fm_embed_type"); + + b.Property("GuildFlags") + .HasColumnType("bigint") + .HasColumnName("guild_flags"); + + b.Property("LastCrownSeed") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_crown_seed"); + + b.Property("LastIndexed") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_indexed"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Prefix") + .HasColumnType("text") + .HasColumnName("prefix"); + + b.Property("RedBotName") + .HasColumnType("text") + .HasColumnName("red_bot_name"); + + b.Property("SpecialGuild") + .HasColumnType("boolean") + .HasColumnName("special_guild"); + + b.Property("UserActivityThresholdDays") + .HasColumnType("integer") + .HasColumnName("user_activity_threshold_days"); + + b.Property("WhoKnowsWhitelistRoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("who_knows_whitelist_role_id"); + + b.HasKey("GuildId") + .HasName("pk_guilds"); + + b.HasIndex("DiscordGuildId") + .HasDatabaseName("ix_guilds_discord_guild_id"); + + b.ToTable("guilds", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.GuildBlockedUser", b => + { + b.Property("GuildId") + .HasColumnType("integer") + .HasColumnName("guild_id"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("BlockedFromCrowns") + .HasColumnType("boolean") + .HasColumnName("blocked_from_crowns"); + + b.Property("BlockedFromWhoKnows") + .HasColumnType("boolean") + .HasColumnName("blocked_from_who_knows"); + + b.Property("SelfBlockFromWhoKnows") + .HasColumnType("boolean") + .HasColumnName("self_block_from_who_knows"); + + b.HasKey("GuildId", "UserId") + .HasName("pk_guild_blocked_users"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_guild_blocked_users_user_id"); + + b.ToTable("guild_blocked_users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.GuildUser", b => + { + b.Property("GuildId") + .HasColumnType("integer") + .HasColumnName("guild_id"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("Bot") + .HasColumnType("boolean") + .HasColumnName("bot"); + + b.Property("LastMessage") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_message"); + + b.Property("Roles") + .HasColumnType("numeric(20,0)[]") + .HasColumnName("roles"); + + b.Property("UserName") + .HasColumnType("text") + .HasColumnName("user_name"); + + b.Property("WhoKnowsBlocked") + .HasColumnType("boolean") + .HasColumnName("who_knows_blocked"); + + b.Property("WhoKnowsWhitelisted") + .HasColumnType("boolean") + .HasColumnName("who_knows_whitelisted"); + + b.HasKey("GuildId", "UserId") + .HasName("pk_guild_users"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_guild_users_user_id"); + + b.ToTable("guild_users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.InactiveUsers", b => + { + b.Property("InactiveUserId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("inactive_user_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("InactiveUserId")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("FailureErrorCount") + .HasColumnType("integer") + .HasColumnName("failure_error_count"); + + b.Property("MissingParametersErrorCount") + .HasColumnType("integer") + .HasColumnName("missing_parameters_error_count"); + + b.Property("NoScrobblesErrorCount") + .HasColumnType("integer") + .HasColumnName("no_scrobbles_error_count"); + + b.Property("RecentTracksPrivateCount") + .HasColumnType("integer") + .HasColumnName("recent_tracks_private_count"); + + b.Property("Removed") + .HasColumnType("boolean") + .HasColumnName("removed"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("UserId1") + .HasColumnType("integer") + .HasColumnName("user_id1"); + + b.Property("UserNameLastFM") + .HasColumnType("text") + .HasColumnName("user_name_last_fm"); + + b.HasKey("InactiveUserId") + .HasName("pk_inactive_users"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_inactive_users_user_id"); + + b.HasIndex("UserId1") + .HasDatabaseName("ix_inactive_users_user_id1"); + + b.ToTable("inactive_users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Supporter", b => + { + b.Property("SupporterId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("supporter_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("SupporterId")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("DiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_user_id"); + + b.Property("Expired") + .HasColumnType("boolean") + .HasColumnName("expired"); + + b.Property("LastPayment") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_payment"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("OpenCollectiveId") + .HasColumnType("text") + .HasColumnName("open_collective_id"); + + b.Property("SubscriptionType") + .HasColumnType("integer") + .HasColumnName("subscription_type"); + + b.Property("SupporterMessagesEnabled") + .HasColumnType("boolean") + .HasColumnName("supporter_messages_enabled"); + + b.Property("SupporterType") + .HasColumnType("integer") + .HasColumnName("supporter_type"); + + b.Property("VisibleInOverview") + .HasColumnType("boolean") + .HasColumnName("visible_in_overview"); + + b.HasKey("SupporterId") + .HasName("pk_supporters"); + + b.ToTable("supporters", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Track", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Acousticness") + .HasColumnType("real") + .HasColumnName("acousticness"); + + b.Property("AlbumId") + .HasColumnType("integer") + .HasColumnName("album_id"); + + b.Property("AlbumName") + .HasColumnType("citext") + .HasColumnName("album_name"); + + b.Property("ArtistId") + .HasColumnType("integer") + .HasColumnName("artist_id"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("Danceability") + .HasColumnType("real") + .HasColumnName("danceability"); + + b.Property("DurationMs") + .HasColumnType("integer") + .HasColumnName("duration_ms"); + + b.Property("Energy") + .HasColumnType("real") + .HasColumnName("energy"); + + b.Property("Instrumentalness") + .HasColumnType("real") + .HasColumnName("instrumentalness"); + + b.Property("Key") + .HasColumnType("integer") + .HasColumnName("key"); + + b.Property("LastFmDescription") + .HasColumnType("text") + .HasColumnName("last_fm_description"); + + b.Property("LastFmUrl") + .HasColumnType("text") + .HasColumnName("last_fm_url"); + + b.Property("LastfmDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("lastfm_date"); + + b.Property("Liveness") + .HasColumnType("real") + .HasColumnName("liveness"); + + b.Property("Loudness") + .HasColumnType("real") + .HasColumnName("loudness"); + + b.Property("Mbid") + .HasColumnType("uuid") + .HasColumnName("mbid"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Popularity") + .HasColumnType("integer") + .HasColumnName("popularity"); + + b.Property("Speechiness") + .HasColumnType("real") + .HasColumnName("speechiness"); + + b.Property("SpotifyId") + .HasColumnType("text") + .HasColumnName("spotify_id"); + + b.Property("SpotifyLastUpdated") + .HasColumnType("timestamp with time zone") + .HasColumnName("spotify_last_updated"); + + b.Property("Tempo") + .HasColumnType("real") + .HasColumnName("tempo"); + + b.Property("Valence") + .HasColumnType("real") + .HasColumnName("valence"); + + b.HasKey("Id") + .HasName("pk_tracks"); + + b.HasIndex("AlbumId") + .HasDatabaseName("ix_tracks_album_id"); + + b.HasIndex("ArtistId") + .HasDatabaseName("ix_tracks_artist_id"); + + b.ToTable("tracks", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("user_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserId")); + + b.Property("Blocked") + .HasColumnType("boolean") + .HasColumnName("blocked"); + + b.Property("DataSource") + .HasColumnType("integer") + .HasColumnName("data_source"); + + b.Property("DiscordUserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_user_id"); + + b.Property("EmoteReactions") + .HasColumnType("text") + .HasColumnName("emote_reactions"); + + b.Property("FmEmbedType") + .HasColumnType("integer") + .HasColumnName("fm_embed_type"); + + b.Property("FmFooterOptions") + .HasColumnType("bigint") + .HasColumnName("fm_footer_options"); + + b.Property("LastIndexed") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_indexed"); + + b.Property("LastScrobbleUpdate") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_scrobble_update"); + + b.Property("LastSmallIndexed") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_small_indexed"); + + b.Property("LastUpdated") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_updated"); + + b.Property("LastUsed") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_used"); + + b.Property("LastfmPro") + .HasColumnType("boolean") + .HasColumnName("lastfm_pro"); + + b.Property("Mode") + .HasColumnType("integer") + .HasColumnName("mode"); + + b.Property("MusicBotTrackingDisabled") + .HasColumnType("boolean") + .HasColumnName("music_bot_tracking_disabled"); + + b.Property("NumberFormat") + .HasColumnType("integer") + .HasColumnName("number_format"); + + b.Property("PrivacyLevel") + .HasColumnType("integer") + .HasColumnName("privacy_level"); + + b.Property("RegisteredLastFm") + .HasColumnType("timestamp with time zone") + .HasColumnName("registered_last_fm"); + + b.Property("RymEnabled") + .HasColumnType("boolean") + .HasColumnName("rym_enabled"); + + b.Property("SessionKeyLastFm") + .HasColumnType("text") + .HasColumnName("session_key_last_fm"); + + b.Property("TimeZone") + .HasColumnType("text") + .HasColumnName("time_zone"); + + b.Property("TotalPlaycount") + .HasColumnType("bigint") + .HasColumnName("total_playcount"); + + b.Property("UserNameLastFM") + .HasColumnType("text") + .HasColumnName("user_name_last_fm"); + + b.Property("UserType") + .HasColumnType("integer") + .HasColumnName("user_type"); + + b.HasKey("UserId") + .HasName("pk_users"); + + b.HasIndex("DiscordUserId") + .HasDatabaseName("ix_users_discord_user_id"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_users_user_id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserAlbum", b => + { + b.Property("UserAlbumId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("user_album_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserAlbumId")); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Playcount") + .HasColumnType("integer") + .HasColumnName("playcount"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserAlbumId") + .HasName("pk_user_albums"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_albums_user_id"); + + b.ToTable("user_albums", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserArtist", b => + { + b.Property("UserArtistId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("user_artist_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserArtistId")); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Playcount") + .HasColumnType("integer") + .HasColumnName("playcount"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserArtistId") + .HasName("pk_user_artists"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_artists_user_id"); + + b.ToTable("user_artists", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserCrown", b => + { + b.Property("CrownId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("crown_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("CrownId")); + + b.Property("Active") + .HasColumnType("boolean") + .HasColumnName("active"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("CurrentPlaycount") + .HasColumnType("integer") + .HasColumnName("current_playcount"); + + b.Property("GuildId") + .HasColumnType("integer") + .HasColumnName("guild_id"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone") + .HasColumnName("modified"); + + b.Property("SeededCrown") + .HasColumnType("boolean") + .HasColumnName("seeded_crown"); + + b.Property("StartPlaycount") + .HasColumnType("integer") + .HasColumnName("start_playcount"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("CrownId") + .HasName("pk_user_crowns"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_user_crowns_guild_id"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_crowns_user_id"); + + b.ToTable("user_crowns", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserDiscogs", b => + { + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("AccessToken") + .HasColumnType("text") + .HasColumnName("access_token"); + + b.Property("AccessTokenSecret") + .HasColumnType("text") + .HasColumnName("access_token_secret"); + + b.Property("DiscogsId") + .HasColumnType("integer") + .HasColumnName("discogs_id"); + + b.Property("LastUpdated") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_updated"); + + b.Property("MaximumValue") + .HasColumnType("text") + .HasColumnName("maximum_value"); + + b.Property("MedianValue") + .HasColumnType("text") + .HasColumnName("median_value"); + + b.Property("MinimumValue") + .HasColumnType("text") + .HasColumnName("minimum_value"); + + b.Property("ReleasesLastUpdated") + .HasColumnType("timestamp with time zone") + .HasColumnName("releases_last_updated"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("UserId") + .HasName("pk_user_discogs"); + + b.ToTable("user_discogs", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserDiscogsReleases", b => + { + b.Property("UserDiscogsReleaseId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("user_discogs_release_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserDiscogsReleaseId")); + + b.Property("DateAdded") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_added"); + + b.Property("InstanceId") + .HasColumnType("integer") + .HasColumnName("instance_id"); + + b.Property("Quantity") + .HasColumnType("text") + .HasColumnName("quantity"); + + b.Property("Rating") + .HasColumnType("integer") + .HasColumnName("rating"); + + b.Property("ReleaseId") + .HasColumnType("integer") + .HasColumnName("release_id"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserDiscogsReleaseId") + .HasName("pk_user_discogs_releases"); + + b.HasIndex("ReleaseId") + .HasDatabaseName("ix_user_discogs_releases_release_id"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_discogs_releases_user_id"); + + b.ToTable("user_discogs_releases", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserInteraction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommandContent") + .HasColumnType("text") + .HasColumnName("command_content"); + + b.Property("CommandName") + .HasColumnType("text") + .HasColumnName("command_name"); + + b.Property>("CommandOptions") + .HasColumnType("hstore") + .HasColumnName("command_options"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_channel_id"); + + b.Property("DiscordGuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_guild_id"); + + b.Property("DiscordId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_id"); + + b.Property("ErrorContent") + .HasColumnType("text") + .HasColumnName("error_content"); + + b.Property("ErrorReferenceId") + .HasColumnType("text") + .HasColumnName("error_reference_id"); + + b.Property("Response") + .HasColumnType("integer") + .HasColumnName("response"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone") + .HasColumnName("timestamp"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_user_interactions"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_interactions_user_id"); + + b.ToTable("user_interactions", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserPlay", b => + { + b.Property("UserPlayId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("user_play_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserPlayId")); + + b.Property("AlbumName") + .HasColumnType("citext") + .HasColumnName("album_name"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("MsPlayed") + .HasColumnType("bigint") + .HasColumnName("ms_played"); + + b.Property("PlaySource") + .HasColumnType("integer") + .HasColumnName("play_source"); + + b.Property("TimePlayed") + .HasColumnType("timestamp with time zone") + .HasColumnName("time_played"); + + b.Property("TrackName") + .HasColumnType("citext") + .HasColumnName("track_name"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserPlayId") + .HasName("pk_user_plays"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_plays_user_id"); + + b.ToTable("user_plays", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserStreak", b => + { + b.Property("UserStreakId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("user_streak_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserStreakId")); + + b.Property("AlbumName") + .HasColumnType("citext") + .HasColumnName("album_name"); + + b.Property("AlbumPlaycount") + .HasColumnType("integer") + .HasColumnName("album_playcount"); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("ArtistPlaycount") + .HasColumnType("integer") + .HasColumnName("artist_playcount"); + + b.Property("StreakEnded") + .HasColumnType("timestamp with time zone") + .HasColumnName("streak_ended"); + + b.Property("StreakStarted") + .HasColumnType("timestamp with time zone") + .HasColumnName("streak_started"); + + b.Property("TrackName") + .HasColumnType("citext") + .HasColumnName("track_name"); + + b.Property("TrackPlaycount") + .HasColumnType("integer") + .HasColumnName("track_playcount"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserStreakId") + .HasName("pk_user_streaks"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_streaks_user_id"); + + b.ToTable("user_streaks", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserTrack", b => + { + b.Property("UserTrackId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("user_track_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserTrackId")); + + b.Property("ArtistName") + .HasColumnType("citext") + .HasColumnName("artist_name"); + + b.Property("Name") + .HasColumnType("citext") + .HasColumnName("name"); + + b.Property("Playcount") + .HasColumnType("integer") + .HasColumnName("playcount"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("UserTrackId") + .HasName("pk_user_tracks"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_user_tracks_user_id"); + + b.ToTable("user_tracks", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BotType") + .HasColumnType("integer") + .HasColumnName("bot_type"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("DiscordThreadId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_thread_id"); + + b.Property("DiscordWebhookId") + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_webhook_id"); + + b.Property("GuildId") + .HasColumnType("integer") + .HasColumnName("guild_id"); + + b.Property("Token") + .HasColumnType("text") + .HasColumnName("token"); + + b.HasKey("Id") + .HasName("pk_webhooks"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_webhooks_guild_id"); + + b.ToTable("webhooks", (string)null); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.AiGeneration", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("AiGenerations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ai_generations_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Album", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Artist", "Artist") + .WithMany("Albums") + .HasForeignKey("ArtistId") + .HasConstraintName("fk_albums_artists_artist_id"); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.ArtistAlias", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Artist", "Artist") + .WithMany("ArtistAliases") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_artist_aliases_artists_artist_id"); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.ArtistGenre", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Artist", "Artist") + .WithMany("ArtistGenres") + .HasForeignKey("ArtistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_artist_genres_artists_artist_id"); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.CensoredMusicReport", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Album", "Album") + .WithMany() + .HasForeignKey("AlbumId") + .HasConstraintName("fk_censored_music_report_albums_album_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.Artist", "Artist") + .WithMany() + .HasForeignKey("ArtistId") + .HasConstraintName("fk_censored_music_report_artists_artist_id"); + + b.Navigation("Album"); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Channel", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Guild", "Guild") + .WithMany("Channels") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_channels_guilds_guild_id"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsFormatDescriptions", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.DiscogsRelease", "DiscogsRelease") + .WithMany("FormatDescriptions") + .HasForeignKey("ReleaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_discogs_format_descriptions_discogs_releases_discogs_releas"); + + b.Navigation("DiscogsRelease"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsGenre", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.DiscogsRelease", "DiscogsRelease") + .WithMany("Genres") + .HasForeignKey("ReleaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_discogs_genre_discogs_releases_discogs_release_temp_id1"); + + b.Navigation("DiscogsRelease"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsStyle", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.DiscogsRelease", "DiscogsRelease") + .WithMany("Styles") + .HasForeignKey("ReleaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_discogs_style_discogs_releases_discogs_release_temp_id2"); + + b.Navigation("DiscogsRelease"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.FeaturedLog", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("FeaturedLogs") + .HasForeignKey("UserId") + .HasConstraintName("fk_featured_logs_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Friend", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "FriendUser") + .WithMany("FriendedByUsers") + .HasForeignKey("FriendUserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK.Friends.Users_FriendUserID"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Friends") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK.Friends.Users_UserID"); + + b.Navigation("FriendUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.GuildBlockedUser", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Guild", "Guild") + .WithMany("GuildBlockedUsers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_guild_blocked_users_guilds_guild_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("GuildBlockedUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_guild_blocked_users_users_user_id"); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.GuildUser", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Guild", "Guild") + .WithMany("GuildUsers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_guild_users_guilds_guild_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("GuildUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_guild_users_users_user_id"); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.InactiveUsers", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_inactive_users_users_user_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany() + .HasForeignKey("UserId1") + .HasConstraintName("fk_inactive_users_users_user_id1"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Track", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Album", "Album") + .WithMany("Tracks") + .HasForeignKey("AlbumId") + .HasConstraintName("fk_tracks_albums_album_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.Artist", "Artist") + .WithMany("Tracks") + .HasForeignKey("ArtistId") + .HasConstraintName("fk_tracks_artists_artist_id"); + + b.Navigation("Album"); + + b.Navigation("Artist"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserAlbum", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Albums") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_albums_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserArtist", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Artists") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_artists_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserCrown", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Guild", "Guild") + .WithMany("GuildCrowns") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_crowns_guilds_guild_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Crowns") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_crowns_users_user_id"); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserDiscogs", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithOne("UserDiscogs") + .HasForeignKey("FMBot.Persistence.Domain.Models.UserDiscogs", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_discogs_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserDiscogsReleases", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.DiscogsRelease", "Release") + .WithMany("UserDiscogsReleases") + .HasForeignKey("ReleaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_discogs_releases_discogs_releases_release_id"); + + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("DiscogsReleases") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_discogs_releases_users_user_id"); + + b.Navigation("Release"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserInteraction", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Interactions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_interactions_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserPlay", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Plays") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_plays_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserStreak", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Streaks") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_streaks_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.UserTrack", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.User", "User") + .WithMany("Tracks") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_tracks_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Webhook", b => + { + b.HasOne("FMBot.Persistence.Domain.Models.Guild", "Guild") + .WithMany("Webhooks") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_webhooks_guilds_guild_id"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Album", b => + { + b.Navigation("Tracks"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Artist", b => + { + b.Navigation("Albums"); + + b.Navigation("ArtistAliases"); + + b.Navigation("ArtistGenres"); + + b.Navigation("Tracks"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.DiscogsRelease", b => + { + b.Navigation("FormatDescriptions"); + + b.Navigation("Genres"); + + b.Navigation("Styles"); + + b.Navigation("UserDiscogsReleases"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.Guild", b => + { + b.Navigation("Channels"); + + b.Navigation("GuildBlockedUsers"); + + b.Navigation("GuildCrowns"); + + b.Navigation("GuildUsers"); + + b.Navigation("Webhooks"); + }); + + modelBuilder.Entity("FMBot.Persistence.Domain.Models.User", b => + { + b.Navigation("AiGenerations"); + + b.Navigation("Albums"); + + b.Navigation("Artists"); + + b.Navigation("Crowns"); + + b.Navigation("DiscogsReleases"); + + b.Navigation("FeaturedLogs"); + + b.Navigation("FriendedByUsers"); + + b.Navigation("Friends"); + + b.Navigation("GuildBlockedUsers"); + + b.Navigation("GuildUsers"); + + b.Navigation("Interactions"); + + b.Navigation("Plays"); + + b.Navigation("Streaks"); + + b.Navigation("Tracks"); + + b.Navigation("UserDiscogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.cs b/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.cs new file mode 100644 index 000000000..709dc3deb --- /dev/null +++ b/src/FMBot.Persistence.EntityFrameWork/Migrations/20231207235943_AddRedBotName.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FMBot.Persistence.EntityFrameWork.Migrations +{ + /// + public partial class AddRedBotName : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "red_bot_name", + table: "guilds", + type: "text", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "red_bot_name", + table: "guilds"); + } + } +} diff --git a/src/FMBot.Persistence.EntityFrameWork/Migrations/FMBotDbContextModelSnapshot.cs b/src/FMBot.Persistence.EntityFrameWork/Migrations/FMBotDbContextModelSnapshot.cs index cda132860..5c8d7fca9 100644 --- a/src/FMBot.Persistence.EntityFrameWork/Migrations/FMBotDbContextModelSnapshot.cs +++ b/src/FMBot.Persistence.EntityFrameWork/Migrations/FMBotDbContextModelSnapshot.cs @@ -18,7 +18,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "citext"); @@ -960,6 +960,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("text") .HasColumnName("prefix"); + b.Property("RedBotName") + .HasColumnType("text") + .HasColumnName("red_bot_name"); + b.Property("SpecialGuild") .HasColumnType("boolean") .HasColumnName("special_guild"); From 31bbcb052267b42634bc168bf64cb41eedf91f37 Mon Sep 17 00:00:00 2001 From: Wilson Biggs Date: Thu, 7 Dec 2023 19:50:08 -0500 Subject: [PATCH 2/3] Fix a few issues --- src/FMBot.Bot/Builders/GuildSettingBuilder.cs | 1 + src/FMBot.Bot/Builders/UserBuilder.cs | 3 ++- src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs | 4 ++-- src/FMBot.Bot/Services/TrackService.cs | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs index c89ace14c..f9a63412f 100644 --- a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs +++ b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs @@ -18,6 +18,7 @@ using FMBot.Domain.Extensions; using FMBot.Domain.Models; using Microsoft.Extensions.Options; +using Newtonsoft.Json; namespace FMBot.Bot.Builders; diff --git a/src/FMBot.Bot/Builders/UserBuilder.cs b/src/FMBot.Bot/Builders/UserBuilder.cs index 58c57664b..9b55e2c7b 100644 --- a/src/FMBot.Bot/Builders/UserBuilder.cs +++ b/src/FMBot.Bot/Builders/UserBuilder.cs @@ -175,7 +175,8 @@ public async Task BotScrobblingAsync(ContextModel context) "Currently supported bots:\n" + "- Cakey Bot\n" + "- Jockie Music\n" + - "- SoundCloud" + "- SoundCloud\n" + + "- Red" ); response.Components = new ComponentBuilder() diff --git a/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs b/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs index 68d4bfbf9..aa35375a7 100644 --- a/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs +++ b/src/FMBot.Bot/Models/MusicBot/RedMusicBot.cs @@ -10,7 +10,7 @@ namespace FMBot.Bot.Models.MusicBot; internal class RedMusicBot : MusicBot { - public RedMusicBot() : base("Red", true, true) + public RedMusicBot() : base("Red", true, false) { } @@ -31,7 +31,7 @@ public override bool ShouldIgnoreMessage(IUserMessage msg) public override string GetTrackQuery(IUserMessage msg) { - return msg.Embeds.First().Description; + return msg.Embeds.First().Description.Replace(@"\",""); } public override async Task IsAuthor(SocketUser user, ICommandContext context, GuildService guildService) diff --git a/src/FMBot.Bot/Services/TrackService.cs b/src/FMBot.Bot/Services/TrackService.cs index 2af4f89c8..c8973d6a0 100644 --- a/src/FMBot.Bot/Services/TrackService.cs +++ b/src/FMBot.Bot/Services/TrackService.cs @@ -385,7 +385,23 @@ public async Task GetTrackFromLink(string description, bool p } } + // Sometimes track and artist are reversed (esp. with YouTube bots, e.g. "Title - Artist - Topic") + // Use the order with the most listeners var trackLfm = await this._dataSourceFactory.GetTrackInfoAsync(trackName, artistName); + var trackLfmReversed = await this._dataSourceFactory.GetTrackInfoAsync(artistName, trackName); + + if (trackLfm.Success && trackLfmReversed.Success) + { + trackLfm = trackLfm.Content.TotalListeners >= trackLfmReversed.Content.TotalListeners + ? trackLfm + : trackLfmReversed; + } + else + { + // Try to use the reversed if the normal order is not successful + trackLfm = trackLfm.Success ? trackLfm : trackLfmReversed; + } + if (trackLfm.Success) { From cde2d1752d0248c91629ca2f1f7685ae258e67c4 Mon Sep 17 00:00:00 2001 From: Wilson Biggs Date: Thu, 7 Dec 2023 20:01:41 -0500 Subject: [PATCH 3/3] Remove stray import --- src/FMBot.Bot/Builders/GuildSettingBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs index f9a63412f..c89ace14c 100644 --- a/src/FMBot.Bot/Builders/GuildSettingBuilder.cs +++ b/src/FMBot.Bot/Builders/GuildSettingBuilder.cs @@ -18,7 +18,6 @@ using FMBot.Domain.Extensions; using FMBot.Domain.Models; using Microsoft.Extensions.Options; -using Newtonsoft.Json; namespace FMBot.Bot.Builders;