diff --git a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs index 677f27ca..5961adbc 100644 --- a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs +++ b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs @@ -17,6 +17,11 @@ // along with Kyoo. If not, see . using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; namespace Kyoo.Abstractions.Models { @@ -53,60 +58,114 @@ namespace Kyoo.Abstractions.Models /// public ItemKind Kind { get; } + /// + /// The title of this show. + /// public string Name { get; } - public DateTime? AirDate { get; } + /// + /// The summary of this show. + /// + public string? Overview { get; } - public Image Poster { get; } + /// + /// The date this movie aired. + /// + public DateTime? AirDate { get; } } - public class BagItem : ILibraryItem + public class LibraryItem : IResource, ILibraryItem, IThumbnails, IMetadata { - public ItemKind Kind { get; } - + /// public int Id { get; set; } - public string Slug { get; set; } + /// + [MaxLength(256)] + public string Slug { get; set; } + /// + /// The title of this show. + /// public string Name { get; set; } + /// + /// A catchphrase for this movie. + /// + public string? Tagline { get; set; } + + /// + /// The list of alternative titles of this show. + /// + public string[] Aliases { get; set; } = Array.Empty(); + + /// + /// The path of the movie video file. + /// + public string? Path { get; set; } + + /// + /// The summary of this show. + /// + public string? Overview { get; set; } + + /// + /// A list of tags that match this movie. + /// + public string[] Tags { get; set; } = Array.Empty(); + + /// + /// The list of genres (themes) this show has. + /// + public Genre[] Genres { get; set; } = Array.Empty(); + + /// + /// Is this show airing, not aired yet or finished? + /// + public Status Status { get; set; } + + /// + /// The date this show started airing. It can be null if this is unknown. + /// + public DateTime? StartAir { get; set; } + + /// + /// The date this show finished airing. + /// It can also be null if this is unknown. + /// + public DateTime? EndAir { get; set; } + + /// + /// The date this movie aired. + /// public DateTime? AirDate { get; set; } - public Image Poster { get; set; } + /// + public Image? Poster { get; set; } - public object Rest { get; set; } + /// + public Image? Thumbnail { get; set; } - public ILibraryItem ToItem() + /// + public Image? Logo { get; set; } + + /// + /// A video of a few minutes that tease the content. + /// + public string? Trailer { get; set; } + + /// + public ItemKind Kind => ItemKind.Movie; + + /// + public Dictionary ExternalId { get; set; } = new(); + + public LibraryItem() { } + + [JsonConstructor] + public LibraryItem(string name) { - return Kind switch - { - ItemKind.Movie => Rest as MovieItem, - ItemKind.Show => Rest as ShowItem, - ItemKind.Collection => Rest as CollectionItem, - }; + Slug = Utility.ToSlug(name); + Name = name; } } - - public sealed class ShowItem : Show, ILibraryItem - { - /// - public ItemKind Kind => ItemKind.Show; - - public DateTime? AirDate => StartAir; - } - - public sealed class MovieItem : Movie, ILibraryItem - { - /// - public ItemKind Kind => ItemKind.Movie; - } - - public sealed class CollectionItem : Collection, ILibraryItem - { - /// - public ItemKind Kind => ItemKind.Collection; - - public DateTime? AirDate => null; - } - } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs index 544e6a17..6cae5231 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs @@ -41,6 +41,11 @@ namespace Kyoo.Abstractions.Models /// public string Name { get; set; } + /// + /// The description of this collection. + /// + public string? Overview { get; set; } + /// public Image? Poster { get; set; } @@ -50,11 +55,6 @@ namespace Kyoo.Abstractions.Models /// public Image? Logo { get; set; } - /// - /// The description of this collection. - /// - public string? Overview { get; set; } - /// /// The list of movies contained in this collection. /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs index 13943ff2..99a9f854 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -124,8 +124,11 @@ namespace Kyoo.Abstractions.Models /// public void OnMerge(object merged) { - foreach (PeopleRole link in People) - link.Movie = this; + if (People != null) + { + foreach (PeopleRole link in People) + link.Movie = this; + } } public Movie() { } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index a73b8b21..38a4a42e 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -80,7 +80,6 @@ namespace Kyoo.Abstractions.Models /// /// The date this show finished airing. - /// It must be after the but can be the same (example: for movies). /// It can also be null if this is unknown. /// public DateTime? EndAir { get; set; } @@ -99,6 +98,8 @@ namespace Kyoo.Abstractions.Models /// public string? Trailer { get; set; } + [SerializeIgnore] public DateTime? AirDate => StartAir; + /// public Dictionary ExternalId { get; set; } = new(); diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs index 593407aa..3414b63c 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs @@ -54,13 +54,13 @@ namespace Kyoo.Core.Controllers /// public override async Task GetOrDefault(int id) { - return (await _database.LibraryItems.FirstOrDefaultAsync(x => x.Id == id)).ToItem(); + return await _database.LibraryItems.FirstOrDefaultAsync(x => x.Id == id); } /// public override async Task GetOrDefault(string slug) { - return (await _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug)).ToItem(); + return await _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug); } /// @@ -68,9 +68,9 @@ namespace Kyoo.Core.Controllers Sort sort = default, Pagination limit = default) { - return (await ApplyFilters(_database.LibraryItems, where, sort, limit)) - .Select(x => (x as BagItem)!.ToItem()) - .ToList(); + return await ApplyFilters(_database.LibraryItems, where, sort, limit); + // .Select(x => x.ToItem()) + // .ToList(); } /// @@ -85,14 +85,12 @@ namespace Kyoo.Core.Controllers /// public override async Task> Search(string query) { - return (await Sort( + return await Sort( _database.LibraryItems - .Where(_database.Like(x => x.Name, $"%{query}%")) + .Where(_database.Like(x => x.Name, $"%{query}%")) ) .Take(20) - .ToListAsync()) - .Select(x => (x as BagItem)!.ToItem()) - .ToList(); + .ToListAsync(); } /// diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index a5d1828a..7982c6e6 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -92,32 +92,7 @@ namespace Kyoo.Postgresql /// /// This set is ready only, on most database this will be a view. /// - public IQueryable LibraryItems => - Shows.Select(x => new BagItem - { - Id = x.Id, - Slug = x.Slug, - Name = x.Name, - AirDate = x.StartAir, - Poster = x.Poster, - Rest = x - }).Union(Movies.Select(x => new BagItem - { - Id = x.Id, - Slug = x.Slug, - Name = x.Name, - AirDate = x.AirDate, - Poster = x.Poster, - Rest = x - })).Union(Collections.Select(x => new BagItem - { - Id = x.Id, - Slug = x.Slug, - Name = x.Name, - AirDate = null, - Poster = x.Poster, - Rest = x - })); + public DbSet LibraryItems { get; set; } /// /// Add a many to many link between two resources. @@ -281,6 +256,7 @@ namespace Kyoo.Postgresql .WithMany(x => x.Shows) .OnDelete(DeleteBehavior.SetNull); + _HasManyToMany(modelBuilder, x => x.Movies, x => x.Collections); _HasManyToMany(modelBuilder, x => x.Shows, x => x.Collections); modelBuilder.Entity() @@ -288,6 +264,7 @@ namespace Kyoo.Postgresql .WithMany("Users") .UsingEntity(x => x.ToTable(LinkName())); + _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); @@ -296,6 +273,7 @@ namespace Kyoo.Postgresql _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); + _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); diff --git a/back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.cs b/back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.cs deleted file mode 100644 index 40e8dd3a..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.cs +++ /dev/null @@ -1,528 +0,0 @@ -using System; -using Kyoo.Abstractions.Models; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Kyoo.Postgresql.Migrations -{ - /// - public partial class initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:Enum:genre", "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western") - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned"); - - migrationBuilder.CreateTable( - name: "collections", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - name = table.Column(type: "text", nullable: false), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - overview = table.Column(type: "text", nullable: true), - external_id = table.Column(type: "json", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_collections", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "people", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - name = table.Column(type: "text", nullable: false), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - external_id = table.Column(type: "json", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_people", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "studios", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - name = table.Column(type: "text", nullable: false), - external_id = table.Column(type: "json", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_studios", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "users", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - username = table.Column(type: "text", nullable: false), - email = table.Column(type: "text", nullable: false), - password = table.Column(type: "text", nullable: false), - permissions = table.Column(type: "text[]", nullable: false), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_users", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "movies", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - name = table.Column(type: "text", nullable: false), - tagline = table.Column(type: "text", nullable: true), - aliases = table.Column(type: "text[]", nullable: false), - path = table.Column(type: "text", nullable: false), - overview = table.Column(type: "text", nullable: true), - tags = table.Column(type: "text[]", nullable: false), - genres = table.Column(type: "genre[]", nullable: false), - status = table.Column(type: "status", nullable: false), - air_date = table.Column(type: "timestamp with time zone", nullable: true), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - trailer = table.Column(type: "text", nullable: true), - external_id = table.Column(type: "json", nullable: false), - studio_id = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_movies", x => x.id); - table.ForeignKey( - name: "fk_movies_studios_studio_id", - column: x => x.studio_id, - principalTable: "studios", - principalColumn: "id", - onDelete: ReferentialAction.SetNull); - }); - - migrationBuilder.CreateTable( - name: "shows", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - name = table.Column(type: "text", nullable: false), - tagline = table.Column(type: "text", nullable: true), - aliases = table.Column(type: "text[]", nullable: false), - overview = table.Column(type: "text", nullable: true), - tags = table.Column(type: "text[]", nullable: false), - genres = table.Column(type: "genre[]", nullable: false), - status = table.Column(type: "status", nullable: false), - start_air = table.Column(type: "timestamp with time zone", nullable: true), - end_air = table.Column(type: "timestamp with time zone", nullable: true), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - trailer = table.Column(type: "text", nullable: true), - external_id = table.Column(type: "json", nullable: false), - studio_id = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_shows", x => x.id); - table.ForeignKey( - name: "fk_shows_studios_studio_id", - column: x => x.studio_id, - principalTable: "studios", - principalColumn: "id", - onDelete: ReferentialAction.SetNull); - }); - - migrationBuilder.CreateTable( - name: "collection_movie", - columns: table => new - { - collections_id = table.Column(type: "integer", nullable: false), - movies_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_collection_movie", x => new { x.collections_id, x.movies_id }); - table.ForeignKey( - name: "fk_collection_movie_collections_collections_id", - column: x => x.collections_id, - principalTable: "collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_collection_movie_movies_movies_id", - column: x => x.movies_id, - principalTable: "movies", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "link_collection_show", - columns: table => new - { - collection_id = table.Column(type: "integer", nullable: false), - show_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_collection_show", x => new { x.collection_id, x.show_id }); - table.ForeignKey( - name: "fk_link_collection_show_collections_collection_id", - column: x => x.collection_id, - principalTable: "collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_collection_show_shows_show_id", - column: x => x.show_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "link_user_show", - columns: table => new - { - users_id = table.Column(type: "integer", nullable: false), - watched_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_user_show", x => new { x.users_id, x.watched_id }); - table.ForeignKey( - name: "fk_link_user_show_shows_watched_id", - column: x => x.watched_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_user_show_users_users_id", - column: x => x.users_id, - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "people_roles", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - people_id = table.Column(type: "integer", nullable: false), - show_id = table.Column(type: "integer", nullable: true), - movie_id = table.Column(type: "integer", nullable: true), - type = table.Column(type: "text", nullable: false), - role = table.Column(type: "text", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_people_roles", x => x.id); - table.ForeignKey( - name: "fk_people_roles_movies_movie_id", - column: x => x.movie_id, - principalTable: "movies", - principalColumn: "id"); - table.ForeignKey( - name: "fk_people_roles_people_people_id", - column: x => x.people_id, - principalTable: "people", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_people_roles_shows_show_id", - column: x => x.show_id, - principalTable: "shows", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "seasons", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - show_id = table.Column(type: "integer", nullable: false), - season_number = table.Column(type: "integer", nullable: false), - name = table.Column(type: "text", nullable: true), - overview = table.Column(type: "text", nullable: true), - start_date = table.Column(type: "timestamp with time zone", nullable: true), - end_date = table.Column(type: "timestamp with time zone", nullable: true), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - external_id = table.Column(type: "json", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_seasons", x => x.id); - table.ForeignKey( - name: "fk_seasons_shows_show_id", - column: x => x.show_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "episodes", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - show_id = table.Column(type: "integer", nullable: false), - season_id = table.Column(type: "integer", nullable: true), - season_number = table.Column(type: "integer", nullable: true), - episode_number = table.Column(type: "integer", nullable: true), - absolute_number = table.Column(type: "integer", nullable: true), - path = table.Column(type: "text", nullable: false), - name = table.Column(type: "text", nullable: true), - overview = table.Column(type: "text", nullable: true), - release_date = table.Column(type: "timestamp with time zone", nullable: true), - poster_source = table.Column(type: "text", nullable: true), - poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - thumbnail_source = table.Column(type: "text", nullable: true), - thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - logo_source = table.Column(type: "text", nullable: true), - logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), - external_id = table.Column(type: "json", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_episodes", x => x.id); - table.ForeignKey( - name: "fk_episodes_seasons_season_id", - column: x => x.season_id, - principalTable: "seasons", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_episodes_shows_show_id", - column: x => x.show_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "watched_episode", - columns: table => new - { - user_id = table.Column(type: "integer", nullable: false), - episode_id = table.Column(type: "integer", nullable: false), - watched_percentage = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_watched_episode", x => new { x.user_id, x.episode_id }); - table.ForeignKey( - name: "fk_watched_episode_episodes_episode_id", - column: x => x.episode_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_watched_episode_users_user_id", - column: x => x.user_id, - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_collection_movie_movies_id", - table: "collection_movie", - column: "movies_id"); - - migrationBuilder.CreateIndex( - name: "ix_collections_slug", - table: "collections", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_episodes_season_id", - table: "episodes", - column: "season_id"); - - migrationBuilder.CreateIndex( - name: "ix_episodes_show_id_season_number_episode_number_absolute_numb", - table: "episodes", - columns: new[] { "show_id", "season_number", "episode_number", "absolute_number" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_episodes_slug", - table: "episodes", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_link_collection_show_show_id", - table: "link_collection_show", - column: "show_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_user_show_watched_id", - table: "link_user_show", - column: "watched_id"); - - migrationBuilder.CreateIndex( - name: "ix_movies_slug", - table: "movies", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_movies_studio_id", - table: "movies", - column: "studio_id"); - - migrationBuilder.CreateIndex( - name: "ix_people_slug", - table: "people", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_people_roles_movie_id", - table: "people_roles", - column: "movie_id"); - - migrationBuilder.CreateIndex( - name: "ix_people_roles_people_id", - table: "people_roles", - column: "people_id"); - - migrationBuilder.CreateIndex( - name: "ix_people_roles_show_id", - table: "people_roles", - column: "show_id"); - - migrationBuilder.CreateIndex( - name: "ix_seasons_show_id_season_number", - table: "seasons", - columns: new[] { "show_id", "season_number" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_seasons_slug", - table: "seasons", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_shows_slug", - table: "shows", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_shows_studio_id", - table: "shows", - column: "studio_id"); - - migrationBuilder.CreateIndex( - name: "ix_studios_slug", - table: "studios", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_users_slug", - table: "users", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_watched_episode_episode_id", - table: "watched_episode", - column: "episode_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "collection_movie"); - - migrationBuilder.DropTable( - name: "link_collection_show"); - - migrationBuilder.DropTable( - name: "link_user_show"); - - migrationBuilder.DropTable( - name: "people_roles"); - - migrationBuilder.DropTable( - name: "watched_episode"); - - migrationBuilder.DropTable( - name: "collections"); - - migrationBuilder.DropTable( - name: "movies"); - - migrationBuilder.DropTable( - name: "people"); - - migrationBuilder.DropTable( - name: "episodes"); - - migrationBuilder.DropTable( - name: "users"); - - migrationBuilder.DropTable( - name: "seasons"); - - migrationBuilder.DropTable( - name: "shows"); - - migrationBuilder.DropTable( - name: "studios"); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.Designer.cs similarity index 86% rename from back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.Designer.cs rename to back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.Designer.cs index 8fa8ae08..b0ecb787 100644 --- a/back/src/Kyoo.Postgresql/Migrations/20230805052627_initial.Designer.cs +++ b/back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Kyoo.Postgresql.Migrations { [DbContext(typeof(PostgresContext))] - [Migration("20230805052627_initial")] + [Migration("20230806025737_initial")] partial class initial { /// @@ -25,28 +25,10 @@ namespace Kyoo.Postgresql.Migrations .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" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_kind", new[] { "show", "movie", "collection" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("CollectionMovie", b => - { - b.Property("CollectionsId") - .HasColumnType("integer") - .HasColumnName("collections_id"); - - b.Property("MoviesId") - .HasColumnType("integer") - .HasColumnName("movies_id"); - - b.HasKey("CollectionsId", "MoviesId") - .HasName("pk_collection_movie"); - - b.HasIndex("MoviesId") - .HasDatabaseName("ix_collection_movie_movies_id"); - - b.ToTable("collection_movie", (string)null); - }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => { b.Property("Id") @@ -160,6 +142,85 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("episodes", (string)null); }); + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + 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_library_items"); + + b.ToTable("library_items", (string)null); + }); + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.Property("Id") @@ -584,6 +645,25 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_user_show", (string)null); }); + modelBuilder.Entity("link_collection_movie", b => + { + b.Property("collection_id") + .HasColumnType("integer") + .HasColumnName("collection_id"); + + b.Property("movie_id") + .HasColumnType("integer") + .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") @@ -603,23 +683,6 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_collection_show", (string)null); }); - modelBuilder.Entity("CollectionMovie", b => - { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("CollectionsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_movie_collections_collections_id"); - - b.HasOne("Kyoo.Abstractions.Models.Movie", null) - .WithMany() - .HasForeignKey("MoviesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_movie_movies_movies_id"); - }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => { b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => @@ -811,6 +874,93 @@ namespace Kyoo.Postgresql.Migrations b.Navigation("Thumbnail"); }); + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") @@ -1277,6 +1427,23 @@ namespace Kyoo.Postgresql.Migrations .HasConstraintName("fk_link_user_show_shows_watched_id"); }); + 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) diff --git a/back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.cs b/back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.cs new file mode 100644 index 00000000..ea2fd7d8 --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230806025737_initial.cs @@ -0,0 +1,547 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System; +using Kyoo.Abstractions.Models; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + /// + public partial class initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterDatabase() + .Annotation("Npgsql:Enum:genre", "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western") + .Annotation("Npgsql:Enum:item_kind", "show,movie,collection") + .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned"); + + migrationBuilder.CreateTable( + name: "collections", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + name = table.Column(type: "text", nullable: false), + overview = table.Column(type: "text", nullable: true), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + external_id = table.Column(type: "json", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_collections", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "people", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + name = table.Column(type: "text", nullable: false), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + external_id = table.Column(type: "json", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_people", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "studios", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + name = table.Column(type: "text", nullable: false), + external_id = table.Column(type: "json", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_studios", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "users", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + username = table.Column(type: "text", nullable: false), + email = table.Column(type: "text", nullable: false), + password = table.Column(type: "text", nullable: false), + permissions = table.Column(type: "text[]", nullable: false), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_users", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "movies", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + name = table.Column(type: "text", nullable: false), + tagline = table.Column(type: "text", nullable: true), + aliases = table.Column(type: "text[]", nullable: false), + path = table.Column(type: "text", nullable: false), + overview = table.Column(type: "text", nullable: true), + tags = table.Column(type: "text[]", nullable: false), + genres = table.Column(type: "genre[]", nullable: false), + status = table.Column(type: "status", nullable: false), + air_date = table.Column(type: "timestamp with time zone", nullable: true), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + trailer = table.Column(type: "text", nullable: true), + external_id = table.Column(type: "json", nullable: false), + studio_id = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_movies", x => x.id); + table.ForeignKey( + name: "fk_movies_studios_studio_id", + column: x => x.studio_id, + principalTable: "studios", + principalColumn: "id", + onDelete: ReferentialAction.SetNull); + }); + + migrationBuilder.CreateTable( + name: "shows", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + name = table.Column(type: "text", nullable: false), + tagline = table.Column(type: "text", nullable: true), + aliases = table.Column(type: "text[]", nullable: false), + overview = table.Column(type: "text", nullable: true), + tags = table.Column(type: "text[]", nullable: false), + genres = table.Column(type: "genre[]", nullable: false), + status = table.Column(type: "status", nullable: false), + start_air = table.Column(type: "timestamp with time zone", nullable: true), + end_air = table.Column(type: "timestamp with time zone", nullable: true), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + trailer = table.Column(type: "text", nullable: true), + external_id = table.Column(type: "json", nullable: false), + studio_id = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_shows", x => x.id); + table.ForeignKey( + name: "fk_shows_studios_studio_id", + column: x => x.studio_id, + principalTable: "studios", + principalColumn: "id", + onDelete: ReferentialAction.SetNull); + }); + + migrationBuilder.CreateTable( + name: "link_collection_movie", + columns: table => new + { + collection_id = table.Column(type: "integer", nullable: false), + movie_id = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_link_collection_movie", x => new { x.collection_id, x.movie_id }); + table.ForeignKey( + name: "fk_link_collection_movie_collections_collection_id", + column: x => x.collection_id, + principalTable: "collections", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_link_collection_movie_movies_movie_id", + column: x => x.movie_id, + principalTable: "movies", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "link_collection_show", + columns: table => new + { + collection_id = table.Column(type: "integer", nullable: false), + show_id = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_link_collection_show", x => new { x.collection_id, x.show_id }); + table.ForeignKey( + name: "fk_link_collection_show_collections_collection_id", + column: x => x.collection_id, + principalTable: "collections", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_link_collection_show_shows_show_id", + column: x => x.show_id, + principalTable: "shows", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "link_user_show", + columns: table => new + { + users_id = table.Column(type: "integer", nullable: false), + watched_id = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_link_user_show", x => new { x.users_id, x.watched_id }); + table.ForeignKey( + name: "fk_link_user_show_shows_watched_id", + column: x => x.watched_id, + principalTable: "shows", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_link_user_show_users_users_id", + column: x => x.users_id, + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "people_roles", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + people_id = table.Column(type: "integer", nullable: false), + show_id = table.Column(type: "integer", nullable: true), + movie_id = table.Column(type: "integer", nullable: true), + type = table.Column(type: "text", nullable: false), + role = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_people_roles", x => x.id); + table.ForeignKey( + name: "fk_people_roles_movies_movie_id", + column: x => x.movie_id, + principalTable: "movies", + principalColumn: "id"); + table.ForeignKey( + name: "fk_people_roles_people_people_id", + column: x => x.people_id, + principalTable: "people", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_people_roles_shows_show_id", + column: x => x.show_id, + principalTable: "shows", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "seasons", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + show_id = table.Column(type: "integer", nullable: false), + season_number = table.Column(type: "integer", nullable: false), + name = table.Column(type: "text", nullable: true), + overview = table.Column(type: "text", nullable: true), + start_date = table.Column(type: "timestamp with time zone", nullable: true), + end_date = table.Column(type: "timestamp with time zone", nullable: true), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + external_id = table.Column(type: "json", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_seasons", x => x.id); + table.ForeignKey( + name: "fk_seasons_shows_show_id", + column: x => x.show_id, + principalTable: "shows", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "episodes", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + show_id = table.Column(type: "integer", nullable: false), + season_id = table.Column(type: "integer", nullable: true), + season_number = table.Column(type: "integer", nullable: true), + episode_number = table.Column(type: "integer", nullable: true), + absolute_number = table.Column(type: "integer", nullable: true), + path = table.Column(type: "text", nullable: false), + name = table.Column(type: "text", nullable: true), + overview = table.Column(type: "text", nullable: true), + release_date = table.Column(type: "timestamp with time zone", nullable: true), + poster_source = table.Column(type: "text", nullable: true), + poster_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + thumbnail_source = table.Column(type: "text", nullable: true), + thumbnail_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + logo_source = table.Column(type: "text", nullable: true), + logo_blurhash = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + external_id = table.Column(type: "json", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_episodes", x => x.id); + table.ForeignKey( + name: "fk_episodes_seasons_season_id", + column: x => x.season_id, + principalTable: "seasons", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_episodes_shows_show_id", + column: x => x.show_id, + principalTable: "shows", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "watched_episode", + columns: table => new + { + user_id = table.Column(type: "integer", nullable: false), + episode_id = table.Column(type: "integer", nullable: false), + watched_percentage = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_watched_episode", x => new { x.user_id, x.episode_id }); + table.ForeignKey( + name: "fk_watched_episode_episodes_episode_id", + column: x => x.episode_id, + principalTable: "episodes", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_watched_episode_users_user_id", + column: x => x.user_id, + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_collections_slug", + table: "collections", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_episodes_season_id", + table: "episodes", + column: "season_id"); + + migrationBuilder.CreateIndex( + name: "ix_episodes_show_id_season_number_episode_number_absolute_numb", + table: "episodes", + columns: new[] { "show_id", "season_number", "episode_number", "absolute_number" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_episodes_slug", + table: "episodes", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_link_collection_movie_movie_id", + table: "link_collection_movie", + column: "movie_id"); + + migrationBuilder.CreateIndex( + name: "ix_link_collection_show_show_id", + table: "link_collection_show", + column: "show_id"); + + migrationBuilder.CreateIndex( + name: "ix_link_user_show_watched_id", + table: "link_user_show", + column: "watched_id"); + + migrationBuilder.CreateIndex( + name: "ix_movies_slug", + table: "movies", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_movies_studio_id", + table: "movies", + column: "studio_id"); + + migrationBuilder.CreateIndex( + name: "ix_people_slug", + table: "people", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_people_roles_movie_id", + table: "people_roles", + column: "movie_id"); + + migrationBuilder.CreateIndex( + name: "ix_people_roles_people_id", + table: "people_roles", + column: "people_id"); + + migrationBuilder.CreateIndex( + name: "ix_people_roles_show_id", + table: "people_roles", + column: "show_id"); + + migrationBuilder.CreateIndex( + name: "ix_seasons_show_id_season_number", + table: "seasons", + columns: new[] { "show_id", "season_number" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_seasons_slug", + table: "seasons", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_shows_slug", + table: "shows", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_shows_studio_id", + table: "shows", + column: "studio_id"); + + migrationBuilder.CreateIndex( + name: "ix_studios_slug", + table: "studios", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_users_slug", + table: "users", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_watched_episode_episode_id", + table: "watched_episode", + column: "episode_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "link_collection_movie"); + + migrationBuilder.DropTable( + name: "link_collection_show"); + + migrationBuilder.DropTable( + name: "link_user_show"); + + migrationBuilder.DropTable( + name: "people_roles"); + + migrationBuilder.DropTable( + name: "watched_episode"); + + migrationBuilder.DropTable( + name: "collections"); + + migrationBuilder.DropTable( + name: "movies"); + + migrationBuilder.DropTable( + name: "people"); + + migrationBuilder.DropTable( + name: "episodes"); + + migrationBuilder.DropTable( + name: "users"); + + migrationBuilder.DropTable( + name: "seasons"); + + migrationBuilder.DropTable( + name: "shows"); + + migrationBuilder.DropTable( + name: "studios"); + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.Designer.cs new file mode 100644 index 00000000..29274d2e --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.Designer.cs @@ -0,0 +1,1502 @@ +// +using System; +using Kyoo.Abstractions.Models; +using Kyoo.Postgresql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + [DbContext(typeof(PostgresContext))] + [Migration("20230806025743_items")] + partial class items + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.9") + .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" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_kind", new[] { "show", "movie", "collection" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + 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("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AbsoluteNumber") + .HasColumnType("integer") + .HasColumnName("absolute_number"); + + 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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("release_date"); + + b.Property("SeasonID") + .HasColumnType("integer") + .HasColumnName("season_id"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowID") + .HasColumnType("integer") + .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.LibraryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + 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_library_items"); + + b.ToTable("library_items", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioID") + .HasColumnType("integer") + .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.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("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_people"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_people_slug"); + + b.ToTable("people", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("MovieID") + .HasColumnType("integer") + .HasColumnName("movie_id"); + + b.Property("PeopleID") + .HasColumnType("integer") + .HasColumnName("people_id"); + + b.Property("Role") + .IsRequired() + .HasColumnType("text") + .HasColumnName("role"); + + b.Property("ShowID") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_people_roles"); + + b.HasIndex("MovieID") + .HasDatabaseName("ix_people_roles_movie_id"); + + b.HasIndex("PeopleID") + .HasDatabaseName("ix_people_roles_people_id"); + + b.HasIndex("ShowID") + .HasDatabaseName("ix_people_roles_show_id"); + + b.ToTable("people_roles", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_date"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowID") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone") + .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("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioID") + .HasColumnType("integer") + .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.Studio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("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("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text") + .HasColumnName("password"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("permissions"); + + 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.ToTable("users", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => + { + b.Property("UserID") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("EpisodeID") + .HasColumnType("integer") + .HasColumnName("episode_id"); + + b.Property("WatchedPercentage") + .HasColumnType("integer") + .HasColumnName("watched_percentage"); + + b.HasKey("UserID", "EpisodeID") + .HasName("pk_watched_episode"); + + b.HasIndex("EpisodeID") + .HasDatabaseName("ix_watched_episode_episode_id"); + + b.ToTable("watched_episode", (string)null); + }); + + modelBuilder.Entity("ShowUser", b => + { + b.Property("UsersId") + .HasColumnType("integer") + .HasColumnName("users_id"); + + b.Property("WatchedId") + .HasColumnType("integer") + .HasColumnName("watched_id"); + + b.HasKey("UsersId", "WatchedId") + .HasName("pk_link_user_show"); + + b.HasIndex("WatchedId") + .HasDatabaseName("ix_link_user_show_watched_id"); + + b.ToTable("link_user_show", (string)null); + }); + + modelBuilder.Entity("link_collection_movie", b => + { + b.Property("collection_id") + .HasColumnType("integer") + .HasColumnName("collection_id"); + + b.Property("movie_id") + .HasColumnType("integer") + .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("integer") + .HasColumnName("collection_id"); + + b.Property("show_id") + .HasColumnType("integer") + .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("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("CollectionId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("CollectionId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + 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("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + 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.LibraryItem", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + 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("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("MovieId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("MovieId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + 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.People", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => + { + b.HasOne("Kyoo.Abstractions.Models.Movie", "Movie") + .WithMany("People") + .HasForeignKey("MovieID") + .HasConstraintName("fk_people_roles_movies_movie_id"); + + b.HasOne("Kyoo.Abstractions.Models.People", "People") + .WithMany("Roles") + .HasForeignKey("PeopleID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_people_roles_people_people_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("People") + .HasForeignKey("ShowID") + .HasConstraintName("fk_people_roles_shows_show_id"); + + b.Navigation("Movie"); + + b.Navigation("People"); + + b.Navigation("Show"); + }); + + 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("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + 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("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + 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.User", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("UserId"); + + b1.ToTable("users"); + + b1.WithOwner() + .HasForeignKey("UserId") + .HasConstraintName("fk_users_users_id"); + }); + + b.Navigation("Logo"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") + .WithMany() + .HasForeignKey("EpisodeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_watched_episode_episodes_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", null) + .WithMany("CurrentlyWatching") + .HasForeignKey("UserID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_watched_episode_users_user_id"); + + b.Navigation("Episode"); + }); + + modelBuilder.Entity("ShowUser", b => + { + b.HasOne("Kyoo.Abstractions.Models.User", null) + .WithMany() + .HasForeignKey("UsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_user_show_users_users_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", null) + .WithMany() + .HasForeignKey("WatchedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_user_show_shows_watched_id"); + }); + + 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.Movie", b => + { + b.Navigation("People"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.Navigation("Episodes"); + + b.Navigation("People"); + + b.Navigation("Seasons"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => + { + b.Navigation("Movies"); + + b.Navigation("Shows"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.User", b => + { + b.Navigation("CurrentlyWatching"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.cs b/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.cs new file mode 100644 index 00000000..85b812ff --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230806025743_items.cs @@ -0,0 +1,64 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + /// + public partial class items : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // language=PostgreSQL + migrationBuilder.Sql(@" + CREATE VIEW library_items AS + SELECT + s.id, s.slug, s.name, s.tagline, s.aliases, s.overview, s.tags, s.genres, s.status, + s.start_air, s.end_air, s.poster_source, s.poster_blurhash, s.thumbnail_source, s.thumbnail_blurhash, + s.logo_source, s.logo_blurhash, s.trailer, s.external_id, s.start_air AS air_date, NULL as path, + 'show'::item_kind AS kind + FROM shows AS s + UNION ALL + SELECT + m.id, m.slug, m.name, m.tagline, m.aliases, m.overview, m.tags, m.genres, m.status, + m.air_date as start_air, m.air_date as end_air, m.poster_source, m.poster_blurhash, m.thumbnail_source, + m.thumbnail_blurhash, m.logo_source, m.logo_blurhash, m.trailer, m.external_id, m.air_date, m.path, + 'movie'::item_kind AS kind + FROM movies AS m + UNION ALL + SELECT + c.id, c.slug, c.name, NULL as tagline, NULL as alises, c.overview, NULL AS tags, NULL AS genres, 'unknown'::status AS status, + NULL AS start_air, NULL AS end_air, c.poster_source, c.poster_blurhash, c.thumbnail_source, + c.thumbnail_blurhash, c.logo_source, c.logo_blurhash, NULL as trailer, c.external_id, NULL AS air_date, NULL as path, + 'collection'::item_kind AS kind + FROM collections AS c + "); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + // language=PostgreSQL + migrationBuilder.Sql(@"DROP VIEW library_items"); + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs index d41b691f..5ac1b0cd 100644 --- a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs +++ b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs @@ -22,28 +22,10 @@ namespace Kyoo.Postgresql.Migrations .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" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_kind", new[] { "show", "movie", "collection" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("CollectionMovie", b => - { - b.Property("CollectionsId") - .HasColumnType("integer") - .HasColumnName("collections_id"); - - b.Property("MoviesId") - .HasColumnType("integer") - .HasColumnName("movies_id"); - - b.HasKey("CollectionsId", "MoviesId") - .HasName("pk_collection_movie"); - - b.HasIndex("MoviesId") - .HasDatabaseName("ix_collection_movie_movies_id"); - - b.ToTable("collection_movie", (string)null); - }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => { b.Property("Id") @@ -157,6 +139,85 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("episodes", (string)null); }); + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .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("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + 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_library_items"); + + b.ToTable("library_items", (string)null); + }); + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.Property("Id") @@ -581,6 +642,25 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_user_show", (string)null); }); + modelBuilder.Entity("link_collection_movie", b => + { + b.Property("collection_id") + .HasColumnType("integer") + .HasColumnName("collection_id"); + + b.Property("movie_id") + .HasColumnType("integer") + .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") @@ -600,23 +680,6 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_collection_show", (string)null); }); - modelBuilder.Entity("CollectionMovie", b => - { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("CollectionsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_movie_collections_collections_id"); - - b.HasOne("Kyoo.Abstractions.Models.Movie", null) - .WithMany() - .HasForeignKey("MoviesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_movie_movies_movies_id"); - }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => { b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => @@ -808,6 +871,93 @@ namespace Kyoo.Postgresql.Migrations b.Navigation("Thumbnail"); }); + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") @@ -1274,6 +1424,23 @@ namespace Kyoo.Postgresql.Migrations .HasConstraintName("fk_link_user_show_shows_watched_id"); }); + 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) diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index dc2918ea..71ec5117 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -49,6 +49,7 @@ namespace Kyoo.Postgresql { NpgsqlConnection.GlobalTypeMapper.MapEnum(); NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); } /// @@ -101,6 +102,7 @@ namespace Kyoo.Postgresql { modelBuilder.HasPostgresEnum(); modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); base.OnModelCreating(modelBuilder); } diff --git a/shell.nix b/shell.nix index 877ae085..970e7db1 100644 --- a/shell.nix +++ b/shell.nix @@ -24,7 +24,7 @@ in openssl mediainfo ffmpeg - postgresql + postgresql_15 ]; RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";