Migrate images

This commit is contained in:
Zoe Roux 2024-04-21 01:53:53 +02:00
parent f15b92aae1
commit c576babde8
No known key found for this signature in database
5 changed files with 1966 additions and 223 deletions

View File

@ -88,6 +88,7 @@ public class Image
Blurhash = blurhash ?? "000000";
}
//
public class ImageConvertor : JsonConverter<Image>
{
/// <inheritdoc />
@ -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<Image>();
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
};
}
/// <inheritdoc />

View File

@ -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;
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// It should not be used directly, to access the database use a <see cref="ILibraryManager"/> or repositories.
/// </remarks>
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();
/// <summary>
/// All collections of Kyoo. See <see cref="Collection"/>.
/// </summary>
public DbSet<Collection> Collections { get; set; }
/// <summary>
/// All movies of Kyoo. See <see cref="Movie"/>.
/// </summary>
public DbSet<Movie> Movies { get; set; }
/// <summary>
/// All shows of Kyoo. See <see cref="Show"/>.
/// </summary>
public DbSet<Show> Shows { get; set; }
/// <summary>
/// All seasons of Kyoo. See <see cref="Season"/>.
/// </summary>
public DbSet<Season> Seasons { get; set; }
/// <summary>
/// All episodes of Kyoo. See <see cref="Episode"/>.
/// </summary>
public DbSet<Episode> Episodes { get; set; }
/// <summary>
/// All studios of Kyoo. See <see cref="Studio"/>.
/// </summary>
public DbSet<Studio> Studios { get; set; }
/// <summary>
/// The list of registered users.
/// </summary>
public DbSet<User> Users { get; set; }
public DbSet<MovieWatchStatus> MovieWatchStatus { get; set; }
@ -129,28 +100,13 @@ public abstract class DatabaseContext : DbContext
_accessor = accessor;
}
/// <summary>
/// Get the name of the link table of the two given types.
/// </summary>
/// <typeparam name="T">The owner type of the relation</typeparam>
/// <typeparam name="T2">The child type of the relation</typeparam>
/// <returns>The name of the table containing the links.</returns>
protected abstract string LinkName<T, T2>()
where T : IResource
where T2 : IResource;
/// <summary>
/// Get the name of a link's foreign key.
/// </summary>
/// <typeparam name="T">The type that will be accessible via the navigation</typeparam>
/// <returns>The name of the foreign key for the given resource.</returns>
protected abstract string LinkNameFk<T>()
where T : IResource;
/// <summary>
/// Set basic configurations (like preventing query tracking)
/// </summary>
/// <param name="optionsBuilder">An option builder to fill.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
@ -227,15 +183,6 @@ public abstract class DatabaseContext : DbContext
.ValueGeneratedOnAdd();
}
/// <summary>
/// Create a many to many relationship between the two entities.
/// The resulting relationship will have an available <see cref="AddLinks{T1,T2}"/> method.
/// </summary>
/// <param name="modelBuilder">The database model builder</param>
/// <param name="firstNavigation">The first navigation expression from T to T2</param>
/// <param name="secondNavigation">The second navigation expression from T2 to T</param>
/// <typeparam name="T">The owning type of the relationship</typeparam>
/// <typeparam name="T2">The owned type of the relationship</typeparam>
private void _HasManyToMany<T, T2>(
ModelBuilder modelBuilder,
Expression<Func<T, IEnumerable<T2>?>> firstNavigation,
@ -263,10 +210,6 @@ public abstract class DatabaseContext : DbContext
);
}
/// <summary>
/// Set database parameters to support every types of Kyoo.
/// </summary>
/// <param name="modelBuilder">The database's model builder.</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@ -412,28 +355,6 @@ public abstract class DatabaseContext : DbContext
_HasJson<Issue, object>(modelBuilder, x => x.Extra);
}
/// <summary>
/// Return a new or an in cache temporary object wih the same ID as the one given
/// </summary>
/// <param name="model">If a resource with the same ID is found in the database, it will be used.
/// <paramref name="model"/> will be used otherwise</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <returns>A resource that is now tracked by this context.</returns>
public T GetTemporaryObject<T>(T model)
where T : class, IResource
{
T? tmp = Set<T>().Local.FirstOrDefault(x => x.Id == model.Id);
if (tmp != null)
return tmp;
Entry(model).State = EntityState.Unchanged;
return model;
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override int SaveChanges()
{
try
@ -449,13 +370,6 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="acceptAllChangesOnSuccess">Indicates whether AcceptAllChanges() is called after the changes
/// have been sent successfully to the database.</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
try
@ -471,14 +385,6 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="acceptAllChangesOnSuccess">Indicates whether AcceptAllChanges() is called after the changes
/// have been sent successfully to the database.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override async Task<int> SaveChangesAsync(
bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = default
@ -497,12 +403,6 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <returns>The number of state entries written to the database.</returns>
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
try
@ -518,14 +418,6 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// Save changes that are applied to this context.
/// </summary>
/// <param name="getExisting">How to retrieve the conflicting item.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <exception cref="DuplicatedItemException">A duplicated item has been found.</exception>
/// <typeparam name="T">The type of the potential duplicate (this is unused).</typeparam>
/// <returns>The number of state entries written to the database.</returns>
public async Task<int> SaveChangesAsync<T>(
Func<Task<T>> getExisting,
CancellationToken cancellationToken = default
@ -548,12 +440,6 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for the task to complete</param>
/// <returns>The number of state entries written to the database or -1 if a duplicate exist.</returns>
public async Task<int> SaveIfNoDuplicates(CancellationToken cancellationToken = default)
{
try
@ -566,30 +452,14 @@ public abstract class DatabaseContext : DbContext
}
}
/// <summary>
/// Return the first resource with the given slug that is currently tracked by this context.
/// This allow one to limit redundant calls to <see cref="IRepository{T}.CreateIfNotExists"/> during the
/// same transaction and prevent fails from EF when two same entities are being tracked.
/// </summary>
/// <param name="slug">The slug of the resource to check</param>
/// <typeparam name="T">The type of entity to check</typeparam>
/// <returns>The local entity representing the resource with the given slug if it exists or null.</returns>
public T? LocalEntity<T>(string slug)
where T : class, IResource
{
return ChangeTracker.Entries<T>().FirstOrDefault(x => x.Entity.Slug == slug)?.Entity;
}
/// <summary>
/// Check if the exception is a duplicated exception.
/// </summary>
/// <param name="ex">The exception to check</param>
/// <returns>True if the exception is a duplicate exception. False otherwise</returns>
protected abstract bool IsDuplicateException(Exception ex);
/// <summary>
/// Delete every changes that are on this context.
/// </summary>
public void DiscardChanges()
{
foreach (

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,460 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kyoo.Postgresql.Migrations
{
/// <inheritdoc />
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'
""");
}
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "logo",
table: "shows",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster",
table: "shows",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail",
table: "shows",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo",
table: "seasons",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster",
table: "seasons",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail",
table: "seasons",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo",
table: "movies",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster",
table: "movies",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail",
table: "movies",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo",
table: "episodes",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster",
table: "episodes",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail",
table: "episodes",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo",
table: "collections",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster",
table: "collections",
type: "jsonb",
nullable: true
);
migrationBuilder.AddColumn<string>(
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");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "logo_blurhash",
table: "shows",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_source",
table: "shows",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_blurhash",
table: "shows",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_source",
table: "shows",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_blurhash",
table: "shows",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_source",
table: "shows",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_blurhash",
table: "seasons",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_source",
table: "seasons",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_blurhash",
table: "seasons",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_source",
table: "seasons",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_blurhash",
table: "seasons",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_source",
table: "seasons",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_blurhash",
table: "movies",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_source",
table: "movies",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_blurhash",
table: "movies",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_source",
table: "movies",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_blurhash",
table: "movies",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_source",
table: "movies",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_blurhash",
table: "episodes",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_source",
table: "episodes",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_blurhash",
table: "episodes",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_source",
table: "episodes",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_blurhash",
table: "episodes",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_source",
table: "episodes",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_blurhash",
table: "collections",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "logo_source",
table: "collections",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_blurhash",
table: "collections",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "poster_source",
table: "collections",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "thumbnail_blurhash",
table: "collections",
type: "character varying(32)",
maxLength: 32,
nullable: true
);
migrationBuilder.AddColumn<string>(
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");
}
}
}

View File

@ -731,24 +731,26 @@ namespace Kyoo.Postgresql.Migrations
b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 =>
{
b1.Property<Guid>("CollectionId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("logo_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("CollectionId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("poster_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("CollectionId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("thumbnail_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("EpisodeId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("logo_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("EpisodeId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("poster_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("EpisodeId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("thumbnail_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("MovieId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("logo_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("MovieId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("poster_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("MovieId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("thumbnail_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("SeasonId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("logo_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("SeasonId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("poster_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("SeasonId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("thumbnail_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("ShowId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("logo_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("ShowId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("poster_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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<Guid>("ShowId")
.HasColumnType("uuid")
.HasColumnName("id");
.HasColumnType("uuid");
b1.Property<string>("Blurhash")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("thumbnail_blurhash");
.HasColumnType("character varying(32)");
b1.Property<Guid>("Id")
.HasColumnType("uuid");
b1.Property<string>("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");