mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Split movies and shows, enable nullable handling (wip)
This commit is contained in:
parent
386c6bf268
commit
19ae15f53f
@ -33,10 +33,11 @@
|
||||
<Rule Id="SA1513" Action="None"/> <!-- ClosingBraceMustBeFollowedByBlankLine -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.DocumentationRules">
|
||||
<Rule Id="SA1600" Action="None" /> <!-- Elements Shuld be Documented -->
|
||||
<Rule Id="SA1602" Action="None" /> <!-- Enums should be documented -->
|
||||
<Rule Id="SA1642" Action="None" /> <!-- ConstructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1643" Action="None" /> <!-- DestructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1623" Action="None" /> <!-- PropertySummaryDocumentationMustMatchAccessors -->
|
||||
<Rule Id="SA1629" Action="None" /> <!-- DocumentationTextMustEndWithAPeriod -->
|
||||
<Rule Id="SA1600" Action="None" /> <!-- Elements Shuld be Documented -->
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
|
@ -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<T> GetRepository<T>()
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries.
|
||||
/// </summary>
|
||||
ILibraryRepository LibraryRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries items (a wrapper around shows and collections).
|
||||
/// </summary>
|
||||
@ -55,6 +49,11 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </summary>
|
||||
ICollectionRepository CollectionRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IMovieRepository MovieRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
@ -80,11 +79,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </summary>
|
||||
IStudioRepository StudioRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle genres.
|
||||
/// </summary>
|
||||
IGenreRepository GenreRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
@ -97,7 +91,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
@ -108,7 +101,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
@ -119,7 +111,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(Expression<Func<T, bool>> where)
|
||||
where T : class, IResource;
|
||||
|
||||
@ -130,7 +121,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
@ -140,7 +130,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
@ -151,7 +140,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
@ -162,7 +150,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
@ -171,8 +158,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(int id)
|
||||
Task<T?> GetOrDefault<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -181,8 +167,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(string slug)
|
||||
Task<T?> GetOrDefault<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -192,8 +177,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T> sortBy = default)
|
||||
Task<T?> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T>? sortBy = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -202,8 +186,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
||||
Task<Season?> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||
Task<Season?> GetOrDefault(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource
|
||||
@ -248,7 +228,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, T2>> member, bool force = false)
|
||||
Task<T> Load<T, T2>(T obj, Expression<Func<T, T2>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class, IResource;
|
||||
|
||||
@ -266,7 +246,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
|
||||
Task<T> Load<T, T2>(T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class;
|
||||
|
||||
@ -283,7 +263,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T>([NotNull] T obj, string memberName, bool force = false)
|
||||
Task<T> Load<T>(T obj, string memberName, bool force = false)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -298,35 +278,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Load([NotNull] IResource obj, string memberName, bool force = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
Task Load(IResource obj, string memberName, bool force = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
@ -338,9 +290,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
@ -352,9 +304,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
@ -366,9 +318,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
@ -380,27 +332,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
/// <param name="showID">The show's ID to setup relations with</param>
|
||||
/// <param name="libraryID">The library's ID to setup relations with (optional)</param>
|
||||
/// <param name="collectionID">The collection's ID to setup relations with (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
/// <param name="show">The show to setup relations with</param>
|
||||
/// <param name="library">The library to setup relations with (optional)</param>
|
||||
/// <param name="collection">The collection to setup relations with (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get all resources with filters
|
||||
@ -410,9 +344,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -421,7 +355,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<int> GetCount<T>(Expression<Func<T, bool>> where = null)
|
||||
Task<int> GetCount<T>(Expression<Func<T, bool>>? where = null)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -439,7 +373,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Create<T>([NotNull] T item)
|
||||
Task<T> Create<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -448,7 +382,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists<T>([NotNull] T item)
|
||||
Task<T> CreateIfNotExists<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
|
@ -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
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(int id);
|
||||
|
||||
/// <summary>
|
||||
@ -54,7 +52,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(string slug);
|
||||
|
||||
/// <summary>
|
||||
@ -63,7 +60,6 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(Expression<Func<T, bool>> where);
|
||||
|
||||
/// <summary>
|
||||
@ -71,16 +67,14 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(int id);
|
||||
Task<T?> GetOrDefault(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(string slug);
|
||||
Task<T?> GetOrDefault(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate or null if it is not found.
|
||||
@ -88,15 +82,13 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(Expression<Func<T, bool>> where, Sort<T> sortBy = default);
|
||||
Task<T?> GetOrDefault(Expression<Func<T, bool>> where, Sort<T>? sortBy = default);
|
||||
|
||||
/// <summary>
|
||||
/// Search for resources.
|
||||
/// </summary>
|
||||
/// <param name="query">The query string.</param>
|
||||
/// <returns>A list of resources found</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> Search(string query);
|
||||
|
||||
/// <summary>
|
||||
@ -106,33 +98,30 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="sort">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default);
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of resources that match the filter's predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <returns>How many resources matched that filter</returns>
|
||||
Task<int> GetCount(Expression<Func<T, bool>> where = null);
|
||||
Task<int> GetCount(Expression<Func<T, bool>>? where = null);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
/// <param name="obj">The item to register</param>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Create([NotNull] T obj);
|
||||
Task<T> Create(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to create</param>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> CreateIfNotExists([NotNull] T obj);
|
||||
Task<T> CreateIfNotExists(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been created.
|
||||
@ -146,8 +135,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||
Task<T> Edit(T edited, bool resetOld);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
@ -176,14 +164,14 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete([NotNull] T obj);
|
||||
Task Delete(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all resources that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DeleteAll([NotNull] Expression<Func<T, bool>> where);
|
||||
Task DeleteAll(Expression<Func<T, bool>> where);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
@ -202,21 +190,16 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle shows.
|
||||
/// </summary>
|
||||
public interface IMovieRepository : IRepository<Movie> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle shows.
|
||||
/// </summary>
|
||||
public interface IShowRepository : IRepository<Show>
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="libraryID">The ID of the library (optional)</param>
|
||||
/// <param name="collectionID">The ID of the collection (optional)</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
|
||||
/// <summary>
|
||||
/// Get a show's slug from it's ID.
|
||||
/// </summary>
|
||||
@ -330,55 +313,16 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle libraries.
|
||||
/// </summary>
|
||||
public interface ILibraryRepository : IRepository<Library> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle library items (A wrapper around shows and collections).
|
||||
/// </summary>
|
||||
public interface ILibraryItemRepository : IRepository<LibraryItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the library</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No library exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
public Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
}
|
||||
public interface ILibraryItemRepository : IRepository<ILibraryItem> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for collections
|
||||
/// </summary>
|
||||
public interface ICollectionRepository : IRepository<Collection> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for genres.
|
||||
/// </summary>
|
||||
public interface IGenreRepository : IRepository<Genre> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for studios.
|
||||
/// </summary>
|
||||
@ -399,9 +343,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
@ -413,9 +357,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
@ -427,9 +371,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
@ -441,9 +385,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,6 +3,7 @@
|
||||
<Title>Kyoo.Abstractions</Title>
|
||||
<Description>Base package to create plugins for Kyoo.</Description>
|
||||
<RootNamespace>Kyoo.Abstractions</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// <summary>
|
||||
/// The public name of this api.
|
||||
/// </summary>
|
||||
[NotNull] public string Name { get; }
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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 <see cref="ApiDefinitionAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the api that will be used on the documentation page.</param>
|
||||
public ApiDefinitionAttribute([NotNull] string name)
|
||||
public ApiDefinitionAttribute(string name)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
|
@ -60,7 +60,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </param>
|
||||
/// <param name="type">The type of the object</param>
|
||||
/// <returns>The list of configuration reference a type has.</returns>
|
||||
public static IEnumerable<ConfigurationReference> CreateReference(string path, [NotNull] Type type)
|
||||
public static IEnumerable<ConfigurationReference> CreateReference(string path, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models.Exceptions
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with the default message.
|
||||
/// </summary>
|
||||
/// <param name="existing">The existing object.</param>
|
||||
public DuplicatedItemException(object existing = null)
|
||||
public DuplicatedItemException(object? existing = null)
|
||||
: base("Already exists in the database.")
|
||||
{
|
||||
Existing = existing;
|
||||
|
@ -19,13 +19,27 @@
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public interface ILink
|
||||
public enum Genre
|
||||
{
|
||||
/// <summary>
|
||||
/// The link to return, in most cases this should be a string.
|
||||
/// </summary>
|
||||
public object Link { get; }
|
||||
Action,
|
||||
Adventure,
|
||||
Animation,
|
||||
Comedy,
|
||||
Crime,
|
||||
Documentary,
|
||||
Drama,
|
||||
Family,
|
||||
Fantasy,
|
||||
History,
|
||||
Horror,
|
||||
Music,
|
||||
Mystery,
|
||||
Romance,
|
||||
ScienceFiction,
|
||||
Thriller,
|
||||
War,
|
||||
Western,
|
||||
}
|
||||
}
|
@ -17,16 +17,13 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of item, ether a show, a movie or a collection.
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
public enum ItemKind
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="LibraryItem"/> is a <see cref="Show"/>.
|
||||
@ -49,138 +46,67 @@ namespace Kyoo.Abstractions.Models
|
||||
/// A type union between <see cref="Show"/> and <see cref="Collection"/>.
|
||||
/// This is used to list content put inside a library.
|
||||
/// </summary>
|
||||
public class LibraryItem : CustomTypeDescriptor, IResource, IThumbnails
|
||||
public interface ILibraryItem : IResource
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Is the item a collection, a movie or a show?
|
||||
/// </summary>
|
||||
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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of the show or collection.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summary of the show or collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
public DateTime? AirDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished? This is only applicable for shows.
|
||||
/// </summary>
|
||||
public Status? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection started airing. It can be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? StartAir { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection finished airing.
|
||||
/// It must be after the <see cref="StartAir"/> but can be the same (example: for movies).
|
||||
/// It can also be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? EndAir { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
public object Rest { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of this item (ether a collection, a show or a movie).
|
||||
/// </summary>
|
||||
public ItemType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty <see cref="LibraryItem"/>.
|
||||
/// </summary>
|
||||
public LibraryItem() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a show.
|
||||
/// </summary>
|
||||
/// <param name="show">The show that this library item should represent.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a collection
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection that this library item should represent.</param>
|
||||
public LibraryItem(Collection collection)
|
||||
return Kind switch
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An expression to create a <see cref="LibraryItem"/> representing a show.
|
||||
/// </summary>
|
||||
public static Expression<Func<Show, LibraryItem>> 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
|
||||
ItemKind.Movie => Rest as MovieItem,
|
||||
ItemKind.Show => Rest as ShowItem,
|
||||
ItemKind.Collection => Rest as CollectionItem,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An expression to create a <see cref="LibraryItem"/> representing a collection.
|
||||
/// </summary>
|
||||
public static Expression<Func<Collection, LibraryItem>> FromCollection => x => new LibraryItem
|
||||
public sealed class ShowItem : Show, ILibraryItem
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetClassName()
|
||||
public ItemKind Kind => ItemKind.Show;
|
||||
|
||||
public DateTime? AirDate => StartAir;
|
||||
}
|
||||
|
||||
public sealed class MovieItem : Movie, ILibraryItem
|
||||
{
|
||||
return Type.ToString();
|
||||
/// <inheritdoc/>
|
||||
public ItemKind Kind => ItemKind.Movie;
|
||||
}
|
||||
|
||||
public sealed class CollectionItem : Collection, ILibraryItem
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ItemKind Kind => ItemKind.Collection;
|
||||
|
||||
public DateTime? AirDate => null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,12 +53,16 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Show where the People playing in.
|
||||
/// </summary>
|
||||
public int ShowID { get; set; }
|
||||
public int? ShowID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show where the People played in.
|
||||
/// </summary>
|
||||
public Show Show { get; set; }
|
||||
public Show? Show { get; set; }
|
||||
|
||||
public int? MovieID { get; set; }
|
||||
|
||||
public Movie? Movie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of work the person has done for the show.
|
||||
|
@ -17,7 +17,10 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
[MaxLength(256)] public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this collection.
|
||||
@ -39,30 +42,39 @@ namespace Kyoo.Abstractions.Models
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of movies contained in this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Movie>? Movies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows contained in this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of libraries that contains this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||
[LoadableRelation] public ICollection<Show>? Shows { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
public Collection() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Collection(string name)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/// <inheritdoc />
|
||||
[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, @"(?<show>.+)-s(?<season>\d+)e(?<episode>\d+)");
|
||||
|
||||
if (match.Success)
|
||||
@ -80,7 +76,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string ShowSlug { private get; set; }
|
||||
[SerializeIgnore] public string? ShowSlug { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this episode.
|
||||
@ -90,7 +86,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The show that contains this episode. This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(ShowID))] public Show Show { get; set; }
|
||||
[LoadableRelation(nameof(ShowID))] public Show? Show { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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 <see cref="AbsoluteNumber"/>.
|
||||
/// </remarks>
|
||||
[LoadableRelation(nameof(SeasonID))] public Season Season { get; set; }
|
||||
[LoadableRelation(nameof(SeasonID))] public Season? Season { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season in witch this episode is in.
|
||||
@ -130,12 +126,12 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The title of this episode.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The overview of this episode.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Get the slug of an episode.
|
||||
@ -172,7 +168,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </param>
|
||||
/// <returns>The slug corresponding to the given arguments</returns>
|
||||
/// <exception cref="ArgumentNullException">The given show slug was null.</exception>
|
||||
public static string GetSlug([NotNull] string showSlug,
|
||||
public static string GetSlug(string showSlug,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? absoluteNumber = 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A genre that allow one to specify categories for shows.
|
||||
/// </summary>
|
||||
public class Genre : IResource
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this genre.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows that have this genre.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty <see cref="Genre"/>.
|
||||
/// </summary>
|
||||
public Genre() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Genre"/> and specify it's <see cref="Name"/>.
|
||||
/// The <see cref="Slug"/> is automatically calculated from it's name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of this genre.</param>
|
||||
public Genre(string name)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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}.
|
||||
/// </remarks>
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; }
|
||||
}
|
||||
}
|
||||
|
@ -28,18 +28,18 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// A poster is a 9/16 format image with the cover of the resource.
|
||||
/// </summary>
|
||||
public Image Poster { get; set; }
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A logo is a small image representing the resource.
|
||||
/// </summary>
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
}
|
||||
|
||||
public class Image
|
||||
|
140
back/src/Kyoo.Abstractions/Models/Resources/Movie.cs
Normal file
140
back/src/Kyoo.Abstractions/Models/Resources/Movie.cs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A series or a movie.
|
||||
/// </summary>
|
||||
public class Movie : IResource, IMetadata, IOnMerge, IThumbnails
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this show.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A catchphrase for this movie.
|
||||
/// </summary>
|
||||
public string? Tagline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of alternative titles of this show.
|
||||
/// </summary>
|
||||
public string[] Aliases { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The path of the movie video file.
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this show.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of tags that match this movie.
|
||||
/// </summary>
|
||||
public string[] Tags { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
public Genre[] Genres { get; set; } = Array.Empty<Genre>();
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished?
|
||||
/// </summary>
|
||||
public Status Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this movie aired.
|
||||
/// </summary>
|
||||
public DateTime? AirDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A video of a few minutes that tease the content.
|
||||
/// </summary>
|
||||
public string? Trailer { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Studio that made this show.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public int? StudioID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Studio that made this show.
|
||||
/// This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(StudioID))][EditableRelation] public Studio? Studio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of people that made this show.
|
||||
/// </summary>
|
||||
[LoadableRelation][EditableRelation] public ICollection<PeopleRole>? People { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections that contains this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Collection>? Collections { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,10 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -38,20 +42,29 @@ namespace Kyoo.Abstractions.Models
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The list of roles this person has played in. See <see cref="PeopleRole"/> for more information.
|
||||
/// </summary>
|
||||
[EditableRelation][LoadableRelation] public ICollection<PeopleRole> Roles { get; set; }
|
||||
[EditableRelation][LoadableRelation] public ICollection<PeopleRole>? Roles { get; set; }
|
||||
|
||||
public People() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public People(string name)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/// <inheritdoc />
|
||||
[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, @"(?<show>.+)-s(?<season>\d+)");
|
||||
Match match = Regex.Match(value, @"(?<show>.+)-s(?<season>\d+)");
|
||||
|
||||
if (!match.Success)
|
||||
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
||||
@ -60,7 +62,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The slug of the Show that contain this episode. If this is not set, this season is ill-formed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string ShowSlug { private get; set; }
|
||||
[SerializeIgnore] public string? ShowSlug { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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 <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(ShowID))] public Show Show { get; set; }
|
||||
[LoadableRelation(nameof(ShowID))] public Show? Show { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of this season. This can be set to 0 to indicate specials.
|
||||
@ -81,12 +83,12 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The title of this season.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A quick overview of this season.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting air date of this season.
|
||||
@ -99,20 +101,20 @@ namespace Kyoo.Abstractions.Models
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes that this season contains.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Episode> Episodes { get; set; }
|
||||
[LoadableRelation] public ICollection<Episode>? Episodes { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this show.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A catchphrase for this show.
|
||||
/// </summary>
|
||||
public string? Tagline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of alternative titles of this show.
|
||||
/// </summary>
|
||||
[EditableRelation] public string[] Aliases { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the root directory of this show.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
public string[] Aliases { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this show.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of tags that match this movie.
|
||||
/// </summary>
|
||||
public string[] Tags { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
public Genre[] Genres { get; set; } = Array.Empty<Genre>();
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished?
|
||||
@ -71,27 +85,22 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
public DateTime? EndAir { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this show represent a movie, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsMovie { get; set; }
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A video of a few minutes that tease the content.
|
||||
/// </summary>
|
||||
public string Trailer { get; set; }
|
||||
public string? Trailer { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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 <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(StudioID))][EditableRelation] public Studio Studio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
[LoadableRelation][EditableRelation] public ICollection<Genre> Genres { get; set; }
|
||||
[LoadableRelation(nameof(StudioID))][EditableRelation] public Studio? Studio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of people that made this show.
|
||||
/// </summary>
|
||||
[LoadableRelation][EditableRelation] public ICollection<PeopleRole> People { get; set; }
|
||||
[LoadableRelation][EditableRelation] public ICollection<PeopleRole>? People { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The different seasons in this show. If this is a movie, this list is always null or empty.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Season> Seasons { get; set; }
|
||||
[LoadableRelation] public ICollection<Season>? Seasons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Episode> Episodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of libraries that contains this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||
[LoadableRelation] public ICollection<Episode>? Episodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections that contains this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Collection> Collections { get; set; }
|
||||
[LoadableRelation] public ICollection<Collection>? Collections { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -17,8 +17,10 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -41,10 +44,15 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The list of shows that are made by this studio.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
[LoadableRelation] public ICollection<Show>? Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of movies that are made by this studio.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Movie>? Movies { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||
public Dictionary<string, MetadataID> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty, <see cref="Studio"/>.
|
||||
@ -55,6 +63,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// Create a new <see cref="Studio"/> with a specific name, the slug is calculated automatically.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the studio.</param>
|
||||
[JsonConstructor]
|
||||
public Studio(string name)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
|
@ -17,7 +17,10 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -53,27 +57,30 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
public string[] Permissions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary extra data that can be used by specific authentication implementations.
|
||||
/// </summary>
|
||||
[SerializeIgnore]
|
||||
public Dictionary<string, string> ExtraData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A logo is a small image representing the resource.
|
||||
/// </summary>
|
||||
public Image Logo { get; set; }
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows the user has finished.
|
||||
/// </summary>
|
||||
[SerializeIgnore]
|
||||
public ICollection<Show> Watched { get; set; }
|
||||
public ICollection<Show>? Watched { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes the user is watching (stopped in progress or the next episode of the show)
|
||||
/// </summary>
|
||||
[SerializeIgnore]
|
||||
public ICollection<WatchedEpisode> CurrentlyWatching { get; set; }
|
||||
public ICollection<WatchedEpisode>? CurrentlyWatching { get; set; }
|
||||
|
||||
public User() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public User(string username)
|
||||
{
|
||||
Slug = Utility.ToSlug(username);
|
||||
Username = username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The <see cref="Episode"/> started.
|
||||
/// </summary>
|
||||
public Episode Episode { get; set; }
|
||||
public Episode? Episode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (between 0 and 100).
|
||||
|
@ -58,7 +58,7 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// Create a new <see cref="Identifier"/> for the given slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource.</param>
|
||||
public Identifier([NotNull] string slug)
|
||||
public Identifier(string slug)
|
||||
{
|
||||
if (slug == null)
|
||||
throw new ArgumentNullException(nameof(slug));
|
||||
|
@ -31,13 +31,13 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// The list of errors that where made in the request.
|
||||
/// </summary>
|
||||
/// <example><c>["InvalidFilter: no field 'startYear' on a collection"]</c></example>
|
||||
[NotNull] public string[] Errors { get; set; }
|
||||
public string[] Errors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="RequestError"/> with one error.
|
||||
/// </summary>
|
||||
/// <param name="error">The error to specify in the response.</param>
|
||||
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 <see cref="RequestError"/> with multiple errors.
|
||||
/// </summary>
|
||||
/// <param name="errors">The errors to specify in the response.</param>
|
||||
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));
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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 <see cref="Episode"/> with another form.
|
||||
/// </summary>
|
||||
public class WatchItem : CustomTypeDescriptor, IThumbnails, ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the episode associated with this item.
|
||||
/// </summary>
|
||||
public int EpisodeID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The slug of this episode.
|
||||
/// </summary>
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of the show containing this episode.
|
||||
/// </summary>
|
||||
public string ShowTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the show containing this episode
|
||||
/// </summary>
|
||||
public string ShowSlug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season in witch this episode is in.
|
||||
/// </summary>
|
||||
public int? SeasonNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of this episode is it's season.
|
||||
/// </summary>
|
||||
public int? EpisodeNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season.
|
||||
/// </summary>
|
||||
public int? AbsoluteNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this episode.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this episode.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The release date of this episode. It can be null if unknown.
|
||||
/// </summary>
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public Episode PreviousEpisode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public Episode NextEpisode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if this is a movie, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The transcoder's info for this item. This include subtitles, fonts, chapters...
|
||||
/// </summary>
|
||||
public object Info { get; set; }
|
||||
|
||||
[SerializeIgnore]
|
||||
private string _Type => IsMovie ? "movie" : "episode";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Link => new
|
||||
{
|
||||
Direct = $"/video/{_Type}/{Slug}/direct",
|
||||
Hls = $"/video/{_Type}/{Slug}/master.m3u8",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="WatchItem"/> from an <see cref="Episode"/>.
|
||||
/// </summary>
|
||||
/// <param name="ep">The episode to transform.</param>
|
||||
/// <param name="library">
|
||||
/// A library manager to retrieve the next and previous episode and load the show and tracks of the episode.
|
||||
/// </param>
|
||||
/// <param name="client">A http client to reach the transcoder.</param>
|
||||
/// <returns>A new WatchItem representing the given episode.</returns>
|
||||
public static async Task<WatchItem> 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<Episode>(
|
||||
where: x => x.ShowID == ep.ShowID,
|
||||
limit: new Pagination(1, ep.ID, true)
|
||||
)).FirstOrDefault(),
|
||||
NextEpisode = ep.Show.IsMovie
|
||||
? null
|
||||
: (await library.GetAll<Episode>(
|
||||
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<object> _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<object>(content);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetClassName()
|
||||
{
|
||||
return nameof(Show);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetComponentName()
|
||||
{
|
||||
return ShowSlug;
|
||||
}
|
||||
}
|
||||
}
|
@ -39,8 +39,8 @@ namespace Kyoo.Utils
|
||||
/// <returns>The list mapped.</returns>
|
||||
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
|
||||
[LinqTunnel]
|
||||
public static IEnumerable<T2> Map<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
[NotNull] Func<T, int, T2> mapper)
|
||||
public static IEnumerable<T2> Map<T, T2>(this IEnumerable<T> self,
|
||||
Func<T, int, T2> mapper)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException(nameof(self));
|
||||
@ -72,8 +72,8 @@ namespace Kyoo.Utils
|
||||
/// <returns>The list mapped as an AsyncEnumerable.</returns>
|
||||
/// <exception cref="ArgumentNullException">The list or the mapper can't be null.</exception>
|
||||
[LinqTunnel]
|
||||
public static IAsyncEnumerable<T2> MapAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
[NotNull] Func<T, int, Task<T2>> mapper)
|
||||
public static IAsyncEnumerable<T2> MapAsync<T, T2>(this IEnumerable<T> self,
|
||||
Func<T, int, Task<T2>> mapper)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException(nameof(self));
|
||||
@ -105,8 +105,8 @@ namespace Kyoo.Utils
|
||||
/// <returns>The list mapped as an AsyncEnumerable</returns>
|
||||
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
|
||||
[LinqTunnel]
|
||||
public static IAsyncEnumerable<T2> SelectAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
[NotNull] Func<T, Task<T2>> mapper)
|
||||
public static IAsyncEnumerable<T2> SelectAsync<T, T2>(this IEnumerable<T> self,
|
||||
Func<T, Task<T2>> mapper)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException(nameof(self));
|
||||
@ -132,7 +132,7 @@ namespace Kyoo.Utils
|
||||
/// <returns>A task that will return a simple list</returns>
|
||||
/// <exception cref="ArgumentNullException">The list can't be null</exception>
|
||||
[LinqTunnel]
|
||||
public static Task<List<T>> ToListAsync<T>([NotNull] this IAsyncEnumerable<T> self)
|
||||
public static Task<List<T>> ToListAsync<T>(this IAsyncEnumerable<T> self)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException(nameof(self));
|
||||
@ -157,7 +157,7 @@ namespace Kyoo.Utils
|
||||
/// <exception cref="ArgumentNullException">The iterable and the action can't be null.</exception>
|
||||
/// <returns>The iterator proxied, there is no dual iterations.</returns>
|
||||
[LinqTunnel]
|
||||
public static IEnumerable<T> IfEmpty<T>([NotNull] this IEnumerable<T> self, [NotNull] Action action)
|
||||
public static IEnumerable<T> IfEmpty<T>(this IEnumerable<T> self, Action action)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException(nameof(self));
|
||||
@ -190,7 +190,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="self">The list to enumerate. If this is null, the function result in a no-op</param>
|
||||
/// <param name="action">The action to execute for each arguments</param>
|
||||
/// <typeparam name="T">The type of items in the list</typeparam>
|
||||
public static void ForEach<T>([CanBeNull] this IEnumerable<T> self, Action<T> action)
|
||||
public static void ForEach<T>(this IEnumerable<T>? self, Action<T> action)
|
||||
{
|
||||
if (self == null)
|
||||
return;
|
||||
@ -203,7 +203,7 @@ namespace Kyoo.Utils
|
||||
/// </summary>
|
||||
/// <param name="self">The list to enumerate. If this is null, the function result in a no-op</param>
|
||||
/// <param name="action">The action to execute for each arguments</param>
|
||||
public static void ForEach([CanBeNull] this IEnumerable self, Action<object> action)
|
||||
public static void ForEach(this IEnumerable? self, Action<object> action)
|
||||
{
|
||||
if (self == null)
|
||||
return;
|
||||
@ -217,7 +217,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="self">The list to enumerate. If this is null, the function result in a no-op</param>
|
||||
/// <param name="action">The action to execute for each arguments</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task ForEachAsync([CanBeNull] this IEnumerable self, Func<object, Task> action)
|
||||
public static async Task ForEachAsync(this IEnumerable? self, Func<object, Task> action)
|
||||
{
|
||||
if (self == null)
|
||||
return;
|
||||
@ -232,7 +232,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="action">The asynchronous action to execute for each arguments</param>
|
||||
/// <typeparam name="T">The type of items in the list.</typeparam>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task ForEachAsync<T>([CanBeNull] this IEnumerable<T> self, Func<T, Task> action)
|
||||
public static async Task ForEachAsync<T>(this IEnumerable<T>? self, Func<T, Task> action)
|
||||
{
|
||||
if (self == null)
|
||||
return;
|
||||
@ -247,7 +247,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="action">The action to execute for each arguments</param>
|
||||
/// <typeparam name="T">The type of items in the list.</typeparam>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task ForEachAsync<T>([CanBeNull] this IAsyncEnumerable<T> self, Action<T> action)
|
||||
public static async Task ForEachAsync<T>(this IAsyncEnumerable<T>? self, Action<T> action)
|
||||
{
|
||||
if (self == null)
|
||||
return;
|
||||
|
@ -42,9 +42,9 @@ namespace Kyoo.Utils
|
||||
/// <typeparam name="T">The type of items in the lists to merge.</typeparam>
|
||||
/// <returns>The two list merged as an array</returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static T[] MergeLists<T>([CanBeNull] IEnumerable<T> first,
|
||||
[CanBeNull] IEnumerable<T> second,
|
||||
[CanBeNull] Func<T, T, bool> isEqual = null)
|
||||
public static T[] MergeLists<T>(IEnumerable<T>? first,
|
||||
IEnumerable<T>? second,
|
||||
Func<T, T, bool>? isEqual = null)
|
||||
{
|
||||
if (first == null)
|
||||
return second?.ToArray();
|
||||
@ -66,8 +66,8 @@ namespace Kyoo.Utils
|
||||
/// <returns>The first dictionary with the missing elements of <paramref name="second"/>.</returns>
|
||||
/// <seealso cref="MergeDictionaries{T,T2}(System.Collections.Generic.IDictionary{T,T2},System.Collections.Generic.IDictionary{T,T2},out bool)"/>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static IDictionary<T, T2> MergeDictionaries<T, T2>([CanBeNull] IDictionary<T, T2> first,
|
||||
[CanBeNull] IDictionary<T, T2> second)
|
||||
public static IDictionary<T, T2> MergeDictionaries<T, T2>(IDictionary<T, T2>? first,
|
||||
IDictionary<T, T2>? second)
|
||||
{
|
||||
return MergeDictionaries(first, second, out bool _);
|
||||
}
|
||||
@ -84,8 +84,8 @@ namespace Kyoo.Utils
|
||||
/// <typeparam name="T2">The type of values in the dictionaries</typeparam>
|
||||
/// <returns>The first dictionary with the missing elements of <paramref name="second"/>.</returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static IDictionary<T, T2> MergeDictionaries<T, T2>([CanBeNull] IDictionary<T, T2> first,
|
||||
[CanBeNull] IDictionary<T, T2> second,
|
||||
public static IDictionary<T, T2> MergeDictionaries<T, T2>(IDictionary<T, T2>? first,
|
||||
IDictionary<T, T2>? second,
|
||||
out bool hasChanged)
|
||||
{
|
||||
if (first == null)
|
||||
@ -138,8 +138,8 @@ namespace Kyoo.Utils
|
||||
/// set to those of <paramref name="first"/>.
|
||||
/// </returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static IDictionary<T, T2> CompleteDictionaries<T, T2>([CanBeNull] IDictionary<T, T2> first,
|
||||
[CanBeNull] IDictionary<T, T2> second,
|
||||
public static IDictionary<T, T2> CompleteDictionaries<T, T2>(IDictionary<T, T2>? first,
|
||||
IDictionary<T, T2>? second,
|
||||
out bool hasChanged)
|
||||
{
|
||||
if (first == null)
|
||||
@ -157,32 +157,6 @@ namespace Kyoo.Utils
|
||||
return second;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set every fields of first to those of second. Ignore fields marked with the <see cref="NotMergeableAttribute"/> attribute
|
||||
/// At the end, the OnMerge method of first will be called if first is a <see cref="IOnMerge"/>
|
||||
/// </summary>
|
||||
/// <param name="first">The object to assign</param>
|
||||
/// <param name="second">The object containing new values</param>
|
||||
/// <typeparam name="T">Fields of T will be used</typeparam>
|
||||
/// <returns><paramref name="first"/></returns>
|
||||
public static T Assign<T>(T first, T second)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
IEnumerable<PropertyInfo> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <returns><paramref name="first"/></returns>
|
||||
/// <exception cref="ArgumentNullException">If first is null</exception>
|
||||
public static T Complete<T>([NotNull] T first,
|
||||
[CanBeNull] T second,
|
||||
[InstantHandle] Func<PropertyInfo, bool> where = null)
|
||||
T? second,
|
||||
[InstantHandle] Func<PropertyInfo, bool>? where = null)
|
||||
{
|
||||
if (first == null)
|
||||
throw new ArgumentNullException(nameof(first));
|
||||
@ -281,9 +255,9 @@ namespace Kyoo.Utils
|
||||
/// <typeparam name="T">Fields of T will be merged</typeparam>
|
||||
/// <returns><paramref name="first"/></returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static T Merge<T>([CanBeNull] T first,
|
||||
[CanBeNull] T second,
|
||||
[InstantHandle] Func<PropertyInfo, bool> where = null)
|
||||
public static T Merge<T>(T? first,
|
||||
T? second,
|
||||
[InstantHandle] Func<PropertyInfo, bool>? where = null)
|
||||
{
|
||||
if (first == null)
|
||||
return second;
|
||||
|
@ -77,8 +77,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="value">The initial task</param>
|
||||
/// <typeparam name="T">The type that the task will return</typeparam>
|
||||
/// <returns>A non-null task.</returns>
|
||||
[NotNull]
|
||||
public static Task<T> DefaultIfNull<T>([CanBeNull] Task<T> value)
|
||||
public static Task<T> DefaultIfNull<T>(Task<T>? value)
|
||||
{
|
||||
return value ?? Task.FromResult<T>(default);
|
||||
}
|
||||
|
@ -63,34 +63,12 @@ namespace Kyoo.Utils
|
||||
return member!.Member.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the value of a member (property or field)
|
||||
/// </summary>
|
||||
/// <param name="member">The member value</param>
|
||||
/// <param name="obj">The owner of this member</param>
|
||||
/// <returns>The value boxed as an object</returns>
|
||||
/// <exception cref="ArgumentNullException">if <paramref name="member"/> or <paramref name="obj"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The member is not a field or a property.</exception>
|
||||
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}).")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slugify a string (Replace spaces by -, Uniformize accents)
|
||||
/// </summary>
|
||||
/// <param name="str">The string to slugify</param>
|
||||
/// <returns>The slug version of the given string</returns>
|
||||
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
|
||||
/// <param name="type">The starting type</param>
|
||||
/// <returns>A list of types</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="type"/> can't be null</exception>
|
||||
public static IEnumerable<Type> GetInheritanceTree([NotNull] this Type type)
|
||||
public static IEnumerable<Type> GetInheritanceTree(this Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
@ -140,20 +118,6 @@ namespace Kyoo.Utils
|
||||
yield return type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if <paramref name="obj"/> inherit from a generic type <paramref name="genericType"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">Does this object's type is a <paramref name="genericType"/></param>
|
||||
/// <param name="genericType">The generic type to check against (Only generic types are supported like typeof(IEnumerable<>).</param>
|
||||
/// <returns>True if obj inherit from genericType. False otherwise</returns>
|
||||
/// <exception cref="ArgumentNullException">obj and genericType can't be null</exception>
|
||||
public static bool IsOfGenericType([NotNull] object obj, [NotNull] Type genericType)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
return IsOfGenericType(obj.GetType(), genericType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if <paramref name="type"/> inherit from a generic type <paramref name="genericType"/>.
|
||||
/// </summary>
|
||||
@ -161,7 +125,7 @@ namespace Kyoo.Utils
|
||||
/// <param name="genericType">The generic type to check against (Only generic types are supported like typeof(IEnumerable<>).</param>
|
||||
/// <returns>True if obj inherit from genericType. False otherwise</returns>
|
||||
/// <exception cref="ArgumentNullException">obj and genericType can't be null</exception>
|
||||
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
|
||||
/// <returns>The generic definition of genericType that type inherit or null if type does not implement the generic type.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="type"/> and <paramref name="genericType"/> can't be null</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="genericType"/> must be a generic type</exception>
|
||||
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
|
||||
/// <exception cref="ArgumentException">No method match the given constraints.</exception>
|
||||
/// <returns>The method handle of the matching method.</returns>
|
||||
[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
|
||||
/// <seealso cref="RunGenericMethod{T}(object,string,System.Type,object[])"/>
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type[],object[])"/>
|
||||
public static T RunGenericMethod<T>(
|
||||
[NotNull] Type owner,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type type,
|
||||
Type owner,
|
||||
string methodName,
|
||||
Type type,
|
||||
params object[] args)
|
||||
{
|
||||
return RunGenericMethod<T>(owner, methodName, new[] { type }, args);
|
||||
@ -334,9 +297,9 @@ namespace Kyoo.Utils
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type,object[])"/>
|
||||
[PublicAPI]
|
||||
public static T RunGenericMethod<T>(
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a generic method for a runtime <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// To run <see cref="Merger.MergeLists{T}"/> for a List where you don't know the type at compile type,
|
||||
/// you could do:
|
||||
/// <code>
|
||||
/// Utility.RunGenericMethod<object>(
|
||||
/// typeof(Utility),
|
||||
/// nameof(MergeLists),
|
||||
/// enumerableType,
|
||||
/// oldValue, newValue, equalityComparer)
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="instance">The <c>this</c> of the method to run.</param>
|
||||
/// <param name="methodName">The name of the method. You should use the <c>nameof</c> keyword.</param>
|
||||
/// <param name="type">The generic type to run the method with.</param>
|
||||
/// <param name="args">The list of arguments of the method</param>
|
||||
/// <typeparam name="T">
|
||||
/// The return type of the method. You can put <see cref="object"/> for an unknown one.
|
||||
/// </typeparam>
|
||||
/// <exception cref="ArgumentException">No method match the given constraints.</exception>
|
||||
/// <returns>The return of the method you wanted to run.</returns>
|
||||
/// <seealso cref="RunGenericMethod{T}(object,string,System.Type,object[])"/>
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type[],object[])"/>
|
||||
public static T RunGenericMethod<T>(
|
||||
[NotNull] object instance,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type type,
|
||||
params object[] args)
|
||||
{
|
||||
return RunGenericMethod<T>(instance, methodName, new[] { type }, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a generic method for a multiple runtime <see cref="Type"/>.
|
||||
/// If your generic method only needs one type, see
|
||||
/// <see cref="RunGenericMethod{T}(object,string,System.Type,object[])"/>
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// To run <see cref="Merger.MergeLists{T}"/> for a List where you don't know the type at compile type,
|
||||
/// you could do:
|
||||
/// <code>
|
||||
/// Utility.RunGenericMethod<object>(
|
||||
/// typeof(Utility),
|
||||
/// nameof(MergeLists),
|
||||
/// enumerableType,
|
||||
/// oldValue, newValue, equalityComparer)
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="instance">The <c>this</c> of the method to run.</param>
|
||||
/// <param name="methodName">The name of the method. You should use the <c>nameof</c> keyword.</param>
|
||||
/// <param name="types">The list of generic types to run the method with.</param>
|
||||
/// <param name="args">The list of arguments of the method</param>
|
||||
/// <typeparam name="T">
|
||||
/// The return type of the method. You can put <see cref="object"/> for an unknown one.
|
||||
/// </typeparam>
|
||||
/// <exception cref="ArgumentException">No method match the given constraints.</exception>
|
||||
/// <returns>The return of the method you wanted to run.</returns>
|
||||
/// <seealso cref="RunGenericMethod{T}(object,string,System.Type[],object[])"/>
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type,object[])"/>
|
||||
public static T RunGenericMethod<T>(
|
||||
[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());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a dictionary to a query string.
|
||||
/// </summary>
|
||||
@ -446,25 +332,11 @@ namespace Kyoo.Utils
|
||||
/// </summary>
|
||||
/// <param name="ex">The exception to rethrow.</param>
|
||||
[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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a friendly type name (supporting generics)
|
||||
/// For example a list of string will be displayed as List<string> and not as List`1.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to use</param>
|
||||
/// <returns>The friendly name of the type</returns>
|
||||
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}>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
Username = Username,
|
||||
Password = BCryptNet.HashPassword(Password),
|
||||
Email = Email,
|
||||
ExtraData = new Dictionary<string, string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -39,15 +39,15 @@ namespace Kyoo.Core.Controllers
|
||||
/// </summary>
|
||||
private readonly IBaseRepository[] _repositories;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILibraryRepository LibraryRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILibraryItemRepository LibraryItemRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollectionRepository CollectionRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMovieRepository MovieRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IShowRepository ShowRepository { get; }
|
||||
|
||||
@ -63,9 +63,6 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc />
|
||||
public IStudioRepository StudioRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IGenreRepository GenreRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUserRepository UserRepository { get; }
|
||||
|
||||
@ -77,15 +74,14 @@ namespace Kyoo.Core.Controllers
|
||||
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
||||
{
|
||||
_repositories = repositories.ToArray();
|
||||
LibraryRepository = GetRepository<Library>() as ILibraryRepository;
|
||||
LibraryItemRepository = GetRepository<LibraryItem>() as ILibraryItemRepository;
|
||||
LibraryItemRepository = GetRepository<ILibraryItem>() as ILibraryItemRepository;
|
||||
CollectionRepository = GetRepository<Collection>() as ICollectionRepository;
|
||||
MovieRepository = GetRepository<Movie>() as IMovieRepository;
|
||||
ShowRepository = GetRepository<Show>() as IShowRepository;
|
||||
SeasonRepository = GetRepository<Season>() as ISeasonRepository;
|
||||
EpisodeRepository = GetRepository<Episode>() as IEpisodeRepository;
|
||||
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
||||
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
||||
GenreRepository = GetRepository<Genre>() as IGenreRepository;
|
||||
UserRepository = GetRepository<User>() 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
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return LibraryItemRepository.GetFromLibrary(id, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return LibraryItemRepository.GetFromLibrary(slug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
@ -410,20 +361,6 @@ namespace Kyoo.Core.Controllers
|
||||
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
||||
{
|
||||
return ShowRepository.AddShowLink(showID, libraryID, collectionID);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
|
@ -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<Episode>(x => x.Title, $"%{query}%"))
|
||||
.Where(_database.Like<Episode>(x => x.Name, $"%{query}%"))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A local repository for genres.
|
||||
/// </summary>
|
||||
public class GenreRepository : LocalRepository<Genre>, IGenreRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Genre> DefaultSort => new Sort<Genre>.By(x => x.Slug);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="GenreRepository"/>.
|
||||
/// </summary>
|
||||
/// <param name="database">The database handle</param>
|
||||
public GenreRepository(DatabaseContext database)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Genre>> Search(string query)
|
||||
{
|
||||
return await Sort(
|
||||
_database.Genres
|
||||
.Where(_database.Like<Genre>(x => x.Name, $"%{query}%"))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task Validate(Genre resource)
|
||||
{
|
||||
resource.Slug ??= Utility.ToSlug(resource.Name);
|
||||
await base.Validate(resource);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Genre> Create(Genre obj)
|
||||
{
|
||||
await base.Create(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
||||
OnResourceCreated(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
/// <summary>
|
||||
/// A local repository to handle library items.
|
||||
/// </summary>
|
||||
public class LibraryItemRepository : LocalRepository<LibraryItem>, ILibraryItemRepository
|
||||
public class LibraryItemRepository : LocalRepository<ILibraryItem>, ILibraryItemRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
/// <summary>
|
||||
/// A lazy loaded library repository to validate queries (check if a library does exist)
|
||||
/// </summary>
|
||||
private readonly Lazy<ILibraryRepository> _libraries;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<LibraryItem> DefaultSort => new Sort<LibraryItem>.By(x => x.Title);
|
||||
protected override Sort<ILibraryItem> DefaultSort => new Sort<ILibraryItem>.By(x => x.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LibraryItemRepository"/>.
|
||||
/// Create a new <see cref="ILibraryItemRepository"/>.
|
||||
/// </summary>
|
||||
/// <param name="database">The database instance</param>
|
||||
/// <param name="libraries">A lazy loaded library repository</param>
|
||||
public LibraryItemRepository(DatabaseContext database,
|
||||
Lazy<ILibraryRepository> libraries)
|
||||
public LibraryItemRepository(DatabaseContext database)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_libraries = libraries;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> GetOrDefault(int id)
|
||||
public override async Task<ILibraryItem> GetOrDefault(int id)
|
||||
{
|
||||
return _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id);
|
||||
return (await _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id)).ToItem();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> GetOrDefault(string slug)
|
||||
public override async Task<ILibraryItem> GetOrDefault(string slug)
|
||||
{
|
||||
return _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug);
|
||||
return (await _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug)).ToItem();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<ICollection<LibraryItem>> GetAll(Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
public override async Task<ICollection<ILibraryItem>> GetAll(Expression<Func<ILibraryItem, bool>> where = null,
|
||||
Sort<ILibraryItem> 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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<int> GetCount(Expression<Func<LibraryItem, bool>> where = null)
|
||||
public override Task<int> GetCount(Expression<Func<ILibraryItem, bool>> where = null)
|
||||
{
|
||||
IQueryable<LibraryItem> query = _database.LibraryItems;
|
||||
IQueryable<ILibraryItem> query = _database.LibraryItems;
|
||||
if (where != null)
|
||||
query = query.Where(where);
|
||||
return query.CountAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<LibraryItem>> Search(string query)
|
||||
public override async Task<ICollection<ILibraryItem>> Search(string query)
|
||||
{
|
||||
return await Sort(
|
||||
return (await Sort(
|
||||
_database.LibraryItems
|
||||
.Where(_database.Like<LibraryItem>(x => x.Title, $"%{query}%"))
|
||||
.Where(_database.Like<ILibraryItem>(x => x.Name, $"%{query}%"))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
.ToListAsync())
|
||||
.Select(x => (x as BagItem)!.ToItem())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> Create(LibraryItem obj)
|
||||
public override Task<ILibraryItem> Create(ILibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj)
|
||||
public override Task<ILibraryItem> CreateIfNotExists(ILibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> Edit(LibraryItem obj, bool resetOld)
|
||||
public override Task<ILibraryItem> Edit(ILibraryItem obj, bool resetOld)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -121,58 +116,7 @@ namespace Kyoo.Core.Controllers
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task Delete(LibraryItem obj)
|
||||
public override Task Delete(ILibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <summary>
|
||||
/// Get a basic queryable for a library with the right mapping from shows and collections.
|
||||
/// Shows contained in a collection are excluded.
|
||||
/// </summary>
|
||||
/// <param name="selector">Only items that are part of a library that match this predicate will be returned.</param>
|
||||
/// <returns>A queryable containing items that are part of a library matching the selector.</returns>
|
||||
private IQueryable<LibraryItem> _LibraryRelatedQuery(Expression<Func<Library, bool>> 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));
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<LibraryItem> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<LibraryItem> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A local repository to handle libraries.
|
||||
/// </summary>
|
||||
public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Library> DefaultSort => new Sort<Library>.By(x => x.ID);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LibraryRepository"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="database">The database handle</param>
|
||||
public LibraryRepository(DatabaseContext database)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Library>> Search(string query)
|
||||
{
|
||||
return await Sort(
|
||||
_database.Libraries
|
||||
.Where(_database.Like<Library>(x => x.Name + " " + x.Slug, $"%{query}%"))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Library> Create(Library obj)
|
||||
{
|
||||
await base.Create(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
||||
OnResourceCreated(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
139
back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
Normal file
139
back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A local repository to handle shows
|
||||
/// </summary>
|
||||
public class MovieRepository : LocalRepository<Movie>, IMovieRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
/// <summary>
|
||||
/// A studio repository to handle creation/validation of related studios.
|
||||
/// </summary>
|
||||
private readonly IStudioRepository _studios;
|
||||
|
||||
/// <summary>
|
||||
/// A people repository to handle creation/validation of related people.
|
||||
/// </summary>
|
||||
private readonly IPeopleRepository _people;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Movie> DefaultSort => new Sort<Movie>.By(x => x.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="MovieRepository"/>.
|
||||
/// </summary>
|
||||
/// <param name="database">The database handle to use</param>
|
||||
/// <param name="studios">A studio repository</param>
|
||||
/// <param name="people">A people repository</param>
|
||||
public MovieRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
IPeopleRepository people)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_studios = studios;
|
||||
_people = people;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Movie>> Search(string query)
|
||||
{
|
||||
query = $"%{query}%";
|
||||
return await Sort(
|
||||
_database.Movies
|
||||
.Where(_database.Like<Movie>(x => x.Name + " " + x.Slug, query))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Movie> Create(Movie obj)
|
||||
{
|
||||
await base.Create(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
||||
OnResourceCreated(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<People>(role.People.Slug)
|
||||
?? await _people.CreateIfNotExists(role.People);
|
||||
role.PeopleID = role.People.ID;
|
||||
_database.Entry(role).State = EntityState.Added;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Delete(Movie obj)
|
||||
{
|
||||
_database.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
await base.Delete(obj);
|
||||
}
|
||||
}
|
||||
}
|
@ -102,7 +102,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
return await Sort(
|
||||
_database.Seasons
|
||||
.Where(_database.Like<Season>(x => x.Title, $"%{query}%"))
|
||||
.Where(_database.Like<Season>(x => x.Name, $"%{query}%"))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
|
@ -47,13 +47,8 @@ namespace Kyoo.Core.Controllers
|
||||
/// </summary>
|
||||
private readonly IPeopleRepository _people;
|
||||
|
||||
/// <summary>
|
||||
/// A genres repository to handle creation/validation of related genres.
|
||||
/// </summary>
|
||||
private readonly IGenreRepository _genres;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Show> DefaultSort => new Sort<Show>.By(x => x.Title);
|
||||
protected override Sort<Show> DefaultSort => new Sort<Show>.By(x => x.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ShowRepository"/>.
|
||||
@ -61,17 +56,14 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="database">The database handle to use</param>
|
||||
/// <param name="studios">A studio repository</param>
|
||||
/// <param name="people">A people repository</param>
|
||||
/// <param name="genres">A genres repository</param>
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
IPeopleRepository people,
|
||||
IGenreRepository genres)
|
||||
IPeopleRepository people)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_studios = studios;
|
||||
_people = people;
|
||||
_genres = genres;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -80,7 +72,7 @@ namespace Kyoo.Core.Controllers
|
||||
query = $"%{query}%";
|
||||
return await Sort(
|
||||
_database.Shows
|
||||
.Where(_database.Like<Show>(x => x.Title + " " + x.Slug, query))
|
||||
.Where(_database.Like<Show>(x => x.Name + " " + x.Slug, query))
|
||||
)
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
@ -99,7 +91,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc />
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
||||
{
|
||||
if (collectionID != null)
|
||||
{
|
||||
await _database.AddLinks<Collection, Show>(collectionID.Value, showID);
|
||||
await _database.SaveIfNoDuplicates();
|
||||
|
||||
if (libraryID != null)
|
||||
{
|
||||
await _database.AddLinks<Library, Collection>(libraryID.Value, collectionID.Value);
|
||||
await _database.SaveIfNoDuplicates();
|
||||
}
|
||||
}
|
||||
if (libraryID != null)
|
||||
{
|
||||
await _database.AddLinks<Library, Show>(libraryID.Value, showID);
|
||||
await _database.SaveIfNoDuplicates();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<string> GetSlug(int showID)
|
||||
{
|
||||
|
@ -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>(T item, string image)
|
||||
|
@ -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<ThumbnailsManager>().As<IThumbnailsManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
|
||||
|
||||
builder.RegisterRepository<ILibraryRepository, LibraryRepository>();
|
||||
builder.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>();
|
||||
builder.RegisterRepository<ICollectionRepository, CollectionRepository>();
|
||||
builder.RegisterRepository<IMovieRepository, MovieRepository>();
|
||||
builder.RegisterRepository<IShowRepository, ShowRepository>();
|
||||
builder.RegisterRepository<ISeasonRepository, SeasonRepository>();
|
||||
builder.RegisterRepository<IEpisodeRepository, EpisodeRepository>();
|
||||
builder.RegisterRepository<IPeopleRepository, PeopleRepository>();
|
||||
builder.RegisterRepository<IStudioRepository, StudioRepository>();
|
||||
builder.RegisterRepository<IGenreRepository, GenreRepository>();
|
||||
builder.RegisterRepository<IUserRepository, UserRepository>();
|
||||
}
|
||||
|
||||
@ -73,6 +73,7 @@ namespace Kyoo.Core
|
||||
.AddNewtonsoftJson(x =>
|
||||
{
|
||||
x.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
|
||||
x.SerializerSettings.Converters.Add(new StringEnumConverter());
|
||||
})
|
||||
.AddDataAnnotations()
|
||||
.AddControllersAsServices()
|
||||
|
@ -16,40 +16,31 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A library containing <see cref="Show"/> and <see cref="Collection"/>.
|
||||
/// </summary>
|
||||
public class Library : IResource
|
||||
public class ImageConverter : JsonConverter<Image>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
public override void WriteJson(JsonWriter writer, Image value, JsonSerializer serializer)
|
||||
{
|
||||
JObject obj = JObject.FromObject(value, serializer);
|
||||
obj.WriteTo(writer);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this library.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of paths that this library is responsible for. This is mainly used by the Scan task.
|
||||
/// </summary>
|
||||
public string[] Paths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows in this library.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections in this library.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Collection> Collections { get; set; }
|
||||
public override Image ReadJson(JsonReader reader,
|
||||
Type objectType,
|
||||
Image existingValue,
|
||||
bool hasExistingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about one or multiple <see cref="Genre"/>.
|
||||
/// </summary>
|
||||
[Route("genres")]
|
||||
[Route("genre", Order = AlternativeRoute)]
|
||||
[ApiController]
|
||||
[PartialPermission(nameof(Genre))]
|
||||
[ApiDefinition("Genres", Group = MetadataGroup)]
|
||||
public class GenreApi : CrudApi<Genre>
|
||||
{
|
||||
/// <summary>
|
||||
/// The library manager used to modify or retrieve information about the data store.
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="GenreApi"/>.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">
|
||||
/// The library manager used to modify or retrieve information about the data store.
|
||||
/// </param>
|
||||
public GenreApi(ILibraryManager libraryManager)
|
||||
: base(libraryManager.GenreRepository)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get shows with genre
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Lists the shows that have the selected genre.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Genre"/>.</param>
|
||||
/// <param name="sortBy">A key to sort shows by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of shows to return and where to start.</param>
|
||||
/// <returns>A page of shows.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No genre with the given ID could be found.</response>
|
||||
[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<ActionResult<Page<Show>>> GetShows(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Genre>(x => x.Genres)),
|
||||
Sort<Show>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Genre>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
}
|
||||
}
|
@ -93,40 +93,5 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get libraries containing this collection
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Lists the libraries that contain the collection with the given id or slug.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Collection"/>.</param>
|
||||
/// <param name="sortBy">A key to sort libraries by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of libraries to return.</param>
|
||||
/// <returns>A page of libraries.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No collection with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Library>>> GetLibraries(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Library> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Library, Collection>(x => x.Collections)),
|
||||
Sort<Library>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Collection>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about one or multiple <see cref="Library"/>.
|
||||
/// </summary>
|
||||
[Route("libraries")]
|
||||
[Route("library", Order = AlternativeRoute)]
|
||||
[ApiController]
|
||||
[ResourceView]
|
||||
[PartialPermission(nameof(Library), Group = Group.Admin)]
|
||||
[ApiDefinition("Library", Group = ResourcesGroup)]
|
||||
public class LibraryApi : CrudApi<Library>
|
||||
{
|
||||
/// <summary>
|
||||
/// The library manager used to modify or retrieve information in the data store.
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="EpisodeApi"/>.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">
|
||||
/// The library manager used to modify or retrieve information in the data store.
|
||||
/// </param>
|
||||
public LibraryApi(ILibraryManager libraryManager)
|
||||
: base(libraryManager.LibraryRepository)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get shows
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List the shows that are part of this library.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Library"/>.</param>
|
||||
/// <param name="sortBy">A key to sort shows by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of shows to return.</param>
|
||||
/// <returns>A page of shows.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No library with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Show>>> GetShows(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Library>(x => x.Libraries)),
|
||||
Sort<Show>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Library>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get collections
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List the collections that are part of this library.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Library"/>.</param>
|
||||
/// <param name="sortBy">A key to sort collections by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of collections to return.</param>
|
||||
/// <returns>A page of collections.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No library with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Collection>>> GetCollections(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Library>(x => x.Libraries)),
|
||||
Sort<Collection>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Library>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get items
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Library"/>.</param>
|
||||
/// <param name="sortBy">A key to sort items by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of items to return.</param>
|
||||
/// <returns>A page of items.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No library with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<LibraryItem>>> GetItems(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
Expression<Func<LibraryItem, bool>> whereQuery = ApiHelper.ParseWhere<LibraryItem>(where);
|
||||
Sort<LibraryItem> sort = Sort<LibraryItem>.From(sortBy);
|
||||
|
||||
ICollection<LibraryItem> resources = await identifier.Match(
|
||||
id => _libraryManager.GetItemsFromLibrary(id, whereQuery, sort, pagination),
|
||||
slug => _libraryManager.GetItemsFromLibrary(slug, whereQuery, sort, pagination)
|
||||
);
|
||||
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<ActionResult<Page<LibraryItem>>> GetAll(
|
||||
public async Task<ActionResult<Page<ILibraryItem>>> GetAll(
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<LibraryItem> resources = await _libraryItems.GetAll(
|
||||
ApiHelper.ParseWhere<LibraryItem>(where),
|
||||
Sort<LibraryItem>.From(sortBy),
|
||||
ICollection<ILibraryItem> resources = await _libraryItems.GetAll(
|
||||
ApiHelper.ParseWhere<ILibraryItem>(where),
|
||||
Sort<ILibraryItem>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
|
149
back/src/Kyoo.Core/Views/Resources/MovieApi.cs
Normal file
149
back/src/Kyoo.Core/Views/Resources/MovieApi.cs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about one or multiple <see cref="Movie"/>.
|
||||
/// </summary>
|
||||
[Route("movies")]
|
||||
[Route("movie", Order = AlternativeRoute)]
|
||||
[ApiController]
|
||||
[PartialPermission(nameof(Show))]
|
||||
[ApiDefinition("Shows", Group = ResourcesGroup)]
|
||||
public class MovieApi : CrudThumbsApi<Movie>
|
||||
{
|
||||
/// <summary>
|
||||
/// The library manager used to modify or retrieve information in the data store.
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ShowApi"/>.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">
|
||||
/// The library manager used to modify or retrieve information about the data store.
|
||||
/// </param>
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
public MovieApi(ILibraryManager libraryManager,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(libraryManager.MovieRepository, thumbs)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Get staff
|
||||
// /// </summary>
|
||||
// /// <remarks>
|
||||
// /// List staff members that made this show.
|
||||
// /// </remarks>
|
||||
// /// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
// /// <param name="sortBy">A key to sort staff members by.</param>
|
||||
// /// <param name="where">An optional list of filters.</param>
|
||||
// /// <param name="pagination">The number of people to return.</param>
|
||||
// /// <returns>A page of people.</returns>
|
||||
// /// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
// /// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
// [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<ActionResult<Page<PeopleRole>>> GetPeople(Identifier identifier,
|
||||
// [FromQuery] string sortBy,
|
||||
// [FromQuery] Dictionary<string, string> where,
|
||||
// [FromQuery] Pagination pagination)
|
||||
// {
|
||||
// Expression<Func<PeopleRole, bool>> whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||
// Sort<PeopleRole> sort = Sort<PeopleRole>.From(sortBy);
|
||||
//
|
||||
// ICollection<PeopleRole> resources = await identifier.Match(
|
||||
// id => _libraryManager.GetPeopleFromShow(id, whereQuery, sort, pagination),
|
||||
// slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sort, pagination)
|
||||
// );
|
||||
// return Page(resources, pagination.Limit);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Get studio that made the show
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Get the studio that made the show.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <returns>The studio that made the show.</returns>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}/studio")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
||||
{
|
||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Movie>(x => x.Movies));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get collections containing this show
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List the collections that contain this show.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="sortBy">A key to sort collections by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of collections to return.</param>
|
||||
/// <returns>A page of collections.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Collection>>> GetCollections(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Movie>(x => x.Movies)),
|
||||
Sort<Collection>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Movie>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
}
|
||||
}
|
@ -79,7 +79,6 @@ namespace Kyoo.Core.Api
|
||||
Shows = await _libraryManager.Search<Show>(query),
|
||||
Episodes = await _libraryManager.Search<Episode>(query),
|
||||
People = await _libraryManager.Search<People>(query),
|
||||
Genres = await _libraryManager.Search<Genre>(query),
|
||||
Studios = await _libraryManager.Search<Studio>(query)
|
||||
};
|
||||
}
|
||||
@ -133,9 +132,9 @@ namespace Kyoo.Core.Api
|
||||
[Permission(nameof(Show), Kind.Read)]
|
||||
[ApiDefinition("Items")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<LibraryItem>> SearchItems(string query)
|
||||
public Task<ICollection<ILibraryItem>> SearchItems(string query)
|
||||
{
|
||||
return _libraryManager.Search<LibraryItem>(query);
|
||||
return _libraryManager.Search<ILibraryItem>(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -175,24 +174,6 @@ namespace Kyoo.Core.Api
|
||||
return _libraryManager.Search<People>(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search genres
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Search for genres
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <returns>A list of genres found for the specified query.</returns>
|
||||
[HttpGet("genres")]
|
||||
[HttpGet("genre", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Genre), Kind.Read)]
|
||||
[ApiDefinition("Genres")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<Genre>> SearchGenres(string query)
|
||||
{
|
||||
return _libraryManager.Search<Genre>(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search studios
|
||||
/// </summary>
|
||||
|
@ -37,8 +37,6 @@ namespace Kyoo.Core.Api
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<ActionResult<Show>> Create([FromBody] Show resource)
|
||||
{
|
||||
ActionResult<Show> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get seasons of this show
|
||||
/// </summary>
|
||||
@ -185,41 +165,6 @@ namespace Kyoo.Core.Api
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get genres of this show
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List the genres that represent this show.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="sortBy">A key to sort genres by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of genres to return.</param>
|
||||
/// <returns>A page of genres.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Genre>>> GetGenres(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Genre> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Genre, Show>(x => x.Shows)),
|
||||
Sort<Genre>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get studio that made the show
|
||||
/// </summary>
|
||||
@ -238,42 +183,6 @@ namespace Kyoo.Core.Api
|
||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Show>(x => x.Shows));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get libraries containing this show
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="sortBy">A key to sort libraries by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of libraries to return.</param>
|
||||
/// <returns>A page of libraries.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<Library>>> GetLibraries(Identifier identifier,
|
||||
[FromQuery] string sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
ICollection<Library> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Library, Show>(x => x.Shows)),
|
||||
Sort<Library>.From(sortBy),
|
||||
pagination
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get collections containing this show
|
||||
/// </summary>
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve information of an <see cref="Episode"/> as a <see cref="WatchItem"/>.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[Route("watch")]
|
||||
[Route("watchitem", Order = AlternativeRoute)]
|
||||
[ApiController]
|
||||
[ApiDefinition("Watch Items", Group = WatchGroup)]
|
||||
public class WatchApi : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The library manager used to modify or retrieve information in the data store.
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The http client to reach transcoder.
|
||||
/// </summary>
|
||||
private readonly HttpClient _client;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="WatchApi"/>.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">
|
||||
/// The library manager used to modify or retrieve information in the data store.
|
||||
/// </param>
|
||||
/// <param name="client">The http client to reach transcoder.</param>
|
||||
public WatchApi(ILibraryManager libraryManager, HttpClient client)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a watch item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Retrieve a watch item of an episode.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Episode"/>.</param>
|
||||
/// <returns>A page of items.</returns>
|
||||
/// <response code="404">No episode with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}")]
|
||||
[Permission("watch", Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<WatchItem>> GetWatchItem(Identifier identifier)
|
||||
{
|
||||
Episode item = await identifier.Match(
|
||||
id => _libraryManager.GetOrDefault<Episode>(id),
|
||||
slug => _libraryManager.GetOrDefault<Episode>(slug)
|
||||
);
|
||||
if (item == null)
|
||||
return NotFound();
|
||||
return await WatchItem.FromEpisode(item, _libraryManager, _client);
|
||||
}
|
||||
}
|
||||
}
|
@ -41,16 +41,16 @@ namespace Kyoo.Postgresql
|
||||
/// </remarks>
|
||||
public abstract class DatabaseContext : DbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// All libraries of Kyoo. See <see cref="Library"/>.
|
||||
/// </summary>
|
||||
public DbSet<Library> Libraries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All collections of Kyoo. See <see cref="Collection"/>.
|
||||
/// </summary>
|
||||
public DbSet<Collection> Collections { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All movies of Kyoo. See <see cref="Movie"/>.
|
||||
/// </summary>
|
||||
public DbSet<Movie> Movies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All shows of Kyoo. See <see cref="Show"/>.
|
||||
/// </summary>
|
||||
@ -66,11 +66,6 @@ namespace Kyoo.Postgresql
|
||||
/// </summary>
|
||||
public DbSet<Episode> Episodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All genres of Kyoo. See <see cref="Genres"/>.
|
||||
/// </summary>
|
||||
public DbSet<Genre> Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All people of Kyoo. See <see cref="People"/>.
|
||||
/// </summary>
|
||||
@ -91,18 +86,38 @@ namespace Kyoo.Postgresql
|
||||
/// </summary>
|
||||
public DbSet<PeopleRole> PeopleRoles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Episodes with a watch percentage. See <see cref="WatchedEpisode"/>.
|
||||
/// </summary>
|
||||
public DbSet<WatchedEpisode> WatchedEpisodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of library items (shows and collections that are part of a library - or the global one).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This set is ready only, on most database this will be a view.
|
||||
/// </remarks>
|
||||
public DbSet<LibraryItem> LibraryItems { get; set; }
|
||||
public IQueryable<BagItem> 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
|
||||
}));
|
||||
|
||||
/// <summary>
|
||||
/// Add a many to many link between two resources.
|
||||
@ -138,14 +153,6 @@ namespace Kyoo.Postgresql
|
||||
: base(options)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the metadata table of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type related to the metadata</typeparam>
|
||||
/// <returns>The name of the table containing the metadata.</returns>
|
||||
protected abstract string MetadataName<T>()
|
||||
where T : IMetadata;
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the link table of the two given types.
|
||||
/// </summary>
|
||||
@ -265,15 +272,16 @@ namespace Kyoo.Postgresql
|
||||
.WithOne(x => x.Season)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Movie>()
|
||||
.HasOne(x => x.Studio)
|
||||
.WithMany(x => x.Movies)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
modelBuilder.Entity<Show>()
|
||||
.HasOne(x => x.Studio)
|
||||
.WithMany(x => x.Shows)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
_HasManyToMany<Library, Collection>(modelBuilder, x => x.Collections, x => x.Libraries);
|
||||
_HasManyToMany<Library, Show>(modelBuilder, x => x.Shows, x => x.Libraries);
|
||||
_HasManyToMany<Collection, Show>(modelBuilder, x => x.Shows, x => x.Collections);
|
||||
_HasManyToMany<Show, Genre>(modelBuilder, x => x.Genres, x => x.Shows);
|
||||
|
||||
modelBuilder.Entity<User>()
|
||||
.HasMany(x => x.Watched)
|
||||
@ -281,14 +289,15 @@ namespace Kyoo.Postgresql
|
||||
.UsingEntity(x => x.ToTable(LinkName<User, Show>()));
|
||||
|
||||
_HasMetadata<Collection>(modelBuilder);
|
||||
_HasMetadata<Movie>(modelBuilder);
|
||||
_HasMetadata<Show>(modelBuilder);
|
||||
_HasMetadata<Season>(modelBuilder);
|
||||
_HasMetadata<Episode>(modelBuilder);
|
||||
_HasMetadata<People>(modelBuilder);
|
||||
_HasMetadata<Studio>(modelBuilder);
|
||||
|
||||
_HasImages<LibraryItem>(modelBuilder);
|
||||
_HasImages<Collection>(modelBuilder);
|
||||
_HasImages<Movie>(modelBuilder);
|
||||
_HasImages<Show>(modelBuilder);
|
||||
_HasImages<Season>(modelBuilder);
|
||||
_HasImages<Episode>(modelBuilder);
|
||||
@ -299,28 +308,15 @@ namespace Kyoo.Postgresql
|
||||
modelBuilder.Entity<WatchedEpisode>()
|
||||
.HasKey(x => new { User = x.UserID, Episode = x.EpisodeID });
|
||||
|
||||
modelBuilder.Entity<Collection>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Genre>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Library>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<People>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Show>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Season>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Episode>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<Studio>().Property(x => x.Slug).IsRequired();
|
||||
modelBuilder.Entity<User>().Property(x => x.Slug).IsRequired();
|
||||
|
||||
modelBuilder.Entity<Collection>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
modelBuilder.Entity<Genre>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
modelBuilder.Entity<Library>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
modelBuilder.Entity<People>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
modelBuilder.Entity<Movie>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
modelBuilder.Entity<Show>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
@ -342,9 +338,6 @@ namespace Kyoo.Postgresql
|
||||
modelBuilder.Entity<User>()
|
||||
.HasIndex(x => x.Slug)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<LibraryItem>()
|
||||
.ToView("library_items");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -18,4 +18,8 @@
|
||||
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// The initial migration that build most of the database.
|
||||
/// </summary>
|
||||
[DbContext(typeof(PostgresContext))]
|
||||
[Migration("20210801171613_Initial")]
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_collections", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "genres",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_genres", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "libraries",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
paths = table.Column<string[]>(type: "text[]", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_libraries", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "people",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_people", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "providers",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_providers", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "studios",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_studios", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "users",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
username = table.Column<string>(type: "text", nullable: true),
|
||||
email = table.Column<string>(type: "text", nullable: true),
|
||||
password = table.Column<string>(type: "text", nullable: true),
|
||||
permissions = table.Column<string[]>(type: "text[]", nullable: true),
|
||||
extra_data = table.Column<Dictionary<string, string>>(type: "jsonb", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(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<int>(type: "integer", nullable: false),
|
||||
library_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
title = table.Column<string>(type: "text", nullable: true),
|
||||
aliases = table.Column<string[]>(type: "text[]", nullable: true),
|
||||
path = table.Column<string>(type: "text", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
status = table.Column<Status>(type: "status", nullable: false),
|
||||
start_air = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
end_air = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
|
||||
is_movie = table.Column<bool>(type: "boolean", nullable: false),
|
||||
studio_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
watched_id = table.Column<int>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
people_id = table.Column<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(type: "integer", nullable: false),
|
||||
type = table.Column<string>(type: "text", nullable: true),
|
||||
role = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: true),
|
||||
show_id = table.Column<int>(type: "integer", nullable: false),
|
||||
season_number = table.Column<int>(type: "integer", nullable: false),
|
||||
title = table.Column<string>(type: "text", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
start_date = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
end_date = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: true),
|
||||
show_id = table.Column<int>(type: "integer", nullable: false),
|
||||
season_id = table.Column<int>(type: "integer", nullable: true),
|
||||
season_number = table.Column<int>(type: "integer", nullable: true),
|
||||
episode_number = table.Column<int>(type: "integer", nullable: true),
|
||||
absolute_number = table.Column<int>(type: "integer", nullable: true),
|
||||
path = table.Column<string>(type: "text", nullable: true),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
|
||||
title = table.Column<string>(type: "text", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
release_date = table.Column<DateTime>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "text", nullable: true),
|
||||
title = table.Column<string>(type: "text", nullable: true),
|
||||
language = table.Column<string>(type: "text", nullable: true),
|
||||
codec = table.Column<string>(type: "text", nullable: true),
|
||||
is_default = table.Column<bool>(type: "boolean", nullable: false),
|
||||
is_forced = table.Column<bool>(type: "boolean", nullable: false),
|
||||
is_external = table.Column<bool>(type: "boolean", nullable: false),
|
||||
path = table.Column<string>(type: "text", nullable: true),
|
||||
type = table.Column<object>(type: "stream_type", nullable: false),
|
||||
episode_id = table.Column<int>(type: "integer", nullable: false),
|
||||
track_index = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
episode_id = table.Column<int>(type: "integer", nullable: false),
|
||||
watched_percentage = table.Column<int>(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");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Kyoo.Postgresql.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// A migration that adds postgres triggers to update slugs.
|
||||
/// </summary>
|
||||
[DbContext(typeof(PostgresContext))]
|
||||
[Migration("20210801171641_Triggers")]
|
||||
public partial class Triggers : Migration
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Kyoo.Postgresql.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Remove triggers
|
||||
/// </summary>
|
||||
[DbContext(typeof(PostgresContext))]
|
||||
[Migration("20230724144449_RemoveTriggers")]
|
||||
public partial class RemoveTriggers : Migration
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
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<string>(
|
||||
name: "slug",
|
||||
table: "tracks",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: string.Empty,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "slug",
|
||||
table: "seasons",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: string.Empty,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "slug",
|
||||
table: "episodes",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: string.Empty,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "slug",
|
||||
table: "tracks",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "slug",
|
||||
table: "seasons",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "slug",
|
||||
table: "episodes",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kyoo.Postgresql.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DbContext(typeof(PostgresContext))]
|
||||
[Migration("20230726100747_Timestamp")]
|
||||
public partial class Timestamp : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
MigrationHelper.DropLibraryItemsView(migrationBuilder);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_air",
|
||||
table: "shows",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp without time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "end_air",
|
||||
table: "shows",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp without time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "seasons",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp without time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "end_date",
|
||||
table: "seasons",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp without time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
MigrationHelper.DropLibraryItemsView(migrationBuilder);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_air",
|
||||
table: "shows",
|
||||
type: "timestamp without time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "end_air",
|
||||
table: "shows",
|
||||
type: "timestamp without time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "start_date",
|
||||
table: "seasons",
|
||||
type: "timestamp without time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "end_date",
|
||||
table: "seasons",
|
||||
type: "timestamp without time zone",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kyoo.Postgresql.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemoveTracks : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
episode_id = table.Column<int>(type: "integer", nullable: false),
|
||||
codec = table.Column<string>(type: "text", nullable: true),
|
||||
is_default = table.Column<bool>(type: "boolean", nullable: false),
|
||||
is_external = table.Column<bool>(type: "boolean", nullable: false),
|
||||
is_forced = table.Column<bool>(type: "boolean", nullable: false),
|
||||
language = table.Column<string>(type: "text", nullable: true),
|
||||
path = table.Column<string>(type: "text", nullable: true),
|
||||
slug = table.Column<string>(type: "text", nullable: false),
|
||||
title = table.Column<string>(type: "text", nullable: true),
|
||||
track_index = table.Column<int>(type: "integer", nullable: false),
|
||||
type = table.Column<string>(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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kyoo.Postgresql.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddBlurhash : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "users",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "users",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "studios",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "shows",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "shows",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "shows",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_blurhash",
|
||||
table: "shows",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_source",
|
||||
table: "shows",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_blurhash",
|
||||
table: "shows",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_source",
|
||||
table: "shows",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "trailer",
|
||||
table: "shows",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "seasons",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "seasons",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "seasons",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_blurhash",
|
||||
table: "seasons",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_source",
|
||||
table: "seasons",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_blurhash",
|
||||
table: "seasons",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_source",
|
||||
table: "seasons",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "people",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "people",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "people",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_blurhash",
|
||||
table: "people",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_source",
|
||||
table: "people",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_blurhash",
|
||||
table: "people",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_source",
|
||||
table: "people",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "episodes",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "episodes",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "episodes",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_blurhash",
|
||||
table: "episodes",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_source",
|
||||
table: "episodes",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_blurhash",
|
||||
table: "episodes",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_source",
|
||||
table: "episodes",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "external_id",
|
||||
table: "collections",
|
||||
type: "json",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_blurhash",
|
||||
table: "collections",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_source",
|
||||
table: "collections",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_blurhash",
|
||||
table: "collections",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "poster_source",
|
||||
table: "collections",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_blurhash",
|
||||
table: "collections",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "thumbnail_source",
|
||||
table: "collections",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
MigrationHelper.CreateLibraryItemsView(migrationBuilder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "users",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "shows",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "seasons",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "people",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "episodes",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||
name: "images",
|
||||
table: "collections",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "providers",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
slug = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||
data_id = table.Column<string>(type: "text", nullable: true),
|
||||
link = table.Column<string>(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);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
528
back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.cs
Normal file
528
back/src/Kyoo.Postgresql/Migrations/20230805051120_initial.cs
Normal file
@ -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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
external_id = table.Column<string>(type: "json", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_collections", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "people",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
external_id = table.Column<string>(type: "json", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_people", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "studios",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
external_id = table.Column<string>(type: "json", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_studios", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "users",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
username = table.Column<string>(type: "text", nullable: false),
|
||||
email = table.Column<string>(type: "text", nullable: false),
|
||||
password = table.Column<string>(type: "text", nullable: false),
|
||||
permissions = table.Column<string[]>(type: "text[]", nullable: false),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
tagline = table.Column<string>(type: "text", nullable: true),
|
||||
aliases = table.Column<string[]>(type: "text[]", nullable: false),
|
||||
path = table.Column<string>(type: "text", nullable: false),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
tags = table.Column<string[]>(type: "text[]", nullable: false),
|
||||
genres = table.Column<Genre[]>(type: "genre[]", nullable: false),
|
||||
status = table.Column<Status>(type: "status", nullable: false),
|
||||
air_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
trailer = table.Column<string>(type: "text", nullable: true),
|
||||
external_id = table.Column<string>(type: "json", nullable: false),
|
||||
studio_id = table.Column<int>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
tagline = table.Column<string>(type: "text", nullable: true),
|
||||
aliases = table.Column<string[]>(type: "text[]", nullable: false),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
tags = table.Column<string[]>(type: "text[]", nullable: false),
|
||||
genres = table.Column<Genre[]>(type: "genre[]", nullable: false),
|
||||
status = table.Column<Status>(type: "status", nullable: false),
|
||||
start_air = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
end_air = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
trailer = table.Column<string>(type: "text", nullable: true),
|
||||
external_id = table.Column<string>(type: "json", nullable: false),
|
||||
studio_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
movies_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(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<int>(type: "integer", nullable: false),
|
||||
watched_id = table.Column<int>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
people_id = table.Column<int>(type: "integer", nullable: false),
|
||||
show_id = table.Column<int>(type: "integer", nullable: true),
|
||||
movie_id = table.Column<int>(type: "integer", nullable: true),
|
||||
type = table.Column<string>(type: "text", nullable: false),
|
||||
role = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
show_id = table.Column<int>(type: "integer", nullable: false),
|
||||
season_number = table.Column<int>(type: "integer", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
start_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
end_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
external_id = table.Column<string>(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<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
slug = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
show_id = table.Column<int>(type: "integer", nullable: false),
|
||||
season_id = table.Column<int>(type: "integer", nullable: true),
|
||||
season_number = table.Column<int>(type: "integer", nullable: true),
|
||||
episode_number = table.Column<int>(type: "integer", nullable: true),
|
||||
absolute_number = table.Column<int>(type: "integer", nullable: true),
|
||||
path = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: true),
|
||||
overview = table.Column<string>(type: "text", nullable: true),
|
||||
release_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
poster_source = table.Column<string>(type: "text", nullable: true),
|
||||
poster_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
thumbnail_source = table.Column<string>(type: "text", nullable: true),
|
||||
thumbnail_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
logo_source = table.Column<string>(type: "text", nullable: true),
|
||||
logo_blurhash = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
external_id = table.Column<string>(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<int>(type: "integer", nullable: false),
|
||||
episode_id = table.Column<int>(type: "integer", nullable: false),
|
||||
watched_percentage = table.Column<int>(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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
// <auto-generated />
|
||||
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<int>("CollectionsID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("collections_id");
|
||||
|
||||
b.Property<int>("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<int>("ID")
|
||||
@ -35,11 +53,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
@ -49,7 +69,8 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
b.Property<string>("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<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("overview");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("path");
|
||||
|
||||
@ -109,13 +136,10 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<string>("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<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
@ -142,97 +166,77 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("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<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string[]>("Paths")
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("paths");
|
||||
|
||||
b.Property<string>("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<int>("ID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTime?>("EndAir")
|
||||
b.Property<DateTime?>("AirDate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("end_air");
|
||||
.HasColumnName("air_date");
|
||||
|
||||
b.Property<string[]>("Aliases")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("aliases");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<Genre[]>("Genres")
|
||||
.IsRequired()
|
||||
.HasColumnType("genre[]")
|
||||
.HasColumnName("genres");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("overview");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
b.Property<string>("Path")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("path");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<DateTime?>("StartAir")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("start_air");
|
||||
|
||||
b.Property<Status?>("Status")
|
||||
b.Property<Status>("Status")
|
||||
.HasColumnType("status")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("title");
|
||||
b.Property<int?>("StudioID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("studio_id");
|
||||
|
||||
b.Property<ItemType>("Type")
|
||||
.HasColumnType("item_type")
|
||||
.HasColumnName("type");
|
||||
b.Property<string>("Tagline")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("tagline");
|
||||
|
||||
b.Property<string[]>("Tags")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("tags");
|
||||
|
||||
b.Property<string>("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<int>("ID"));
|
||||
|
||||
b.Property<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("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<int>("ID"));
|
||||
|
||||
b.Property<int?>("MovieID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("movie_id");
|
||||
|
||||
b.Property<int>("PeopleID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("people_id");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("role");
|
||||
|
||||
b.Property<int>("ShowID")
|
||||
b.Property<int?>("ShowID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("show_id");
|
||||
|
||||
b.Property<string>("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<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text")
|
||||
@ -335,17 +356,14 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<DateTime?>("StartDate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("start_date");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("ID")
|
||||
.HasName("pk_seasons");
|
||||
|
||||
@ -370,6 +388,7 @@ namespace Kyoo.Postgresql.Migrations
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string[]>("Aliases")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("aliases");
|
||||
|
||||
@ -377,25 +396,29 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("end_air");
|
||||
|
||||
b.Property<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<bool>("IsMovie")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_movie");
|
||||
b.Property<Genre[]>("Genres")
|
||||
.IsRequired()
|
||||
.HasColumnType("genre[]")
|
||||
.HasColumnName("genres");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("overview");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("path");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<DateTime?>("StartAir")
|
||||
@ -410,9 +433,14 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("studio_id");
|
||||
|
||||
b.Property<string>("Title")
|
||||
b.Property<string>("Tagline")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("title");
|
||||
.HasColumnName("tagline");
|
||||
|
||||
b.Property<string[]>("Tags")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("tags");
|
||||
|
||||
b.Property<string>("Trailer")
|
||||
.HasColumnType("text")
|
||||
@ -440,17 +468,20 @@ namespace Kyoo.Postgresql.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("ExternalIDs")
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("json")
|
||||
.HasColumnName("external_i_ds");
|
||||
.HasColumnName("external_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("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<int>("ID"));
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("email");
|
||||
|
||||
b.Property<Dictionary<string, string>>("ExtraData")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("extra_data");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("password");
|
||||
|
||||
b.Property<string[]>("Permissions")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("permissions");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<string>("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<int>("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<int>("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<int>("library_id")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("library_id");
|
||||
|
||||
b.Property<int>("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<int>("genre_id")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("genre_id");
|
||||
|
||||
b.Property<int>("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<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("logo_source");
|
||||
|
||||
@ -658,11 +652,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("poster_source");
|
||||
|
||||
@ -682,11 +678,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("thumbnail_source");
|
||||
|
||||
@ -728,11 +726,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("logo_source");
|
||||
|
||||
@ -752,11 +752,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("poster_source");
|
||||
|
||||
@ -776,11 +778,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("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<int>("LibraryItemID")
|
||||
b1.Property<int>("MovieID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("library_item_id");
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("blurhash");
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("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<int>("LibraryItemID")
|
||||
b1.Property<int>("MovieID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("library_item_id");
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("blurhash");
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("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<int>("LibraryItemID")
|
||||
b1.Property<int>("MovieID")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("library_item_id");
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("blurhash");
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("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<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("logo_source");
|
||||
|
||||
@ -921,11 +938,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("poster_source");
|
||||
|
||||
@ -945,11 +964,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("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<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("logo_source");
|
||||
|
||||
@ -1030,11 +1058,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("poster_source");
|
||||
|
||||
@ -1054,11 +1084,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("thumbnail_source");
|
||||
|
||||
@ -1095,11 +1127,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("logo_source");
|
||||
|
||||
@ -1119,11 +1153,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("poster_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("poster_source");
|
||||
|
||||
@ -1143,11 +1179,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("thumbnail_blurhash");
|
||||
|
||||
b1.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("thumbnail_source");
|
||||
|
||||
@ -1178,11 +1216,13 @@ namespace Kyoo.Postgresql.Migrations
|
||||
.HasColumnName("id");
|
||||
|
||||
b1.Property<string>("Blurhash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("logo_blurhash");
|
||||
|
||||
b1.Property<string>("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");
|
||||
});
|
||||
|
||||
|
@ -43,12 +43,12 @@ namespace Kyoo.Postgresql
|
||||
/// </summary>
|
||||
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<Status>();
|
||||
NpgsqlConnection.GlobalTypeMapper.MapEnum<ItemType>();
|
||||
NpgsqlConnection.GlobalTypeMapper.MapEnum<Genre>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -100,26 +100,11 @@ namespace Kyoo.Postgresql
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.HasPostgresEnum<Status>();
|
||||
modelBuilder.HasPostgresEnum<ItemType>();
|
||||
|
||||
modelBuilder.Entity<LibraryItem>()
|
||||
.ToView("library_items")
|
||||
.HasKey(x => x.ID);
|
||||
|
||||
modelBuilder.Entity<User>()
|
||||
.Property(x => x.ExtraData)
|
||||
.HasColumnType("jsonb");
|
||||
modelBuilder.HasPostgresEnum<Genre>();
|
||||
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string MetadataName<T>()
|
||||
{
|
||||
SnakeCaseNameRewriter rewriter = new(CultureInfo.InvariantCulture);
|
||||
return rewriter.RewriteName(typeof(T).Name + nameof(MetadataID));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string LinkName<T, T2>()
|
||||
{
|
||||
|
@ -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<IShowRepository>(() => 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<ILibraryRepository>(() => 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
|
||||
});
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ namespace Kyoo.Tests.Database
|
||||
public async Task EditTest()
|
||||
{
|
||||
Episode value = await _repository.Get(TestSample.Get<Episode>().Slug);
|
||||
value.Title = "New Title";
|
||||
value.Name = "New Title";
|
||||
value.Images = new Dictionary<int, string>
|
||||
{
|
||||
[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
|
||||
};
|
||||
|
@ -121,7 +121,7 @@ namespace Kyoo.Tests.Database
|
||||
public async Task EditTest()
|
||||
{
|
||||
Season value = await _repository.Get(TestSample.Get<Season>().Slug);
|
||||
value.Title = "New Title";
|
||||
value.Name = "New Title";
|
||||
value.Images = new Dictionary<int, string>
|
||||
{
|
||||
[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);
|
||||
|
@ -56,7 +56,7 @@ namespace Kyoo.Tests.Database
|
||||
{
|
||||
Show value = await _repository.Get(TestSample.Get<Show>().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<Show> ret = await _repository.Search(query);
|
||||
|
@ -27,16 +27,6 @@ namespace Kyoo.Tests
|
||||
{
|
||||
private static readonly Dictionary<Type, Func<object>> 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<Show>().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<int, string>
|
||||
@ -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()
|
||||
};
|
||||
|
@ -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"]),
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ class Genre(str, Enum):
|
||||
WESTERN = "Western"
|
||||
|
||||
def to_kyoo(self):
|
||||
return {"name": self.value}
|
||||
return self.value
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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],
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user