diff --git a/back/Kyoo.ruleset b/back/Kyoo.ruleset index 13d29e23..9a9c6d14 100644 --- a/back/Kyoo.ruleset +++ b/back/Kyoo.ruleset @@ -33,10 +33,11 @@ + + - diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs index 194fc2b4..646f44ca 100644 --- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs +++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; -using JetBrains.Annotations; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Exceptions; @@ -40,11 +39,6 @@ namespace Kyoo.Abstractions.Controllers IRepository GetRepository() where T : class, IResource; - /// - /// The repository that handle libraries. - /// - ILibraryRepository LibraryRepository { get; } - /// /// The repository that handle libraries items (a wrapper around shows and collections). /// @@ -55,6 +49,11 @@ namespace Kyoo.Abstractions.Controllers /// ICollectionRepository CollectionRepository { get; } + /// + /// The repository that handle shows. + /// + IMovieRepository MovieRepository { get; } + /// /// The repository that handle shows. /// @@ -80,11 +79,6 @@ namespace Kyoo.Abstractions.Controllers /// IStudioRepository StudioRepository { get; } - /// - /// The repository that handle genres. - /// - IGenreRepository GenreRepository { get; } - /// /// The repository that handle users. /// @@ -97,7 +91,6 @@ namespace Kyoo.Abstractions.Controllers /// The type of the resource /// If the item is not found /// The resource found - [ItemNotNull] Task Get(int id) where T : class, IResource; @@ -108,7 +101,6 @@ namespace Kyoo.Abstractions.Controllers /// The type of the resource /// If the item is not found /// The resource found - [ItemNotNull] Task Get(string slug) where T : class, IResource; @@ -119,7 +111,6 @@ namespace Kyoo.Abstractions.Controllers /// The type of the resource /// If the item is not found /// The first resource found that match the where function - [ItemNotNull] Task Get(Expression> where) where T : class, IResource; @@ -130,7 +121,6 @@ namespace Kyoo.Abstractions.Controllers /// The season's number /// If the item is not found /// The season found - [ItemNotNull] Task Get(int showID, int seasonNumber); /// @@ -140,7 +130,6 @@ namespace Kyoo.Abstractions.Controllers /// The season's number /// If the item is not found /// The season found - [ItemNotNull] Task Get(string showSlug, int seasonNumber); /// @@ -151,7 +140,6 @@ namespace Kyoo.Abstractions.Controllers /// The episode's number /// If the item is not found /// The episode found - [ItemNotNull] Task Get(int showID, int seasonNumber, int episodeNumber); /// @@ -162,7 +150,6 @@ namespace Kyoo.Abstractions.Controllers /// The episode's number /// If the item is not found /// The episode found - [ItemNotNull] Task Get(string showSlug, int seasonNumber, int episodeNumber); /// @@ -171,8 +158,7 @@ namespace Kyoo.Abstractions.Controllers /// The id of the resource /// The type of the resource /// The resource found - [ItemCanBeNull] - Task GetOrDefault(int id) + Task GetOrDefault(int id) where T : class, IResource; /// @@ -181,8 +167,7 @@ namespace Kyoo.Abstractions.Controllers /// The slug of the resource /// The type of the resource /// The resource found - [ItemCanBeNull] - Task GetOrDefault(string slug) + Task GetOrDefault(string slug) where T : class, IResource; /// @@ -192,8 +177,7 @@ namespace Kyoo.Abstractions.Controllers /// A custom sort method to handle cases where multiples items match the filters. /// The type of the resource /// The first resource found that match the where function - [ItemCanBeNull] - Task GetOrDefault(Expression> where, Sort sortBy = default) + Task GetOrDefault(Expression> where, Sort? sortBy = default) where T : class, IResource; /// @@ -202,8 +186,7 @@ namespace Kyoo.Abstractions.Controllers /// The id of the show /// The season's number /// The season found - [ItemCanBeNull] - Task GetOrDefault(int showID, int seasonNumber); + Task GetOrDefault(int showID, int seasonNumber); /// /// Get a season from it's show slug and it's seasonNumber or null if it is not found. @@ -211,8 +194,7 @@ namespace Kyoo.Abstractions.Controllers /// The slug of the show /// The season's number /// The season found - [ItemCanBeNull] - Task GetOrDefault(string showSlug, int seasonNumber); + Task GetOrDefault(string showSlug, int seasonNumber); /// /// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found. @@ -221,8 +203,7 @@ namespace Kyoo.Abstractions.Controllers /// The season's number /// The episode's number /// The episode found - [ItemCanBeNull] - Task GetOrDefault(int showID, int seasonNumber, int episodeNumber); + Task GetOrDefault(int showID, int seasonNumber, int episodeNumber); /// /// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found. @@ -231,8 +212,7 @@ namespace Kyoo.Abstractions.Controllers /// The season's number /// The episode's number /// The episode found - [ItemCanBeNull] - Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber); + Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber); /// /// Load a related resource @@ -248,7 +228,7 @@ namespace Kyoo.Abstractions.Controllers /// /// /// - Task Load([NotNull] T obj, Expression> member, bool force = false) + Task Load(T obj, Expression> member, bool force = false) where T : class, IResource where T2 : class, IResource; @@ -266,7 +246,7 @@ namespace Kyoo.Abstractions.Controllers /// /// /// - Task Load([NotNull] T obj, Expression>> member, bool force = false) + Task Load(T obj, Expression>> member, bool force = false) where T : class, IResource where T2 : class; @@ -283,7 +263,7 @@ namespace Kyoo.Abstractions.Controllers /// /// /// - Task Load([NotNull] T obj, string memberName, bool force = false) + Task Load(T obj, string memberName, bool force = false) where T : class, IResource; /// @@ -298,35 +278,7 @@ namespace Kyoo.Abstractions.Controllers /// /// /// A representing the asynchronous operation. - Task Load([NotNull] IResource obj, string memberName, bool force = false); - - /// - /// Get items (A wrapper around shows or collections) from a library. - /// - /// The ID of the library - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No library exist with the given ID. - /// A list of items that match every filters - Task> GetItemsFromLibrary(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default); - - /// - /// Get items (A wrapper around shows or collections) from a library. - /// - /// The slug of the library - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No library exist with the given slug. - /// A list of items that match every filters - Task> GetItemsFromLibrary(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Task Load(IResource obj, string memberName, bool force = false); /// /// Get people's roles from a show. @@ -338,9 +290,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given ID. /// A list of items that match every filters Task> GetPeopleFromShow(int showID, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a show. @@ -352,9 +304,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given slug. /// A list of items that match every filters Task> GetPeopleFromShow(string showSlug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a person. @@ -366,9 +318,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given ID. /// A list of items that match every filters Task> GetRolesFromPeople(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a person. @@ -380,27 +332,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given slug. /// A list of items that match every filters Task> GetRolesFromPeople(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); - - /// - /// Setup relations between a show, a library and a collection - /// - /// The show's ID to setup relations with - /// The library's ID to setup relations with (optional) - /// The collection's ID to setup relations with (optional) - /// A representing the asynchronous operation. - Task AddShowLink(int showID, int? libraryID, int? collectionID); - - /// - /// Setup relations between a show, a library and a collection - /// - /// The show to setup relations with - /// The library to setup relations with (optional) - /// The collection to setup relations with (optional) - /// A representing the asynchronous operation. - Task AddShowLink([NotNull] Show show, Library library, Collection collection); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get all resources with filters @@ -410,9 +344,9 @@ namespace Kyoo.Abstractions.Controllers /// How many items to return and where to start /// The type of resources to load /// A list of resources that match every filters - Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) + Task> GetAll(Expression>? where = null, + Sort? sort = default, + Pagination? limit = default) where T : class, IResource; /// @@ -421,7 +355,7 @@ namespace Kyoo.Abstractions.Controllers /// A filter function /// The type of resources to load /// A list of resources that match every filters - Task GetCount(Expression> where = null) + Task GetCount(Expression>? where = null) where T : class, IResource; /// @@ -439,7 +373,7 @@ namespace Kyoo.Abstractions.Controllers /// The item to register /// The type of resource /// The resource registers and completed by database's information (related items and so on) - Task Create([NotNull] T item) + Task Create(T item) where T : class, IResource; /// @@ -448,7 +382,7 @@ namespace Kyoo.Abstractions.Controllers /// The item to register /// The type of resource /// The newly created item or the existing value if it existed. - Task CreateIfNotExists([NotNull] T item) + Task CreateIfNotExists(T item) where T : class, IResource; /// diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs index 5c8e438d..ead00dbf 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; -using JetBrains.Annotations; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Exceptions; @@ -45,7 +44,6 @@ namespace Kyoo.Abstractions.Controllers /// The id of the resource /// If the item could not be found. /// The resource found - [ItemNotNull] Task Get(int id); /// @@ -54,7 +52,6 @@ namespace Kyoo.Abstractions.Controllers /// The slug of the resource /// If the item could not be found. /// The resource found - [ItemNotNull] Task Get(string slug); /// @@ -63,7 +60,6 @@ namespace Kyoo.Abstractions.Controllers /// A predicate to filter the resource. /// If the item could not be found. /// The resource found - [ItemNotNull] Task Get(Expression> where); /// @@ -71,16 +67,14 @@ namespace Kyoo.Abstractions.Controllers /// /// The id of the resource /// The resource found - [ItemCanBeNull] - Task GetOrDefault(int id); + Task GetOrDefault(int id); /// /// Get a resource from it's slug or null if it is not found. /// /// The slug of the resource /// The resource found - [ItemCanBeNull] - Task GetOrDefault(string slug); + Task GetOrDefault(string slug); /// /// Get the first resource that match the predicate or null if it is not found. @@ -88,15 +82,13 @@ namespace Kyoo.Abstractions.Controllers /// A predicate to filter the resource. /// A custom sort method to handle cases where multiples items match the filters. /// The resource found - [ItemCanBeNull] - Task GetOrDefault(Expression> where, Sort sortBy = default); + Task GetOrDefault(Expression> where, Sort? sortBy = default); /// /// Search for resources. /// /// The query string. /// A list of resources found - [ItemNotNull] Task> Search(string query); /// @@ -106,33 +98,30 @@ namespace Kyoo.Abstractions.Controllers /// Sort information about the query (sort by, sort order) /// How pagination should be done (where to start and how many to return) /// A list of resources that match every filters - [ItemNotNull] - Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default); + Task> GetAll(Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get the number of resources that match the filter's predicate. /// /// A filter predicate /// How many resources matched that filter - Task GetCount(Expression> where = null); + Task GetCount(Expression>? where = null); /// /// Create a new resource. /// /// The item to register /// The resource registers and completed by database's information (related items and so on) - [ItemNotNull] - Task Create([NotNull] T obj); + Task Create(T obj); /// /// Create a new resource if it does not exist already. If it does, the existing value is returned instead. /// /// The object to create /// The newly created item or the existing value if it existed. - [ItemNotNull] - Task CreateIfNotExists([NotNull] T obj); + Task CreateIfNotExists(T obj); /// /// Called when a resource has been created. @@ -146,8 +135,7 @@ namespace Kyoo.Abstractions.Controllers /// Should old properties of the resource be discarded or should null values considered as not changed? /// If the item is not found /// The resource edited and completed by database's information (related items and so on) - [ItemNotNull] - Task Edit([NotNull] T edited, bool resetOld); + Task Edit(T edited, bool resetOld); /// /// Called when a resource has been edited. @@ -176,14 +164,14 @@ namespace Kyoo.Abstractions.Controllers /// The resource to delete /// If the item is not found /// A representing the asynchronous operation. - Task Delete([NotNull] T obj); + Task Delete(T obj); /// /// Delete all resources that match the predicate. /// /// A predicate to filter resources to delete. Every resource that match this will be deleted. /// A representing the asynchronous operation. - Task DeleteAll([NotNull] Expression> where); + Task DeleteAll(Expression> where); /// /// Called when a resource has been edited. @@ -202,21 +190,16 @@ namespace Kyoo.Abstractions.Controllers Type RepositoryType { get; } } + /// + /// A repository to handle shows. + /// + public interface IMovieRepository : IRepository { } + /// /// A repository to handle shows. /// public interface IShowRepository : IRepository { - /// - /// Link a show to a collection and/or a library. The given show is now part of those containers. - /// If both a library and a collection are given, the collection is added to the library too. - /// - /// The ID of the show - /// The ID of the library (optional) - /// The ID of the collection (optional) - /// A representing the asynchronous operation. - Task AddShowLink(int showID, int? libraryID, int? collectionID); - /// /// Get a show's slug from it's ID. /// @@ -330,55 +313,16 @@ namespace Kyoo.Abstractions.Controllers Task GetAbsolute(string showSlug, int absoluteNumber); } - /// - /// A repository to handle libraries. - /// - public interface ILibraryRepository : IRepository { } - /// /// A repository to handle library items (A wrapper around shows and collections). /// - public interface ILibraryItemRepository : IRepository - { - /// - /// Get items (A wrapper around shows or collections) from a library. - /// - /// The ID of the library - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No library exist with the given ID. - /// A list of items that match every filters - public Task> GetFromLibrary(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default); - - /// - /// Get items (A wrapper around shows or collections) from a library. - /// - /// The slug of the library - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No library exist with the given slug. - /// A list of items that match every filters - public Task> GetFromLibrary(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); - } + public interface ILibraryItemRepository : IRepository { } /// /// A repository for collections /// public interface ICollectionRepository : IRepository { } - /// - /// A repository for genres. - /// - public interface IGenreRepository : IRepository { } - /// /// A repository for studios. /// @@ -399,9 +343,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given ID. /// A list of items that match every filters Task> GetFromShow(int showID, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a show. @@ -413,9 +357,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given slug. /// A list of items that match every filters Task> GetFromShow(string showSlug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a person. @@ -427,9 +371,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given ID. /// A list of items that match every filters Task> GetFromPeople(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); /// /// Get people's roles from a person. @@ -441,9 +385,9 @@ namespace Kyoo.Abstractions.Controllers /// No exist with the given slug. /// A list of items that match every filters Task> GetFromPeople(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default); + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default); } /// diff --git a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj index 9d8ddb0c..3433f9f1 100644 --- a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj +++ b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj @@ -3,6 +3,7 @@ Kyoo.Abstractions Base package to create plugins for Kyoo. Kyoo.Abstractions + enable diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs index cd946714..228dc187 100644 --- a/back/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs +++ b/back/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs @@ -32,7 +32,7 @@ namespace Kyoo.Abstractions.Models.Attributes /// /// The public name of this api. /// - [NotNull] public string Name { get; } + public string Name { get; } /// /// The name of the group in witch this API is. You can also specify a custom sort order using the following @@ -45,7 +45,7 @@ namespace Kyoo.Abstractions.Models.Attributes /// Create a new . /// /// The name of the api that will be used on the documentation page. - public ApiDefinitionAttribute([NotNull] string name) + public ApiDefinitionAttribute(string name) { if (name == null) throw new ArgumentNullException(nameof(name)); diff --git a/back/src/Kyoo.Abstractions/Models/ConfigurationReference.cs b/back/src/Kyoo.Abstractions/Models/ConfigurationReference.cs index 635bbb97..76294ca2 100644 --- a/back/src/Kyoo.Abstractions/Models/ConfigurationReference.cs +++ b/back/src/Kyoo.Abstractions/Models/ConfigurationReference.cs @@ -60,7 +60,7 @@ namespace Kyoo.Abstractions.Models /// /// The type of the object /// The list of configuration reference a type has. - public static IEnumerable CreateReference(string path, [NotNull] Type type) + public static IEnumerable CreateReference(string path, Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); diff --git a/back/src/Kyoo.Abstractions/Models/Exceptions/DuplicatedItemException.cs b/back/src/Kyoo.Abstractions/Models/Exceptions/DuplicatedItemException.cs index 0cd21975..c608b63a 100644 --- a/back/src/Kyoo.Abstractions/Models/Exceptions/DuplicatedItemException.cs +++ b/back/src/Kyoo.Abstractions/Models/Exceptions/DuplicatedItemException.cs @@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models.Exceptions /// Create a new with the default message. /// /// The existing object. - public DuplicatedItemException(object existing = null) + public DuplicatedItemException(object? existing = null) : base("Already exists in the database.") { Existing = existing; diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/ILink.cs b/back/src/Kyoo.Abstractions/Models/Genre.cs similarity index 75% rename from back/src/Kyoo.Abstractions/Models/Resources/Interfaces/ILink.cs rename to back/src/Kyoo.Abstractions/Models/Genre.cs index 5c146786..2b7e16f0 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/ILink.cs +++ b/back/src/Kyoo.Abstractions/Models/Genre.cs @@ -19,13 +19,27 @@ namespace Kyoo.Abstractions.Models { /// - /// An interface to represent resources that should have a link field in their return values (like videos). + /// A genre that allow one to specify categories for shows. /// - public interface ILink + public enum Genre { - /// - /// The link to return, in most cases this should be a string. - /// - public object Link { get; } + Action, + Adventure, + Animation, + Comedy, + Crime, + Documentary, + Drama, + Family, + Fantasy, + History, + Horror, + Music, + Mystery, + Romance, + ScienceFiction, + Thriller, + War, + Western, } } diff --git a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs index 852e48f9..0b66d2e1 100644 --- a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs +++ b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs @@ -17,16 +17,13 @@ // along with Kyoo. If not, see . using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq.Expressions; namespace Kyoo.Abstractions.Models { /// /// The type of item, ether a show, a movie or a collection. /// - public enum ItemType + public enum ItemKind { /// /// The is a . @@ -49,138 +46,67 @@ namespace Kyoo.Abstractions.Models /// A type union between and . /// This is used to list content put inside a library. /// - public class LibraryItem : CustomTypeDescriptor, IResource, IThumbnails + public interface ILibraryItem : IResource { - /// + /// + /// Is the item a collection, a movie or a show? + /// + public ItemKind Kind { get; } + + public string Name { get; } + + public DateTime? AirDate { get; } + + public Image Poster { get; } + } + + public class BagItem : ILibraryItem + { + public ItemKind Kind { get; } + public int ID { get; set; } - /// - public string Slug { get; set; } + public string Slug { get; set; } - /// - /// The title of the show or collection. - /// - public string Title { get; set; } + public string Name { get; set; } - /// - /// The summary of the show or collection. - /// - public string Overview { get; set; } + public DateTime? AirDate { get; set; } - /// - /// Is this show airing, not aired yet or finished? This is only applicable for shows. - /// - public Status? Status { get; set; } - - /// - /// The date this show or collection started airing. It can be null if this is unknown. - /// - public DateTime? StartAir { get; set; } - - /// - /// The date this show or collection 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; } - - /// public Image Poster { get; set; } - /// - public Image Thumbnail { get; set; } + public object Rest { get; set; } - /// - public Image Logo { get; set; } - - /// - /// The type of this item (ether a collection, a show or a movie). - /// - public ItemType Type { get; set; } - - /// - /// Create a new, empty . - /// - public LibraryItem() { } - - /// - /// Create a from a show. - /// - /// The show that this library item should represent. - public LibraryItem(Show show) + public ILibraryItem ToItem() { - ID = show.ID; - Slug = show.Slug; - Title = show.Title; - Overview = show.Overview; - Status = show.Status; - StartAir = show.StartAir; - EndAir = show.EndAir; - Poster = show.Poster; - Thumbnail = show.Thumbnail; - Logo = show.Logo; - Type = show.IsMovie ? ItemType.Movie : ItemType.Show; - } - - /// - /// Create a from a collection - /// - /// The collection that this library item should represent. - public LibraryItem(Collection collection) - { - ID = -collection.ID; - Slug = collection.Slug; - Title = collection.Name; - Overview = collection.Overview; - Status = Models.Status.Unknown; - StartAir = null; - EndAir = null; - Poster = collection.Poster; - Thumbnail = collection.Thumbnail; - Logo = collection.Logo; - Type = ItemType.Collection; - } - - /// - /// An expression to create a representing a show. - /// - public static Expression> FromShow => x => new LibraryItem - { - ID = x.ID, - Slug = x.Slug, - Title = x.Title, - Overview = x.Overview, - Status = x.Status, - StartAir = x.StartAir, - EndAir = x.EndAir, - Poster = x.Poster, - Thumbnail = x.Thumbnail, - Logo = x.Logo, - Type = x.IsMovie ? ItemType.Movie : ItemType.Show - }; - - /// - /// An expression to create a representing a collection. - /// - public static Expression> FromCollection => x => new LibraryItem - { - ID = -x.ID, - Slug = x.Slug, - Title = x.Name, - Overview = x.Overview, - Status = Models.Status.Unknown, - StartAir = null, - EndAir = null, - Poster = x.Poster, - Thumbnail = x.Thumbnail, - Logo = x.Logo, - Type = ItemType.Collection - }; - - /// - public override string GetClassName() - { - return Type.ToString(); + return Kind switch + { + ItemKind.Movie => Rest as MovieItem, + ItemKind.Show => Rest as ShowItem, + ItemKind.Collection => Rest as CollectionItem, + }; } } + + 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/PeopleRole.cs b/back/src/Kyoo.Abstractions/Models/PeopleRole.cs index 3a416927..dab757a1 100644 --- a/back/src/Kyoo.Abstractions/Models/PeopleRole.cs +++ b/back/src/Kyoo.Abstractions/Models/PeopleRole.cs @@ -53,12 +53,16 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the Show where the People playing in. /// - public int ShowID { get; set; } + public int? ShowID { get; set; } /// /// The show where the People played in. /// - public Show Show { get; set; } + public Show? Show { get; set; } + + public int? MovieID { get; set; } + + public Movie? Movie { get; set; } /// /// The type of work the person has done for the show. diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs index e3fa14cf..a6f3043f 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs @@ -17,7 +17,10 @@ // along with Kyoo. If not, see . using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; +using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -31,7 +34,7 @@ namespace Kyoo.Abstractions.Models public int ID { get; set; } /// - public string Slug { get; set; } + [MaxLength(256)] public string Slug { get; set; } /// /// The name of this collection. @@ -39,30 +42,39 @@ namespace Kyoo.Abstractions.Models public string Name { get; set; } /// - public Image Poster { get; set; } + public Image? Poster { get; set; } /// - public Image Thumbnail { get; set; } + public Image? Thumbnail { get; set; } /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// /// The description of this collection. /// - public string Overview { get; set; } + public string? Overview { get; set; } + + /// + /// The list of movies contained in this collection. + /// + [LoadableRelation] public ICollection? Movies { get; set; } /// /// The list of shows contained in this collection. /// - [LoadableRelation] public ICollection Shows { get; set; } - - /// - /// The list of libraries that contains this collection. - /// - [LoadableRelation] public ICollection Libraries { get; set; } + [LoadableRelation] public ICollection? Shows { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); + + public Collection() { } + + [JsonConstructor] + public Collection(string name) + { + Slug = Utility.ToSlug(name); + Name = name; + } } } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs index 86e11442..87b20a5e 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using JetBrains.Annotations; using Kyoo.Abstractions.Controllers; @@ -35,24 +36,19 @@ namespace Kyoo.Abstractions.Models /// [Computed] + [MaxLength(256)] public string Slug { get { if (ShowSlug != null || Show?.Slug != null) return GetSlug(ShowSlug ?? Show.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber); - return ShowID != 0 - ? GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber) - : null; + return GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber); } [UsedImplicitly] - [NotNull] private set { - if (value == null) - throw new ArgumentNullException(nameof(value)); - Match match = Regex.Match(value, @"(?.+)-s(?\d+)e(?\d+)"); if (match.Success) @@ -80,7 +76,7 @@ namespace Kyoo.Abstractions.Models /// /// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed. /// - [SerializeIgnore] public string ShowSlug { private get; set; } + [SerializeIgnore] public string? ShowSlug { private get; set; } /// /// The ID of the Show containing this episode. @@ -90,7 +86,7 @@ namespace Kyoo.Abstractions.Models /// /// The show that contains this episode. This must be explicitly loaded via a call to . /// - [LoadableRelation(nameof(ShowID))] public Show Show { get; set; } + [LoadableRelation(nameof(ShowID))] public Show? Show { get; set; } /// /// The ID of the Season containing this episode. @@ -105,7 +101,7 @@ namespace Kyoo.Abstractions.Models /// This can be null if the season is unknown and the episode is only identified /// by it's . /// - [LoadableRelation(nameof(SeasonID))] public Season Season { get; set; } + [LoadableRelation(nameof(SeasonID))] public Season? Season { get; set; } /// /// The season in witch this episode is in. @@ -130,12 +126,12 @@ namespace Kyoo.Abstractions.Models /// /// The title of this episode. /// - public string Title { get; set; } + public string? Name { get; set; } /// /// The overview of this episode. /// - public string Overview { get; set; } + public string? Overview { get; set; } /// /// The release date of this episode. It can be null if unknown. @@ -143,16 +139,16 @@ namespace Kyoo.Abstractions.Models public DateTime? ReleaseDate { get; set; } /// - public Image Poster { get; set; } + public Image? Poster { get; set; } /// - public Image Thumbnail { get; set; } + public Image? Thumbnail { get; set; } /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); /// /// Get the slug of an episode. @@ -172,7 +168,7 @@ namespace Kyoo.Abstractions.Models /// /// The slug corresponding to the given arguments /// The given show slug was null. - public static string GetSlug([NotNull] string showSlug, + public static string GetSlug(string showSlug, int? seasonNumber, int? episodeNumber, int? absoluteNumber = null) diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Genre.cs b/back/src/Kyoo.Abstractions/Models/Resources/Genre.cs deleted file mode 100644 index 5bf8ceee..00000000 --- a/back/src/Kyoo.Abstractions/Models/Resources/Genre.cs +++ /dev/null @@ -1,62 +0,0 @@ -// 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.Collections.Generic; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Utils; - -namespace Kyoo.Abstractions.Models -{ - /// - /// A genre that allow one to specify categories for shows. - /// - public class Genre : IResource - { - /// - public int ID { get; set; } - - /// - public string Slug { get; set; } - - /// - /// The name of this genre. - /// - public string Name { get; set; } - - /// - /// The list of shows that have this genre. - /// - [LoadableRelation] public ICollection Shows { get; set; } - - /// - /// Create a new, empty . - /// - public Genre() { } - - /// - /// Create a new and specify it's . - /// The is automatically calculated from it's name. - /// - /// The name of this genre. - public Genre(string name) - { - Slug = Utility.ToSlug(name); - Name = name; - } - } -} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IResource.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IResource.cs index 509006e5..69e77f21 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IResource.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IResource.cs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Controllers; namespace Kyoo.Abstractions.Models @@ -42,6 +43,7 @@ namespace Kyoo.Abstractions.Models /// There is no setter for a slug since it can be computed from other fields. /// For example, a season slug is {ShowSlug}-s{SeasonNumber}. /// + [MaxLength(256)] public string Slug { get; } } } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs index c69c984d..10e1b742 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs @@ -28,18 +28,18 @@ namespace Kyoo.Abstractions.Models /// /// A poster is a 9/16 format image with the cover of the resource. /// - public Image Poster { get; set; } + public Image? Poster { get; set; } /// /// A thumbnail is a 16/9 format image, it could ether be used as a background or as a preview but it usually /// is not an official image. /// - public Image Thumbnail { get; set; } + public Image? Thumbnail { get; set; } /// /// A logo is a small image representing the resource. /// - public Image Logo { get; set; } + public Image? Logo { get; set; } } public class Image diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs new file mode 100644 index 00000000..a6f8ec27 --- /dev/null +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -0,0 +1,140 @@ +// 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 System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; +using Newtonsoft.Json; + +namespace Kyoo.Abstractions.Models +{ + /// + /// A series or a movie. + /// + public class Movie : IResource, IMetadata, IOnMerge, IThumbnails + { + /// + public int ID { 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 movie aired. + /// + public DateTime? AirDate { get; set; } + + /// + public Image? Poster { get; set; } + + /// + public Image? Thumbnail { get; set; } + + /// + public Image? Logo { get; set; } + + /// + /// A video of a few minutes that tease the content. + /// + public string? Trailer { get; set; } + + /// + public Dictionary ExternalId { get; set; } = new(); + + /// + /// The ID of the Studio that made this show. + /// + [SerializeIgnore] public int? StudioID { get; set; } + + /// + /// The Studio that made this show. + /// This must be explicitly loaded via a call to . + /// + [LoadableRelation(nameof(StudioID))][EditableRelation] public Studio? Studio { get; set; } + + /// + /// The list of people that made this show. + /// + [LoadableRelation][EditableRelation] public ICollection? People { get; set; } + + /// + /// The list of collections that contains this show. + /// + [LoadableRelation] public ICollection? Collections { get; set; } + + /// + public void OnMerge(object merged) + { + foreach (PeopleRole link in People) + link.Movie = this; + } + + public Movie() { } + + [JsonConstructor] + public Movie(string name) + { + Slug = Utility.ToSlug(name); + Name = name; + } + } +} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/People.cs b/back/src/Kyoo.Abstractions/Models/Resources/People.cs index c5a32429..ed56d5e5 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/People.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/People.cs @@ -17,7 +17,10 @@ // along with Kyoo. If not, see . using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; +using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -30,6 +33,7 @@ namespace Kyoo.Abstractions.Models public int ID { get; set; } /// + [MaxLength(256)] public string Slug { get; set; } /// @@ -38,20 +42,29 @@ namespace Kyoo.Abstractions.Models public string Name { get; set; } /// - public Image Poster { get; set; } + public Image? Poster { get; set; } /// - public Image Thumbnail { get; set; } + public Image? Thumbnail { get; set; } /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); /// /// The list of roles this person has played in. See for more information. /// - [EditableRelation][LoadableRelation] public ICollection Roles { get; set; } + [EditableRelation][LoadableRelation] public ICollection? Roles { get; set; } + + public People() { } + + [JsonConstructor] + public People(string name) + { + Slug = Utility.ToSlug(name); + Name = name; + } } } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs index 1b31d2c3..0d0e0130 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using JetBrains.Annotations; using Kyoo.Abstractions.Controllers; @@ -35,6 +36,7 @@ namespace Kyoo.Abstractions.Models /// [Computed] + [MaxLength(256)] public string Slug { get @@ -48,7 +50,7 @@ namespace Kyoo.Abstractions.Models [NotNull] private set { - Match match = Regex.Match(value ?? string.Empty, @"(?.+)-s(?\d+)"); + Match match = Regex.Match(value, @"(?.+)-s(?\d+)"); if (!match.Success) throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}"); @@ -60,7 +62,7 @@ namespace Kyoo.Abstractions.Models /// /// The slug of the Show that contain this episode. If this is not set, this season is ill-formed. /// - [SerializeIgnore] public string ShowSlug { private get; set; } + [SerializeIgnore] public string? ShowSlug { private get; set; } /// /// The ID of the Show containing this season. @@ -71,7 +73,7 @@ namespace Kyoo.Abstractions.Models /// The show that contains this season. /// This must be explicitly loaded via a call to . /// - [LoadableRelation(nameof(ShowID))] public Show Show { get; set; } + [LoadableRelation(nameof(ShowID))] public Show? Show { get; set; } /// /// The number of this season. This can be set to 0 to indicate specials. @@ -81,12 +83,12 @@ namespace Kyoo.Abstractions.Models /// /// The title of this season. /// - public string Title { get; set; } + public string? Name { get; set; } /// /// A quick overview of this season. /// - public string Overview { get; set; } + public string? Overview { get; set; } /// /// The starting air date of this season. @@ -99,20 +101,20 @@ namespace Kyoo.Abstractions.Models public DateTime? EndDate { get; set; } /// - public Image Poster { get; set; } + public Image? Poster { get; set; } /// - public Image Thumbnail { get; set; } + public Image? Thumbnail { get; set; } /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); /// /// The list of episodes that this season contains. /// - [LoadableRelation] public ICollection Episodes { get; set; } + [LoadableRelation] public ICollection? Episodes { get; set; } } } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index 0dc30b30..30da3693 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -18,8 +18,11 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; +using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -32,27 +35,38 @@ namespace Kyoo.Abstractions.Models public int ID { get; set; } /// + [MaxLength(256)] public string Slug { get; set; } /// /// The title of this show. /// - public string Title { get; set; } + public string Name { get; set; } + + /// + /// A catchphrase for this show. + /// + public string? Tagline { get; set; } /// /// The list of alternative titles of this show. /// - [EditableRelation] public string[] Aliases { get; set; } - - /// - /// The path of the root directory of this show. - /// - [SerializeIgnore] public string Path { get; set; } + public string[] Aliases { get; set; } = Array.Empty(); /// /// The summary of this show. /// - public string Overview { get; set; } + 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? @@ -71,27 +85,22 @@ namespace Kyoo.Abstractions.Models /// public DateTime? EndAir { get; set; } - /// - /// True if this show represent a movie, false otherwise. - /// - public bool IsMovie { get; set; } + /// + public Image? Poster { get; set; } /// - public Image Poster { get; set; } + public Image? Thumbnail { get; set; } /// - public Image Thumbnail { get; set; } - - /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// /// A video of a few minutes that tease the content. /// - public string Trailer { get; set; } + public string? Trailer { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); /// /// The ID of the Studio that made this show. @@ -102,39 +111,29 @@ namespace Kyoo.Abstractions.Models /// The Studio that made this show. /// This must be explicitly loaded via a call to . /// - [LoadableRelation(nameof(StudioID))][EditableRelation] public Studio Studio { get; set; } - - /// - /// The list of genres (themes) this show has. - /// - [LoadableRelation][EditableRelation] public ICollection Genres { get; set; } + [LoadableRelation(nameof(StudioID))][EditableRelation] public Studio? Studio { get; set; } /// /// The list of people that made this show. /// - [LoadableRelation][EditableRelation] public ICollection People { get; set; } + [LoadableRelation][EditableRelation] public ICollection? People { get; set; } /// /// The different seasons in this show. If this is a movie, this list is always null or empty. /// - [LoadableRelation] public ICollection Seasons { get; set; } + [LoadableRelation] public ICollection? Seasons { get; set; } /// /// The list of episodes in this show. /// If this is a movie, there will be a unique episode (with the seasonNumber and episodeNumber set to null). /// Having an episode is necessary to store metadata and tracks. /// - [LoadableRelation] public ICollection Episodes { get; set; } - - /// - /// The list of libraries that contains this show. - /// - [LoadableRelation] public ICollection Libraries { get; set; } + [LoadableRelation] public ICollection? Episodes { get; set; } /// /// The list of collections that contains this show. /// - [LoadableRelation] public ICollection Collections { get; set; } + [LoadableRelation] public ICollection? Collections { get; set; } /// public void OnMerge(object merged) @@ -157,6 +156,15 @@ namespace Kyoo.Abstractions.Models episode.Show = this; } } + + public Show() { } + + [JsonConstructor] + public Show(string name) + { + Slug = Utility.ToSlug(name); + Name = name; + } } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs index e3923d3a..ab61b149 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs @@ -17,8 +17,10 @@ // along with Kyoo. If not, see . using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; +using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -31,6 +33,7 @@ namespace Kyoo.Abstractions.Models public int ID { get; set; } /// + [MaxLength(256)] public string Slug { get; set; } /// @@ -41,10 +44,15 @@ namespace Kyoo.Abstractions.Models /// /// The list of shows that are made by this studio. /// - [LoadableRelation] public ICollection Shows { get; set; } + [LoadableRelation] public ICollection? Shows { get; set; } + + /// + /// The list of movies that are made by this studio. + /// + [LoadableRelation] public ICollection? Movies { get; set; } /// - public Dictionary ExternalId { get; set; } + public Dictionary ExternalId { get; set; } = new(); /// /// Create a new, empty, . @@ -55,6 +63,7 @@ namespace Kyoo.Abstractions.Models /// Create a new with a specific name, the slug is calculated automatically. /// /// The name of the studio. + [JsonConstructor] public Studio(string name) { Slug = Utility.ToSlug(name); diff --git a/back/src/Kyoo.Abstractions/Models/Resources/User.cs b/back/src/Kyoo.Abstractions/Models/Resources/User.cs index 2fde3468..3b5168a7 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/User.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/User.cs @@ -17,7 +17,10 @@ // along with Kyoo. If not, see . using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Utils; +using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -30,6 +33,7 @@ namespace Kyoo.Abstractions.Models public int ID { get; set; } /// + [MaxLength(256)] public string Slug { get; set; } /// @@ -53,27 +57,30 @@ namespace Kyoo.Abstractions.Models /// public string[] Permissions { get; set; } - /// - /// Arbitrary extra data that can be used by specific authentication implementations. - /// - [SerializeIgnore] - public Dictionary ExtraData { get; set; } - /// /// A logo is a small image representing the resource. /// - public Image Logo { get; set; } + public Image? Logo { get; set; } /// /// The list of shows the user has finished. /// [SerializeIgnore] - public ICollection Watched { get; set; } + public ICollection? Watched { get; set; } /// /// The list of episodes the user is watching (stopped in progress or the next episode of the show) /// [SerializeIgnore] - public ICollection CurrentlyWatching { get; set; } + public ICollection? CurrentlyWatching { get; set; } + + public User() { } + + [JsonConstructor] + public User(string username) + { + Slug = Utility.ToSlug(username); + Username = username; + } } } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/WatchedEpisode.cs b/back/src/Kyoo.Abstractions/Models/Resources/WatchedEpisode.cs index 66a11a3c..b5a76d68 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/WatchedEpisode.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/WatchedEpisode.cs @@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models /// /// The started. /// - public Episode Episode { get; set; } + public Episode? Episode { get; set; } /// /// Where the player has stopped watching the episode (between 0 and 100). diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs b/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs index 0c56b2b1..97c8c8e9 100644 --- a/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs +++ b/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs @@ -58,7 +58,7 @@ namespace Kyoo.Abstractions.Models.Utils /// Create a new for the given slug. /// /// The slug of the resource. - public Identifier([NotNull] string slug) + public Identifier(string slug) { if (slug == null) throw new ArgumentNullException(nameof(slug)); diff --git a/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs b/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs index fa40fc64..2d55d4ed 100644 --- a/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs +++ b/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs @@ -31,13 +31,13 @@ namespace Kyoo.Abstractions.Models.Utils /// The list of errors that where made in the request. /// /// ["InvalidFilter: no field 'startYear' on a collection"] - [NotNull] public string[] Errors { get; set; } + public string[] Errors { get; set; } /// /// Create a new with one error. /// /// The error to specify in the response. - public RequestError([NotNull] string error) + public RequestError(string error) { if (error == null) throw new ArgumentNullException(nameof(error)); @@ -48,7 +48,7 @@ namespace Kyoo.Abstractions.Models.Utils /// Create a new with multiple errors. /// /// The errors to specify in the response. - public RequestError([NotNull] string[] errors) + public RequestError(string[] errors) { if (errors == null || !errors.Any()) throw new ArgumentException("Errors must be non null and not empty", nameof(errors)); diff --git a/back/src/Kyoo.Abstractions/Models/WatchItem.cs b/back/src/Kyoo.Abstractions/Models/WatchItem.cs deleted file mode 100644 index 7ec67e4b..00000000 --- a/back/src/Kyoo.Abstractions/Models/WatchItem.cs +++ /dev/null @@ -1,194 +0,0 @@ -// 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 System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Attributes; -using Newtonsoft.Json; - -namespace Kyoo.Abstractions.Models -{ - /// - /// A watch item give information useful for playback. - /// Information about tracks and display information that could be used by the player. - /// This contains mostly data from an with another form. - /// - public class WatchItem : CustomTypeDescriptor, IThumbnails, ILink - { - /// - /// The ID of the episode associated with this item. - /// - public int EpisodeID { get; set; } - - /// - /// The slug of this episode. - /// - public string Slug { get; set; } - - /// - /// The title of the show containing this episode. - /// - public string ShowTitle { get; set; } - - /// - /// The slug of the show containing this episode - /// - public string ShowSlug { get; set; } - - /// - /// The season in witch this episode is in. - /// - public int? SeasonNumber { get; set; } - - /// - /// The number of this episode is it's season. - /// - public int? EpisodeNumber { get; set; } - - /// - /// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season. - /// - public int? AbsoluteNumber { get; set; } - - /// - /// The title of this episode. - /// - public string Title { get; set; } - - /// - /// The summary of this episode. - /// - public string Overview { get; set; } - - /// - /// The release date of this episode. It can be null if unknown. - /// - public DateTime? ReleaseDate { get; set; } - - /// - /// The episode that come before this one if you follow usual watch orders. - /// If this is the first episode or this is a movie, it will be null. - /// - public Episode PreviousEpisode { get; set; } - - /// - /// The episode that come after this one if you follow usual watch orders. - /// If this is the last aired episode or this is a movie, it will be null. - /// - public Episode NextEpisode { get; set; } - - /// - /// true if this is a movie, false otherwise. - /// - public bool IsMovie { get; set; } - - /// - public Image Poster { get; set; } - - /// - public Image Thumbnail { get; set; } - - /// - public Image Logo { get; set; } - - /// - /// The transcoder's info for this item. This include subtitles, fonts, chapters... - /// - public object Info { get; set; } - - [SerializeIgnore] - private string _Type => IsMovie ? "movie" : "episode"; - - /// - public object Link => new - { - Direct = $"/video/{_Type}/{Slug}/direct", - Hls = $"/video/{_Type}/{Slug}/master.m3u8", - }; - - /// - /// Create a from an . - /// - /// The episode to transform. - /// - /// A library manager to retrieve the next and previous episode and load the show and tracks of the episode. - /// - /// A http client to reach the transcoder. - /// A new WatchItem representing the given episode. - public static async Task FromEpisode(Episode ep, ILibraryManager library, HttpClient client) - { - await library.Load(ep, x => x.Show); - - return new WatchItem - { - EpisodeID = ep.ID, - Slug = ep.Slug, - ShowSlug = ep.Show.Slug, - ShowTitle = ep.Show.Title, - SeasonNumber = ep.SeasonNumber, - EpisodeNumber = ep.EpisodeNumber, - AbsoluteNumber = ep.AbsoluteNumber, - Title = ep.Title, - Overview = ep.Overview, - ReleaseDate = ep.ReleaseDate, - Poster = ep.Poster, - Thumbnail = ep.Thumbnail, - Logo = ep.Logo, - PreviousEpisode = ep.Show.IsMovie - ? null - : (await library.GetAll( - where: x => x.ShowID == ep.ShowID, - limit: new Pagination(1, ep.ID, true) - )).FirstOrDefault(), - NextEpisode = ep.Show.IsMovie - ? null - : (await library.GetAll( - where: x => x.ShowID == ep.ShowID, - limit: new Pagination(1, ep.ID) - )).FirstOrDefault(), - IsMovie = ep.Show.IsMovie, - Info = await _GetInfo(ep, client), - }; - } - - private static async Task _GetInfo(Episode ep, HttpClient client) - { - HttpResponseMessage ret = await client.GetAsync($"http://transcoder:7666/{(ep.Show.IsMovie ? "movie" : "episode")}/{ep.Slug}/info"); - ret.EnsureSuccessStatusCode(); - string content = await ret.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(content); - } - - /// - public override string GetClassName() - { - return nameof(Show); - } - - /// - public override string GetComponentName() - { - return ShowSlug; - } - } -} diff --git a/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs b/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs index 34ba106a..fd1e4f4d 100644 --- a/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs +++ b/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs @@ -39,8 +39,8 @@ namespace Kyoo.Utils /// The list mapped. /// The list or the mapper can't be null [LinqTunnel] - public static IEnumerable Map([NotNull] this IEnumerable self, - [NotNull] Func mapper) + public static IEnumerable Map(this IEnumerable self, + Func mapper) { if (self == null) throw new ArgumentNullException(nameof(self)); @@ -72,8 +72,8 @@ namespace Kyoo.Utils /// The list mapped as an AsyncEnumerable. /// The list or the mapper can't be null. [LinqTunnel] - public static IAsyncEnumerable MapAsync([NotNull] this IEnumerable self, - [NotNull] Func> mapper) + public static IAsyncEnumerable MapAsync(this IEnumerable self, + Func> mapper) { if (self == null) throw new ArgumentNullException(nameof(self)); @@ -105,8 +105,8 @@ namespace Kyoo.Utils /// The list mapped as an AsyncEnumerable /// The list or the mapper can't be null [LinqTunnel] - public static IAsyncEnumerable SelectAsync([NotNull] this IEnumerable self, - [NotNull] Func> mapper) + public static IAsyncEnumerable SelectAsync(this IEnumerable self, + Func> mapper) { if (self == null) throw new ArgumentNullException(nameof(self)); @@ -132,7 +132,7 @@ namespace Kyoo.Utils /// A task that will return a simple list /// The list can't be null [LinqTunnel] - public static Task> ToListAsync([NotNull] this IAsyncEnumerable self) + public static Task> ToListAsync(this IAsyncEnumerable self) { if (self == null) throw new ArgumentNullException(nameof(self)); @@ -157,7 +157,7 @@ namespace Kyoo.Utils /// The iterable and the action can't be null. /// The iterator proxied, there is no dual iterations. [LinqTunnel] - public static IEnumerable IfEmpty([NotNull] this IEnumerable self, [NotNull] Action action) + public static IEnumerable IfEmpty(this IEnumerable self, Action action) { if (self == null) throw new ArgumentNullException(nameof(self)); @@ -190,7 +190,7 @@ namespace Kyoo.Utils /// The list to enumerate. If this is null, the function result in a no-op /// The action to execute for each arguments /// The type of items in the list - public static void ForEach([CanBeNull] this IEnumerable self, Action action) + public static void ForEach(this IEnumerable? self, Action action) { if (self == null) return; @@ -203,7 +203,7 @@ namespace Kyoo.Utils /// /// The list to enumerate. If this is null, the function result in a no-op /// The action to execute for each arguments - public static void ForEach([CanBeNull] this IEnumerable self, Action action) + public static void ForEach(this IEnumerable? self, Action action) { if (self == null) return; @@ -217,7 +217,7 @@ namespace Kyoo.Utils /// The list to enumerate. If this is null, the function result in a no-op /// The action to execute for each arguments /// A representing the asynchronous operation. - public static async Task ForEachAsync([CanBeNull] this IEnumerable self, Func action) + public static async Task ForEachAsync(this IEnumerable? self, Func action) { if (self == null) return; @@ -232,7 +232,7 @@ namespace Kyoo.Utils /// The asynchronous action to execute for each arguments /// The type of items in the list. /// A representing the asynchronous operation. - public static async Task ForEachAsync([CanBeNull] this IEnumerable self, Func action) + public static async Task ForEachAsync(this IEnumerable? self, Func action) { if (self == null) return; @@ -247,7 +247,7 @@ namespace Kyoo.Utils /// The action to execute for each arguments /// The type of items in the list. /// A representing the asynchronous operation. - public static async Task ForEachAsync([CanBeNull] this IAsyncEnumerable self, Action action) + public static async Task ForEachAsync(this IAsyncEnumerable? self, Action action) { if (self == null) return; diff --git a/back/src/Kyoo.Abstractions/Utility/Merger.cs b/back/src/Kyoo.Abstractions/Utility/Merger.cs index 237eff06..951f379b 100644 --- a/back/src/Kyoo.Abstractions/Utility/Merger.cs +++ b/back/src/Kyoo.Abstractions/Utility/Merger.cs @@ -42,9 +42,9 @@ namespace Kyoo.Utils /// The type of items in the lists to merge. /// The two list merged as an array [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] - public static T[] MergeLists([CanBeNull] IEnumerable first, - [CanBeNull] IEnumerable second, - [CanBeNull] Func isEqual = null) + public static T[] MergeLists(IEnumerable? first, + IEnumerable? second, + Func? isEqual = null) { if (first == null) return second?.ToArray(); @@ -66,8 +66,8 @@ namespace Kyoo.Utils /// The first dictionary with the missing elements of . /// [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] - public static IDictionary MergeDictionaries([CanBeNull] IDictionary first, - [CanBeNull] IDictionary second) + public static IDictionary MergeDictionaries(IDictionary? first, + IDictionary? second) { return MergeDictionaries(first, second, out bool _); } @@ -84,8 +84,8 @@ namespace Kyoo.Utils /// The type of values in the dictionaries /// The first dictionary with the missing elements of . [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] - public static IDictionary MergeDictionaries([CanBeNull] IDictionary first, - [CanBeNull] IDictionary second, + public static IDictionary MergeDictionaries(IDictionary? first, + IDictionary? second, out bool hasChanged) { if (first == null) @@ -138,8 +138,8 @@ namespace Kyoo.Utils /// set to those of . /// [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] - public static IDictionary CompleteDictionaries([CanBeNull] IDictionary first, - [CanBeNull] IDictionary second, + public static IDictionary CompleteDictionaries(IDictionary? first, + IDictionary? second, out bool hasChanged) { if (first == null) @@ -157,32 +157,6 @@ namespace Kyoo.Utils return second; } - /// - /// Set every fields of first to those of second. Ignore fields marked with the attribute - /// At the end, the OnMerge method of first will be called if first is a - /// - /// The object to assign - /// The object containing new values - /// Fields of T will be used - /// - public static T Assign(T first, T second) - { - Type type = typeof(T); - IEnumerable properties = type.GetProperties() - .Where(x => x.CanRead && x.CanWrite - && Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null); - - foreach (PropertyInfo property in properties) - { - object value = property.GetValue(second); - property.SetValue(first, value); - } - - if (first is IOnMerge merge) - merge.OnMerge(second); - return first; - } - /// /// Set every non-default values of seconds to the corresponding property of second. /// Dictionaries are handled like anonymous objects with a property per key/pair value @@ -210,8 +184,8 @@ namespace Kyoo.Utils /// /// If first is null public static T Complete([NotNull] T first, - [CanBeNull] T second, - [InstantHandle] Func where = null) + T? second, + [InstantHandle] Func? where = null) { if (first == null) throw new ArgumentNullException(nameof(first)); @@ -281,9 +255,9 @@ namespace Kyoo.Utils /// Fields of T will be merged /// [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] - public static T Merge([CanBeNull] T first, - [CanBeNull] T second, - [InstantHandle] Func where = null) + public static T Merge(T? first, + T? second, + [InstantHandle] Func? where = null) { if (first == null) return second; diff --git a/back/src/Kyoo.Abstractions/Utility/TaskUtils.cs b/back/src/Kyoo.Abstractions/Utility/TaskUtils.cs index 69da84cc..42c01027 100644 --- a/back/src/Kyoo.Abstractions/Utility/TaskUtils.cs +++ b/back/src/Kyoo.Abstractions/Utility/TaskUtils.cs @@ -77,8 +77,7 @@ namespace Kyoo.Utils /// The initial task /// The type that the task will return /// A non-null task. - [NotNull] - public static Task DefaultIfNull([CanBeNull] Task value) + public static Task DefaultIfNull(Task? value) { return value ?? Task.FromResult(default); } diff --git a/back/src/Kyoo.Abstractions/Utility/Utility.cs b/back/src/Kyoo.Abstractions/Utility/Utility.cs index bce40f4e..57e261df 100644 --- a/back/src/Kyoo.Abstractions/Utility/Utility.cs +++ b/back/src/Kyoo.Abstractions/Utility/Utility.cs @@ -63,34 +63,12 @@ namespace Kyoo.Utils return member!.Member.Name; } - /// - /// Get the value of a member (property or field) - /// - /// The member value - /// The owner of this member - /// The value boxed as an object - /// if or is null. - /// The member is not a field or a property. - public static object GetValue([NotNull] this MemberInfo member, [NotNull] object obj) - { - if (member == null) - throw new ArgumentNullException(nameof(member)); - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - return member switch - { - PropertyInfo property => property.GetValue(obj), - FieldInfo field => field.GetValue(obj), - _ => throw new ArgumentException($"Can't get value of a non property/field (member: {member}).") - }; - } - /// /// Slugify a string (Replace spaces by -, Uniformize accents) /// /// The string to slugify /// The slug version of the given string - public static string ToSlug([CanBeNull] string str) + public static string ToSlug(string? str) { if (str == null) return null; @@ -132,7 +110,7 @@ namespace Kyoo.Utils /// The starting type /// A list of types /// can't be null - public static IEnumerable GetInheritanceTree([NotNull] this Type type) + public static IEnumerable GetInheritanceTree(this Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); @@ -140,20 +118,6 @@ namespace Kyoo.Utils yield return type; } - /// - /// Check if inherit from a generic type . - /// - /// Does this object's type is a - /// The generic type to check against (Only generic types are supported like typeof(IEnumerable<>). - /// True if obj inherit from genericType. False otherwise - /// obj and genericType can't be null - public static bool IsOfGenericType([NotNull] object obj, [NotNull] Type genericType) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - return IsOfGenericType(obj.GetType(), genericType); - } - /// /// Check if inherit from a generic type . /// @@ -161,7 +125,7 @@ namespace Kyoo.Utils /// The generic type to check against (Only generic types are supported like typeof(IEnumerable<>). /// True if obj inherit from genericType. False otherwise /// obj and genericType can't be null - public static bool IsOfGenericType([NotNull] Type type, [NotNull] Type genericType) + public static bool IsOfGenericType(Type type, Type genericType) { if (type == null) throw new ArgumentNullException(nameof(type)); @@ -186,7 +150,7 @@ namespace Kyoo.Utils /// The generic definition of genericType that type inherit or null if type does not implement the generic type. /// and can't be null /// must be a generic type - public static Type GetGenericDefinition([NotNull] Type type, [NotNull] Type genericType) + public static Type GetGenericDefinition(Type type, Type genericType) { if (type == null) throw new ArgumentNullException(nameof(type)); @@ -224,12 +188,11 @@ namespace Kyoo.Utils /// No method match the given constraints. /// The method handle of the matching method. [PublicAPI] - [NotNull] - public static MethodInfo GetMethod([NotNull] Type type, + public static MethodInfo GetMethod(Type type, BindingFlags flag, string name, - [NotNull] Type[] generics, - [NotNull] object[] args) + Type[] generics, + object[] args) { if (type == null) throw new ArgumentNullException(nameof(type)); @@ -297,9 +260,9 @@ namespace Kyoo.Utils /// /// public static T RunGenericMethod( - [NotNull] Type owner, - [NotNull] string methodName, - [NotNull] Type type, + Type owner, + string methodName, + Type type, params object[] args) { return RunGenericMethod(owner, methodName, new[] { type }, args); @@ -334,9 +297,9 @@ namespace Kyoo.Utils /// [PublicAPI] public static T RunGenericMethod( - [NotNull] Type owner, - [NotNull] string methodName, - [NotNull] Type[] types, + Type owner, + string methodName, + Type[] types, params object[] args) { if (owner == null) @@ -351,83 +314,6 @@ namespace Kyoo.Utils return (T)method.MakeGenericMethod(types).Invoke(null, args); } - /// - /// Run a generic method for a runtime . - /// - /// - /// To run for a List where you don't know the type at compile type, - /// you could do: - /// - /// Utility.RunGenericMethod<object>( - /// typeof(Utility), - /// nameof(MergeLists), - /// enumerableType, - /// oldValue, newValue, equalityComparer) - /// - /// - /// The this of the method to run. - /// The name of the method. You should use the nameof keyword. - /// The generic type to run the method with. - /// The list of arguments of the method - /// - /// The return type of the method. You can put for an unknown one. - /// - /// No method match the given constraints. - /// The return of the method you wanted to run. - /// - /// - public static T RunGenericMethod( - [NotNull] object instance, - [NotNull] string methodName, - [NotNull] Type type, - params object[] args) - { - return RunGenericMethod(instance, methodName, new[] { type }, args); - } - - /// - /// Run a generic method for a multiple runtime . - /// If your generic method only needs one type, see - /// - /// - /// - /// To run for a List where you don't know the type at compile type, - /// you could do: - /// - /// Utility.RunGenericMethod<object>( - /// typeof(Utility), - /// nameof(MergeLists), - /// enumerableType, - /// oldValue, newValue, equalityComparer) - /// - /// - /// The this of the method to run. - /// The name of the method. You should use the nameof keyword. - /// The list of generic types to run the method with. - /// The list of arguments of the method - /// - /// The return type of the method. You can put for an unknown one. - /// - /// No method match the given constraints. - /// The return of the method you wanted to run. - /// - /// - public static T RunGenericMethod( - [NotNull] object instance, - [NotNull] string methodName, - [NotNull] Type[] types, - params object[] args) - { - if (instance == null) - throw new ArgumentNullException(nameof(instance)); - if (methodName == null) - throw new ArgumentNullException(nameof(methodName)); - if (types == null || types.Length == 0) - throw new ArgumentNullException(nameof(types)); - MethodInfo method = GetMethod(instance.GetType(), BindingFlags.Instance, methodName, types, args); - return (T)method.MakeGenericMethod(types).Invoke(instance, args.ToArray()); - } - /// /// Convert a dictionary to a query string. /// @@ -446,25 +332,11 @@ namespace Kyoo.Utils /// /// The exception to rethrow. [System.Diagnostics.CodeAnalysis.DoesNotReturn] - public static void ReThrow([NotNull] this Exception ex) + public static void ReThrow(this Exception ex) { if (ex == null) throw new ArgumentNullException(nameof(ex)); ExceptionDispatchInfo.Capture(ex).Throw(); } - - /// - /// Get a friendly type name (supporting generics) - /// For example a list of string will be displayed as List<string> and not as List`1. - /// - /// The type to use - /// The friendly name of the type - public static string FriendlyName(this Type type) - { - if (!type.IsGenericType) - return type.Name; - string generics = string.Join(", ", type.GetGenericArguments().Select(x => x.FriendlyName())); - return $"{type.Name[..type.Name.IndexOf('`')]}<{generics}>"; - } } } diff --git a/back/src/Kyoo.Authentication/Models/DTO/RegisterRequest.cs b/back/src/Kyoo.Authentication/Models/DTO/RegisterRequest.cs index e8e76750..394cbf74 100644 --- a/back/src/Kyoo.Authentication/Models/DTO/RegisterRequest.cs +++ b/back/src/Kyoo.Authentication/Models/DTO/RegisterRequest.cs @@ -72,7 +72,6 @@ namespace Kyoo.Authentication.Models.DTO Username = Username, Password = BCryptNet.HashPassword(Password), Email = Email, - ExtraData = new Dictionary() }; } } diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs index edced1e7..6ce6857e 100644 --- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs +++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs @@ -39,15 +39,15 @@ namespace Kyoo.Core.Controllers /// private readonly IBaseRepository[] _repositories; - /// - public ILibraryRepository LibraryRepository { get; } - /// public ILibraryItemRepository LibraryItemRepository { get; } /// public ICollectionRepository CollectionRepository { get; } + /// + public IMovieRepository MovieRepository { get; } + /// public IShowRepository ShowRepository { get; } @@ -63,9 +63,6 @@ namespace Kyoo.Core.Controllers /// public IStudioRepository StudioRepository { get; } - /// - public IGenreRepository GenreRepository { get; } - /// public IUserRepository UserRepository { get; } @@ -77,15 +74,14 @@ namespace Kyoo.Core.Controllers public LibraryManager(IEnumerable repositories) { _repositories = repositories.ToArray(); - LibraryRepository = GetRepository() as ILibraryRepository; - LibraryItemRepository = GetRepository() as ILibraryItemRepository; + LibraryItemRepository = GetRepository() as ILibraryItemRepository; CollectionRepository = GetRepository() as ICollectionRepository; + MovieRepository = GetRepository() as IMovieRepository; ShowRepository = GetRepository() as IShowRepository; SeasonRepository = GetRepository() as ISeasonRepository; EpisodeRepository = GetRepository() as IEpisodeRepository; PeopleRepository = GetRepository() as IPeopleRepository; StudioRepository = GetRepository() as IStudioRepository; - GenreRepository = GetRepository() as IGenreRepository; UserRepository = GetRepository() as IUserRepository; } @@ -255,28 +251,10 @@ namespace Kyoo.Core.Controllers return (obj, member: memberName) switch { - (Library l, nameof(Library.Shows)) => ShowRepository - .GetAll(x => x.Libraries.Any(y => y.ID == obj.ID)) - .Then(x => l.Shows = x), - - (Library l, nameof(Library.Collections)) => CollectionRepository - .GetAll(x => x.Libraries.Any(y => y.ID == obj.ID)) - .Then(x => l.Collections = x), - - (Collection c, nameof(Collection.Shows)) => ShowRepository .GetAll(x => x.Collections.Any(y => y.ID == obj.ID)) .Then(x => c.Shows = x), - (Collection c, nameof(Collection.Libraries)) => LibraryRepository - .GetAll(x => x.Collections.Any(y => y.ID == obj.ID)) - .Then(x => c.Libraries = x), - - - (Show s, nameof(Show.Genres)) => GenreRepository - .GetAll(x => x.Shows.Any(y => y.ID == obj.ID)) - .Then(x => s.Genres = x), - (Show s, nameof(Show.People)) => PeopleRepository .GetFromShow(obj.ID) .Then(x => s.People = x), @@ -291,10 +269,6 @@ namespace Kyoo.Core.Controllers (x, y) => x.Episodes = y, (x, y) => { x.Show = y; x.ShowID = y.ID; }), - (Show s, nameof(Show.Libraries)) => LibraryRepository - .GetAll(x => x.Shows.Any(y => y.ID == obj.ID)) - .Then(x => s.Libraries = x), - (Show s, nameof(Show.Collections)) => CollectionRepository .GetAll(x => x.Shows.Any(y => y.ID == obj.ID)) .Then(x => s.Collections = x), @@ -339,11 +313,6 @@ namespace Kyoo.Core.Controllers }), - (Genre g, nameof(Genre.Shows)) => ShowRepository - .GetAll(x => x.Genres.Any(y => y.ID == obj.ID)) - .Then(x => g.Shows = x), - - (Studio s, nameof(Studio.Shows)) => ShowRepository .GetAll(x => x.Studio.ID == obj.ID) .Then(x => s.Shows = x), @@ -356,24 +325,6 @@ namespace Kyoo.Core.Controllers }; } - /// - public Task> GetItemsFromLibrary(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return LibraryItemRepository.GetFromLibrary(id, where, sort, limit); - } - - /// - public Task> GetItemsFromLibrary(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return LibraryItemRepository.GetFromLibrary(slug, where, sort, limit); - } - /// public Task> GetPeopleFromShow(int showID, Expression> where = null, @@ -410,20 +361,6 @@ namespace Kyoo.Core.Controllers return PeopleRepository.GetFromPeople(slug, where, sort, limit); } - /// - public Task AddShowLink(int showID, int? libraryID, int? collectionID) - { - return ShowRepository.AddShowLink(showID, libraryID, collectionID); - } - - /// - public Task AddShowLink(Show show, Library library, Collection collection) - { - if (show == null) - throw new ArgumentNullException(nameof(show)); - return ShowRepository.AddShowLink(show.ID, library?.ID, collection?.ID); - } - /// public Task> GetAll(Expression> where = null, Sort sort = default, diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs index eb58fe98..489865ac 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs @@ -129,7 +129,7 @@ namespace Kyoo.Core.Controllers _database.Episodes .Include(x => x.Show) .Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null) - .Where(_database.Like(x => x.Title, $"%{query}%")) + .Where(_database.Like(x => x.Name, $"%{query}%")) ) .Take(20) .ToListAsync(); diff --git a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs deleted file mode 100644 index 73c05a68..00000000 --- a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs +++ /dev/null @@ -1,93 +0,0 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Kyoo.Utils; -using Microsoft.EntityFrameworkCore; - -namespace Kyoo.Core.Controllers -{ - /// - /// A local repository for genres. - /// - public class GenreRepository : LocalRepository, IGenreRepository - { - /// - /// The database handle - /// - private readonly DatabaseContext _database; - - /// - protected override Sort DefaultSort => new Sort.By(x => x.Slug); - - /// - /// Create a new . - /// - /// The database handle - public GenreRepository(DatabaseContext database) - : base(database) - { - _database = database; - } - - /// - public override async Task> Search(string query) - { - return await Sort( - _database.Genres - .Where(_database.Like(x => x.Name, $"%{query}%")) - ) - .Take(20) - .ToListAsync(); - } - - /// - protected override async Task Validate(Genre resource) - { - resource.Slug ??= Utility.ToSlug(resource.Name); - await base.Validate(resource); - } - - /// - public override async Task Create(Genre obj) - { - await base.Create(obj); - _database.Entry(obj).State = EntityState.Added; - await _database.SaveChangesAsync(() => Get(obj.Slug)); - OnResourceCreated(obj); - return obj; - } - - /// - public override async Task Delete(Genre obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - _database.Entry(obj).State = EntityState.Deleted; - await _database.SaveChangesAsync(); - await base.Delete(obj); - } - } -} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs index a9b15fb5..d8325a51 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs @@ -23,7 +23,6 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Postgresql; using Microsoft.EntityFrameworkCore; @@ -32,84 +31,80 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle library items. /// - public class LibraryItemRepository : LocalRepository, ILibraryItemRepository + public class LibraryItemRepository : LocalRepository, ILibraryItemRepository { /// /// The database handle /// private readonly DatabaseContext _database; - /// - /// A lazy loaded library repository to validate queries (check if a library does exist) - /// - private readonly Lazy _libraries; - /// - protected override Sort DefaultSort => new Sort.By(x => x.Title); + protected override Sort DefaultSort => new Sort.By(x => x.Name); /// - /// Create a new . + /// Create a new . /// /// The database instance - /// A lazy loaded library repository - public LibraryItemRepository(DatabaseContext database, - Lazy libraries) + public LibraryItemRepository(DatabaseContext database) : base(database) { _database = database; - _libraries = libraries; } /// - public override Task GetOrDefault(int id) + public override async Task GetOrDefault(int id) { - return _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id); + return (await _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id)).ToItem(); } /// - public override Task GetOrDefault(string slug) + public override async Task GetOrDefault(string slug) { - return _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug); + return (await _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug)).ToItem(); } /// - public override Task> GetAll(Expression> where = null, - Sort sort = default, + public override async Task> GetAll(Expression> where = null, + Sort sort = default, Pagination limit = default) { - return ApplyFilters(_database.LibraryItems, where, sort, limit); + return (await ApplyFilters(_database.LibraryItems, where, sort, limit)) + .Select(x => (x as BagItem)!.ToItem()) + .ToList(); } /// - public override Task GetCount(Expression> where = null) + public override Task GetCount(Expression> where = null) { - IQueryable query = _database.LibraryItems; + IQueryable query = _database.LibraryItems; if (where != null) query = query.Where(where); return query.CountAsync(); } /// - public override async Task> Search(string query) + public override async Task> Search(string query) { - return await Sort( - _database.LibraryItems - .Where(_database.Like(x => x.Title, $"%{query}%")) + return (await Sort( + _database.LibraryItems + .Where(_database.Like(x => x.Name, $"%{query}%")) ) .Take(20) - .ToListAsync(); + .ToListAsync()) + .Select(x => (x as BagItem)!.ToItem()) + .ToList(); } /// - public override Task Create(LibraryItem obj) + public override Task Create(ILibraryItem obj) => throw new InvalidOperationException(); /// - public override Task CreateIfNotExists(LibraryItem obj) + public override Task CreateIfNotExists(ILibraryItem obj) => throw new InvalidOperationException(); /// - public override Task Edit(LibraryItem obj, bool resetOld) + public override Task Edit(ILibraryItem obj, bool resetOld) => throw new InvalidOperationException(); /// @@ -121,58 +116,7 @@ namespace Kyoo.Core.Controllers => throw new InvalidOperationException(); /// - public override Task Delete(LibraryItem obj) + public override Task Delete(ILibraryItem obj) => throw new InvalidOperationException(); - - /// - /// Get a basic queryable for a library with the right mapping from shows and collections. - /// Shows contained in a collection are excluded. - /// - /// Only items that are part of a library that match this predicate will be returned. - /// A queryable containing items that are part of a library matching the selector. - private IQueryable _LibraryRelatedQuery(Expression> selector) - => _database.Libraries - .Where(selector) - .SelectMany(x => x.Shows) - .Where(x => !x.Collections.Any()) - .Select(LibraryItem.FromShow) - .Concat(_database.Libraries - .Where(selector) - .SelectMany(x => x.Collections) - .Select(LibraryItem.FromCollection)); - - /// - public async Task> GetFromLibrary(int id, - Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - ICollection items = await ApplyFilters( - _LibraryRelatedQuery(x => x.ID == id), - where, - sort, - limit - ); - if (!items.Any() && await _libraries.Value.GetOrDefault(id) == null) - throw new ItemNotFoundException(); - return items; - } - - /// - public async Task> GetFromLibrary(string slug, - Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - ICollection items = await ApplyFilters( - _LibraryRelatedQuery(x => x.Slug == slug), - where, - sort, - limit - ); - if (!items.Any() && await _libraries.Value.GetOrDefault(slug) == null) - throw new ItemNotFoundException(); - return items; - } } } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs deleted file mode 100644 index 59e7083c..00000000 --- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs +++ /dev/null @@ -1,99 +0,0 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Kyoo.Utils; -using Microsoft.EntityFrameworkCore; - -namespace Kyoo.Core.Controllers -{ - /// - /// A local repository to handle libraries. - /// - public class LibraryRepository : LocalRepository, ILibraryRepository - { - /// - /// The database handle - /// - private readonly DatabaseContext _database; - - /// - protected override Sort DefaultSort => new Sort.By(x => x.ID); - - /// - /// Create a new instance. - /// - /// The database handle - public LibraryRepository(DatabaseContext database) - : base(database) - { - _database = database; - } - - /// - public override async Task> Search(string query) - { - return await Sort( - _database.Libraries - .Where(_database.Like(x => x.Name + " " + x.Slug, $"%{query}%")) - ) - .Take(20) - .ToListAsync(); - } - - /// - public override async Task Create(Library obj) - { - await base.Create(obj); - _database.Entry(obj).State = EntityState.Added; - await _database.SaveChangesAsync(() => Get(obj.Slug)); - OnResourceCreated(obj); - return obj; - } - - /// - protected override async Task Validate(Library resource) - { - await base.Validate(resource); - - if (string.IsNullOrEmpty(resource.Slug)) - throw new ArgumentException("The library's slug must be set and not empty"); - if (string.IsNullOrEmpty(resource.Name)) - throw new ArgumentException("The library's name must be set and not empty"); - if (resource.Paths == null || !resource.Paths.Any()) - throw new ArgumentException("The library should have a least one path."); - } - - /// - public override async Task Delete(Library obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - _database.Entry(obj).State = EntityState.Deleted; - await _database.SaveChangesAsync(); - await base.Delete(obj); - } - } -} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs new file mode 100644 index 00000000..1b6fe33a --- /dev/null +++ b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs @@ -0,0 +1,139 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models; +using Kyoo.Postgresql; +using Kyoo.Utils; +using Microsoft.EntityFrameworkCore; + +namespace Kyoo.Core.Controllers +{ + /// + /// A local repository to handle shows + /// + public class MovieRepository : LocalRepository, IMovieRepository + { + /// + /// The database handle + /// + private readonly DatabaseContext _database; + + /// + /// A studio repository to handle creation/validation of related studios. + /// + private readonly IStudioRepository _studios; + + /// + /// A people repository to handle creation/validation of related people. + /// + private readonly IPeopleRepository _people; + + /// + protected override Sort DefaultSort => new Sort.By(x => x.Name); + + /// + /// Create a new . + /// + /// The database handle to use + /// A studio repository + /// A people repository + public MovieRepository(DatabaseContext database, + IStudioRepository studios, + IPeopleRepository people) + : base(database) + { + _database = database; + _studios = studios; + _people = people; + } + + /// + public override async Task> Search(string query) + { + query = $"%{query}%"; + return await Sort( + _database.Movies + .Where(_database.Like(x => x.Name + " " + x.Slug, query)) + ) + .Take(20) + .ToListAsync(); + } + + /// + public override async Task Create(Movie obj) + { + await base.Create(obj); + _database.Entry(obj).State = EntityState.Added; + await _database.SaveChangesAsync(() => Get(obj.Slug)); + OnResourceCreated(obj); + return obj; + } + + /// + protected override async Task Validate(Movie resource) + { + await base.Validate(resource); + if (resource.Studio != null) + { + resource.Studio = await _studios.CreateIfNotExists(resource.Studio); + resource.StudioID = resource.Studio.ID; + } + + if (resource.People != null) + { + foreach (PeopleRole role in resource.People) + { + role.People = _database.LocalEntity(role.People.Slug) + ?? await _people.CreateIfNotExists(role.People); + role.PeopleID = role.People.ID; + _database.Entry(role).State = EntityState.Added; + } + } + } + + /// + protected override async Task EditRelations(Movie resource, Movie changed, bool resetOld) + { + await Validate(changed); + + if (changed.Studio != null || resetOld) + { + await Database.Entry(resource).Reference(x => x.Studio).LoadAsync(); + resource.Studio = changed.Studio; + } + + if (changed.People != null || resetOld) + { + await Database.Entry(resource).Collection(x => x.People).LoadAsync(); + resource.People = changed.People; + } + } + + /// + public override async Task Delete(Movie obj) + { + _database.Remove(obj); + await _database.SaveChangesAsync(); + await base.Delete(obj); + } + } +} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs index 7b12cf73..104b2367 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs @@ -102,7 +102,7 @@ namespace Kyoo.Core.Controllers { return await Sort( _database.Seasons - .Where(_database.Like(x => x.Title, $"%{query}%")) + .Where(_database.Like(x => x.Name, $"%{query}%")) ) .Take(20) .ToListAsync(); diff --git a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs index 4e2092b2..32e378ff 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs @@ -47,13 +47,8 @@ namespace Kyoo.Core.Controllers /// private readonly IPeopleRepository _people; - /// - /// A genres repository to handle creation/validation of related genres. - /// - private readonly IGenreRepository _genres; - /// - protected override Sort DefaultSort => new Sort.By(x => x.Title); + protected override Sort DefaultSort => new Sort.By(x => x.Name); /// /// Create a new . @@ -61,17 +56,14 @@ namespace Kyoo.Core.Controllers /// The database handle to use /// A studio repository /// A people repository - /// A genres repository public ShowRepository(DatabaseContext database, IStudioRepository studios, - IPeopleRepository people, - IGenreRepository genres) + IPeopleRepository people) : base(database) { _database = database; _studios = studios; _people = people; - _genres = genres; } /// @@ -80,7 +72,7 @@ namespace Kyoo.Core.Controllers query = $"%{query}%"; return await Sort( _database.Shows - .Where(_database.Like(x => x.Title + " " + x.Slug, query)) + .Where(_database.Like(x => x.Name + " " + x.Slug, query)) ) .Take(20) .ToListAsync(); @@ -99,7 +91,7 @@ namespace Kyoo.Core.Controllers /// protected override async Task Validate(Show resource) { - resource.Slug ??= Utility.ToSlug(resource.Title); + resource.Slug ??= Utility.ToSlug(resource.Name); await base.Validate(resource); if (resource.Studio != null) @@ -108,14 +100,6 @@ namespace Kyoo.Core.Controllers resource.StudioID = resource.Studio.ID; } - if (resource.Genres != null) - { - resource.Genres = await resource.Genres - .SelectAsync(x => _genres.CreateIfNotExists(x)) - .ToListAsync(); - _database.AttachRange(resource.Genres); - } - if (resource.People != null) { foreach (PeopleRole role in resource.People) @@ -133,21 +117,12 @@ namespace Kyoo.Core.Controllers { await Validate(changed); - if (changed.Aliases != null || resetOld) - resource.Aliases = changed.Aliases; - if (changed.Studio != null || resetOld) { await Database.Entry(resource).Reference(x => x.Studio).LoadAsync(); resource.Studio = changed.Studio; } - if (changed.Genres != null || resetOld) - { - await Database.Entry(resource).Collection(x => x.Genres).LoadAsync(); - resource.Genres = changed.Genres; - } - if (changed.People != null || resetOld) { await Database.Entry(resource).Collection(x => x.People).LoadAsync(); @@ -155,27 +130,6 @@ namespace Kyoo.Core.Controllers } } - /// - public async Task AddShowLink(int showID, int? libraryID, int? collectionID) - { - if (collectionID != null) - { - await _database.AddLinks(collectionID.Value, showID); - await _database.SaveIfNoDuplicates(); - - if (libraryID != null) - { - await _database.AddLinks(libraryID.Value, collectionID.Value); - await _database.SaveIfNoDuplicates(); - } - } - if (libraryID != null) - { - await _database.AddLinks(libraryID.Value, showID); - await _database.SaveIfNoDuplicates(); - } - } - /// public Task GetSlug(int showID) { diff --git a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs index 4d561b2a..652380d2 100644 --- a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs +++ b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs @@ -98,9 +98,9 @@ namespace Kyoo.Core.Controllers throw new ArgumentNullException(nameof(item)); string name = item is IResource res ? res.Slug : "???"; - await _DownloadImage(item.Poster.Source, _GetBaseImagePath(item, "poster"), $"The poster of {name}"); - await _DownloadImage(item.Thumbnail.Source, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}"); - await _DownloadImage(item.Logo.Source, _GetBaseImagePath(item, "logo"), $"The poster of {name}"); + await _DownloadImage(item.Poster?.Source, _GetBaseImagePath(item, "poster"), $"The poster of {name}"); + await _DownloadImage(item.Thumbnail?.Source, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}"); + await _DownloadImage(item.Logo?.Source, _GetBaseImagePath(item, "logo"), $"The poster of {name}"); } private static string _GetBaseImagePath(T item, string image) diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index 162ce4bc..ff6e9535 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -30,6 +30,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using JsonOptions = Kyoo.Core.Api.JsonOptions; namespace Kyoo.Core @@ -48,15 +49,14 @@ namespace Kyoo.Core builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); + builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); - builder.RegisterRepository(); builder.RegisterRepository(); } @@ -73,6 +73,7 @@ namespace Kyoo.Core .AddNewtonsoftJson(x => { x.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; + x.SerializerSettings.Converters.Add(new StringEnumConverter()); }) .AddDataAnnotations() .AddControllersAsServices() diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Library.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs similarity index 50% rename from back/src/Kyoo.Abstractions/Models/Resources/Library.cs rename to back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs index 0c4129f4..52674995 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Library.cs +++ b/back/src/Kyoo.Core/Views/Helper/Serializers/ImageConvertor.cs @@ -16,40 +16,31 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; using System.Collections.Generic; -using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Abstractions.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; -namespace Kyoo.Abstractions.Models +namespace Kyoo.Core.Api { - /// - /// A library containing and . - /// - public class Library : IResource + public class ImageConverter : JsonConverter { /// - public int ID { get; set; } + public override void WriteJson(JsonWriter writer, Image value, JsonSerializer serializer) + { + JObject obj = JObject.FromObject(value, serializer); + obj.WriteTo(writer); + } /// - public string Slug { get; set; } - - /// - /// The name of this library. - /// - public string Name { get; set; } - - /// - /// The list of paths that this library is responsible for. This is mainly used by the Scan task. - /// - public string[] Paths { get; set; } - - /// - /// The list of shows in this library. - /// - [LoadableRelation] public ICollection Shows { get; set; } - - /// - /// The list of collections in this library. - /// - [LoadableRelation] public ICollection Collections { get; set; } + public override Image ReadJson(JsonReader reader, + Type objectType, + Image existingValue, + bool hasExistingValue, + JsonSerializer serializer) + { + throw new NotImplementedException(); + } } } diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs index c0b1d8bb..98429630 100644 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs +++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Reflection; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; diff --git a/back/src/Kyoo.Core/Views/Metadata/GenreApi.cs b/back/src/Kyoo.Core/Views/Metadata/GenreApi.cs deleted file mode 100644 index eb72b284..00000000 --- a/back/src/Kyoo.Core/Views/Metadata/GenreApi.cs +++ /dev/null @@ -1,95 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Abstractions.Models.Permissions; -using Kyoo.Abstractions.Models.Utils; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using static Kyoo.Abstractions.Models.Utils.Constants; - -namespace Kyoo.Core.Api -{ - /// - /// Information about one or multiple . - /// - [Route("genres")] - [Route("genre", Order = AlternativeRoute)] - [ApiController] - [PartialPermission(nameof(Genre))] - [ApiDefinition("Genres", Group = MetadataGroup)] - public class GenreApi : CrudApi - { - /// - /// The library manager used to modify or retrieve information about the data store. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// Create a new . - /// - /// - /// The library manager used to modify or retrieve information about the data store. - /// - public GenreApi(ILibraryManager libraryManager) - : base(libraryManager.GenreRepository) - { - _libraryManager = libraryManager; - } - - /// - /// Get shows with genre - /// - /// - /// Lists the shows that have the selected genre. - /// - /// The ID or slug of the . - /// A key to sort shows by. - /// An optional list of filters. - /// The number of shows to return and where to start. - /// A page of shows. - /// The filters or the sort parameters are invalid. - /// No genre with the given ID could be found. - [HttpGet("{identifier:id}/shows")] - [HttpGet("{identifier:id}/show", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetShows(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Genres)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } - } -} diff --git a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs index ffd13752..bc15368a 100644 --- a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs @@ -93,40 +93,5 @@ namespace Kyoo.Core.Api return NotFound(); return Page(resources, pagination.Limit); } - - /// - /// Get libraries containing this collection - /// - /// - /// Lists the libraries that contain the collection with the given id or slug. - /// - /// The ID or slug of the . - /// A key to sort libraries by. - /// An optional list of filters. - /// The number of libraries to return. - /// A page of libraries. - /// The filters or the sort parameters are invalid. - /// No collection with the given ID or slug could be found. - [HttpGet("{identifier:id}/libraries")] - [HttpGet("{identifier:id}/library", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetLibraries(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Collections)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } } } diff --git a/back/src/Kyoo.Core/Views/Resources/LibraryApi.cs b/back/src/Kyoo.Core/Views/Resources/LibraryApi.cs deleted file mode 100644 index 6551a99a..00000000 --- a/back/src/Kyoo.Core/Views/Resources/LibraryApi.cs +++ /dev/null @@ -1,171 +0,0 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Abstractions.Models.Permissions; -using Kyoo.Abstractions.Models.Utils; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using static Kyoo.Abstractions.Models.Utils.Constants; - -namespace Kyoo.Core.Api -{ - /// - /// Information about one or multiple . - /// - [Route("libraries")] - [Route("library", Order = AlternativeRoute)] - [ApiController] - [ResourceView] - [PartialPermission(nameof(Library), Group = Group.Admin)] - [ApiDefinition("Library", Group = ResourcesGroup)] - public class LibraryApi : CrudApi - { - /// - /// The library manager used to modify or retrieve information in the data store. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// Create a new . - /// - /// - /// The library manager used to modify or retrieve information in the data store. - /// - public LibraryApi(ILibraryManager libraryManager) - : base(libraryManager.LibraryRepository) - { - _libraryManager = libraryManager; - } - - /// - /// Get shows - /// - /// - /// List the shows that are part of this library. - /// - /// The ID or slug of the . - /// A key to sort shows by. - /// An optional list of filters. - /// The number of shows to return. - /// A page of shows. - /// The filters or the sort parameters are invalid. - /// No library with the given ID or slug could be found. - [HttpGet("{identifier:id}/shows")] - [HttpGet("{identifier:id}/show", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetShows(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Libraries)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } - - /// - /// Get collections - /// - /// - /// List the collections that are part of this library. - /// - /// The ID or slug of the . - /// A key to sort collections by. - /// An optional list of filters. - /// The number of collections to return. - /// A page of collections. - /// The filters or the sort parameters are invalid. - /// No library with the given ID or slug could be found. - [HttpGet("{identifier:id}/collections")] - [HttpGet("{identifier:id}/collection", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetCollections(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Libraries)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } - - /// - /// Get items - /// - /// - /// List all items of this library. - /// An item can ether represent a collection or a show. - /// This endpoint allow one to retrieve all collections and shows that are not contained in a collection. - /// This is what is displayed on the /browse/library page of the webapp. - /// - /// The ID or slug of the . - /// A key to sort items by. - /// An optional list of filters. - /// The number of items to return. - /// A page of items. - /// The filters or the sort parameters are invalid. - /// No library with the given ID or slug could be found. - [HttpGet("{identifier:id}/items")] - [HttpGet("{identifier:id}/item", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetItems(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - Expression> whereQuery = ApiHelper.ParseWhere(where); - Sort sort = Sort.From(sortBy); - - ICollection resources = await identifier.Match( - id => _libraryManager.GetItemsFromLibrary(id, whereQuery, sort, pagination), - slug => _libraryManager.GetItemsFromLibrary(slug, whereQuery, sort, pagination) - ); - - return Page(resources, pagination.Limit); - } - } -} diff --git a/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs b/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs index f1b6747d..8046a942 100644 --- a/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; using System.Collections.Generic; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; @@ -38,7 +37,7 @@ namespace Kyoo.Core.Api [Route("item", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(LibraryItem))] + [PartialPermission("LibraryItem")] [ApiDefinition("Items", Group = ResourcesGroup)] public class LibraryItemApi : BaseApi { @@ -78,14 +77,14 @@ namespace Kyoo.Core.Api [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetAll( + public async Task>> GetAll( [FromQuery] string sortBy, [FromQuery] Dictionary where, [FromQuery] Pagination pagination) { - ICollection resources = await _libraryItems.GetAll( - ApiHelper.ParseWhere(where), - Sort.From(sortBy), + ICollection resources = await _libraryItems.GetAll( + ApiHelper.ParseWhere(where), + Sort.From(sortBy), pagination ); diff --git a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs new file mode 100644 index 00000000..a1825517 --- /dev/null +++ b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs @@ -0,0 +1,149 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models; +using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Abstractions.Models.Permissions; +using Kyoo.Abstractions.Models.Utils; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using static Kyoo.Abstractions.Models.Utils.Constants; + +namespace Kyoo.Core.Api +{ + /// + /// Information about one or multiple . + /// + [Route("movies")] + [Route("movie", Order = AlternativeRoute)] + [ApiController] + [PartialPermission(nameof(Show))] + [ApiDefinition("Shows", Group = ResourcesGroup)] + public class MovieApi : CrudThumbsApi + { + /// + /// The library manager used to modify or retrieve information in the data store. + /// + private readonly ILibraryManager _libraryManager; + + /// + /// Create a new . + /// + /// + /// The library manager used to modify or retrieve information about the data store. + /// + /// The thumbnail manager used to retrieve images paths. + public MovieApi(ILibraryManager libraryManager, + IThumbnailsManager thumbs) + : base(libraryManager.MovieRepository, thumbs) + { + _libraryManager = libraryManager; + } + + // /// + // /// Get staff + // /// + // /// + // /// List staff members that made this show. + // /// + // /// The ID or slug of the . + // /// A key to sort staff members by. + // /// An optional list of filters. + // /// The number of people to return. + // /// A page of people. + // /// The filters or the sort parameters are invalid. + // /// No show with the given ID or slug could be found. + // [HttpGet("{identifier:id}/staff")] + // [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] + // [PartialPermission(Kind.Read)] + // [ProducesResponseType(StatusCodes.Status200OK)] + // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + // [ProducesResponseType(StatusCodes.Status404NotFound)] + // public async Task>> GetPeople(Identifier identifier, + // [FromQuery] string sortBy, + // [FromQuery] Dictionary where, + // [FromQuery] Pagination pagination) + // { + // Expression> whereQuery = ApiHelper.ParseWhere(where); + // Sort sort = Sort.From(sortBy); + // + // ICollection resources = await identifier.Match( + // id => _libraryManager.GetPeopleFromShow(id, whereQuery, sort, pagination), + // slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sort, pagination) + // ); + // return Page(resources, pagination.Limit); + // } + + /// + /// Get studio that made the show + /// + /// + /// Get the studio that made the show. + /// + /// The ID or slug of the . + /// The studio that made the show. + /// No show with the given ID or slug could be found. + [HttpGet("{identifier:id}/studio")] + [PartialPermission(Kind.Read)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> GetStudio(Identifier identifier) + { + return await _libraryManager.Get(identifier.IsContainedIn(x => x.Movies)); + } + + /// + /// Get collections containing this show + /// + /// + /// List the collections that contain this show. + /// + /// The ID or slug of the . + /// A key to sort collections by. + /// An optional list of filters. + /// The number of collections to return. + /// A page of collections. + /// The filters or the sort parameters are invalid. + /// No show with the given ID or slug could be found. + [HttpGet("{identifier:id}/collections")] + [HttpGet("{identifier:id}/collection", Order = AlternativeRoute)] + [PartialPermission(Kind.Read)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task>> GetCollections(Identifier identifier, + [FromQuery] string sortBy, + [FromQuery] Dictionary where, + [FromQuery] Pagination pagination) + { + ICollection resources = await _libraryManager.GetAll( + ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Movies)), + Sort.From(sortBy), + pagination + ); + + if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + return NotFound(); + return Page(resources, pagination.Limit); + } + } +} diff --git a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs index 79e9ec2b..5c09d896 100644 --- a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs @@ -79,7 +79,6 @@ namespace Kyoo.Core.Api Shows = await _libraryManager.Search(query), Episodes = await _libraryManager.Search(query), People = await _libraryManager.Search(query), - Genres = await _libraryManager.Search(query), Studios = await _libraryManager.Search(query) }; } @@ -133,9 +132,9 @@ namespace Kyoo.Core.Api [Permission(nameof(Show), Kind.Read)] [ApiDefinition("Items")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchItems(string query) + public Task> SearchItems(string query) { - return _libraryManager.Search(query); + return _libraryManager.Search(query); } /// @@ -175,24 +174,6 @@ namespace Kyoo.Core.Api return _libraryManager.Search(query); } - /// - /// Search genres - /// - /// - /// Search for genres - /// - /// The query to search for. - /// A list of genres found for the specified query. - [HttpGet("genres")] - [HttpGet("genre", Order = AlternativeRoute)] - [Permission(nameof(Genre), Kind.Read)] - [ApiDefinition("Genres")] - [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchGenres(string query) - { - return _libraryManager.Search(query); - } - /// /// Search studios /// diff --git a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs index 95a9492e..68d44eb1 100644 --- a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs @@ -37,8 +37,6 @@ namespace Kyoo.Core.Api /// [Route("shows")] [Route("show", Order = AlternativeRoute)] - [Route("movie", Order = AlternativeRoute)] - [Route("movies", Order = AlternativeRoute)] [ApiController] [PartialPermission(nameof(Show))] [ApiDefinition("Shows", Group = ResourcesGroup)] @@ -63,24 +61,6 @@ namespace Kyoo.Core.Api _libraryManager = libraryManager; } - /// - public override async Task> Create([FromBody] Show resource) - { - ActionResult ret = await base.Create(resource); - if (ret.Value.IsMovie) - { - Episode episode = new() - { - Show = ret.Value, - Title = ret.Value.Title, - Path = ret.Value.Path - }; - - await _libraryManager.Create(episode); - } - return ret; - } - /// /// Get seasons of this show /// @@ -185,41 +165,6 @@ namespace Kyoo.Core.Api return Page(resources, pagination.Limit); } - /// - /// Get genres of this show - /// - /// - /// List the genres that represent this show. - /// - /// The ID or slug of the . - /// A key to sort genres by. - /// An optional list of filters. - /// The number of genres to return. - /// A page of genres. - /// The filters or the sort parameters are invalid. - /// No show with the given ID or slug could be found. - [HttpGet("{identifier:id}/genres")] - [HttpGet("{identifier:id}/genre", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetGenres(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } - /// /// Get studio that made the show /// @@ -238,42 +183,6 @@ namespace Kyoo.Core.Api return await _libraryManager.Get(identifier.IsContainedIn(x => x.Shows)); } - /// - /// Get libraries containing this show - /// - /// - /// List the libraries that contain this show. If this show is contained in a collection that is contained in - /// a library, this library will be returned too. - /// - /// The ID or slug of the . - /// A key to sort libraries by. - /// An optional list of filters. - /// The number of libraries to return. - /// A page of libraries. - /// The filters or the sort parameters are invalid. - /// No show with the given ID or slug could be found. - [HttpGet("{identifier:id}/libraries")] - [HttpGet("{identifier:id}/library", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetLibraries(Identifier identifier, - [FromQuery] string sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - ICollection resources = await _libraryManager.GetAll( - ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows)), - Sort.From(sortBy), - pagination - ); - - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) - return NotFound(); - return Page(resources, pagination.Limit); - } - /// /// Get collections containing this show /// diff --git a/back/src/Kyoo.Core/Views/Watch/WatchApi.cs b/back/src/Kyoo.Core/Views/Watch/WatchApi.cs deleted file mode 100644 index 24f53174..00000000 --- a/back/src/Kyoo.Core/Views/Watch/WatchApi.cs +++ /dev/null @@ -1,91 +0,0 @@ -// 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.Net.Http; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Abstractions.Models.Permissions; -using Kyoo.Abstractions.Models.Utils; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using static Kyoo.Abstractions.Models.Utils.Constants; - -namespace Kyoo.Core.Api -{ - /// - /// Retrieve information of an as a . - /// A watch item is another representation of an episode in a form easier to read and display for playback. - /// It contains streams (video, audio, subtitles) information, chapters, next and previous episodes and a bit of - /// information of the show. - /// - [Route("watch")] - [Route("watchitem", Order = AlternativeRoute)] - [ApiController] - [ApiDefinition("Watch Items", Group = WatchGroup)] - public class WatchApi : ControllerBase - { - /// - /// The library manager used to modify or retrieve information in the data store. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// The http client to reach transcoder. - /// - private readonly HttpClient _client; - - /// - /// Create a new . - /// - /// - /// The library manager used to modify or retrieve information in the data store. - /// - /// The http client to reach transcoder. - public WatchApi(ILibraryManager libraryManager, HttpClient client) - { - _libraryManager = libraryManager; - _client = client; - } - - /// - /// Get a watch item - /// - /// - /// Retrieve a watch item of an episode. - /// - /// The ID or slug of the . - /// A page of items. - /// No episode with the given ID or slug could be found. - [HttpGet("{identifier:id}")] - [Permission("watch", Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetWatchItem(Identifier identifier) - { - Episode item = await identifier.Match( - id => _libraryManager.GetOrDefault(id), - slug => _libraryManager.GetOrDefault(slug) - ); - if (item == null) - return NotFound(); - return await WatchItem.FromEpisode(item, _libraryManager, _client); - } - } -} diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index b5a15d25..bef2dd16 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -41,16 +41,16 @@ namespace Kyoo.Postgresql /// public abstract class DatabaseContext : DbContext { - /// - /// All libraries of Kyoo. See . - /// - public DbSet Libraries { get; set; } - /// /// All collections of Kyoo. See . /// public DbSet Collections { get; set; } + /// + /// All movies of Kyoo. See . + /// + public DbSet Movies { get; set; } + /// /// All shows of Kyoo. See . /// @@ -66,11 +66,6 @@ namespace Kyoo.Postgresql /// public DbSet Episodes { get; set; } - /// - /// All genres of Kyoo. See . - /// - public DbSet Genres { get; set; } - /// /// All people of Kyoo. See . /// @@ -91,18 +86,38 @@ namespace Kyoo.Postgresql /// public DbSet PeopleRoles { get; set; } - /// - /// Episodes with a watch percentage. See . - /// - public DbSet WatchedEpisodes { get; set; } - /// /// The list of library items (shows and collections that are part of a library - or the global one). /// /// /// This set is ready only, on most database this will be a view. /// - public DbSet LibraryItems { get; set; } + 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 + })); /// /// Add a many to many link between two resources. @@ -138,14 +153,6 @@ namespace Kyoo.Postgresql : base(options) { } - /// - /// Get the name of the metadata table of the given type. - /// - /// The type related to the metadata - /// The name of the table containing the metadata. - protected abstract string MetadataName() - where T : IMetadata; - /// /// Get the name of the link table of the two given types. /// @@ -265,15 +272,16 @@ namespace Kyoo.Postgresql .WithOne(x => x.Season) .OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity() + .HasOne(x => x.Studio) + .WithMany(x => x.Movies) + .OnDelete(DeleteBehavior.SetNull); modelBuilder.Entity() .HasOne(x => x.Studio) .WithMany(x => x.Shows) .OnDelete(DeleteBehavior.SetNull); - _HasManyToMany(modelBuilder, x => x.Collections, x => x.Libraries); - _HasManyToMany(modelBuilder, x => x.Shows, x => x.Libraries); _HasManyToMany(modelBuilder, x => x.Shows, x => x.Collections); - _HasManyToMany(modelBuilder, x => x.Genres, x => x.Shows); modelBuilder.Entity() .HasMany(x => x.Watched) @@ -281,14 +289,15 @@ namespace Kyoo.Postgresql .UsingEntity(x => x.ToTable(LinkName())); _HasMetadata(modelBuilder); + _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); - _HasImages(modelBuilder); _HasImages(modelBuilder); + _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); @@ -299,28 +308,15 @@ namespace Kyoo.Postgresql modelBuilder.Entity() .HasKey(x => new { User = x.UserID, Episode = x.EpisodeID }); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity().Property(x => x.Slug).IsRequired(); - modelBuilder.Entity() .HasIndex(x => x.Slug) .IsUnique(); - modelBuilder.Entity() - .HasIndex(x => x.Slug) - .IsUnique(); - modelBuilder.Entity() - .HasIndex(x => x.Slug) - .IsUnique(); modelBuilder.Entity() .HasIndex(x => x.Slug) .IsUnique(); + modelBuilder.Entity() + .HasIndex(x => x.Slug) + .IsUnique(); modelBuilder.Entity() .HasIndex(x => x.Slug) .IsUnique(); @@ -342,9 +338,6 @@ namespace Kyoo.Postgresql modelBuilder.Entity() .HasIndex(x => x.Slug) .IsUnique(); - - modelBuilder.Entity() - .ToView("library_items"); } /// diff --git a/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj index 2eb64ec0..44ff1a9d 100644 --- a/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj +++ b/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -18,4 +18,8 @@ + + + + diff --git a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs b/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs deleted file mode 100644 index 5321a0a1..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs +++ /dev/null @@ -1,872 +0,0 @@ -// 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 System.Collections.Generic; -using Kyoo.Abstractions.Models; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace Kyoo.Postgresql.Migrations -{ - /// - /// The initial migration that build most of the database. - /// - [DbContext(typeof(PostgresContext))] - [Migration("20210801171613_Initial")] - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:Enum:item_type", "show,movie,collection") - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .Annotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,attachment"); - - migrationBuilder.CreateTable( - name: "collections", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: false), - name = table.Column(type: "text", nullable: true), - images = table.Column>(type: "jsonb", nullable: true), - overview = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_collections", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "genres", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: false), - name = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_genres", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "libraries", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: false), - name = table.Column(type: "text", nullable: true), - paths = table.Column(type: "text[]", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_libraries", 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: "text", nullable: false), - name = table.Column(type: "text", nullable: true), - images = table.Column>(type: "jsonb", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_people", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "providers", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: false), - name = table.Column(type: "text", nullable: true), - images = table.Column>(type: "jsonb", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_providers", 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: "text", nullable: false), - name = table.Column(type: "text", nullable: true) - }, - 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: "text", nullable: false), - username = table.Column(type: "text", nullable: true), - email = table.Column(type: "text", nullable: true), - password = table.Column(type: "text", nullable: true), - permissions = table.Column(type: "text[]", nullable: true), - extra_data = table.Column>(type: "jsonb", nullable: true), - images = table.Column>(type: "jsonb", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_users", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "link_library_collection", - columns: table => new - { - collection_id = table.Column(type: "integer", nullable: false), - library_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_library_collection", x => new { x.collection_id, x.library_id }); - table.ForeignKey( - name: "fk_link_library_collection_collections_collection_id", - column: x => x.collection_id, - principalTable: "collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_library_collection_libraries_library_id", - column: x => x.library_id, - principalTable: "libraries", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "collection_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_collection_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_collection_metadata_id_collections_collection_id", - column: x => x.resource_id, - principalTable: "collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_collection_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "link_library_provider", - columns: table => new - { - library_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_library_provider", x => new { x.library_id, x.provider_id }); - table.ForeignKey( - name: "fk_link_library_provider_libraries_library_id", - column: x => x.library_id, - principalTable: "libraries", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_library_provider_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "people_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_people_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_people_metadata_id_people_people_id", - column: x => x.resource_id, - principalTable: "people", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_people_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "shows", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: false), - title = table.Column(type: "text", nullable: true), - aliases = table.Column(type: "text[]", nullable: true), - path = table.Column(type: "text", nullable: true), - overview = table.Column(type: "text", nullable: true), - status = table.Column(type: "status", nullable: false), - start_air = table.Column(type: "timestamp without time zone", nullable: true), - end_air = table.Column(type: "timestamp without time zone", nullable: true), - images = table.Column>(type: "jsonb", nullable: true), - is_movie = table.Column(type: "boolean", 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: "studio_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_studio_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_studio_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_studio_metadata_id_studios_studio_id", - column: x => x.resource_id, - principalTable: "studios", - 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_library_show", - columns: table => new - { - library_id = table.Column(type: "integer", nullable: false), - show_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_library_show", x => new { x.library_id, x.show_id }); - table.ForeignKey( - name: "fk_link_library_show_libraries_library_id", - column: x => x.library_id, - principalTable: "libraries", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_library_show_shows_show_id", - column: x => x.show_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "link_show_genre", - columns: table => new - { - genre_id = table.Column(type: "integer", nullable: false), - show_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_show_genre", x => new { x.genre_id, x.show_id }); - table.ForeignKey( - name: "fk_link_show_genre_genres_genre_id", - column: x => x.genre_id, - principalTable: "genres", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_show_genre_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: false), - type = table.Column(type: "text", nullable: true), - role = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_people_roles", x => x.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", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "seasons", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: true), - show_id = table.Column(type: "integer", nullable: false), - season_number = table.Column(type: "integer", nullable: false), - title = table.Column(type: "text", nullable: true), - overview = table.Column(type: "text", nullable: true), - start_date = table.Column(type: "timestamp without time zone", nullable: true), - end_date = table.Column(type: "timestamp without time zone", nullable: true), - images = table.Column>(type: "jsonb", nullable: true) - }, - 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: "show_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_show_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_show_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_show_metadata_id_shows_show_id", - column: x => x.resource_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: "text", nullable: true), - 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: true), - images = table.Column>(type: "jsonb", nullable: true), - title = table.Column(type: "text", nullable: true), - overview = table.Column(type: "text", nullable: true), - release_date = table.Column(type: "timestamp without time zone", nullable: true) - }, - 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: "season_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_season_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_season_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_season_metadata_id_seasons_season_id", - column: x => x.resource_id, - principalTable: "seasons", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "episode_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_episode_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_episode_metadata_id_episodes_episode_id", - column: x => x.resource_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_episode_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "tracks", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "text", nullable: true), - title = table.Column(type: "text", nullable: true), - language = table.Column(type: "text", nullable: true), - codec = table.Column(type: "text", nullable: true), - is_default = table.Column(type: "boolean", nullable: false), - is_forced = table.Column(type: "boolean", nullable: false), - is_external = table.Column(type: "boolean", nullable: false), - path = table.Column(type: "text", nullable: true), - type = table.Column(type: "stream_type", nullable: false), - episode_id = table.Column(type: "integer", nullable: false), - track_index = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_tracks", x => x.id); - table.ForeignKey( - name: "fk_tracks_episodes_episode_id", - column: x => x.episode_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "watched_episodes", - 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_episodes", x => new { x.user_id, x.episode_id }); - table.ForeignKey( - name: "fk_watched_episodes_episodes_episode_id", - column: x => x.episode_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_watched_episodes_users_user_id", - column: x => x.user_id, - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_collection_metadata_id_provider_id", - table: "collection_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_collections_slug", - table: "collections", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_episode_metadata_id_provider_id", - table: "episode_metadata_id", - column: "provider_id"); - - 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_genres_slug", - table: "genres", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_libraries_slug", - table: "libraries", - 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_library_collection_library_id", - table: "link_library_collection", - column: "library_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_library_provider_provider_id", - table: "link_library_provider", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_library_show_show_id", - table: "link_library_show", - column: "show_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_show_genre_show_id", - table: "link_show_genre", - column: "show_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_user_show_watched_id", - table: "link_user_show", - column: "watched_id"); - - migrationBuilder.CreateIndex( - name: "ix_people_slug", - table: "people", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_people_metadata_id_provider_id", - table: "people_metadata_id", - column: "provider_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_providers_slug", - table: "providers", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_season_metadata_id_provider_id", - table: "season_metadata_id", - column: "provider_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_show_metadata_id_provider_id", - table: "show_metadata_id", - column: "provider_id"); - - 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_studio_metadata_id_provider_id", - table: "studio_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_studios_slug", - table: "studios", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_tracks_episode_id_type_language_track_index_is_forced", - table: "tracks", - columns: new[] { "episode_id", "type", "language", "track_index", "is_forced" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_tracks_slug", - table: "tracks", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_users_slug", - table: "users", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_watched_episodes_episode_id", - table: "watched_episodes", - column: "episode_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "collection_metadata_id"); - - migrationBuilder.DropTable( - name: "episode_metadata_id"); - - migrationBuilder.DropTable( - name: "link_collection_show"); - - migrationBuilder.DropTable( - name: "link_library_collection"); - - migrationBuilder.DropTable( - name: "link_library_provider"); - - migrationBuilder.DropTable( - name: "link_library_show"); - - migrationBuilder.DropTable( - name: "link_show_genre"); - - migrationBuilder.DropTable( - name: "link_user_show"); - - migrationBuilder.DropTable( - name: "people_metadata_id"); - - migrationBuilder.DropTable( - name: "people_roles"); - - migrationBuilder.DropTable( - name: "season_metadata_id"); - - migrationBuilder.DropTable( - name: "show_metadata_id"); - - migrationBuilder.DropTable( - name: "studio_metadata_id"); - - migrationBuilder.DropTable( - name: "tracks"); - - migrationBuilder.DropTable( - name: "watched_episodes"); - - migrationBuilder.DropTable( - name: "collections"); - - migrationBuilder.DropTable( - name: "libraries"); - - migrationBuilder.DropTable( - name: "genres"); - - migrationBuilder.DropTable( - name: "people"); - - migrationBuilder.DropTable( - name: "providers"); - - 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/20210801171641_Triggers.cs b/back/src/Kyoo.Postgresql/Migrations/20210801171641_Triggers.cs deleted file mode 100644 index cc0468a5..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20210801171641_Triggers.cs +++ /dev/null @@ -1,192 +0,0 @@ -// 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.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Kyoo.Postgresql.Migrations -{ - /// - /// A migration that adds postgres triggers to update slugs. - /// - [DbContext(typeof(PostgresContext))] - [Migration("20210801171641_Triggers")] - public partial class Triggers : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE FUNCTION season_slug_update() - RETURNS TRIGGER - LANGUAGE PLPGSQL - AS $$ - BEGIN - NEW.slug := CONCAT( - (SELECT slug FROM shows WHERE id = NEW.show_id), - '-s', - NEW.season_number - ); - RETURN NEW; - END - $$;"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE TRIGGER season_slug_trigger BEFORE INSERT OR UPDATE OF season_number, show_id ON seasons - FOR EACH ROW EXECUTE PROCEDURE season_slug_update();"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE FUNCTION episode_slug_update() - RETURNS TRIGGER - LANGUAGE PLPGSQL - AS $$ - BEGIN - NEW.slug := CONCAT( - (SELECT slug FROM shows WHERE id = NEW.show_id), - CASE - WHEN NEW.season_number IS NULL AND NEW.episode_number IS NULL THEN NULL - WHEN NEW.season_number IS NULL THEN CONCAT('-', NEW.absolute_number) - ELSE CONCAT('-s', NEW.season_number, 'e', NEW.episode_number) - END - ); - RETURN NEW; - END - $$;"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE TRIGGER episode_slug_trigger - BEFORE INSERT OR UPDATE OF absolute_number, episode_number, season_number, show_id ON episodes - FOR EACH ROW EXECUTE PROCEDURE episode_slug_update();"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE FUNCTION show_slug_update() - RETURNS TRIGGER - LANGUAGE PLPGSQL - AS $$ - BEGIN - UPDATE seasons SET slug = CONCAT(NEW.slug, '-s', season_number) WHERE show_id = NEW.id; - UPDATE episodes SET slug = CASE - WHEN season_number IS NULL AND episode_number IS NULL THEN NEW.slug - WHEN season_number IS NULL THEN CONCAT(NEW.slug, '-', absolute_number) - ELSE CONCAT(NEW.slug, '-s', season_number, 'e', episode_number) - END WHERE show_id = NEW.id; - RETURN NEW; - END - $$;"); - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE TRIGGER show_slug_trigger AFTER UPDATE OF slug ON shows - FOR EACH ROW EXECUTE PROCEDURE show_slug_update();"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE FUNCTION episode_update_tracks_slug() - RETURNS TRIGGER - LANGUAGE PLPGSQL - AS $$ - BEGIN - UPDATE tracks SET slug = CONCAT( - NEW.slug, - '.', language, - CASE (track_index) - WHEN 0 THEN '' - ELSE CONCAT('-', track_index) - END, - CASE (is_forced) - WHEN false THEN '' - ELSE '.forced' - END, - '.', type - ) WHERE episode_id = NEW.id; - RETURN NEW; - END; - $$;"); - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE TRIGGER episode_track_slug_trigger AFTER UPDATE OF slug ON episodes - FOR EACH ROW EXECUTE PROCEDURE episode_update_tracks_slug();"); - - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE FUNCTION track_slug_update() - RETURNS TRIGGER - LANGUAGE PLPGSQL - AS $$ - BEGIN - IF NEW.track_index = 0 THEN - NEW.track_index := (SELECT COUNT(*) FROM tracks - WHERE episode_id = NEW.episode_id AND type = NEW.type - AND language = NEW.language AND is_forced = NEW.is_forced); - END IF; - NEW.slug := CONCAT( - (SELECT slug FROM episodes WHERE id = NEW.episode_id), - '.', COALESCE(NEW.language, 'und'), - CASE (NEW.track_index) - WHEN 0 THEN '' - ELSE CONCAT('-', NEW.track_index) - END, - CASE (NEW.is_forced) - WHEN false THEN '' - ELSE '.forced' - END, - '.', NEW.type - ); - RETURN NEW; - END - $$;"); - // language=PostgreSQL - migrationBuilder.Sql(@" - CREATE TRIGGER track_slug_trigger - BEFORE INSERT OR UPDATE OF episode_id, is_forced, language, track_index, type ON tracks - FOR EACH ROW EXECUTE PROCEDURE track_slug_update();"); - - MigrationHelper.CreateLibraryItemsView(migrationBuilder); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER show_slug_trigger ON shows;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION show_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP TRIGGER season_slug_trigger ON seasons;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION season_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER episode_slug_trigger ON episodes;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION episode_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER track_slug_trigger ON tracks;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION track_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER episode_track_slug_trigger ON episodes;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION episode_update_tracks_slug;"); - MigrationHelper.DropLibraryItemsView(migrationBuilder); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230724144449_RemoveTriggers.cs b/back/src/Kyoo.Postgresql/Migrations/20230724144449_RemoveTriggers.cs deleted file mode 100644 index f235cdf6..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230724144449_RemoveTriggers.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Kyoo.Postgresql.Migrations -{ - /// - /// Remove triggers - /// - [DbContext(typeof(PostgresContext))] - [Migration("20230724144449_RemoveTriggers")] - public partial class RemoveTriggers : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER show_slug_trigger ON shows;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION show_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP TRIGGER season_slug_trigger ON seasons;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION season_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER episode_slug_trigger ON episodes;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION episode_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER track_slug_trigger ON tracks;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION track_slug_update;"); - // language=PostgreSQL - migrationBuilder.Sql("DROP TRIGGER episode_track_slug_trigger ON episodes;"); - // language=PostgreSQL - migrationBuilder.Sql(@"DROP FUNCTION episode_update_tracks_slug;"); - - migrationBuilder.AlterColumn( - name: "slug", - table: "tracks", - type: "text", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "slug", - table: "seasons", - type: "text", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "slug", - table: "episodes", - type: "text", - nullable: false, - defaultValue: string.Empty, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "slug", - table: "tracks", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AlterColumn( - name: "slug", - table: "seasons", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AlterColumn( - name: "slug", - table: "episodes", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "text"); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230726100747_Timestamp.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230726100747_Timestamp.Designer.cs deleted file mode 100644 index 2a80f33b..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230726100747_Timestamp.Designer.cs +++ /dev/null @@ -1,1273 +0,0 @@ -// -using System; -using System.Collections.Generic; -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 -{ - partial class Timestamp - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_type", new[] { "show", "movie", "collection" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "stream_type", new[] { "unknown", "video", "audio", "subtitle" }); - 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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Path") - .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() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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.Genre", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_genres"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_genres_slug"); - - b.ToTable("genres", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Paths") - .HasColumnType("text[]") - .HasColumnName("paths"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_libraries"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_libraries_slug"); - - b.ToTable("libraries", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => - { - b.Property("ID") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("EndAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Slug") - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("StartAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_air"); - - b.Property("Status") - .HasColumnType("status") - .HasColumnName("status"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("item_type") - .HasColumnName("type"); - - b.HasKey("ID") - .HasName("pk_library_items"); - - b.ToTable((string)null); - - b.ToView("library_items", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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("PeopleID") - .HasColumnType("integer") - .HasColumnName("people_id"); - - b.Property("Role") - .HasColumnType("text") - .HasColumnName("role"); - - b.Property("ShowID") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.Property("Type") - .HasColumnType("text") - .HasColumnName("type"); - - b.HasKey("ID") - .HasName("pk_people_roles"); - - 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.Provider", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_providers"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_providers_slug"); - - b.ToTable("providers", (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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - 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() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("StartDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_date"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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") - .HasColumnType("text[]") - .HasColumnName("aliases"); - - b.Property("EndAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("IsMovie") - .HasColumnType("boolean") - .HasColumnName("is_movie"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Path") - .HasColumnType("text") - .HasColumnName("path"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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.Track", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Codec") - .HasColumnType("text") - .HasColumnName("codec"); - - b.Property("EpisodeID") - .HasColumnType("integer") - .HasColumnName("episode_id"); - - b.Property("IsDefault") - .HasColumnType("boolean") - .HasColumnName("is_default"); - - b.Property("IsExternal") - .HasColumnType("boolean") - .HasColumnName("is_external"); - - b.Property("IsForced") - .HasColumnType("boolean") - .HasColumnName("is_forced"); - - b.Property("Language") - .HasColumnType("text") - .HasColumnName("language"); - - b.Property("Path") - .HasColumnType("text") - .HasColumnName("path"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - b.Property("TrackIndex") - .HasColumnType("integer") - .HasColumnName("track_index"); - - b.Property("Type") - .HasColumnType("stream_type") - .HasColumnName("type"); - - b.HasKey("ID") - .HasName("pk_tracks"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_tracks_slug"); - - b.HasIndex("EpisodeID", "Type", "Language", "TrackIndex", "IsForced") - .IsUnique() - .HasDatabaseName("ix_tracks_episode_id_type_language_track_index_is_forced"); - - b.ToTable("tracks", (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") - .HasColumnType("text") - .HasColumnName("email"); - - b.Property>("ExtraData") - .HasColumnType("jsonb") - .HasColumnName("extra_data"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Password") - .HasColumnType("text") - .HasColumnName("password"); - - b.Property("Permissions") - .HasColumnType("text[]") - .HasColumnName("permissions"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("Username") - .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_episodes"); - - b.HasIndex("EpisodeID") - .HasDatabaseName("ix_watched_episodes_episode_id"); - - b.ToTable("watched_episodes", (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("collection_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_collection_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_collection_metadata_id_provider_id"); - - b.ToTable("collection_metadata_id", (string)null); - }); - - modelBuilder.Entity("episode_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_episode_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_episode_metadata_id_provider_id"); - - b.ToTable("episode_metadata_id", (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("link_library_collection", b => - { - b.Property("collection_id") - .HasColumnType("integer") - .HasColumnName("collection_id"); - - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.HasKey("collection_id", "library_id") - .HasName("pk_link_library_collection"); - - b.HasIndex("library_id") - .HasDatabaseName("ix_link_library_collection_library_id"); - - b.ToTable("link_library_collection", (string)null); - }); - - modelBuilder.Entity("link_library_provider", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("provider_id") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.HasKey("library_id", "provider_id") - .HasName("pk_link_library_provider"); - - b.HasIndex("provider_id") - .HasDatabaseName("ix_link_library_provider_provider_id"); - - b.ToTable("link_library_provider", (string)null); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("library_id", "show_id") - .HasName("pk_link_library_show"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_library_show_show_id"); - - b.ToTable("link_library_show", (string)null); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.Property("genre_id") - .HasColumnType("integer") - .HasColumnName("genre_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("genre_id", "show_id") - .HasName("pk_link_show_genre"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_show_genre_show_id"); - - b.ToTable("link_show_genre", (string)null); - }); - - modelBuilder.Entity("people_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_people_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_people_metadata_id_provider_id"); - - b.ToTable("people_metadata_id", (string)null); - }); - - modelBuilder.Entity("season_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_season_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_season_metadata_id_provider_id"); - - b.ToTable("season_metadata_id", (string)null); - }); - - modelBuilder.Entity("show_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_show_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_show_metadata_id_provider_id"); - - b.ToTable("show_metadata_id", (string)null); - }); - - modelBuilder.Entity("studio_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_studio_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_studio_metadata_id_provider_id"); - - b.ToTable("studio_metadata_id", (string)null); - }); - - 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.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => - { - 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") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_roles_shows_show_id"); - - 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.Navigation("Show"); - }); - - 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.Navigation("Studio"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Track", b => - { - b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") - .WithMany("Tracks") - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_tracks_episodes_episode_id"); - - b.Navigation("Episode"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => - { - b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") - .WithMany() - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_watched_episodes_episodes_episode_id"); - - b.HasOne("Kyoo.Abstractions.Models.User", null) - .WithMany("CurrentlyWatching") - .HasForeignKey("UserID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_watched_episodes_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("collection_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_metadata_id_collections_collection_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("episode_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_episode_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Episode", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_episode_metadata_id_episodes_episode_id"); - - b.Navigation("Provider"); - }); - - 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("link_library_collection", b => - { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("collection_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_collections_collection_id"); - - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_libraries_library_id"); - }); - - modelBuilder.Entity("link_library_provider", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_provider_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Provider", null) - .WithMany() - .HasForeignKey("provider_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_provider_providers_provider_id"); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_shows_show_id"); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.HasOne("Kyoo.Abstractions.Models.Genre", null) - .WithMany() - .HasForeignKey("genre_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_genres_genre_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_shows_show_id"); - }); - - modelBuilder.Entity("people_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.People", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_metadata_id_people_people_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("season_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_season_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Season", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_season_metadata_id_seasons_season_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("show_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_show_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_show_metadata_id_shows_show_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("studio_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_studio_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Studio", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_studio_metadata_id_studios_studio_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => - { - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Tracks"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Roles"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - - b.Navigation("People"); - - b.Navigation("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => - { - b.Navigation("ExternalIDs"); - - 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/20230726100747_Timestamp.cs b/back/src/Kyoo.Postgresql/Migrations/20230726100747_Timestamp.cs deleted file mode 100644 index 3fd9cd6b..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230726100747_Timestamp.cs +++ /dev/null @@ -1,138 +0,0 @@ -// 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 Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Kyoo.Postgresql.Migrations -{ - /// - [DbContext(typeof(PostgresContext))] - [Migration("20230726100747_Timestamp")] - public partial class Timestamp : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - MigrationHelper.DropLibraryItemsView(migrationBuilder); - - migrationBuilder.AlterColumn( - name: "start_air", - table: "shows", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp without time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "end_air", - table: "shows", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp without time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "start_date", - table: "seasons", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp without time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "end_date", - table: "seasons", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp without time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "release_date", - table: "episodes", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp without time zone", - oldNullable: true); - - MigrationHelper.CreateLibraryItemsView(migrationBuilder); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - MigrationHelper.DropLibraryItemsView(migrationBuilder); - - migrationBuilder.AlterColumn( - name: "start_air", - table: "shows", - type: "timestamp without time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "end_air", - table: "shows", - type: "timestamp without time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "start_date", - table: "seasons", - type: "timestamp without time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "end_date", - table: "seasons", - type: "timestamp without time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "release_date", - table: "episodes", - type: "timestamp without time zone", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true); - - MigrationHelper.CreateLibraryItemsView(migrationBuilder); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230731065523_RemoveTracks.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230731065523_RemoveTracks.Designer.cs deleted file mode 100644 index e86a0b3f..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230731065523_RemoveTracks.Designer.cs +++ /dev/null @@ -1,1189 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Kyoo.Abstractions.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Kyoo.Postgresql.Migrations -{ - [DbContext(typeof(PostgresContext))] - [Migration("20230731065523_RemoveTracks")] - partial class RemoveTracks - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_type", 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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Path") - .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() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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.Genre", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_genres"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_genres_slug"); - - b.ToTable("genres", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Paths") - .HasColumnType("text[]") - .HasColumnName("paths"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_libraries"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_libraries_slug"); - - b.ToTable("libraries", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => - { - b.Property("ID") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("EndAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Slug") - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("StartAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_air"); - - b.Property("Status") - .HasColumnType("status") - .HasColumnName("status"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("item_type") - .HasColumnName("type"); - - b.HasKey("ID") - .HasName("pk_library_items"); - - b.ToTable((string)null); - - b.ToView("library_items", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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("PeopleID") - .HasColumnType("integer") - .HasColumnName("people_id"); - - b.Property("Role") - .HasColumnType("text") - .HasColumnName("role"); - - b.Property("ShowID") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.Property("Type") - .HasColumnType("text") - .HasColumnName("type"); - - b.HasKey("ID") - .HasName("pk_people_roles"); - - 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.Provider", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_providers"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_providers_slug"); - - b.ToTable("providers", (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>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - 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() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("StartDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_date"); - - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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") - .HasColumnType("text[]") - .HasColumnName("aliases"); - - b.Property("EndAir") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("IsMovie") - .HasColumnType("boolean") - .HasColumnName("is_movie"); - - b.Property("Overview") - .HasColumnType("text") - .HasColumnName("overview"); - - b.Property("Path") - .HasColumnType("text") - .HasColumnName("path"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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("Title") - .HasColumnType("text") - .HasColumnName("title"); - - 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("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .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") - .HasColumnType("text") - .HasColumnName("email"); - - b.Property>("ExtraData") - .HasColumnType("jsonb") - .HasColumnName("extra_data"); - - b.Property>("Images") - .HasColumnType("jsonb") - .HasColumnName("images"); - - b.Property("Password") - .HasColumnType("text") - .HasColumnName("password"); - - b.Property("Permissions") - .HasColumnType("text[]") - .HasColumnName("permissions"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.Property("Username") - .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_episodes"); - - b.HasIndex("EpisodeID") - .HasDatabaseName("ix_watched_episodes_episode_id"); - - b.ToTable("watched_episodes", (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("collection_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_collection_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_collection_metadata_id_provider_id"); - - b.ToTable("collection_metadata_id", (string)null); - }); - - modelBuilder.Entity("episode_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_episode_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_episode_metadata_id_provider_id"); - - b.ToTable("episode_metadata_id", (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("link_library_collection", b => - { - b.Property("collection_id") - .HasColumnType("integer") - .HasColumnName("collection_id"); - - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.HasKey("collection_id", "library_id") - .HasName("pk_link_library_collection"); - - b.HasIndex("library_id") - .HasDatabaseName("ix_link_library_collection_library_id"); - - b.ToTable("link_library_collection", (string)null); - }); - - modelBuilder.Entity("link_library_provider", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("provider_id") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.HasKey("library_id", "provider_id") - .HasName("pk_link_library_provider"); - - b.HasIndex("provider_id") - .HasDatabaseName("ix_link_library_provider_provider_id"); - - b.ToTable("link_library_provider", (string)null); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("library_id", "show_id") - .HasName("pk_link_library_show"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_library_show_show_id"); - - b.ToTable("link_library_show", (string)null); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.Property("genre_id") - .HasColumnType("integer") - .HasColumnName("genre_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("genre_id", "show_id") - .HasName("pk_link_show_genre"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_show_genre_show_id"); - - b.ToTable("link_show_genre", (string)null); - }); - - modelBuilder.Entity("people_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_people_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_people_metadata_id_provider_id"); - - b.ToTable("people_metadata_id", (string)null); - }); - - modelBuilder.Entity("season_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_season_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_season_metadata_id_provider_id"); - - b.ToTable("season_metadata_id", (string)null); - }); - - modelBuilder.Entity("show_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_show_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_show_metadata_id_provider_id"); - - b.ToTable("show_metadata_id", (string)null); - }); - - modelBuilder.Entity("studio_metadata_id", b => - { - b.Property("ResourceID") - .HasColumnType("integer") - .HasColumnName("resource_id"); - - b.Property("ProviderID") - .HasColumnType("integer") - .HasColumnName("provider_id"); - - b.Property("DataID") - .HasColumnType("text") - .HasColumnName("data_id"); - - b.Property("Link") - .HasColumnType("text") - .HasColumnName("link"); - - b.HasKey("ResourceID", "ProviderID") - .HasName("pk_studio_metadata_id"); - - b.HasIndex("ProviderID") - .HasDatabaseName("ix_studio_metadata_id_provider_id"); - - b.ToTable("studio_metadata_id", (string)null); - }); - - 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.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => - { - 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") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_roles_shows_show_id"); - - 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.Navigation("Show"); - }); - - 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.Navigation("Studio"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => - { - b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") - .WithMany() - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_watched_episodes_episodes_episode_id"); - - b.HasOne("Kyoo.Abstractions.Models.User", null) - .WithMany("CurrentlyWatching") - .HasForeignKey("UserID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_watched_episodes_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("collection_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_collection_metadata_id_collections_collection_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("episode_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_episode_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Episode", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_episode_metadata_id_episodes_episode_id"); - - b.Navigation("Provider"); - }); - - 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("link_library_collection", b => - { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("collection_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_collections_collection_id"); - - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_libraries_library_id"); - }); - - modelBuilder.Entity("link_library_provider", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_provider_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Provider", null) - .WithMany() - .HasForeignKey("provider_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_provider_providers_provider_id"); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_shows_show_id"); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.HasOne("Kyoo.Abstractions.Models.Genre", null) - .WithMany() - .HasForeignKey("genre_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_genres_genre_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_shows_show_id"); - }); - - modelBuilder.Entity("people_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.People", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_people_metadata_id_people_people_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("season_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_season_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Season", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_season_metadata_id_seasons_season_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("show_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_show_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_show_metadata_id_shows_show_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("studio_metadata_id", b => - { - b.HasOne("Kyoo.Abstractions.Models.Provider", "Provider") - .WithMany() - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_studio_metadata_id_providers_provider_id"); - - b.HasOne("Kyoo.Abstractions.Models.Studio", null) - .WithMany("ExternalIDs") - .HasForeignKey("ResourceID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_studio_metadata_id_studios_studio_id"); - - b.Navigation("Provider"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => - { - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => - { - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Roles"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - - b.Navigation("People"); - - b.Navigation("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => - { - b.Navigation("ExternalIDs"); - - 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/20230731065523_RemoveTracks.cs b/back/src/Kyoo.Postgresql/Migrations/20230731065523_RemoveTracks.cs deleted file mode 100644 index a9e58f16..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230731065523_RemoveTracks.cs +++ /dev/null @@ -1,95 +0,0 @@ -// 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; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Kyoo.Postgresql.Migrations -{ - /// - public partial class RemoveTracks : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "tracks"); - - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:Enum:item_type", "show,movie,collection") - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation("Npgsql:Enum:item_type", "show,movie,collection") - .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:Enum:item_type", "show,movie,collection") - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .Annotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle") - .OldAnnotation("Npgsql:Enum:item_type", "show,movie,collection") - .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned"); - - migrationBuilder.CreateTable( - name: "tracks", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - episode_id = table.Column(type: "integer", nullable: false), - codec = table.Column(type: "text", nullable: true), - is_default = table.Column(type: "boolean", nullable: false), - is_external = table.Column(type: "boolean", nullable: false), - is_forced = table.Column(type: "boolean", nullable: false), - language = table.Column(type: "text", nullable: true), - path = table.Column(type: "text", nullable: true), - slug = table.Column(type: "text", nullable: false), - title = table.Column(type: "text", nullable: true), - track_index = table.Column(type: "integer", nullable: false), - type = table.Column(type: "stream_type", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_tracks", x => x.id); - table.ForeignKey( - name: "fk_tracks_episodes_episode_id", - column: x => x.episode_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_tracks_episode_id_type_language_track_index_is_forced", - table: "tracks", - columns: new[] { "episode_id", "type", "language", "track_index", "is_forced" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_tracks_slug", - table: "tracks", - column: "slug", - unique: true); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.cs b/back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.cs deleted file mode 100644 index 98a3a9af..00000000 --- a/back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.cs +++ /dev/null @@ -1,772 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Kyoo.Postgresql.Migrations -{ - /// - public partial class AddBlurhash : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - MigrationHelper.DropLibraryItemsView(migrationBuilder); - - migrationBuilder.DropTable( - name: "collection_metadata_id"); - - migrationBuilder.DropTable( - name: "episode_metadata_id"); - - migrationBuilder.DropTable( - name: "link_library_provider"); - - migrationBuilder.DropTable( - name: "people_metadata_id"); - - migrationBuilder.DropTable( - name: "season_metadata_id"); - - migrationBuilder.DropTable( - name: "show_metadata_id"); - - migrationBuilder.DropTable( - name: "studio_metadata_id"); - - migrationBuilder.DropTable( - name: "providers"); - - migrationBuilder.DropColumn( - name: "images", - table: "users"); - - migrationBuilder.DropColumn( - name: "images", - table: "shows"); - - migrationBuilder.DropColumn( - name: "images", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "images", - table: "people"); - - migrationBuilder.DropColumn( - name: "images", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "images", - table: "collections"); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "users", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "users", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "studios", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "shows", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "shows", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "shows", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_blurhash", - table: "shows", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_source", - table: "shows", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_blurhash", - table: "shows", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_source", - table: "shows", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "trailer", - table: "shows", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "seasons", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "seasons", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "seasons", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_blurhash", - table: "seasons", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_source", - table: "seasons", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_blurhash", - table: "seasons", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_source", - table: "seasons", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "people", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "people", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "people", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_blurhash", - table: "people", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_source", - table: "people", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_blurhash", - table: "people", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_source", - table: "people", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "episodes", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "episodes", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "episodes", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_blurhash", - table: "episodes", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_source", - table: "episodes", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_blurhash", - table: "episodes", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_source", - table: "episodes", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "external_id", - table: "collections", - type: "json", - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_blurhash", - table: "collections", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "logo_source", - table: "collections", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_blurhash", - table: "collections", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "poster_source", - table: "collections", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_blurhash", - table: "collections", - type: "character varying(32)", - maxLength: 32, - nullable: true); - - migrationBuilder.AddColumn( - name: "thumbnail_source", - table: "collections", - type: "text", - nullable: true); - - MigrationHelper.CreateLibraryItemsView(migrationBuilder); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - MigrationHelper.DropLibraryItemsView(migrationBuilder); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "users"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "users"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "studios"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "shows"); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "shows"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "shows"); - - migrationBuilder.DropColumn( - name: "poster_blurhash", - table: "shows"); - - migrationBuilder.DropColumn( - name: "poster_source", - table: "shows"); - - migrationBuilder.DropColumn( - name: "thumbnail_blurhash", - table: "shows"); - - migrationBuilder.DropColumn( - name: "thumbnail_source", - table: "shows"); - - migrationBuilder.DropColumn( - name: "trailer", - table: "shows"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "poster_blurhash", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "poster_source", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "thumbnail_blurhash", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "thumbnail_source", - table: "seasons"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "people"); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "people"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "people"); - - migrationBuilder.DropColumn( - name: "poster_blurhash", - table: "people"); - - migrationBuilder.DropColumn( - name: "poster_source", - table: "people"); - - migrationBuilder.DropColumn( - name: "thumbnail_blurhash", - table: "people"); - - migrationBuilder.DropColumn( - name: "thumbnail_source", - table: "people"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "poster_blurhash", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "poster_source", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "thumbnail_blurhash", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "thumbnail_source", - table: "episodes"); - - migrationBuilder.DropColumn( - name: "external_id", - table: "collections"); - - migrationBuilder.DropColumn( - name: "logo_blurhash", - table: "collections"); - - migrationBuilder.DropColumn( - name: "logo_source", - table: "collections"); - - migrationBuilder.DropColumn( - name: "poster_blurhash", - table: "collections"); - - migrationBuilder.DropColumn( - name: "poster_source", - table: "collections"); - - migrationBuilder.DropColumn( - name: "thumbnail_blurhash", - table: "collections"); - - migrationBuilder.DropColumn( - name: "thumbnail_source", - table: "collections"); - - migrationBuilder.AddColumn>( - name: "images", - table: "users", - type: "jsonb", - nullable: true); - - migrationBuilder.AddColumn>( - name: "images", - table: "shows", - type: "jsonb", - nullable: true); - - migrationBuilder.AddColumn>( - name: "images", - table: "seasons", - type: "jsonb", - nullable: true); - - migrationBuilder.AddColumn>( - name: "images", - table: "people", - type: "jsonb", - nullable: true); - - migrationBuilder.AddColumn>( - name: "images", - table: "episodes", - type: "jsonb", - nullable: true); - - migrationBuilder.AddColumn>( - name: "images", - table: "collections", - type: "jsonb", - nullable: true); - - migrationBuilder.CreateTable( - name: "providers", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - images = table.Column>(type: "jsonb", nullable: true), - name = table.Column(type: "text", nullable: true), - slug = table.Column(type: "text", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_providers", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "collection_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_collection_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_collection_metadata_id_collections_collection_id", - column: x => x.resource_id, - principalTable: "collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_collection_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "episode_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_episode_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_episode_metadata_id_episodes_episode_id", - column: x => x.resource_id, - principalTable: "episodes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_episode_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "link_library_provider", - columns: table => new - { - library_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_link_library_provider", x => new { x.library_id, x.provider_id }); - table.ForeignKey( - name: "fk_link_library_provider_libraries_library_id", - column: x => x.library_id, - principalTable: "libraries", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_link_library_provider_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "people_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_people_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_people_metadata_id_people_people_id", - column: x => x.resource_id, - principalTable: "people", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_people_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "season_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_season_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_season_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_season_metadata_id_seasons_season_id", - column: x => x.resource_id, - principalTable: "seasons", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "show_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_show_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_show_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_show_metadata_id_shows_show_id", - column: x => x.resource_id, - principalTable: "shows", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "studio_metadata_id", - columns: table => new - { - resource_id = table.Column(type: "integer", nullable: false), - provider_id = table.Column(type: "integer", nullable: false), - data_id = table.Column(type: "text", nullable: true), - link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_studio_metadata_id", x => new { x.resource_id, x.provider_id }); - table.ForeignKey( - name: "fk_studio_metadata_id_providers_provider_id", - column: x => x.provider_id, - principalTable: "providers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_studio_metadata_id_studios_studio_id", - column: x => x.resource_id, - principalTable: "studios", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_collection_metadata_id_provider_id", - table: "collection_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_episode_metadata_id_provider_id", - table: "episode_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_link_library_provider_provider_id", - table: "link_library_provider", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_people_metadata_id_provider_id", - table: "people_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_providers_slug", - table: "providers", - column: "slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_season_metadata_id_provider_id", - table: "season_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_show_metadata_id_provider_id", - table: "show_metadata_id", - column: "provider_id"); - - migrationBuilder.CreateIndex( - name: "ix_studio_metadata_id_provider_id", - table: "studio_metadata_id", - column: "provider_id"); - - MigrationHelper.CreateLibraryItemsView(migrationBuilder); - } - } -} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.Designer.cs similarity index 80% rename from back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.Designer.cs rename to back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.Designer.cs index cc630b9f..98114327 100644 --- a/back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.Designer.cs +++ b/back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.Designer.cs @@ -1,6 +1,5 @@ // using System; -using System.Collections.Generic; using Kyoo.Abstractions.Models; using Kyoo.Postgresql; using Microsoft.EntityFrameworkCore; @@ -14,8 +13,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Kyoo.Postgresql.Migrations { [DbContext(typeof(PostgresContext))] - [Migration("20230804143919_AddBlurhash")] - partial class AddBlurhash + [Migration("20230805051120_initial")] + partial class initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -25,10 +24,29 @@ namespace Kyoo.Postgresql.Migrations .HasAnnotation("ProductVersion", "7.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 63); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_type", new[] { "show", "movie", "collection" }); + 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, "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") @@ -38,11 +56,13 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); @@ -52,7 +72,8 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -82,15 +103,21 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("episode_number"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .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"); @@ -112,13 +139,10 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - b.HasKey("ID") .HasName("pk_episodes"); @@ -136,7 +160,7 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("episodes", (string)null); }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Genre", b => + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.Property("ID") .ValueGeneratedOnAdd() @@ -145,97 +169,77 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_genres"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_genres_slug"); - - b.ToTable("genres", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Paths") - .HasColumnType("text[]") - .HasColumnName("paths"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_libraries"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_libraries_slug"); - - b.ToTable("libraries", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => - { - b.Property("ID") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("EndAir") + b.Property("AirDate") .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); + .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("Slug") + 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") + b.Property("Status") .HasColumnType("status") .HasColumnName("status"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); + b.Property("StudioID") + .HasColumnType("integer") + .HasColumnName("studio_id"); - b.Property("Type") - .HasColumnType("item_type") - .HasColumnName("type"); + 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"); + .HasName("pk_movies"); - b.ToTable((string)null); + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_movies_slug"); - b.ToView("library_items", (string)null); + b.HasIndex("StudioID") + .HasDatabaseName("ix_movies_studio_id"); + + b.ToTable("movies", (string)null); }); modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => @@ -247,17 +251,20 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -279,25 +286,34 @@ namespace Kyoo.Postgresql.Migrations 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") + 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"); @@ -320,9 +336,14 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("end_date"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); b.Property("Overview") .HasColumnType("text") @@ -338,17 +359,14 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("StartDate") .HasColumnType("timestamp with time zone") .HasColumnName("start_date"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - b.HasKey("ID") .HasName("pk_seasons"); @@ -373,6 +391,7 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); b.Property("Aliases") + .IsRequired() .HasColumnType("text[]") .HasColumnName("aliases"); @@ -380,25 +399,29 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("end_air"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); - b.Property("IsMovie") - .HasColumnType("boolean") - .HasColumnName("is_movie"); + 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") - .HasColumnType("text") - .HasColumnName("path"); - b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("StartAir") @@ -413,9 +436,14 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("studio_id"); - b.Property("Title") + b.Property("Tagline") .HasColumnType("text") - .HasColumnName("title"); + .HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); b.Property("Trailer") .HasColumnType("text") @@ -443,17 +471,20 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -476,27 +507,28 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); b.Property("Email") + .IsRequired() .HasColumnType("text") .HasColumnName("email"); - b.Property>("ExtraData") - .HasColumnType("jsonb") - .HasColumnName("extra_data"); - b.Property("Password") + .IsRequired() .HasColumnType("text") .HasColumnName("password"); b.Property("Permissions") + .IsRequired() .HasColumnType("text[]") .HasColumnName("permissions"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("Username") + .IsRequired() .HasColumnType("text") .HasColumnName("username"); @@ -525,12 +557,12 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("watched_percentage"); b.HasKey("UserID", "EpisodeID") - .HasName("pk_watched_episodes"); + .HasName("pk_watched_episode"); b.HasIndex("EpisodeID") - .HasDatabaseName("ix_watched_episodes_episode_id"); + .HasDatabaseName("ix_watched_episode_episode_id"); - b.ToTable("watched_episodes", (string)null); + b.ToTable("watched_episode", (string)null); }); modelBuilder.Entity("ShowUser", b => @@ -571,61 +603,21 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_collection_show", (string)null); }); - modelBuilder.Entity("link_library_collection", b => + modelBuilder.Entity("CollectionMovie", b => { - b.Property("collection_id") - .HasColumnType("integer") - .HasColumnName("collection_id"); + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("CollectionsID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_collection_movie_collections_collections_id"); - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.HasKey("collection_id", "library_id") - .HasName("pk_link_library_collection"); - - b.HasIndex("library_id") - .HasDatabaseName("ix_link_library_collection_library_id"); - - b.ToTable("link_library_collection", (string)null); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("library_id", "show_id") - .HasName("pk_link_library_show"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_library_show_show_id"); - - b.ToTable("link_library_show", (string)null); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.Property("genre_id") - .HasColumnType("integer") - .HasColumnName("genre_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("genre_id", "show_id") - .HasName("pk_link_show_genre"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_show_genre_show_id"); - - b.ToTable("link_show_genre", (string)null); + 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 => @@ -637,11 +629,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -661,11 +655,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -685,11 +681,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -731,11 +729,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -755,11 +755,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -779,11 +781,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -807,87 +811,98 @@ namespace Kyoo.Postgresql.Migrations b.Navigation("Thumbnail"); }); - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + 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("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("logo_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { - b1.Property("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("poster_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { - b1.Property("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("thumbnail_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.Navigation("Logo"); b.Navigation("Poster"); + b.Navigation("Studio"); + b.Navigation("Thumbnail"); }); @@ -900,11 +915,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -924,11 +941,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -948,11 +967,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -974,6 +995,11 @@ namespace Kyoo.Postgresql.Migrations 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") @@ -984,10 +1010,10 @@ namespace Kyoo.Postgresql.Migrations b.HasOne("Kyoo.Abstractions.Models.Show", "Show") .WithMany("People") .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() .HasConstraintName("fk_people_roles_shows_show_id"); + b.Navigation("Movie"); + b.Navigation("People"); b.Navigation("Show"); @@ -1009,11 +1035,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1033,11 +1061,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -1057,11 +1087,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -1098,11 +1130,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1122,11 +1156,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -1146,11 +1182,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -1181,11 +1219,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1208,14 +1248,14 @@ namespace Kyoo.Postgresql.Migrations .HasForeignKey("EpisodeID") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_watched_episodes_episodes_episode_id"); + .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_episodes_users_user_id"); + .HasConstraintName("fk_watched_episode_users_user_id"); b.Navigation("Episode"); }); @@ -1254,55 +1294,9 @@ namespace Kyoo.Postgresql.Migrations .HasConstraintName("fk_link_collection_show_shows_show_id"); }); - modelBuilder.Entity("link_library_collection", b => + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("collection_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_collections_collection_id"); - - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_libraries_library_id"); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_shows_show_id"); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.HasOne("Kyoo.Abstractions.Models.Genre", null) - .WithMany() - .HasForeignKey("genre_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_genres_genre_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_shows_show_id"); + b.Navigation("People"); }); modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => @@ -1326,6 +1320,8 @@ namespace Kyoo.Postgresql.Migrations modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => { + b.Navigation("Movies"); + b.Navigation("Shows"); }); diff --git a/back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.cs b/back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.cs new file mode 100644 index 00000000..40e8dd3a --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.cs @@ -0,0 +1,528 @@ +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/PostgresContextModelSnapshot.cs b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs index 69fc5caf..93540795 100644 --- a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs +++ b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs @@ -1,6 +1,5 @@ // using System; -using System.Collections.Generic; using Kyoo.Abstractions.Models; using Kyoo.Postgresql; using Microsoft.EntityFrameworkCore; @@ -22,10 +21,29 @@ namespace Kyoo.Postgresql.Migrations .HasAnnotation("ProductVersion", "7.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 63); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_type", new[] { "show", "movie", "collection" }); + 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, "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") @@ -35,11 +53,13 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); @@ -49,7 +69,8 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -79,15 +100,21 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("episode_number"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .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"); @@ -109,13 +136,10 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - b.HasKey("ID") .HasName("pk_episodes"); @@ -133,7 +157,7 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("episodes", (string)null); }); - modelBuilder.Entity("Kyoo.Abstractions.Models.Genre", b => + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { b.Property("ID") .ValueGeneratedOnAdd() @@ -142,97 +166,77 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_genres"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_genres_slug"); - - b.ToTable("genres", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("Paths") - .HasColumnType("text[]") - .HasColumnName("paths"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text") - .HasColumnName("slug"); - - b.HasKey("ID") - .HasName("pk_libraries"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("ix_libraries_slug"); - - b.ToTable("libraries", (string)null); - }); - - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => - { - b.Property("ID") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("EndAir") + b.Property("AirDate") .HasColumnType("timestamp with time zone") - .HasColumnName("end_air"); + .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("Slug") + 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") + b.Property("Status") .HasColumnType("status") .HasColumnName("status"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); + b.Property("StudioID") + .HasColumnType("integer") + .HasColumnName("studio_id"); - b.Property("Type") - .HasColumnType("item_type") - .HasColumnName("type"); + 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"); + .HasName("pk_movies"); - b.ToTable((string)null); + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_movies_slug"); - b.ToView("library_items", (string)null); + b.HasIndex("StudioID") + .HasDatabaseName("ix_movies_studio_id"); + + b.ToTable("movies", (string)null); }); modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => @@ -244,17 +248,20 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -276,25 +283,34 @@ namespace Kyoo.Postgresql.Migrations 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") + 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"); @@ -317,9 +333,14 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("end_date"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); b.Property("Overview") .HasColumnType("text") @@ -335,17 +356,14 @@ namespace Kyoo.Postgresql.Migrations b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("StartDate") .HasColumnType("timestamp with time zone") .HasColumnName("start_date"); - b.Property("Title") - .HasColumnType("text") - .HasColumnName("title"); - b.HasKey("ID") .HasName("pk_seasons"); @@ -370,6 +388,7 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); b.Property("Aliases") + .IsRequired() .HasColumnType("text[]") .HasColumnName("aliases"); @@ -377,25 +396,29 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("end_air"); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); - b.Property("IsMovie") - .HasColumnType("boolean") - .HasColumnName("is_movie"); + 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") - .HasColumnType("text") - .HasColumnName("path"); - b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("StartAir") @@ -410,9 +433,14 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("studio_id"); - b.Property("Title") + b.Property("Tagline") .HasColumnType("text") - .HasColumnName("title"); + .HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); b.Property("Trailer") .HasColumnType("text") @@ -440,17 +468,20 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); - b.Property("ExternalIDs") + b.Property("ExternalId") + .IsRequired() .HasColumnType("json") - .HasColumnName("external_i_ds"); + .HasColumnName("external_id"); b.Property("Name") + .IsRequired() .HasColumnType("text") .HasColumnName("name"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.HasKey("ID") @@ -473,27 +504,28 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID")); b.Property("Email") + .IsRequired() .HasColumnType("text") .HasColumnName("email"); - b.Property>("ExtraData") - .HasColumnType("jsonb") - .HasColumnName("extra_data"); - b.Property("Password") + .IsRequired() .HasColumnType("text") .HasColumnName("password"); b.Property("Permissions") + .IsRequired() .HasColumnType("text[]") .HasColumnName("permissions"); b.Property("Slug") .IsRequired() - .HasColumnType("text") + .HasMaxLength(256) + .HasColumnType("character varying(256)") .HasColumnName("slug"); b.Property("Username") + .IsRequired() .HasColumnType("text") .HasColumnName("username"); @@ -522,12 +554,12 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("watched_percentage"); b.HasKey("UserID", "EpisodeID") - .HasName("pk_watched_episodes"); + .HasName("pk_watched_episode"); b.HasIndex("EpisodeID") - .HasDatabaseName("ix_watched_episodes_episode_id"); + .HasDatabaseName("ix_watched_episode_episode_id"); - b.ToTable("watched_episodes", (string)null); + b.ToTable("watched_episode", (string)null); }); modelBuilder.Entity("ShowUser", b => @@ -568,61 +600,21 @@ namespace Kyoo.Postgresql.Migrations b.ToTable("link_collection_show", (string)null); }); - modelBuilder.Entity("link_library_collection", b => + modelBuilder.Entity("CollectionMovie", b => { - b.Property("collection_id") - .HasColumnType("integer") - .HasColumnName("collection_id"); + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("CollectionsID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_collection_movie_collections_collections_id"); - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.HasKey("collection_id", "library_id") - .HasName("pk_link_library_collection"); - - b.HasIndex("library_id") - .HasDatabaseName("ix_link_library_collection_library_id"); - - b.ToTable("link_library_collection", (string)null); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.Property("library_id") - .HasColumnType("integer") - .HasColumnName("library_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("library_id", "show_id") - .HasName("pk_link_library_show"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_library_show_show_id"); - - b.ToTable("link_library_show", (string)null); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.Property("genre_id") - .HasColumnType("integer") - .HasColumnName("genre_id"); - - b.Property("show_id") - .HasColumnType("integer") - .HasColumnName("show_id"); - - b.HasKey("genre_id", "show_id") - .HasName("pk_link_show_genre"); - - b.HasIndex("show_id") - .HasDatabaseName("ix_link_show_genre_show_id"); - - b.ToTable("link_show_genre", (string)null); + 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 => @@ -634,11 +626,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -658,11 +652,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -682,11 +678,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -728,11 +726,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -752,11 +752,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -776,11 +778,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -804,87 +808,98 @@ namespace Kyoo.Postgresql.Migrations b.Navigation("Thumbnail"); }); - modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + 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("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("logo_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => { - b1.Property("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("poster_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => { - b1.Property("LibraryItemID") + b1.Property("MovieID") .HasColumnType("integer") - .HasColumnName("library_item_id"); + .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") - .HasColumnName("blurhash"); + .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") - .HasColumnName("source"); + .HasColumnName("thumbnail_source"); - b1.HasKey("LibraryItemID"); + b1.HasKey("MovieID"); - b1.ToTable((string)null); - - b1.ToView("library_items"); + b1.ToTable("movies"); b1.WithOwner() - .HasForeignKey("LibraryItemID"); + .HasForeignKey("MovieID") + .HasConstraintName("fk_movies_movies_id"); }); b.Navigation("Logo"); b.Navigation("Poster"); + b.Navigation("Studio"); + b.Navigation("Thumbnail"); }); @@ -897,11 +912,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -921,11 +938,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -945,11 +964,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -971,6 +992,11 @@ namespace Kyoo.Postgresql.Migrations 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") @@ -981,10 +1007,10 @@ namespace Kyoo.Postgresql.Migrations b.HasOne("Kyoo.Abstractions.Models.Show", "Show") .WithMany("People") .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() .HasConstraintName("fk_people_roles_shows_show_id"); + b.Navigation("Movie"); + b.Navigation("People"); b.Navigation("Show"); @@ -1006,11 +1032,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1030,11 +1058,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -1054,11 +1084,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -1095,11 +1127,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1119,11 +1153,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("poster_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("poster_source"); @@ -1143,11 +1179,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("thumbnail_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("thumbnail_source"); @@ -1178,11 +1216,13 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("id"); b1.Property("Blurhash") + .IsRequired() .HasMaxLength(32) .HasColumnType("character varying(32)") .HasColumnName("logo_blurhash"); b1.Property("Source") + .IsRequired() .HasColumnType("text") .HasColumnName("logo_source"); @@ -1205,14 +1245,14 @@ namespace Kyoo.Postgresql.Migrations .HasForeignKey("EpisodeID") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_watched_episodes_episodes_episode_id"); + .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_episodes_users_user_id"); + .HasConstraintName("fk_watched_episode_users_user_id"); b.Navigation("Episode"); }); @@ -1251,55 +1291,9 @@ namespace Kyoo.Postgresql.Migrations .HasConstraintName("fk_link_collection_show_shows_show_id"); }); - modelBuilder.Entity("link_library_collection", b => + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => { - b.HasOne("Kyoo.Abstractions.Models.Collection", null) - .WithMany() - .HasForeignKey("collection_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_collections_collection_id"); - - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_collection_libraries_library_id"); - }); - - modelBuilder.Entity("link_library_show", b => - { - b.HasOne("Kyoo.Abstractions.Models.Library", null) - .WithMany() - .HasForeignKey("library_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_libraries_library_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_library_show_shows_show_id"); - }); - - modelBuilder.Entity("link_show_genre", b => - { - b.HasOne("Kyoo.Abstractions.Models.Genre", null) - .WithMany() - .HasForeignKey("genre_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_genres_genre_id"); - - b.HasOne("Kyoo.Abstractions.Models.Show", null) - .WithMany() - .HasForeignKey("show_id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_link_show_genre_shows_show_id"); + b.Navigation("People"); }); modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => @@ -1323,6 +1317,8 @@ namespace Kyoo.Postgresql.Migrations modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => { + b.Navigation("Movies"); + b.Navigation("Shows"); }); diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index cff6167d..dc2918ea 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -43,12 +43,12 @@ namespace Kyoo.Postgresql /// private readonly bool _skipConfigure; - // TOOD: This needs ot be updated but ef-core still does not offer a way to use this. + // TODO: This needs ot be updated but ef-core still does not offer a way to use this. [Obsolete] static PostgresContext() { NpgsqlConnection.GlobalTypeMapper.MapEnum(); - NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); } /// @@ -100,26 +100,11 @@ namespace Kyoo.Postgresql protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasPostgresEnum(); - modelBuilder.HasPostgresEnum(); - - modelBuilder.Entity() - .ToView("library_items") - .HasKey(x => x.ID); - - modelBuilder.Entity() - .Property(x => x.ExtraData) - .HasColumnType("jsonb"); + modelBuilder.HasPostgresEnum(); base.OnModelCreating(modelBuilder); } - /// - protected override string MetadataName() - { - SnakeCaseNameRewriter rewriter = new(CultureInfo.InvariantCulture); - return rewriter.RewriteName(typeof(T).Name + nameof(MetadataID)); - } - /// protected override string LinkName() { diff --git a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs index 476dc0b6..aa2fee16 100644 --- a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs +++ b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs @@ -37,21 +37,17 @@ namespace Kyoo.Tests.Database { Context = new PostgresTestContext(postgres, output); - LibraryRepository library = new(_NewContext()); CollectionRepository collection = new(_NewContext()); - GenreRepository genre = new(_NewContext()); StudioRepository studio = new(_NewContext()); PeopleRepository people = new(_NewContext(), new Lazy(() => LibraryManager.ShowRepository)); - ShowRepository show = new(_NewContext(), studio, people, genre); + ShowRepository show = new(_NewContext(), studio, people); SeasonRepository season = new(_NewContext(), show); - LibraryItemRepository libraryItem = new(_NewContext(), - new Lazy(() => LibraryManager.LibraryRepository)); + LibraryItemRepository libraryItem = new(_NewContext()); EpisodeRepository episode = new(_NewContext(), show); UserRepository user = new(_NewContext()); LibraryManager = new LibraryManager(new IBaseRepository[] { - library, libraryItem, collection, show, @@ -59,7 +55,6 @@ namespace Kyoo.Tests.Database episode, people, studio, - genre, user }); } diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs index 1fc78b23..6e3a6b18 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs @@ -234,7 +234,7 @@ namespace Kyoo.Tests.Database public async Task EditTest() { Episode value = await _repository.Get(TestSample.Get().Slug); - value.Title = "New Title"; + value.Name = "New Title"; value.Images = new Dictionary { [Images.Poster] = "new-poster" @@ -325,7 +325,7 @@ namespace Kyoo.Tests.Database { Episode value = new() { - Title = "This is a test super title", + Name = "This is a test super title", ShowID = 1, AbsoluteNumber = 2 }; diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs index 7a336183..c1107617 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs @@ -121,7 +121,7 @@ namespace Kyoo.Tests.Database public async Task EditTest() { Season value = await _repository.Get(TestSample.Get().Slug); - value.Title = "New Title"; + value.Name = "New Title"; value.Images = new Dictionary { [Images.Poster] = "new-poster" @@ -212,7 +212,7 @@ namespace Kyoo.Tests.Database { Season value = new() { - Title = "This is a test super title", + Name = "This is a test super title", ShowID = 1 }; await _repository.Create(value); diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs index 77895d8f..b8a40ae5 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs @@ -56,7 +56,7 @@ namespace Kyoo.Tests.Database { Show value = await _repository.Get(TestSample.Get().Slug); value.Path = "/super"; - value.Title = "New Title"; + value.Name = "New Title"; Show edited = await _repository.Edit(value, false); KAssert.DeepEqual(value, edited); @@ -215,7 +215,7 @@ namespace Kyoo.Tests.Database { ID = value.ID, Slug = "reset", - Title = "Reset" + Name = "Reset" }; Show edited = await _repository.Edit(newValue, true); @@ -223,7 +223,7 @@ namespace Kyoo.Tests.Database Assert.Equal(value.ID, edited.ID); Assert.Null(edited.Overview); Assert.Equal("reset", edited.Slug); - Assert.Equal("Reset", edited.Title); + Assert.Equal("Reset", edited.Name); Assert.Null(edited.Aliases); Assert.Null(edited.ExternalId); Assert.Null(edited.People); @@ -348,7 +348,7 @@ namespace Kyoo.Tests.Database Show value = new() { Slug = "super-test", - Title = "This is a test title?" + Name = "This is a test title?" }; await _repository.Create(value); ICollection ret = await _repository.Search(query); diff --git a/back/tests/Kyoo.Tests/Database/TestSample.cs b/back/tests/Kyoo.Tests/Database/TestSample.cs index 0971de68..5fbe23a8 100644 --- a/back/tests/Kyoo.Tests/Database/TestSample.cs +++ b/back/tests/Kyoo.Tests/Database/TestSample.cs @@ -27,16 +27,6 @@ namespace Kyoo.Tests { private static readonly Dictionary> NewSamples = new() { - { - typeof(Library), - () => new Library - { - ID = 2, - Slug = "new-library", - Name = "New Library", - Paths = new[] { "/a/random/path" } - } - }, { typeof(Collection), () => new Collection @@ -57,7 +47,7 @@ namespace Kyoo.Tests { ID = 2, Slug = "new-show", - Title = "New Show", + Name = "New Show", Overview = "overview", Status = Status.Planned, StartAir = new DateTime(2011, 1, 1).ToUniversalTime(), @@ -79,7 +69,7 @@ namespace Kyoo.Tests ID = 2, ShowID = 1, ShowSlug = Get().Slug, - Title = "New season", + Name = "New season", Overview = "New overview", EndDate = new DateTime(2000, 10, 10).ToUniversalTime(), SeasonNumber = 2, @@ -102,7 +92,7 @@ namespace Kyoo.Tests EpisodeNumber = 3, AbsoluteNumber = 4, Path = "/episode-path", - Title = "New Episode Title", + Name = "New Episode Title", ReleaseDate = new DateTime(2000, 10, 10).ToUniversalTime(), Overview = "new episode overview", Images = new Dictionary @@ -172,7 +162,7 @@ namespace Kyoo.Tests { ID = 1, Slug = "anohana", - Title = "Anohana: The Flower We Saw That Day", + Name = "Anohana: The Flower We Saw That Day", Aliases = new[] { "Ano Hi Mita Hana no Namae o Bokutachi wa Mada Shiranai.", @@ -204,7 +194,7 @@ namespace Kyoo.Tests ShowSlug = "anohana", ShowID = 1, SeasonNumber = 1, - Title = "Season 1", + Name = "Season 1", Overview = "The first season", StartDate = new DateTime(2020, 06, 05).ToUniversalTime(), EndDate = new DateTime(2020, 07, 05).ToUniversalTime(), @@ -234,7 +224,7 @@ namespace Kyoo.Tests [Images.Logo] = "Logo", [Images.Thumbnail] = "Thumbnail" }, - Title = "Episode 1", + Name = "Episode 1", Overview = "Summary of the first episode", ReleaseDate = new DateTime(2020, 06, 05).ToUniversalTime() } @@ -379,7 +369,7 @@ namespace Kyoo.Tests [Images.Logo] = "Logo", [Images.Thumbnail] = "Thumbnail" }, - Title = "Episode 3", + Name = "Episode 3", Overview = "Summary of the third absolute episode", ReleaseDate = new DateTime(2020, 06, 05).ToUniversalTime() }; @@ -399,7 +389,7 @@ namespace Kyoo.Tests [Images.Logo] = "Logo", [Images.Thumbnail] = "Thumbnail" }, - Title = "John wick", + Name = "John wick", Overview = "A movie episode test", ReleaseDate = new DateTime(1595, 05, 12).ToUniversalTime() }; diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index e72d8cc7..2b86dda5 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -123,7 +123,7 @@ class TheMovieDatabase(Provider): ret = Movie( original_language=movie["original_language"], aliases=[x["title"] for x in movie["alternative_titles"]["titles"]], - release_date=datetime.strptime(movie["release_date"], "%Y-%m-%d").date() + air_date=datetime.strptime(movie["release_date"], "%Y-%m-%d").date() if movie["release_date"] else None, status=MovieStatus.FINISHED @@ -148,8 +148,8 @@ class TheMovieDatabase(Provider): ) translation = MovieTranslation( name=movie["title"], - tagline=movie["tagline"], - keywords=list(map(lambda x: x["name"], movie["keywords"]["keywords"])), + tagline=movie["tagline"] if movie["tagline"] else None, + tags=list(map(lambda x: x["name"], movie["keywords"]["keywords"])), overview=movie["overview"], posters=self.get_image(movie["images"]["posters"]), logos=self.get_image(movie["images"]["logos"]), @@ -224,8 +224,8 @@ class TheMovieDatabase(Provider): ) translation = ShowTranslation( name=show["name"], - tagline=show["tagline"], - keywords=list(map(lambda x: x["name"], show["keywords"]["results"])), + tagline=show["tagline"] if show["tagline"] else None, + tags=list(map(lambda x: x["name"], show["keywords"]["results"])), overview=show["overview"], posters=self.get_image(show["images"]["posters"]), logos=self.get_image(show["images"]["logos"]), diff --git a/scanner/providers/types/episode.py b/scanner/providers/types/episode.py index 4d2bb676..72723b13 100644 --- a/scanner/providers/types/episode.py +++ b/scanner/providers/types/episode.py @@ -40,9 +40,9 @@ class Episode: return { **asdict(self), **asdict(self.translations[default_language]), - "title": self.translations[default_language].name, - "images": { - "1": self.thumbnail, - }, + # "poster": next(iter(self.translations[default_language].posters), None), + # "thumbnail": next(iter(self.translations[default_language].thumbnails), None), + # "logo": next(iter(self.translations[default_language].logos), None), + "thumbnail": None, "show": None, } diff --git a/scanner/providers/types/genre.py b/scanner/providers/types/genre.py index 79c8c3ed..287c07a4 100644 --- a/scanner/providers/types/genre.py +++ b/scanner/providers/types/genre.py @@ -16,10 +16,10 @@ class Genre(str, Enum): MUSIC = "Music" MYSTERY = "Mystery" ROMANCE = "Romance" - SCIENCE_FICTION = "Science Fiction" + SCIENCE_FICTION = "ScienceFiction" THRILLER = "Thriller" WAR = "War" WESTERN = "Western" def to_kyoo(self): - return {"name": self.value} + return self.value diff --git a/scanner/providers/types/movie.py b/scanner/providers/types/movie.py index d0963153..c4e7eeb4 100644 --- a/scanner/providers/types/movie.py +++ b/scanner/providers/types/movie.py @@ -20,7 +20,7 @@ class Status(str, Enum): class MovieTranslation: name: str tagline: Optional[str] = None - keywords: list[str] = field(default_factory=list) + tags: list[str] = field(default_factory=list) overview: Optional[str] = None posters: list[str] = field(default_factory=list) @@ -33,7 +33,7 @@ class MovieTranslation: class Movie: original_language: Optional[str] = None aliases: list[str] = field(default_factory=list) - release_date: Optional[date | int] = None + air_date: Optional[date | int] = None status: Status = Status.UNKNOWN path: Optional[str] = None studios: list[Studio] = field(default_factory=list) @@ -50,18 +50,10 @@ class Movie: return { **asdict(self), **asdict(self.translations[default_language]), - "images": { - "0": next(iter(self.translations[default_language].posters), None), - "1": next(iter(self.translations[default_language].thumbnails), None), - "2": next(iter(self.translations[default_language].logos), None), - "3": next(iter(self.translations[default_language].trailers), None), - }, + # "poster": next(iter(self.translations[default_language].posters), None), + # "thumbnail": next(iter(self.translations[default_language].thumbnails), None), + # "logo": next(iter(self.translations[default_language].logos), None), + "trailer": next(iter(self.translations[default_language].trailers), None), "studio": next((x.to_kyoo() for x in self.studios), None), - "release_date": None, - "startAir": format_date(self.release_date), - "title": self.translations[default_language].name, "genres": [x.to_kyoo() for x in self.genres], - "isMovie": True, - # TODO: The back has bad external id support, we disable it for now - "external_ids": None, } diff --git a/scanner/providers/types/season.py b/scanner/providers/types/season.py index 92e3dd7e..b4e68170 100644 --- a/scanner/providers/types/season.py +++ b/scanner/providers/types/season.py @@ -30,11 +30,7 @@ class Season: return { **asdict(self), **asdict(self.translations[default_language]), - "images": { - "0": next(iter(self.translations[default_language].posters), None), - "1": next(iter(self.translations[default_language].thumbnails), None), - }, - "title": self.translations[default_language].name, - # TODO: The back has bad external id support, we disable it for now - "external_ids": None, + # "poster": next(iter(self.translations[default_language].posters), None), + # "thumbnail": next(iter(self.translations[default_language].thumbnails), None), + # "logo": next(iter(self.translations[default_language].logos), None), } diff --git a/scanner/providers/types/show.py b/scanner/providers/types/show.py index cf3258b5..a7229519 100644 --- a/scanner/providers/types/show.py +++ b/scanner/providers/types/show.py @@ -21,7 +21,7 @@ class Status(str, Enum): class ShowTranslation: name: str tagline: Optional[str] - keywords: list[str] + tags: list[str] overview: Optional[str] posters: list[str] @@ -52,16 +52,11 @@ class Show: return { **asdict(self), **asdict(self.translations[default_language]), - "images": { - "0": next(iter(self.translations[default_language].posters), None), - "1": next(iter(self.translations[default_language].thumbnails), None), - "2": next(iter(self.translations[default_language].logos), None), - "3": next(iter(self.translations[default_language].trailers), None), - }, "studio": next((x.to_kyoo() for x in self.studios), None), - "title": self.translations[default_language].name, - "genres": [x.to_kyoo() for x in self.genres], "seasons": None, - # TODO: The back has bad external id support, we disable it for now - "external_ids": None, + # "poster": next(iter(self.translations[default_language].posters), None), + # "thumbnail": next(iter(self.translations[default_language].thumbnails), None), + # "logo": next(iter(self.translations[default_language].logos), None), + "trailer": next(iter(self.translations[default_language].trailers), None), + "genres": [x.to_kyoo() for x in self.genres], } diff --git a/scanner/providers/types/studio.py b/scanner/providers/types/studio.py index d952b63d..7f7b3149 100644 --- a/scanner/providers/types/studio.py +++ b/scanner/providers/types/studio.py @@ -12,9 +12,5 @@ class Studio: def to_kyoo(self): return { **asdict(self), - "images": { - "2": next(iter(self.logos), None), - }, - # TODO: The back has bad external id support, we disable it for now - "external_ids": None, + # "logo": next(iter(self.logos), None), } diff --git a/scanner/scanner/scanner.py b/scanner/scanner/scanner.py index e7a3e432..babda259 100644 --- a/scanner/scanner/scanner.py +++ b/scanner/scanner/scanner.py @@ -48,7 +48,7 @@ class Scanner: await asyncio.gather(*map(self.identify, group)) async def get_registered_paths(self) -> List[str]: - # TODO: Once movies are separated from the api, a new endpoint should be created to check for paths. + paths = None async with self._client.get( f"{self._url}/episodes", params={"limit": 0}, @@ -56,7 +56,17 @@ class Scanner: ) as r: r.raise_for_status() ret = await r.json() - return list(x["path"] for x in ret["items"]) + paths = list(x["path"] for x in ret["items"]) + + async with self._client.get( + f"{self._url}/movies", + params={"limit": 0}, + headers={"X-API-Key": self._api_key}, + ) as r: + r.raise_for_status() + ret = await r.json() + paths += list(x["path"] for x in ret["items"]) + return paths; @log_errors async def identify(self, path: str): @@ -157,7 +167,13 @@ class Scanner: async def delete(self, path: str): logging.info("Deleting %s", path) - # TODO: Adapt this for movies as well when they are split + async with self._client.delete( + f"{self._url}/movies?path={path}", headers={"X-API-Key": self._api_key} + ) as r: + if not r.ok: + logging.error(f"Request error: {await r.text()}") + r.raise_for_status() + async with self._client.delete( f"{self._url}/episodes?path={path}", headers={"X-API-Key": self._api_key} ) as r: diff --git a/shell.nix b/shell.nix index a2f69d2f..877ae085 100644 --- a/shell.nix +++ b/shell.nix @@ -24,6 +24,7 @@ in openssl mediainfo ffmpeg + postgresql ]; RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";