diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs index 2bbffa72..92402690 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs @@ -88,6 +88,7 @@ public class Image Blurhash = blurhash ?? "000000"; } + // public class ImageConvertor : JsonConverter { /// @@ -100,7 +101,13 @@ public class Image if (reader.TokenType == JsonTokenType.String && reader.GetString() is string source) return new Image(source); using JsonDocument document = JsonDocument.ParseValue(ref reader); - return document.RootElement.Deserialize(); + string? src = document.RootElement.GetProperty("Source").GetString(); + string? blurhash = document.RootElement.GetProperty("Blurhash").GetString(); + Guid? id = document.RootElement.GetProperty("Id").GetGuid(); + return new Image(src ?? string.Empty, blurhash) + { + Id = id ?? Guid.Empty + }; } /// diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index 320021d3..3f2cd14c 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -23,7 +23,6 @@ using System.Linq.Expressions; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Authentication; @@ -33,13 +32,6 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; namespace Kyoo.Postgresql; -/// -/// The database handle used for all local repositories. -/// This is an abstract class. It is meant to be implemented by plugins. This allow the core to be database agnostic. -/// -/// -/// It should not be used directly, to access the database use a or repositories. -/// public abstract class DatabaseContext : DbContext { private readonly IHttpContextAccessor _accessor; @@ -53,39 +45,18 @@ public abstract class DatabaseContext : DbContext public Guid? CurrentUserId => _accessor.HttpContext?.User.GetId(); - /// - /// All collections of Kyoo. See . - /// public DbSet Collections { get; set; } - /// - /// All movies of Kyoo. See . - /// public DbSet Movies { get; set; } - /// - /// All shows of Kyoo. See . - /// public DbSet Shows { get; set; } - /// - /// All seasons of Kyoo. See . - /// public DbSet Seasons { get; set; } - /// - /// All episodes of Kyoo. See . - /// public DbSet Episodes { get; set; } - /// - /// All studios of Kyoo. See . - /// public DbSet Studios { get; set; } - /// - /// The list of registered users. - /// public DbSet Users { get; set; } public DbSet MovieWatchStatus { get; set; } @@ -129,28 +100,13 @@ public abstract class DatabaseContext : DbContext _accessor = accessor; } - /// - /// Get the name of the link table of the two given types. - /// - /// The owner type of the relation - /// The child type of the relation - /// The name of the table containing the links. protected abstract string LinkName() where T : IResource where T2 : IResource; - /// - /// Get the name of a link's foreign key. - /// - /// The type that will be accessible via the navigation - /// The name of the foreign key for the given resource. protected abstract string LinkNameFk() where T : IResource; - /// - /// Set basic configurations (like preventing query tracking) - /// - /// An option builder to fill. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); @@ -227,15 +183,6 @@ public abstract class DatabaseContext : DbContext .ValueGeneratedOnAdd(); } - /// - /// Create a many to many relationship between the two entities. - /// The resulting relationship will have an available method. - /// - /// The database model builder - /// The first navigation expression from T to T2 - /// The second navigation expression from T2 to T - /// The owning type of the relationship - /// The owned type of the relationship private void _HasManyToMany( ModelBuilder modelBuilder, Expression?>> firstNavigation, @@ -263,10 +210,6 @@ public abstract class DatabaseContext : DbContext ); } - /// - /// Set database parameters to support every types of Kyoo. - /// - /// The database's model builder. protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); @@ -412,28 +355,6 @@ public abstract class DatabaseContext : DbContext _HasJson(modelBuilder, x => x.Extra); } - /// - /// Return a new or an in cache temporary object wih the same ID as the one given - /// - /// If a resource with the same ID is found in the database, it will be used. - /// will be used otherwise - /// The type of the resource - /// A resource that is now tracked by this context. - public T GetTemporaryObject(T model) - where T : class, IResource - { - T? tmp = Set().Local.FirstOrDefault(x => x.Id == model.Id); - if (tmp != null) - return tmp; - Entry(model).State = EntityState.Unchanged; - return model; - } - - /// - /// Save changes that are applied to this context. - /// - /// A duplicated item has been found. - /// The number of state entries written to the database. public override int SaveChanges() { try @@ -449,13 +370,6 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Save changes that are applied to this context. - /// - /// Indicates whether AcceptAllChanges() is called after the changes - /// have been sent successfully to the database. - /// A duplicated item has been found. - /// The number of state entries written to the database. public override int SaveChanges(bool acceptAllChangesOnSuccess) { try @@ -471,14 +385,6 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Save changes that are applied to this context. - /// - /// Indicates whether AcceptAllChanges() is called after the changes - /// have been sent successfully to the database. - /// A to observe while waiting for the task to complete - /// A duplicated item has been found. - /// The number of state entries written to the database. public override async Task SaveChangesAsync( bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default @@ -497,12 +403,6 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Save changes that are applied to this context. - /// - /// A to observe while waiting for the task to complete - /// A duplicated item has been found. - /// The number of state entries written to the database. public override async Task SaveChangesAsync(CancellationToken cancellationToken = default) { try @@ -518,14 +418,6 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Save changes that are applied to this context. - /// - /// How to retrieve the conflicting item. - /// A to observe while waiting for the task to complete - /// A duplicated item has been found. - /// The type of the potential duplicate (this is unused). - /// The number of state entries written to the database. public async Task SaveChangesAsync( Func> getExisting, CancellationToken cancellationToken = default @@ -548,12 +440,6 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Save changes if no duplicates are found. If one is found, no change are saved but the current changes are no discarded. - /// The current context will still hold those invalid changes. - /// - /// A to observe while waiting for the task to complete - /// The number of state entries written to the database or -1 if a duplicate exist. public async Task SaveIfNoDuplicates(CancellationToken cancellationToken = default) { try @@ -566,30 +452,14 @@ public abstract class DatabaseContext : DbContext } } - /// - /// Return the first resource with the given slug that is currently tracked by this context. - /// This allow one to limit redundant calls to during the - /// same transaction and prevent fails from EF when two same entities are being tracked. - /// - /// The slug of the resource to check - /// The type of entity to check - /// The local entity representing the resource with the given slug if it exists or null. public T? LocalEntity(string slug) where T : class, IResource { return ChangeTracker.Entries().FirstOrDefault(x => x.Entity.Slug == slug)?.Entity; } - /// - /// Check if the exception is a duplicated exception. - /// - /// The exception to check - /// True if the exception is a duplicate exception. False otherwise protected abstract bool IsDuplicateException(Exception ex); - /// - /// Delete every changes that are on this context. - /// public void DiscardChanges() { foreach ( diff --git a/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.Designer.cs new file mode 100644 index 00000000..0157c3cd --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.Designer.cs @@ -0,0 +1,1375 @@ +// +using System; +using System.Collections.Generic; +using Kyoo.Abstractions.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + [DbContext(typeof(PostgresContext))] + [Migration("20240420124608_ReworkImages")] + partial class ReworkImages + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "genre", new[] { "action", "adventure", "animation", "comedy", "crime", "documentary", "drama", "family", "fantasy", "history", "horror", "music", "mystery", "romance", "science_fiction", "thriller", "war", "western", "kids", "news", "reality", "soap", "talk", "politics" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "watch_status", new[] { "completed", "watching", "droped", "planned", "deleted" }); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("NextMetadataRefresh") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("next_metadata_refresh") + .HasDefaultValueSql("now() at time zone 'utc' + interval '2 hours'"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_collections"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_collections_slug"); + + b.ToTable("collections", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AbsoluteNumber") + .HasColumnType("integer") + .HasColumnName("absolute_number"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EpisodeNumber") + .HasColumnType("integer") + .HasColumnName("episode_number"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("NextMetadataRefresh") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("next_metadata_refresh") + .HasDefaultValueSql("now() at time zone 'utc' + interval '2 hours'"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("ReleaseDate") + .HasColumnType("date") + .HasColumnName("release_date"); + + b.Property("Runtime") + .HasColumnType("integer") + .HasColumnName("runtime"); + + b.Property("SeasonId") + .HasColumnType("uuid") + .HasColumnName("season_id"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId") + .HasColumnType("uuid") + .HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_episodes"); + + b.HasIndex("SeasonId") + .HasDatabaseName("ix_episodes_season_id"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_episodes_slug"); + + b.HasIndex("ShowId", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") + .IsUnique() + .HasDatabaseName("ix_episodes_show_id_season_number_episode_number_absolute_numb"); + + b.ToTable("episodes", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.EpisodeWatchStatus", b => + { + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("EpisodeId") + .HasColumnType("uuid") + .HasColumnName("episode_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "EpisodeId") + .HasName("pk_episode_watch_status"); + + b.HasIndex("EpisodeId") + .HasDatabaseName("ix_episode_watch_status_episode_id"); + + b.ToTable("episode_watch_status", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Issue", b => + { + b.Property("Domain") + .HasColumnType("text") + .HasColumnName("domain"); + + b.Property("Cause") + .HasColumnType("text") + .HasColumnName("cause"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("json") + .HasColumnName("extra"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reason"); + + b.HasKey("Domain", "Cause") + .HasName("pk_issues"); + + b.ToTable("issues", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("AirDate") + .HasColumnType("date") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property>("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("NextMetadataRefresh") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("next_metadata_refresh") + .HasDefaultValueSql("now() at time zone 'utc' + interval '2 hours'"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Rating") + .HasColumnType("integer") + .HasColumnName("rating"); + + b.Property("Runtime") + .HasColumnType("integer") + .HasColumnName("runtime"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioId") + .HasColumnType("uuid") + .HasColumnName("studio_id"); + + b.Property("Tagline") + .HasColumnType("text") + .HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer") + .HasColumnType("text") + .HasColumnName("trailer"); + + b.HasKey("Id") + .HasName("pk_movies"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_movies_slug"); + + b.HasIndex("StudioId") + .HasDatabaseName("ix_movies_studio_id"); + + b.ToTable("movies", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.MovieWatchStatus", b => + { + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("MovieId") + .HasColumnType("uuid") + .HasColumnName("movie_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "MovieId") + .HasName("pk_movie_watch_status"); + + b.HasIndex("MovieId") + .HasDatabaseName("ix_movie_watch_status_movie_id"); + + b.ToTable("movie_watch_status", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EndDate") + .HasColumnType("date") + .HasColumnName("end_date"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("NextMetadataRefresh") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("next_metadata_refresh") + .HasDefaultValueSql("now() at time zone 'utc' + interval '2 hours'"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId") + .HasColumnType("uuid") + .HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartDate") + .HasColumnType("date") + .HasColumnName("start_date"); + + b.HasKey("Id") + .HasName("pk_seasons"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_seasons_slug"); + + b.HasIndex("ShowId", "SeasonNumber") + .IsUnique() + .HasDatabaseName("ix_seasons_show_id_season_number"); + + b.ToTable("seasons", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property>("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("date") + .HasColumnName("end_air"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property>("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("NextMetadataRefresh") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("next_metadata_refresh") + .HasDefaultValueSql("now() at time zone 'utc' + interval '2 hours'"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Rating") + .HasColumnType("integer") + .HasColumnName("rating"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("date") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioId") + .HasColumnType("uuid") + .HasColumnName("studio_id"); + + b.Property("Tagline") + .HasColumnType("text") + .HasColumnName("tagline"); + + b.Property>("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer") + .HasColumnType("text") + .HasColumnName("trailer"); + + b.HasKey("Id") + .HasName("pk_shows"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_shows_slug"); + + b.HasIndex("StudioId") + .HasDatabaseName("ix_shows_studio_id"); + + b.ToTable("shows", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.ShowWatchStatus", b => + { + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("ShowId") + .HasColumnType("uuid") + .HasColumnName("show_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("NextEpisodeId") + .HasColumnType("uuid") + .HasColumnName("next_episode_id"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("UnseenEpisodesCount") + .HasColumnType("integer") + .HasColumnName("unseen_episodes_count"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "ShowId") + .HasName("pk_show_watch_status"); + + b.HasIndex("NextEpisodeId") + .HasDatabaseName("ix_show_watch_status_next_episode_id"); + + b.HasIndex("ShowId") + .HasDatabaseName("ix_show_watch_status_show_id"); + + b.ToTable("show_watch_status", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_studios"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_studios_slug"); + + b.ToTable("studios", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Password") + .HasColumnType("text") + .HasColumnName("password"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("permissions"); + + b.Property("Settings") + .IsRequired() + .HasColumnType("json") + .HasColumnName("settings"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_users"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_users_slug"); + + b.HasIndex("Username") + .IsUnique() + .HasDatabaseName("ix_users_username"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("link_collection_movie", b => + { + b.Property("collection_id") + .HasColumnType("uuid") + .HasColumnName("collection_id"); + + b.Property("movie_id") + .HasColumnType("uuid") + .HasColumnName("movie_id"); + + b.HasKey("collection_id", "movie_id") + .HasName("pk_link_collection_movie"); + + b.HasIndex("movie_id") + .HasDatabaseName("ix_link_collection_movie_movie_id"); + + b.ToTable("link_collection_movie", (string)null); + }); + + modelBuilder.Entity("link_collection_show", b => + { + b.Property("collection_id") + .HasColumnType("uuid") + .HasColumnName("collection_id"); + + b.Property("show_id") + .HasColumnType("uuid") + .HasColumnName("show_id"); + + b.HasKey("collection_id", "show_id") + .HasName("pk_link_collection_show"); + + b.HasIndex("show_id") + .HasDatabaseName("ix_link_collection_show_show_id"); + + b.ToTable("link_collection_show", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.ToJson("logo"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("CollectionId") + .HasName("pk_collections"); + + b1.ToTable("collections"); + + b1.ToJson("poster"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_collection_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.ToJson("thumbnail"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => + { + b.HasOne("Kyoo.Abstractions.Models.Season", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_episodes_seasons_season_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Episodes") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episodes_shows_show_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.ToJson("logo"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.ToJson("poster"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.ToJson("thumbnail"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Season"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.EpisodeWatchStatus", b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") + .WithMany("Watched") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episode_watch_status_episodes_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episode_watch_status_users_user_id"); + + b.Navigation("Episode"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Movies") + .HasForeignKey("StudioId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_movies_studios_studio_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("MovieId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.ToJson("logo"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("MovieId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.ToJson("poster"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("MovieId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.ToJson("thumbnail"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.MovieWatchStatus", b => + { + b.HasOne("Kyoo.Abstractions.Models.Movie", "Movie") + .WithMany("Watched") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_movie_watch_status_movies_movie_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_movie_watch_status_users_user_id"); + + b.Navigation("Movie"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Seasons") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_seasons_shows_show_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("SeasonId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.ToJson("logo"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("SeasonId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.ToJson("poster"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("SeasonId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.ToJson("thumbnail"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Shows") + .HasForeignKey("StudioId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_shows_studios_studio_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("ShowId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.ToJson("logo"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("ShowId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.ToJson("poster"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("ShowId") + .HasColumnType("uuid"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.ToJson("thumbnail"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.ShowWatchStatus", b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "NextEpisode") + .WithMany() + .HasForeignKey("NextEpisodeId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_show_watch_status_episodes_next_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Watched") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_show_watch_status_shows_show_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_show_watch_status_users_user_id"); + + b.Navigation("NextEpisode"); + + b.Navigation("Show"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("link_collection_movie", b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Movie", null) + .WithMany() + .HasForeignKey("movie_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_movies_movie_id"); + }); + + modelBuilder.Entity("link_collection_show", b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", null) + .WithMany() + .HasForeignKey("show_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_shows_show_id"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => + { + b.Navigation("Watched"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.Navigation("Watched"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.Navigation("Episodes"); + + b.Navigation("Seasons"); + + b.Navigation("Watched"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => + { + b.Navigation("Movies"); + + b.Navigation("Shows"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.cs b/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.cs new file mode 100644 index 00000000..9606e2d7 --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20240420124608_ReworkImages.cs @@ -0,0 +1,460 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + /// + public partial class ReworkImages : Migration + { + private void MigrateImage(MigrationBuilder migrationBuilder, string table, string type) + { + migrationBuilder.Sql($""" + update {table} as r set {type} = json_build_object( + 'Id', gen_random_uuid(), + 'Source', r.{type}_source, + 'Blurhash', r.{type}_blurhash + ) + where r.{type}_source is not null + """); + } + + private void UnMigrateImage(MigrationBuilder migrationBuilder, string table, string type) + { + migrationBuilder.Sql($""" + update {table} as r + set {type}_source = r.{type}->>'Source', + {type}_blurhash = r.{type}->>'Blurhash' + """); + } + + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "logo", + table: "shows", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster", + table: "shows", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail", + table: "shows", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo", + table: "seasons", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster", + table: "seasons", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail", + table: "seasons", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo", + table: "movies", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster", + table: "movies", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail", + table: "movies", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo", + table: "episodes", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster", + table: "episodes", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail", + table: "episodes", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo", + table: "collections", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster", + table: "collections", + type: "jsonb", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail", + table: "collections", + type: "jsonb", + nullable: true + ); + + MigrateImage(migrationBuilder, "shows", "logo"); + MigrateImage(migrationBuilder, "shows", "poster"); + MigrateImage(migrationBuilder, "shows", "thumbnail"); + + MigrateImage(migrationBuilder, "seasons", "logo"); + MigrateImage(migrationBuilder, "seasons", "poster"); + MigrateImage(migrationBuilder, "seasons", "thumbnail"); + + MigrateImage(migrationBuilder, "movies", "logo"); + MigrateImage(migrationBuilder, "movies", "poster"); + MigrateImage(migrationBuilder, "movies", "thumbnail"); + + MigrateImage(migrationBuilder, "episodes", "logo"); + MigrateImage(migrationBuilder, "episodes", "poster"); + MigrateImage(migrationBuilder, "episodes", "thumbnail"); + + MigrateImage(migrationBuilder, "collections", "logo"); + MigrateImage(migrationBuilder, "collections", "poster"); + MigrateImage(migrationBuilder, "collections", "thumbnail"); + + migrationBuilder.DropColumn(name: "logo_blurhash", table: "shows"); + migrationBuilder.DropColumn(name: "logo_source", table: "shows"); + migrationBuilder.DropColumn(name: "poster_blurhash", table: "shows"); + migrationBuilder.DropColumn(name: "poster_source", table: "shows"); + migrationBuilder.DropColumn(name: "thumbnail_blurhash", table: "shows"); + migrationBuilder.DropColumn(name: "thumbnail_source", table: "shows"); + + migrationBuilder.DropColumn(name: "logo_blurhash", table: "seasons"); + migrationBuilder.DropColumn(name: "logo_source", table: "seasons"); + migrationBuilder.DropColumn(name: "poster_blurhash", table: "seasons"); + migrationBuilder.DropColumn(name: "poster_source", table: "seasons"); + migrationBuilder.DropColumn(name: "thumbnail_blurhash", table: "seasons"); + migrationBuilder.DropColumn(name: "thumbnail_source", table: "seasons"); + + migrationBuilder.DropColumn(name: "logo_blurhash", table: "movies"); + migrationBuilder.DropColumn(name: "logo_source", table: "movies"); + migrationBuilder.DropColumn(name: "poster_blurhash", table: "movies"); + migrationBuilder.DropColumn(name: "poster_source", table: "movies"); + migrationBuilder.DropColumn(name: "thumbnail_blurhash", table: "movies"); + migrationBuilder.DropColumn(name: "thumbnail_source", table: "movies"); + + migrationBuilder.DropColumn(name: "logo_blurhash", table: "episodes"); + migrationBuilder.DropColumn(name: "logo_source", table: "episodes"); + migrationBuilder.DropColumn(name: "poster_blurhash", table: "episodes"); + migrationBuilder.DropColumn(name: "poster_source", table: "episodes"); + migrationBuilder.DropColumn(name: "thumbnail_blurhash", table: "episodes"); + migrationBuilder.DropColumn(name: "thumbnail_source", table: "episodes"); + + migrationBuilder.DropColumn(name: "logo_blurhash", table: "collections"); + migrationBuilder.DropColumn(name: "logo_source", table: "collections"); + migrationBuilder.DropColumn(name: "poster_blurhash", table: "collections"); + migrationBuilder.DropColumn(name: "poster_source", table: "collections"); + migrationBuilder.DropColumn(name: "thumbnail_blurhash", table: "collections"); + migrationBuilder.DropColumn(name: "thumbnail_source", table: "collections"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "logo_blurhash", + table: "shows", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_source", + table: "shows", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_blurhash", + table: "shows", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_source", + table: "shows", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_blurhash", + table: "shows", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_source", + table: "shows", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_blurhash", + table: "seasons", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_source", + table: "seasons", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_blurhash", + table: "seasons", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_source", + table: "seasons", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_blurhash", + table: "seasons", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_source", + table: "seasons", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_blurhash", + table: "movies", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_source", + table: "movies", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_blurhash", + table: "movies", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_source", + table: "movies", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_blurhash", + table: "movies", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_source", + table: "movies", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_blurhash", + table: "episodes", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_source", + table: "episodes", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_blurhash", + table: "episodes", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_source", + table: "episodes", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_blurhash", + table: "episodes", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_source", + table: "episodes", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_blurhash", + table: "collections", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "logo_source", + table: "collections", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_blurhash", + table: "collections", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "poster_source", + table: "collections", + type: "text", + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_blurhash", + table: "collections", + type: "character varying(32)", + maxLength: 32, + nullable: true + ); + + migrationBuilder.AddColumn( + name: "thumbnail_source", + table: "collections", + type: "text", + nullable: true + ); + + UnMigrateImage(migrationBuilder, "shows", "logo"); + UnMigrateImage(migrationBuilder, "shows", "poster"); + UnMigrateImage(migrationBuilder, "shows", "thumbnail"); + + UnMigrateImage(migrationBuilder, "seasons", "logo"); + UnMigrateImage(migrationBuilder, "seasons", "poster"); + UnMigrateImage(migrationBuilder, "seasons", "thumbnail"); + + UnMigrateImage(migrationBuilder, "movies", "logo"); + UnMigrateImage(migrationBuilder, "movies", "poster"); + UnMigrateImage(migrationBuilder, "movies", "thumbnail"); + + UnMigrateImage(migrationBuilder, "episodes", "logo"); + UnMigrateImage(migrationBuilder, "episodes", "poster"); + UnMigrateImage(migrationBuilder, "episodes", "thumbnail"); + + UnMigrateImage(migrationBuilder, "collections", "logo"); + UnMigrateImage(migrationBuilder, "collections", "poster"); + UnMigrateImage(migrationBuilder, "collections", "thumbnail"); + + migrationBuilder.DropColumn(name: "logo", table: "shows"); + migrationBuilder.DropColumn(name: "poster", table: "shows"); + migrationBuilder.DropColumn(name: "thumbnail", table: "shows"); + migrationBuilder.DropColumn(name: "logo", table: "seasons"); + migrationBuilder.DropColumn(name: "poster", table: "seasons"); + migrationBuilder.DropColumn(name: "thumbnail", table: "seasons"); + migrationBuilder.DropColumn(name: "logo", table: "movies"); + migrationBuilder.DropColumn(name: "poster", table: "movies"); + migrationBuilder.DropColumn(name: "thumbnail", table: "movies"); + migrationBuilder.DropColumn(name: "logo", table: "episodes"); + migrationBuilder.DropColumn(name: "poster", table: "episodes"); + migrationBuilder.DropColumn(name: "thumbnail", table: "episodes"); + migrationBuilder.DropColumn(name: "logo", table: "collections"); + migrationBuilder.DropColumn(name: "poster", table: "collections"); + migrationBuilder.DropColumn(name: "thumbnail", table: "collections"); + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs index 8968aaca..f895138f 100644 --- a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs +++ b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs @@ -731,24 +731,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => { b1.Property("CollectionId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("logo_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("logo_source"); + .HasColumnType("text"); b1.HasKey("CollectionId"); b1.ToTable("collections"); + b1.ToJson("logo"); + b1.WithOwner() .HasForeignKey("CollectionId") .HasConstraintName("fk_collections_collections_id"); @@ -757,50 +759,55 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { b1.Property("CollectionId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("poster_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("poster_source"); + .HasColumnType("text"); - b1.HasKey("CollectionId"); + b1.HasKey("CollectionId") + .HasName("pk_collections"); b1.ToTable("collections"); + b1.ToJson("poster"); + b1.WithOwner() .HasForeignKey("CollectionId") - .HasConstraintName("fk_collections_collections_id"); + .HasConstraintName("fk_collections_collections_collection_id"); }); b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { b1.Property("CollectionId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("thumbnail_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("thumbnail_source"); + .HasColumnType("text"); b1.HasKey("CollectionId"); b1.ToTable("collections"); + b1.ToJson("thumbnail"); + b1.WithOwner() .HasForeignKey("CollectionId") .HasConstraintName("fk_collections_collections_id"); @@ -831,24 +838,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => { b1.Property("EpisodeId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("logo_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("logo_source"); + .HasColumnType("text"); b1.HasKey("EpisodeId"); b1.ToTable("episodes"); + b1.ToJson("logo"); + b1.WithOwner() .HasForeignKey("EpisodeId") .HasConstraintName("fk_episodes_episodes_id"); @@ -857,24 +866,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { b1.Property("EpisodeId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("poster_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("poster_source"); + .HasColumnType("text"); b1.HasKey("EpisodeId"); b1.ToTable("episodes"); + b1.ToJson("poster"); + b1.WithOwner() .HasForeignKey("EpisodeId") .HasConstraintName("fk_episodes_episodes_id"); @@ -883,24 +894,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { b1.Property("EpisodeId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("thumbnail_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("thumbnail_source"); + .HasColumnType("text"); b1.HasKey("EpisodeId"); b1.ToTable("episodes"); + b1.ToJson("thumbnail"); + b1.WithOwner() .HasForeignKey("EpisodeId") .HasConstraintName("fk_episodes_episodes_id"); @@ -949,24 +962,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => { b1.Property("MovieId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("logo_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("logo_source"); + .HasColumnType("text"); b1.HasKey("MovieId"); b1.ToTable("movies"); + b1.ToJson("logo"); + b1.WithOwner() .HasForeignKey("MovieId") .HasConstraintName("fk_movies_movies_id"); @@ -975,24 +990,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { b1.Property("MovieId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("poster_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("poster_source"); + .HasColumnType("text"); b1.HasKey("MovieId"); b1.ToTable("movies"); + b1.ToJson("poster"); + b1.WithOwner() .HasForeignKey("MovieId") .HasConstraintName("fk_movies_movies_id"); @@ -1001,24 +1018,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { b1.Property("MovieId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("thumbnail_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("thumbnail_source"); + .HasColumnType("text"); b1.HasKey("MovieId"); b1.ToTable("movies"); + b1.ToJson("thumbnail"); + b1.WithOwner() .HasForeignKey("MovieId") .HasConstraintName("fk_movies_movies_id"); @@ -1066,24 +1085,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => { b1.Property("SeasonId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("logo_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("logo_source"); + .HasColumnType("text"); b1.HasKey("SeasonId"); b1.ToTable("seasons"); + b1.ToJson("logo"); + b1.WithOwner() .HasForeignKey("SeasonId") .HasConstraintName("fk_seasons_seasons_id"); @@ -1092,24 +1113,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { b1.Property("SeasonId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("poster_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("poster_source"); + .HasColumnType("text"); b1.HasKey("SeasonId"); b1.ToTable("seasons"); + b1.ToJson("poster"); + b1.WithOwner() .HasForeignKey("SeasonId") .HasConstraintName("fk_seasons_seasons_id"); @@ -1118,24 +1141,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { b1.Property("SeasonId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("thumbnail_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("thumbnail_source"); + .HasColumnType("text"); b1.HasKey("SeasonId"); b1.ToTable("seasons"); + b1.ToJson("thumbnail"); + b1.WithOwner() .HasForeignKey("SeasonId") .HasConstraintName("fk_seasons_seasons_id"); @@ -1161,24 +1186,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => { b1.Property("ShowId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("logo_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("logo_source"); + .HasColumnType("text"); b1.HasKey("ShowId"); b1.ToTable("shows"); + b1.ToJson("logo"); + b1.WithOwner() .HasForeignKey("ShowId") .HasConstraintName("fk_shows_shows_id"); @@ -1187,24 +1214,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { b1.Property("ShowId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("poster_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("poster_source"); + .HasColumnType("text"); b1.HasKey("ShowId"); b1.ToTable("shows"); + b1.ToJson("poster"); + b1.WithOwner() .HasForeignKey("ShowId") .HasConstraintName("fk_shows_shows_id"); @@ -1213,24 +1242,26 @@ namespace Kyoo.Postgresql.Migrations b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { b1.Property("ShowId") - .HasColumnType("uuid") - .HasColumnName("id"); + .HasColumnType("uuid"); b1.Property("Blurhash") .IsRequired() .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("thumbnail_blurhash"); + .HasColumnType("character varying(32)"); + + b1.Property("Id") + .HasColumnType("uuid"); b1.Property("Source") .IsRequired() - .HasColumnType("text") - .HasColumnName("thumbnail_source"); + .HasColumnType("text"); b1.HasKey("ShowId"); b1.ToTable("shows"); + b1.ToJson("thumbnail"); + b1.WithOwner() .HasForeignKey("ShowId") .HasConstraintName("fk_shows_shows_id");