diff options
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.Designer.cs | 1624 | ||||
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.cs | 1104 | ||||
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/JellyfinDbContextModelSnapshot.cs | 1621 | ||||
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/PgSqlDesignTimeJellyfinDbFactory.cs | 26 | ||||
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.PgSql/PgSqlDatabaseProvider.cs | 75 | ||||
| -rw-r--r-- | Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs (renamed from Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs) | 2 | ||||
| -rw-r--r-- | Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs | 5 | ||||
| -rw-r--r-- | Jellyfin.Server.Implementations/DbConfiguration/PostgreSqlOptions.cs | 39 |
8 files changed, 4495 insertions, 1 deletions
diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.Designer.cs b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.Designer.cs new file mode 100644 index 000000000..47fff0721 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.Designer.cs @@ -0,0 +1,1624 @@ +// <auto-generated /> +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PgSql.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20250127174201_InitMigration")] + partial class InitMigration + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("DayOfWeek") + .HasColumnType("integer"); + + b.Property<double>("EndHour") + .HasColumnType("double precision"); + + b.Property<double>("StartHour") + .HasColumnType("double precision"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("ItemId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<int>("LogSeverity") + .HasColumnType("integer"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<string>("Overview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<string>("ShortOverview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<string>("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("ParentItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("Index") + .HasColumnType("integer"); + + b.Property<string>("Codec") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("CodecTag") + .HasColumnType("text"); + + b.Property<string>("Comment") + .HasColumnType("text"); + + b.Property<string>("Filename") + .HasColumnType("text"); + + b.Property<string>("MimeType") + .HasColumnType("text"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("Album") + .HasColumnType("text"); + + b.Property<string>("AlbumArtists") + .HasColumnType("text"); + + b.Property<string>("Artists") + .HasColumnType("text"); + + b.Property<int?>("Audio") + .HasColumnType("integer"); + + b.Property<string>("ChannelId") + .HasColumnType("text"); + + b.Property<string>("CleanName") + .HasColumnType("text"); + + b.Property<float?>("CommunityRating") + .HasColumnType("real"); + + b.Property<float?>("CriticRating") + .HasColumnType("real"); + + b.Property<string>("CustomRating") + .HasColumnType("text"); + + b.Property<string>("Data") + .HasColumnType("text"); + + b.Property<DateTime?>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastMediaAdded") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastRefreshed") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastSaved") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("EpisodeTitle") + .HasColumnType("text"); + + b.Property<string>("ExternalId") + .HasColumnType("text"); + + b.Property<string>("ExternalSeriesId") + .HasColumnType("text"); + + b.Property<string>("ExternalServiceId") + .HasColumnType("text"); + + b.Property<string>("ExtraIds") + .HasColumnType("text"); + + b.Property<int?>("ExtraType") + .HasColumnType("integer"); + + b.Property<string>("ForcedSortName") + .HasColumnType("text"); + + b.Property<string>("Genres") + .HasColumnType("text"); + + b.Property<int?>("Height") + .HasColumnType("integer"); + + b.Property<int?>("IndexNumber") + .HasColumnType("integer"); + + b.Property<int?>("InheritedParentalRatingValue") + .HasColumnType("integer"); + + b.Property<bool>("IsFolder") + .HasColumnType("boolean"); + + b.Property<bool>("IsInMixedFolder") + .HasColumnType("boolean"); + + b.Property<bool>("IsLocked") + .HasColumnType("boolean"); + + b.Property<bool>("IsMovie") + .HasColumnType("boolean"); + + b.Property<bool>("IsRepeat") + .HasColumnType("boolean"); + + b.Property<bool>("IsSeries") + .HasColumnType("boolean"); + + b.Property<bool>("IsVirtualItem") + .HasColumnType("boolean"); + + b.Property<float?>("LUFS") + .HasColumnType("real"); + + b.Property<string>("MediaType") + .HasColumnType("text"); + + b.Property<string>("Name") + .HasColumnType("text"); + + b.Property<float?>("NormalizationGain") + .HasColumnType("real"); + + b.Property<string>("OfficialRating") + .HasColumnType("text"); + + b.Property<string>("OriginalTitle") + .HasColumnType("text"); + + b.Property<string>("Overview") + .HasColumnType("text"); + + b.Property<string>("OwnerId") + .HasColumnType("text"); + + b.Property<Guid?>("ParentId") + .HasColumnType("uuid"); + + b.Property<int?>("ParentIndexNumber") + .HasColumnType("integer"); + + b.Property<string>("Path") + .HasColumnType("text"); + + b.Property<string>("PreferredMetadataCountryCode") + .HasColumnType("text"); + + b.Property<string>("PreferredMetadataLanguage") + .HasColumnType("text"); + + b.Property<DateTime?>("PremiereDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("PresentationUniqueKey") + .HasColumnType("text"); + + b.Property<string>("PrimaryVersionId") + .HasColumnType("text"); + + b.Property<string>("ProductionLocations") + .HasColumnType("text"); + + b.Property<int?>("ProductionYear") + .HasColumnType("integer"); + + b.Property<long?>("RunTimeTicks") + .HasColumnType("bigint"); + + b.Property<Guid?>("SeasonId") + .HasColumnType("uuid"); + + b.Property<string>("SeasonName") + .HasColumnType("text"); + + b.Property<Guid?>("SeriesId") + .HasColumnType("uuid"); + + b.Property<string>("SeriesName") + .HasColumnType("text"); + + b.Property<string>("SeriesPresentationUniqueKey") + .HasColumnType("text"); + + b.Property<string>("ShowId") + .HasColumnType("text"); + + b.Property<long?>("Size") + .HasColumnType("bigint"); + + b.Property<string>("SortName") + .HasColumnType("text"); + + b.Property<DateTime>("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Studios") + .HasColumnType("text"); + + b.Property<string>("Tagline") + .HasColumnType("text"); + + b.Property<string>("Tags") + .HasColumnType("text"); + + b.Property<Guid?>("TopParentId") + .HasColumnType("uuid"); + + b.Property<int?>("TotalBitrate") + .HasColumnType("integer"); + + b.Property<string>("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("UnratedType") + .HasColumnType("text"); + + b.Property<int?>("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<byte[]>("Blurhash") + .HasColumnType("bytea"); + + b.Property<DateTime>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<int>("Height") + .HasColumnType("integer"); + + b.Property<int>("ImageType") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property<int>("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property<int>("Id") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("ProviderId") + .HasColumnType("text"); + + b.Property<string>("ProviderValue") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property<int>("Id") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("ChapterIndex") + .HasColumnType("integer"); + + b.Property<DateTime?>("ImageDateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("ImagePath") + .HasColumnType("text"); + + b.Property<string>("Name") + .HasColumnType("text"); + + b.Property<long>("StartPositionTicks") + .HasColumnType("bigint"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("ChromecastVersion") + .HasColumnType("integer"); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<string>("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<bool>("EnableNextVideoInfoOverlay") + .HasColumnType("boolean"); + + b.Property<int?>("IndexBy") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("ScrollDirection") + .HasColumnType("integer"); + + b.Property<bool>("ShowBackdrop") + .HasColumnType("boolean"); + + b.Property<bool>("ShowSidebar") + .HasColumnType("boolean"); + + b.Property<int>("SkipBackwardLength") + .HasColumnType("integer"); + + b.Property<int>("SkipForwardLength") + .HasColumnType("integer"); + + b.Property<string>("TvHome") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("DisplayPreferencesId") + .HasColumnType("integer"); + + b.Property<int>("Order") + .HasColumnType("integer"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<int?>("IndexBy") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<bool>("RememberIndexing") + .HasColumnType("boolean"); + + b.Property<bool>("RememberSorting") + .HasColumnType("boolean"); + + b.Property<string>("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<int>("SortOrder") + .HasColumnType("integer"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<int>("ViewType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property<Guid>("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("CleanValue") + .IsRequired() + .HasColumnType("text"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.Property<string>("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property<Guid>("ItemValueId") + .HasColumnType("uuid"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<long>("EndTicks") + .HasColumnType("bigint"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("SegmentProviderId") + .IsRequired() + .HasColumnType("text"); + + b.Property<long>("StartTicks") + .HasColumnType("bigint"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("StreamIndex") + .HasColumnType("integer"); + + b.Property<string>("AspectRatio") + .HasColumnType("text"); + + b.Property<float?>("AverageFrameRate") + .HasColumnType("real"); + + b.Property<int?>("BitDepth") + .HasColumnType("integer"); + + b.Property<int?>("BitRate") + .HasColumnType("integer"); + + b.Property<int?>("BlPresentFlag") + .HasColumnType("integer"); + + b.Property<string>("ChannelLayout") + .HasColumnType("text"); + + b.Property<int?>("Channels") + .HasColumnType("integer"); + + b.Property<string>("Codec") + .HasColumnType("text"); + + b.Property<string>("CodecTag") + .HasColumnType("text"); + + b.Property<string>("CodecTimeBase") + .HasColumnType("text"); + + b.Property<string>("ColorPrimaries") + .HasColumnType("text"); + + b.Property<string>("ColorSpace") + .HasColumnType("text"); + + b.Property<string>("ColorTransfer") + .HasColumnType("text"); + + b.Property<string>("Comment") + .HasColumnType("text"); + + b.Property<int?>("DvBlSignalCompatibilityId") + .HasColumnType("integer"); + + b.Property<int?>("DvLevel") + .HasColumnType("integer"); + + b.Property<int?>("DvProfile") + .HasColumnType("integer"); + + b.Property<int?>("DvVersionMajor") + .HasColumnType("integer"); + + b.Property<int?>("DvVersionMinor") + .HasColumnType("integer"); + + b.Property<int?>("ElPresentFlag") + .HasColumnType("integer"); + + b.Property<int?>("Height") + .HasColumnType("integer"); + + b.Property<bool?>("IsAnamorphic") + .HasColumnType("boolean"); + + b.Property<bool?>("IsAvc") + .HasColumnType("boolean"); + + b.Property<bool>("IsDefault") + .HasColumnType("boolean"); + + b.Property<bool>("IsExternal") + .HasColumnType("boolean"); + + b.Property<bool>("IsForced") + .HasColumnType("boolean"); + + b.Property<bool?>("IsHearingImpaired") + .HasColumnType("boolean"); + + b.Property<bool?>("IsInterlaced") + .HasColumnType("boolean"); + + b.Property<string>("KeyFrames") + .HasColumnType("text"); + + b.Property<string>("Language") + .HasColumnType("text"); + + b.Property<float?>("Level") + .HasColumnType("real"); + + b.Property<string>("NalLengthSize") + .HasColumnType("text"); + + b.Property<string>("Path") + .HasColumnType("text"); + + b.Property<string>("PixelFormat") + .HasColumnType("text"); + + b.Property<string>("Profile") + .HasColumnType("text"); + + b.Property<float?>("RealFrameRate") + .HasColumnType("real"); + + b.Property<int?>("RefFrames") + .HasColumnType("integer"); + + b.Property<int?>("Rotation") + .HasColumnType("integer"); + + b.Property<int?>("RpuPresentFlag") + .HasColumnType("integer"); + + b.Property<int?>("SampleRate") + .HasColumnType("integer"); + + b.Property<int>("StreamType") + .HasColumnType("integer"); + + b.Property<string>("TimeBase") + .HasColumnType("text"); + + b.Property<string>("Title") + .HasColumnType("text"); + + b.Property<int?>("Width") + .HasColumnType("integer"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("PersonType") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("PeopleId") + .HasColumnType("uuid"); + + b.Property<int?>("ListOrder") + .HasColumnType("integer"); + + b.Property<string>("Role") + .HasColumnType("text"); + + b.Property<int?>("SortOrder") + .HasColumnType("integer"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("Kind") + .HasColumnType("integer"); + + b.Property<Guid?>("Permission_Permissions_Guid") + .HasColumnType("uuid"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.Property<bool>("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("Kind") + .HasColumnType("integer"); + + b.Property<Guid?>("Preference_Preferences_Guid") + .HasColumnType("uuid"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<string>("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<string>("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<bool>("IsActive") + .HasColumnType("boolean"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("CustomName") + .HasColumnType("text"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("Width") + .HasColumnType("integer"); + + b.Property<int>("Bandwidth") + .HasColumnType("integer"); + + b.Property<int>("Height") + .HasColumnType("integer"); + + b.Property<int>("Interval") + .HasColumnType("integer"); + + b.Property<int>("ThumbnailCount") + .HasColumnType("integer"); + + b.Property<int>("TileHeight") + .HasColumnType("integer"); + + b.Property<int>("TileWidth") + .HasColumnType("integer"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<string>("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<string>("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<bool>("DisplayCollectionsView") + .HasColumnType("boolean"); + + b.Property<bool>("DisplayMissingEpisodes") + .HasColumnType("boolean"); + + b.Property<bool>("EnableAutoLogin") + .HasColumnType("boolean"); + + b.Property<bool>("EnableLocalPassword") + .HasColumnType("boolean"); + + b.Property<bool>("EnableNextEpisodeAutoPlay") + .HasColumnType("boolean"); + + b.Property<bool>("EnableUserPreferenceAccess") + .HasColumnType("boolean"); + + b.Property<bool>("HidePlayedInLatest") + .HasColumnType("boolean"); + + b.Property<long>("InternalId") + .HasColumnType("bigint"); + + b.Property<int>("InvalidLoginAttemptCount") + .HasColumnType("integer"); + + b.Property<DateTime?>("LastActivityDate") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("LastLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property<int?>("LoginAttemptsBeforeLockout") + .HasColumnType("integer"); + + b.Property<int>("MaxActiveSessions") + .HasColumnType("integer"); + + b.Property<int?>("MaxParentalAgeRating") + .HasColumnType("integer"); + + b.Property<bool>("MustUpdatePassword") + .HasColumnType("boolean"); + + b.Property<string>("Password") + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.Property<string>("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<bool>("PlayDefaultAudioTrack") + .HasColumnType("boolean"); + + b.Property<bool>("RememberAudioSelections") + .HasColumnType("boolean"); + + b.Property<bool>("RememberSubtitleSelections") + .HasColumnType("boolean"); + + b.Property<int?>("RemoteClientBitrateLimit") + .HasColumnType("integer"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<string>("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<int>("SubtitleMode") + .HasColumnType("integer"); + + b.Property<int>("SyncPlayAccess") + .HasColumnType("integer"); + + b.Property<string>("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("CustomDataKey") + .HasColumnType("text"); + + b.Property<int?>("AudioStreamIndex") + .HasColumnType("integer"); + + b.Property<bool>("IsFavorite") + .HasColumnType("boolean"); + + b.Property<DateTime?>("LastPlayedDate") + .HasColumnType("timestamp with time zone"); + + b.Property<bool?>("Likes") + .HasColumnType("boolean"); + + b.Property<int>("PlayCount") + .HasColumnType("integer"); + + b.Property<long>("PlaybackPositionTicks") + .HasColumnType("bigint"); + + b.Property<bool>("Played") + .HasColumnType("boolean"); + + b.Property<double?>("Rating") + .HasColumnType("double precision"); + + b.Property<int?>("SubtitleStreamIndex") + .HasColumnType("integer"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.cs b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.cs new file mode 100644 index 000000000..f1d0d1564 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/20250127174201_InitMigration.cs @@ -0,0 +1,1104 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PgSql.Migrations +{ + /// <inheritdoc /> + public partial class InitMigration : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ActivityLogs", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false), + Overview = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true), + ShortOverview = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true), + Type = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + LogSeverity = table.Column<int>(type: "integer", nullable: false), + RowVersion = table.Column<long>(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ActivityLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ApiKeys", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + DateLastActivity = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false), + AccessToken = table.Column<string>(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiKeys", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "BaseItems", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Type = table.Column<string>(type: "text", nullable: false), + Data = table.Column<string>(type: "text", nullable: true), + Path = table.Column<string>(type: "text", nullable: true), + StartDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + EndDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + ChannelId = table.Column<string>(type: "text", nullable: true), + IsMovie = table.Column<bool>(type: "boolean", nullable: false), + CommunityRating = table.Column<float>(type: "real", nullable: true), + CustomRating = table.Column<string>(type: "text", nullable: true), + IndexNumber = table.Column<int>(type: "integer", nullable: true), + IsLocked = table.Column<bool>(type: "boolean", nullable: false), + Name = table.Column<string>(type: "text", nullable: true), + OfficialRating = table.Column<string>(type: "text", nullable: true), + MediaType = table.Column<string>(type: "text", nullable: true), + Overview = table.Column<string>(type: "text", nullable: true), + ParentIndexNumber = table.Column<int>(type: "integer", nullable: true), + PremiereDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + ProductionYear = table.Column<int>(type: "integer", nullable: true), + Genres = table.Column<string>(type: "text", nullable: true), + SortName = table.Column<string>(type: "text", nullable: true), + ForcedSortName = table.Column<string>(type: "text", nullable: true), + RunTimeTicks = table.Column<long>(type: "bigint", nullable: true), + DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + DateModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + IsSeries = table.Column<bool>(type: "boolean", nullable: false), + EpisodeTitle = table.Column<string>(type: "text", nullable: true), + IsRepeat = table.Column<bool>(type: "boolean", nullable: false), + PreferredMetadataLanguage = table.Column<string>(type: "text", nullable: true), + PreferredMetadataCountryCode = table.Column<string>(type: "text", nullable: true), + DateLastRefreshed = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + DateLastSaved = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + IsInMixedFolder = table.Column<bool>(type: "boolean", nullable: false), + Studios = table.Column<string>(type: "text", nullable: true), + ExternalServiceId = table.Column<string>(type: "text", nullable: true), + Tags = table.Column<string>(type: "text", nullable: true), + IsFolder = table.Column<bool>(type: "boolean", nullable: false), + InheritedParentalRatingValue = table.Column<int>(type: "integer", nullable: true), + UnratedType = table.Column<string>(type: "text", nullable: true), + CriticRating = table.Column<float>(type: "real", nullable: true), + CleanName = table.Column<string>(type: "text", nullable: true), + PresentationUniqueKey = table.Column<string>(type: "text", nullable: true), + OriginalTitle = table.Column<string>(type: "text", nullable: true), + PrimaryVersionId = table.Column<string>(type: "text", nullable: true), + DateLastMediaAdded = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + Album = table.Column<string>(type: "text", nullable: true), + LUFS = table.Column<float>(type: "real", nullable: true), + NormalizationGain = table.Column<float>(type: "real", nullable: true), + IsVirtualItem = table.Column<bool>(type: "boolean", nullable: false), + SeriesName = table.Column<string>(type: "text", nullable: true), + SeasonName = table.Column<string>(type: "text", nullable: true), + ExternalSeriesId = table.Column<string>(type: "text", nullable: true), + Tagline = table.Column<string>(type: "text", nullable: true), + ProductionLocations = table.Column<string>(type: "text", nullable: true), + ExtraIds = table.Column<string>(type: "text", nullable: true), + TotalBitrate = table.Column<int>(type: "integer", nullable: true), + ExtraType = table.Column<int>(type: "integer", nullable: true), + Artists = table.Column<string>(type: "text", nullable: true), + AlbumArtists = table.Column<string>(type: "text", nullable: true), + ExternalId = table.Column<string>(type: "text", nullable: true), + SeriesPresentationUniqueKey = table.Column<string>(type: "text", nullable: true), + ShowId = table.Column<string>(type: "text", nullable: true), + OwnerId = table.Column<string>(type: "text", nullable: true), + Width = table.Column<int>(type: "integer", nullable: true), + Height = table.Column<int>(type: "integer", nullable: true), + Size = table.Column<long>(type: "bigint", nullable: true), + Audio = table.Column<int>(type: "integer", nullable: true), + ParentId = table.Column<Guid>(type: "uuid", nullable: true), + TopParentId = table.Column<Guid>(type: "uuid", nullable: true), + SeasonId = table.Column<Guid>(type: "uuid", nullable: true), + SeriesId = table.Column<Guid>(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItems", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CustomItemDisplayPreferences", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Client = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), + Key = table.Column<string>(type: "text", nullable: false), + Value = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomItemDisplayPreferences", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DeviceOptions", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DeviceId = table.Column<string>(type: "text", nullable: false), + CustomName = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DeviceOptions", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ItemValues", + columns: table => new + { + ItemValueId = table.Column<Guid>(type: "uuid", nullable: false), + Type = table.Column<int>(type: "integer", nullable: false), + Value = table.Column<string>(type: "text", nullable: false), + CleanValue = table.Column<string>(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValues", x => x.ItemValueId); + }); + + migrationBuilder.CreateTable( + name: "MediaSegments", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Type = table.Column<int>(type: "integer", nullable: false), + EndTicks = table.Column<long>(type: "bigint", nullable: false), + StartTicks = table.Column<long>(type: "bigint", nullable: false), + SegmentProviderId = table.Column<string>(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaSegments", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Peoples", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Name = table.Column<string>(type: "text", nullable: false), + PersonType = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Peoples", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TrickplayInfos", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Width = table.Column<int>(type: "integer", nullable: false), + Height = table.Column<int>(type: "integer", nullable: false), + TileWidth = table.Column<int>(type: "integer", nullable: false), + TileHeight = table.Column<int>(type: "integer", nullable: false), + ThumbnailCount = table.Column<int>(type: "integer", nullable: false), + Interval = table.Column<int>(type: "integer", nullable: false), + Bandwidth = table.Column<int>(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TrickplayInfos", x => new { x.ItemId, x.Width }); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Username = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false, collation: "NOCASE"), + Password = table.Column<string>(type: "character varying(65535)", maxLength: 65535, nullable: true), + MustUpdatePassword = table.Column<bool>(type: "boolean", nullable: false), + AudioLanguagePreference = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true), + AuthenticationProviderId = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false), + PasswordResetProviderId = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false), + InvalidLoginAttemptCount = table.Column<int>(type: "integer", nullable: false), + LastActivityDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + LastLoginDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + LoginAttemptsBeforeLockout = table.Column<int>(type: "integer", nullable: true), + MaxActiveSessions = table.Column<int>(type: "integer", nullable: false), + SubtitleMode = table.Column<int>(type: "integer", nullable: false), + PlayDefaultAudioTrack = table.Column<bool>(type: "boolean", nullable: false), + SubtitleLanguagePreference = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true), + DisplayMissingEpisodes = table.Column<bool>(type: "boolean", nullable: false), + DisplayCollectionsView = table.Column<bool>(type: "boolean", nullable: false), + EnableLocalPassword = table.Column<bool>(type: "boolean", nullable: false), + HidePlayedInLatest = table.Column<bool>(type: "boolean", nullable: false), + RememberAudioSelections = table.Column<bool>(type: "boolean", nullable: false), + RememberSubtitleSelections = table.Column<bool>(type: "boolean", nullable: false), + EnableNextEpisodeAutoPlay = table.Column<bool>(type: "boolean", nullable: false), + EnableAutoLogin = table.Column<bool>(type: "boolean", nullable: false), + EnableUserPreferenceAccess = table.Column<bool>(type: "boolean", nullable: false), + MaxParentalAgeRating = table.Column<int>(type: "integer", nullable: true), + RemoteClientBitrateLimit = table.Column<int>(type: "integer", nullable: true), + InternalId = table.Column<long>(type: "bigint", nullable: false), + SyncPlayAccess = table.Column<int>(type: "integer", nullable: false), + CastReceiverId = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true), + RowVersion = table.Column<long>(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AncestorIds", + columns: table => new + { + ParentItemId = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AncestorIds", x => new { x.ItemId, x.ParentItemId }); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ParentItemId", + column: x => x.ParentItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AttachmentStreamInfos", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Index = table.Column<int>(type: "integer", nullable: false), + Codec = table.Column<string>(type: "text", nullable: false), + CodecTag = table.Column<string>(type: "text", nullable: true), + Comment = table.Column<string>(type: "text", nullable: true), + Filename = table.Column<string>(type: "text", nullable: true), + MimeType = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AttachmentStreamInfos", x => new { x.ItemId, x.Index }); + table.ForeignKey( + name: "FK_AttachmentStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemImageInfos", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Path = table.Column<string>(type: "text", nullable: false), + DateModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + ImageType = table.Column<int>(type: "integer", nullable: false), + Width = table.Column<int>(type: "integer", nullable: false), + Height = table.Column<int>(type: "integer", nullable: false), + Blurhash = table.Column<byte[]>(type: "bytea", nullable: true), + ItemId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_BaseItemImageInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemMetadataFields", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemMetadataFields", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemMetadataFields_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemProviders", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + ProviderId = table.Column<string>(type: "text", nullable: false), + ProviderValue = table.Column<string>(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemProviders", x => new { x.ItemId, x.ProviderId }); + table.ForeignKey( + name: "FK_BaseItemProviders_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemTrailerTypes", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemTrailerTypes", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemTrailerTypes_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Chapters", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + ChapterIndex = table.Column<int>(type: "integer", nullable: false), + StartPositionTicks = table.Column<long>(type: "bigint", nullable: false), + Name = table.Column<string>(type: "text", nullable: true), + ImagePath = table.Column<string>(type: "text", nullable: true), + ImageDateModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Chapters", x => new { x.ItemId, x.ChapterIndex }); + table.ForeignKey( + name: "FK_Chapters_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MediaStreamInfos", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + StreamIndex = table.Column<int>(type: "integer", nullable: false), + StreamType = table.Column<int>(type: "integer", nullable: false), + Codec = table.Column<string>(type: "text", nullable: true), + Language = table.Column<string>(type: "text", nullable: true), + ChannelLayout = table.Column<string>(type: "text", nullable: true), + Profile = table.Column<string>(type: "text", nullable: true), + AspectRatio = table.Column<string>(type: "text", nullable: true), + Path = table.Column<string>(type: "text", nullable: true), + IsInterlaced = table.Column<bool>(type: "boolean", nullable: true), + BitRate = table.Column<int>(type: "integer", nullable: true), + Channels = table.Column<int>(type: "integer", nullable: true), + SampleRate = table.Column<int>(type: "integer", nullable: true), + IsDefault = table.Column<bool>(type: "boolean", nullable: false), + IsForced = table.Column<bool>(type: "boolean", nullable: false), + IsExternal = table.Column<bool>(type: "boolean", nullable: false), + Height = table.Column<int>(type: "integer", nullable: true), + Width = table.Column<int>(type: "integer", nullable: true), + AverageFrameRate = table.Column<float>(type: "real", nullable: true), + RealFrameRate = table.Column<float>(type: "real", nullable: true), + Level = table.Column<float>(type: "real", nullable: true), + PixelFormat = table.Column<string>(type: "text", nullable: true), + BitDepth = table.Column<int>(type: "integer", nullable: true), + IsAnamorphic = table.Column<bool>(type: "boolean", nullable: true), + RefFrames = table.Column<int>(type: "integer", nullable: true), + CodecTag = table.Column<string>(type: "text", nullable: true), + Comment = table.Column<string>(type: "text", nullable: true), + NalLengthSize = table.Column<string>(type: "text", nullable: true), + IsAvc = table.Column<bool>(type: "boolean", nullable: true), + Title = table.Column<string>(type: "text", nullable: true), + TimeBase = table.Column<string>(type: "text", nullable: true), + CodecTimeBase = table.Column<string>(type: "text", nullable: true), + ColorPrimaries = table.Column<string>(type: "text", nullable: true), + ColorSpace = table.Column<string>(type: "text", nullable: true), + ColorTransfer = table.Column<string>(type: "text", nullable: true), + DvVersionMajor = table.Column<int>(type: "integer", nullable: true), + DvVersionMinor = table.Column<int>(type: "integer", nullable: true), + DvProfile = table.Column<int>(type: "integer", nullable: true), + DvLevel = table.Column<int>(type: "integer", nullable: true), + RpuPresentFlag = table.Column<int>(type: "integer", nullable: true), + ElPresentFlag = table.Column<int>(type: "integer", nullable: true), + BlPresentFlag = table.Column<int>(type: "integer", nullable: true), + DvBlSignalCompatibilityId = table.Column<int>(type: "integer", nullable: true), + IsHearingImpaired = table.Column<bool>(type: "boolean", nullable: true), + Rotation = table.Column<int>(type: "integer", nullable: true), + KeyFrames = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaStreamInfos", x => new { x.ItemId, x.StreamIndex }); + table.ForeignKey( + name: "FK_MediaStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemValuesMap", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + ItemValueId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValuesMap", x => new { x.ItemValueId, x.ItemId }); + table.ForeignKey( + name: "FK_ItemValuesMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ItemValuesMap_ItemValues_ItemValueId", + column: x => x.ItemValueId, + principalTable: "ItemValues", + principalColumn: "ItemValueId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PeopleBaseItemMap", + columns: table => new + { + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + PeopleId = table.Column<Guid>(type: "uuid", nullable: false), + SortOrder = table.Column<int>(type: "integer", nullable: true), + ListOrder = table.Column<int>(type: "integer", nullable: true), + Role = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PeopleBaseItemMap", x => new { x.ItemId, x.PeopleId }); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_Peoples_PeopleId", + column: x => x.PeopleId, + principalTable: "Peoples", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AccessSchedules", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + DayOfWeek = table.Column<int>(type: "integer", nullable: false), + StartHour = table.Column<double>(type: "double precision", nullable: false), + EndHour = table.Column<double>(type: "double precision", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccessSchedules", x => x.Id); + table.ForeignKey( + name: "FK_AccessSchedules_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Devices", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + AccessToken = table.Column<string>(type: "text", nullable: false), + AppName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false), + AppVersion = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), + DeviceName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false), + DeviceId = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false), + IsActive = table.Column<bool>(type: "boolean", nullable: false), + DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + DateModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), + DateLastActivity = table.Column<DateTime>(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Devices", x => x.Id); + table.ForeignKey( + name: "FK_Devices_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "DisplayPreferences", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Client = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), + ShowSidebar = table.Column<bool>(type: "boolean", nullable: false), + ShowBackdrop = table.Column<bool>(type: "boolean", nullable: false), + ScrollDirection = table.Column<int>(type: "integer", nullable: false), + IndexBy = table.Column<int>(type: "integer", nullable: true), + SkipForwardLength = table.Column<int>(type: "integer", nullable: false), + SkipBackwardLength = table.Column<int>(type: "integer", nullable: false), + ChromecastVersion = table.Column<int>(type: "integer", nullable: false), + EnableNextVideoInfoOverlay = table.Column<bool>(type: "boolean", nullable: false), + DashboardTheme = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true), + TvHome = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ImageInfos", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: true), + Path = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false), + LastModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_ImageInfos_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemDisplayPreferences", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + Client = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), + ViewType = table.Column<int>(type: "integer", nullable: false), + RememberIndexing = table.Column<bool>(type: "boolean", nullable: false), + IndexBy = table.Column<int>(type: "integer", nullable: true), + RememberSorting = table.Column<bool>(type: "boolean", nullable: false), + SortBy = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false), + SortOrder = table.Column<int>(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemDisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_ItemDisplayPreferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Permissions", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: true), + Kind = table.Column<int>(type: "integer", nullable: false), + Value = table.Column<bool>(type: "boolean", nullable: false), + RowVersion = table.Column<long>(type: "bigint", nullable: false), + Permission_Permissions_Guid = table.Column<Guid>(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Permissions", x => x.Id); + table.ForeignKey( + name: "FK_Permissions_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Preferences", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: true), + Kind = table.Column<int>(type: "integer", nullable: false), + Value = table.Column<string>(type: "character varying(65535)", maxLength: 65535, nullable: false), + RowVersion = table.Column<long>(type: "bigint", nullable: false), + Preference_Preferences_Guid = table.Column<Guid>(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Preferences", x => x.Id); + table.ForeignKey( + name: "FK_Preferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserData", + columns: table => new + { + CustomDataKey = table.Column<string>(type: "text", nullable: false), + ItemId = table.Column<Guid>(type: "uuid", nullable: false), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + Rating = table.Column<double>(type: "double precision", nullable: true), + PlaybackPositionTicks = table.Column<long>(type: "bigint", nullable: false), + PlayCount = table.Column<int>(type: "integer", nullable: false), + IsFavorite = table.Column<bool>(type: "boolean", nullable: false), + LastPlayedDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true), + Played = table.Column<bool>(type: "boolean", nullable: false), + AudioStreamIndex = table.Column<int>(type: "integer", nullable: true), + SubtitleStreamIndex = table.Column<int>(type: "integer", nullable: true), + Likes = table.Column<bool>(type: "boolean", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserData", x => new { x.ItemId, x.UserId, x.CustomDataKey }); + table.ForeignKey( + name: "FK_UserData_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserData_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DisplayPreferencesId = table.Column<int>(type: "integer", nullable: false), + Order = table.Column<int>(type: "integer", nullable: false), + Type = table.Column<int>(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AccessSchedules_UserId", + table: "AccessSchedules", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_ActivityLogs_DateCreated", + table: "ActivityLogs", + column: "DateCreated"); + + migrationBuilder.CreateIndex( + name: "IX_AncestorIds_ParentItemId", + table: "AncestorIds", + column: "ParentItemId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiKeys_AccessToken", + table: "ApiKeys", + column: "AccessToken", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemImageInfos_ItemId", + table: "BaseItemImageInfos", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemMetadataFields_ItemId", + table: "BaseItemMetadataFields", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemProviders_ProviderId_ProviderValue_ItemId", + table: "BaseItemProviders", + columns: new[] { "ProviderId", "ProviderValue", "ItemId" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Id_Type_IsFolder_IsVirtualItem", + table: "BaseItems", + columns: new[] { "Id", "Type", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_IsFolder_TopParentId_IsVirtualItem_PresentationUn~", + table: "BaseItems", + columns: new[] { "IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_MediaType_TopParentId_IsVirtualItem_PresentationU~", + table: "BaseItems", + columns: new[] { "MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_ParentId", + table: "BaseItems", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Path", + table: "BaseItems", + column: "Path"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_PresentationUniqueKey", + table: "BaseItems", + column: "PresentationUniqueKey"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_TopParentId_Id", + table: "BaseItems", + columns: new[] { "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_IsFolder_IsVirtu~", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_PresentationUniq~", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_Id", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_IsVirtualItem_PresentationUnique~", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_PresentationUniqueKey", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_StartDate", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "StartDate" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemTrailerTypes_ItemId", + table: "BaseItemTrailerTypes", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomItemDisplayPreferences_UserId_ItemId_Client_Key", + table: "CustomItemDisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client", "Key" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_DeviceOptions_DeviceId", + table: "DeviceOptions", + column: "DeviceId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Devices_AccessToken_DateLastActivity", + table: "Devices", + columns: new[] { "AccessToken", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId", + table: "Devices", + column: "DeviceId"); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId_DateLastActivity", + table: "Devices", + columns: new[] { "DeviceId", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_UserId_DeviceId", + table: "Devices", + columns: new[] { "UserId", "DeviceId" }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId_ItemId_Client", + table: "DisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + table: "HomeSection", + column: "DisplayPreferencesId"); + + migrationBuilder.CreateIndex( + name: "IX_ImageInfos_UserId", + table: "ImageInfos", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ItemDisplayPreferences_UserId", + table: "ItemDisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues", + columns: new[] { "Type", "CleanValue" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ItemValuesMap_ItemId", + table: "ItemValuesMap", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex", + table: "MediaStreamInfos", + column: "StreamIndex"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType_Language", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType", "Language" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamType", + table: "MediaStreamInfos", + column: "StreamType"); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_ListOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "ListOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_SortOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "SortOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_PeopleId", + table: "PeopleBaseItemMap", + column: "PeopleId"); + + migrationBuilder.CreateIndex( + name: "IX_Peoples_Name", + table: "Peoples", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_UserId_Kind", + table: "Permissions", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "[UserId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_Preferences_UserId_Kind", + table: "Preferences", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "[UserId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_IsFavorite", + table: "UserData", + columns: new[] { "ItemId", "UserId", "IsFavorite" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_LastPlayedDate", + table: "UserData", + columns: new[] { "ItemId", "UserId", "LastPlayedDate" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_PlaybackPositionTicks", + table: "UserData", + columns: new[] { "ItemId", "UserId", "PlaybackPositionTicks" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_Played", + table: "UserData", + columns: new[] { "ItemId", "UserId", "Played" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_UserId", + table: "UserData", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + table: "Users", + column: "Username", + unique: true); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccessSchedules"); + + migrationBuilder.DropTable( + name: "ActivityLogs"); + + migrationBuilder.DropTable( + name: "AncestorIds"); + + migrationBuilder.DropTable( + name: "ApiKeys"); + + migrationBuilder.DropTable( + name: "AttachmentStreamInfos"); + + migrationBuilder.DropTable( + name: "BaseItemImageInfos"); + + migrationBuilder.DropTable( + name: "BaseItemMetadataFields"); + + migrationBuilder.DropTable( + name: "BaseItemProviders"); + + migrationBuilder.DropTable( + name: "BaseItemTrailerTypes"); + + migrationBuilder.DropTable( + name: "Chapters"); + + migrationBuilder.DropTable( + name: "CustomItemDisplayPreferences"); + + migrationBuilder.DropTable( + name: "DeviceOptions"); + + migrationBuilder.DropTable( + name: "Devices"); + + migrationBuilder.DropTable( + name: "HomeSection"); + + migrationBuilder.DropTable( + name: "ImageInfos"); + + migrationBuilder.DropTable( + name: "ItemDisplayPreferences"); + + migrationBuilder.DropTable( + name: "ItemValuesMap"); + + migrationBuilder.DropTable( + name: "MediaSegments"); + + migrationBuilder.DropTable( + name: "MediaStreamInfos"); + + migrationBuilder.DropTable( + name: "PeopleBaseItemMap"); + + migrationBuilder.DropTable( + name: "Permissions"); + + migrationBuilder.DropTable( + name: "Preferences"); + + migrationBuilder.DropTable( + name: "TrickplayInfos"); + + migrationBuilder.DropTable( + name: "UserData"); + + migrationBuilder.DropTable( + name: "DisplayPreferences"); + + migrationBuilder.DropTable( + name: "ItemValues"); + + migrationBuilder.DropTable( + name: "Peoples"); + + migrationBuilder.DropTable( + name: "BaseItems"); + + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/JellyfinDbContextModelSnapshot.cs b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/JellyfinDbContextModelSnapshot.cs new file mode 100644 index 000000000..cdaf257d4 --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/JellyfinDbContextModelSnapshot.cs @@ -0,0 +1,1621 @@ +// <auto-generated /> +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PgSql.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + partial class JellyfinDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("DayOfWeek") + .HasColumnType("integer"); + + b.Property<double>("EndHour") + .HasColumnType("double precision"); + + b.Property<double>("StartHour") + .HasColumnType("double precision"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("ItemId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<int>("LogSeverity") + .HasColumnType("integer"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<string>("Overview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<string>("ShortOverview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<string>("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("ParentItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("Index") + .HasColumnType("integer"); + + b.Property<string>("Codec") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("CodecTag") + .HasColumnType("text"); + + b.Property<string>("Comment") + .HasColumnType("text"); + + b.Property<string>("Filename") + .HasColumnType("text"); + + b.Property<string>("MimeType") + .HasColumnType("text"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("Album") + .HasColumnType("text"); + + b.Property<string>("AlbumArtists") + .HasColumnType("text"); + + b.Property<string>("Artists") + .HasColumnType("text"); + + b.Property<int?>("Audio") + .HasColumnType("integer"); + + b.Property<string>("ChannelId") + .HasColumnType("text"); + + b.Property<string>("CleanName") + .HasColumnType("text"); + + b.Property<float?>("CommunityRating") + .HasColumnType("real"); + + b.Property<float?>("CriticRating") + .HasColumnType("real"); + + b.Property<string>("CustomRating") + .HasColumnType("text"); + + b.Property<string>("Data") + .HasColumnType("text"); + + b.Property<DateTime?>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastMediaAdded") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastRefreshed") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateLastSaved") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("EpisodeTitle") + .HasColumnType("text"); + + b.Property<string>("ExternalId") + .HasColumnType("text"); + + b.Property<string>("ExternalSeriesId") + .HasColumnType("text"); + + b.Property<string>("ExternalServiceId") + .HasColumnType("text"); + + b.Property<string>("ExtraIds") + .HasColumnType("text"); + + b.Property<int?>("ExtraType") + .HasColumnType("integer"); + + b.Property<string>("ForcedSortName") + .HasColumnType("text"); + + b.Property<string>("Genres") + .HasColumnType("text"); + + b.Property<int?>("Height") + .HasColumnType("integer"); + + b.Property<int?>("IndexNumber") + .HasColumnType("integer"); + + b.Property<int?>("InheritedParentalRatingValue") + .HasColumnType("integer"); + + b.Property<bool>("IsFolder") + .HasColumnType("boolean"); + + b.Property<bool>("IsInMixedFolder") + .HasColumnType("boolean"); + + b.Property<bool>("IsLocked") + .HasColumnType("boolean"); + + b.Property<bool>("IsMovie") + .HasColumnType("boolean"); + + b.Property<bool>("IsRepeat") + .HasColumnType("boolean"); + + b.Property<bool>("IsSeries") + .HasColumnType("boolean"); + + b.Property<bool>("IsVirtualItem") + .HasColumnType("boolean"); + + b.Property<float?>("LUFS") + .HasColumnType("real"); + + b.Property<string>("MediaType") + .HasColumnType("text"); + + b.Property<string>("Name") + .HasColumnType("text"); + + b.Property<float?>("NormalizationGain") + .HasColumnType("real"); + + b.Property<string>("OfficialRating") + .HasColumnType("text"); + + b.Property<string>("OriginalTitle") + .HasColumnType("text"); + + b.Property<string>("Overview") + .HasColumnType("text"); + + b.Property<string>("OwnerId") + .HasColumnType("text"); + + b.Property<Guid?>("ParentId") + .HasColumnType("uuid"); + + b.Property<int?>("ParentIndexNumber") + .HasColumnType("integer"); + + b.Property<string>("Path") + .HasColumnType("text"); + + b.Property<string>("PreferredMetadataCountryCode") + .HasColumnType("text"); + + b.Property<string>("PreferredMetadataLanguage") + .HasColumnType("text"); + + b.Property<DateTime?>("PremiereDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("PresentationUniqueKey") + .HasColumnType("text"); + + b.Property<string>("PrimaryVersionId") + .HasColumnType("text"); + + b.Property<string>("ProductionLocations") + .HasColumnType("text"); + + b.Property<int?>("ProductionYear") + .HasColumnType("integer"); + + b.Property<long?>("RunTimeTicks") + .HasColumnType("bigint"); + + b.Property<Guid?>("SeasonId") + .HasColumnType("uuid"); + + b.Property<string>("SeasonName") + .HasColumnType("text"); + + b.Property<Guid?>("SeriesId") + .HasColumnType("uuid"); + + b.Property<string>("SeriesName") + .HasColumnType("text"); + + b.Property<string>("SeriesPresentationUniqueKey") + .HasColumnType("text"); + + b.Property<string>("ShowId") + .HasColumnType("text"); + + b.Property<long?>("Size") + .HasColumnType("bigint"); + + b.Property<string>("SortName") + .HasColumnType("text"); + + b.Property<DateTime>("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Studios") + .HasColumnType("text"); + + b.Property<string>("Tagline") + .HasColumnType("text"); + + b.Property<string>("Tags") + .HasColumnType("text"); + + b.Property<Guid?>("TopParentId") + .HasColumnType("uuid"); + + b.Property<int?>("TotalBitrate") + .HasColumnType("integer"); + + b.Property<string>("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("UnratedType") + .HasColumnType("text"); + + b.Property<int?>("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<byte[]>("Blurhash") + .HasColumnType("bytea"); + + b.Property<DateTime>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<int>("Height") + .HasColumnType("integer"); + + b.Property<int>("ImageType") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property<int>("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.Property<int>("Id") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("ProviderId") + .HasColumnType("text"); + + b.Property<string>("ProviderValue") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.Property<int>("Id") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("ChapterIndex") + .HasColumnType("integer"); + + b.Property<DateTime?>("ImageDateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("ImagePath") + .HasColumnType("text"); + + b.Property<string>("Name") + .HasColumnType("text"); + + b.Property<long>("StartPositionTicks") + .HasColumnType("bigint"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("ChromecastVersion") + .HasColumnType("integer"); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<string>("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<bool>("EnableNextVideoInfoOverlay") + .HasColumnType("boolean"); + + b.Property<int?>("IndexBy") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("ScrollDirection") + .HasColumnType("integer"); + + b.Property<bool>("ShowBackdrop") + .HasColumnType("boolean"); + + b.Property<bool>("ShowSidebar") + .HasColumnType("boolean"); + + b.Property<int>("SkipBackwardLength") + .HasColumnType("integer"); + + b.Property<int>("SkipForwardLength") + .HasColumnType("integer"); + + b.Property<string>("TvHome") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("DisplayPreferencesId") + .HasColumnType("integer"); + + b.Property<int>("Order") + .HasColumnType("integer"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<int?>("IndexBy") + .HasColumnType("integer"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<bool>("RememberIndexing") + .HasColumnType("boolean"); + + b.Property<bool>("RememberSorting") + .HasColumnType("boolean"); + + b.Property<string>("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<int>("SortOrder") + .HasColumnType("integer"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<int>("ViewType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Property<Guid>("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("CleanValue") + .IsRequired() + .HasColumnType("text"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.Property<string>("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.Property<Guid>("ItemValueId") + .HasColumnType("uuid"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaSegment", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<long>("EndTicks") + .HasColumnType("bigint"); + + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<string>("SegmentProviderId") + .IsRequired() + .HasColumnType("text"); + + b.Property<long>("StartTicks") + .HasColumnType("bigint"); + + b.Property<int>("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("StreamIndex") + .HasColumnType("integer"); + + b.Property<string>("AspectRatio") + .HasColumnType("text"); + + b.Property<float?>("AverageFrameRate") + .HasColumnType("real"); + + b.Property<int?>("BitDepth") + .HasColumnType("integer"); + + b.Property<int?>("BitRate") + .HasColumnType("integer"); + + b.Property<int?>("BlPresentFlag") + .HasColumnType("integer"); + + b.Property<string>("ChannelLayout") + .HasColumnType("text"); + + b.Property<int?>("Channels") + .HasColumnType("integer"); + + b.Property<string>("Codec") + .HasColumnType("text"); + + b.Property<string>("CodecTag") + .HasColumnType("text"); + + b.Property<string>("CodecTimeBase") + .HasColumnType("text"); + + b.Property<string>("ColorPrimaries") + .HasColumnType("text"); + + b.Property<string>("ColorSpace") + .HasColumnType("text"); + + b.Property<string>("ColorTransfer") + .HasColumnType("text"); + + b.Property<string>("Comment") + .HasColumnType("text"); + + b.Property<int?>("DvBlSignalCompatibilityId") + .HasColumnType("integer"); + + b.Property<int?>("DvLevel") + .HasColumnType("integer"); + + b.Property<int?>("DvProfile") + .HasColumnType("integer"); + + b.Property<int?>("DvVersionMajor") + .HasColumnType("integer"); + + b.Property<int?>("DvVersionMinor") + .HasColumnType("integer"); + + b.Property<int?>("ElPresentFlag") + .HasColumnType("integer"); + + b.Property<int?>("Height") + .HasColumnType("integer"); + + b.Property<bool?>("IsAnamorphic") + .HasColumnType("boolean"); + + b.Property<bool?>("IsAvc") + .HasColumnType("boolean"); + + b.Property<bool>("IsDefault") + .HasColumnType("boolean"); + + b.Property<bool>("IsExternal") + .HasColumnType("boolean"); + + b.Property<bool>("IsForced") + .HasColumnType("boolean"); + + b.Property<bool?>("IsHearingImpaired") + .HasColumnType("boolean"); + + b.Property<bool?>("IsInterlaced") + .HasColumnType("boolean"); + + b.Property<string>("KeyFrames") + .HasColumnType("text"); + + b.Property<string>("Language") + .HasColumnType("text"); + + b.Property<float?>("Level") + .HasColumnType("real"); + + b.Property<string>("NalLengthSize") + .HasColumnType("text"); + + b.Property<string>("Path") + .HasColumnType("text"); + + b.Property<string>("PixelFormat") + .HasColumnType("text"); + + b.Property<string>("Profile") + .HasColumnType("text"); + + b.Property<float?>("RealFrameRate") + .HasColumnType("real"); + + b.Property<int?>("RefFrames") + .HasColumnType("integer"); + + b.Property<int?>("Rotation") + .HasColumnType("integer"); + + b.Property<int?>("RpuPresentFlag") + .HasColumnType("integer"); + + b.Property<int?>("SampleRate") + .HasColumnType("integer"); + + b.Property<int>("StreamType") + .HasColumnType("integer"); + + b.Property<string>("TimeBase") + .HasColumnType("text"); + + b.Property<string>("Title") + .HasColumnType("text"); + + b.Property<int?>("Width") + .HasColumnType("integer"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("PersonType") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("PeopleId") + .HasColumnType("uuid"); + + b.Property<int?>("ListOrder") + .HasColumnType("integer"); + + b.Property<string>("Role") + .HasColumnType("text"); + + b.Property<int?>("SortOrder") + .HasColumnType("integer"); + + b.HasKey("ItemId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("Kind") + .HasColumnType("integer"); + + b.Property<Guid?>("Permission_Permissions_Guid") + .HasColumnType("uuid"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.Property<bool>("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("Kind") + .HasColumnType("integer"); + + b.Property<Guid?>("Preference_Preferences_Guid") + .HasColumnType("uuid"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property<string>("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<string>("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime>("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property<string>("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property<bool>("IsActive") + .HasColumnType("boolean"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("CustomName") + .HasColumnType("text"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.TrickplayInfo", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<int>("Width") + .HasColumnType("integer"); + + b.Property<int>("Bandwidth") + .HasColumnType("integer"); + + b.Property<int>("Height") + .HasColumnType("integer"); + + b.Property<int>("Interval") + .HasColumnType("integer"); + + b.Property<int>("ThumbnailCount") + .HasColumnType("integer"); + + b.Property<int>("TileHeight") + .HasColumnType("integer"); + + b.Property<int>("TileWidth") + .HasColumnType("integer"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property<string>("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<string>("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<string>("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property<bool>("DisplayCollectionsView") + .HasColumnType("boolean"); + + b.Property<bool>("DisplayMissingEpisodes") + .HasColumnType("boolean"); + + b.Property<bool>("EnableAutoLogin") + .HasColumnType("boolean"); + + b.Property<bool>("EnableLocalPassword") + .HasColumnType("boolean"); + + b.Property<bool>("EnableNextEpisodeAutoPlay") + .HasColumnType("boolean"); + + b.Property<bool>("EnableUserPreferenceAccess") + .HasColumnType("boolean"); + + b.Property<bool>("HidePlayedInLatest") + .HasColumnType("boolean"); + + b.Property<long>("InternalId") + .HasColumnType("bigint"); + + b.Property<int>("InvalidLoginAttemptCount") + .HasColumnType("integer"); + + b.Property<DateTime?>("LastActivityDate") + .HasColumnType("timestamp with time zone"); + + b.Property<DateTime?>("LastLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property<int?>("LoginAttemptsBeforeLockout") + .HasColumnType("integer"); + + b.Property<int>("MaxActiveSessions") + .HasColumnType("integer"); + + b.Property<int?>("MaxParentalAgeRating") + .HasColumnType("integer"); + + b.Property<bool>("MustUpdatePassword") + .HasColumnType("boolean"); + + b.Property<string>("Password") + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.Property<string>("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<bool>("PlayDefaultAudioTrack") + .HasColumnType("boolean"); + + b.Property<bool>("RememberAudioSelections") + .HasColumnType("boolean"); + + b.Property<bool>("RememberSubtitleSelections") + .HasColumnType("boolean"); + + b.Property<int?>("RemoteClientBitrateLimit") + .HasColumnType("integer"); + + b.Property<long>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property<string>("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property<int>("SubtitleMode") + .HasColumnType("integer"); + + b.Property<int>("SyncPlayAccess") + .HasColumnType("integer"); + + b.Property<string>("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.Property<Guid>("ItemId") + .HasColumnType("uuid"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid"); + + b.Property<string>("CustomDataKey") + .HasColumnType("text"); + + b.Property<int?>("AudioStreamIndex") + .HasColumnType("integer"); + + b.Property<bool>("IsFavorite") + .HasColumnType("boolean"); + + b.Property<DateTime?>("LastPlayedDate") + .HasColumnType("timestamp with time zone"); + + b.Property<bool?>("Likes") + .HasColumnType("boolean"); + + b.Property<int>("PlayCount") + .HasColumnType("integer"); + + b.Property<long>("PlaybackPositionTicks") + .HasColumnType("bigint"); + + b.Property<bool>("Played") + .HasColumnType("boolean"); + + b.Property<double?>("Rating") + .HasColumnType("double precision"); + + b.Property<int?>("SubtitleStreamIndex") + .HasColumnType("integer"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Children") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "ParentItem") + .WithMany("ParentAncestors") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.UserData", b => + { + b.HasOne("Jellyfin.Data.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("ParentAncestors"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/PgSqlDesignTimeJellyfinDbFactory.cs b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/PgSqlDesignTimeJellyfinDbFactory.cs new file mode 100644 index 000000000..8f5e2e82b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/Migrations/PgSqlDesignTimeJellyfinDbFactory.cs @@ -0,0 +1,26 @@ +using Jellyfin.Database.Providers.SqLite; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Jellyfin.Database.Providers.PgSql +{ + /// <summary> + /// The design time factory for <see cref="JellyfinDbContext"/>. + /// This is only used for the creation of migrations and not during runtime. + /// </summary> + internal sealed class PgSqlDesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDbContext> + { + public JellyfinDbContext CreateDbContext(string[] args) + { + var optionsBuilder = new DbContextOptionsBuilder<JellyfinDbContext>(); + optionsBuilder.UseNpgsql(f => f.MigrationsAssembly(GetType().Assembly)); + + return new JellyfinDbContext( + optionsBuilder.Options, + NullLogger<JellyfinDbContext>.Instance, + new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance)); + } + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/PgSqlDatabaseProvider.cs b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/PgSqlDatabaseProvider.cs new file mode 100644 index 000000000..1dae3401b --- /dev/null +++ b/Jellyfin.Database/Jellyfin.Database.Providers.PgSql/PgSqlDatabaseProvider.cs @@ -0,0 +1,75 @@ +using System; +using Jellyfin.Server.Implementations; +using Jellyfin.Server.Implementations.DatabaseConfiguration; +using MediaBrowser.Common.Configuration; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Npgsql; + +namespace Jellyfin.Database.Providers.PgSql; + +/// <summary> +/// Configures jellyfin to use an SqLite database. +/// </summary> +[JellyfinDatabaseProviderKey("Jellyfin-PgSql")] +public sealed class PgSqlDatabaseProvider : IJellyfinDatabaseProvider +{ + private readonly IConfigurationManager _configurationManager; + private readonly ILogger<PgSqlDatabaseProvider> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="PgSqlDatabaseProvider"/> class. + /// </summary> + /// <param name="configurationManager">Configuration manager to get PgSQL connection data.</param> + /// <param name="logger">A logger.</param> + public PgSqlDatabaseProvider(IConfigurationManager configurationManager, ILogger<PgSqlDatabaseProvider> logger) + { + _configurationManager = configurationManager; + _logger = logger; + } + + /// <inheritdoc/> + public IDbContextFactory<JellyfinDbContext>? DbContextFactory { get; set; } + + /// <inheritdoc/> + public void Initialise(DbContextOptionsBuilder options) + { + var dbSettings = _configurationManager.GetConfiguration<DatabaseConfigurationOptions>("database"); + + if (dbSettings.PostgreSql is null) + { + throw new InvalidOperationException("Selected PgSQL as database provider but did not provide required configuration. Please see docs."); + } + + var connectionBuilder = new NpgsqlConnectionStringBuilder(); + connectionBuilder.ApplicationName = "jellyfin"; + connectionBuilder.CommandTimeout = dbSettings.PostgreSql.Timeout; + connectionBuilder.Database = dbSettings.PostgreSql.DatabaseName; + connectionBuilder.Username = dbSettings.PostgreSql.Username; + connectionBuilder.Password = dbSettings.PostgreSql.Password; + connectionBuilder.Host = dbSettings.PostgreSql.ServerName; + connectionBuilder.Port = dbSettings.PostgreSql.Port; + + var connectionString = connectionBuilder.ToString(); + + options + .UseNpgsql(connectionString, pgSqlOptions => pgSqlOptions.MigrationsAssembly(GetType().Assembly)); + } + + /// <inheritdoc/> + public Task RunScheduledOptimisation(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + /// <inheritdoc/> + public void OnModelCreating(ModelBuilder modelBuilder) + { + } + + /// <inheritdoc/> + public ValueTask DisposeAsync() + { + return ValueTask.CompletedTask; + } +} diff --git a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs index fdd9a5136..11eeb8e02 100644 --- a/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/DesignTimeJellyfinDbFactory.cs +++ b/Jellyfin.Database/Jellyfin.Database.Providers.SqLite/Migrations/SqliteDesignTimeJellyfinDbFactory.cs @@ -9,7 +9,7 @@ namespace Jellyfin.Server.Implementations.Migrations /// The design time factory for <see cref="JellyfinDbContext"/>. /// This is only used for the creation of migrations and not during runtime. /// </summary> - internal sealed class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDbContext> + internal sealed class SqliteDesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDbContext> { public JellyfinDbContext CreateDbContext(string[] args) { diff --git a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs index af2ede701..d49d8536a 100644 --- a/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs +++ b/Jellyfin.Server.Implementations/DbConfiguration/DatabaseConfigurationOptions.cs @@ -11,4 +11,9 @@ public class DatabaseConfigurationOptions /// Gets or Sets the type of database jellyfin should use. /// </summary> public required string DatabaseType { get; set; } + + /// <summary> + /// Gets or Sets the settings to run jellyfin with Postgres. + /// </summary> + public PostgreSqlOptions? PostgreSql { get; set; } } diff --git a/Jellyfin.Server.Implementations/DbConfiguration/PostgreSqlOptions.cs b/Jellyfin.Server.Implementations/DbConfiguration/PostgreSqlOptions.cs new file mode 100644 index 000000000..1f7c30b09 --- /dev/null +++ b/Jellyfin.Server.Implementations/DbConfiguration/PostgreSqlOptions.cs @@ -0,0 +1,39 @@ +using System; + +namespace Jellyfin.Server.Implementations.DatabaseConfiguration; + +/// <summary> +/// Options specific to run jellyfin on a postgreSql database. +/// </summary> +public class PostgreSqlOptions +{ + /// <summary> + /// Gets or Sets the Port. Defaults to 5432. + /// </summary> + public required int Port { get; set; } = 5432; + + /// <summary> + /// Gets or Sets the Server name. + /// </summary> + public required string ServerName { get; set; } + + /// <summary> + /// Gets or Sets the username. + /// </summary> + public required string Username { get; set; } + + /// <summary> + /// Gets or Sets the password. + /// </summary> + public required string Password { get; set; } + + /// <summary> + /// Gets or Sets the database name. Defaults to "Jellyfin". + /// </summary> + public string DatabaseName { get; set; } = "Jellyfin"; + + /// <summary> + /// Gets or Sets the timeout in secounds before a running command is terminated. Defaults to 30. + /// </summary> + public int Timeout { get; set; } = 30; +} |
