mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Unifing ItemNotFound behaviors and adding GetOrDefault.
This commit is contained in:
parent
5dd79d59eb
commit
411eaa7aed
@ -143,13 +143,79 @@ namespace Kyoo.Controllers
|
|||||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a tracck from it's slug and it's type.
|
/// Get a track from it's slug and it's type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slug">The slug of the track</param>
|
/// <param name="slug">The slug of the track</param>
|
||||||
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
/// <returns>The tracl found</returns>
|
/// <returns>The tracl found</returns>
|
||||||
Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknown);
|
Task<Track> Get(string slug, StreamType type = StreamType.Unknown);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the resource by it's ID or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The id of the resource</param>
|
||||||
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
|
/// <returns>The resource found</returns>
|
||||||
|
Task<T> GetOrDefault<T>(int id) where T : class, IResource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the resource by it's slug or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slug">The slug of the resource</param>
|
||||||
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
|
/// <returns>The resource found</returns>
|
||||||
|
Task<T> GetOrDefault<T>(string slug) where T : class, IResource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the resource by a filter function or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="where">The filter function.</param>
|
||||||
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
|
/// <returns>The first resource found that match the where function</returns>
|
||||||
|
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where) where T : class, IResource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a track from it's slug and it's type or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slug">The slug of the track</param>
|
||||||
|
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||||
|
/// <returns>The tracl found</returns>
|
||||||
|
Task<Track> GetOrDefault(string slug, StreamType type = StreamType.Unknown);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -423,7 +489,15 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="item">The item to register</param>
|
/// <param name="item">The item to register</param>
|
||||||
/// <typeparam name="T">The type of resource</typeparam>
|
/// <typeparam name="T">The type of resource</typeparam>
|
||||||
/// <returns>The resource registers and completed by database's informations (related items & so on)</returns>
|
/// <returns>The resource registers and completed by database's informations (related items & so on)</returns>
|
||||||
Task<T> Create<T>(T item) where T : class, IResource;
|
Task<T> Create<T>([NotNull] T item) where T : class, IResource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||||
|
/// </summary>
|
||||||
|
/// <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) where T : class, IResource;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Edit a resource
|
/// Edit a resource
|
||||||
@ -431,6 +505,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
|
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
|
||||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||||
/// <typeparam name="T">The type of resources</typeparam>
|
/// <typeparam name="T">The type of resources</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
||||||
Task<T> Edit<T>(T item, bool resetOld) where T : class, IResource;
|
Task<T> Edit<T>(T item, bool resetOld) where T : class, IResource;
|
||||||
|
|
||||||
@ -439,6 +514,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The resource to delete</param>
|
/// <param name="item">The resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete<T>(T item) where T : class, IResource;
|
Task Delete<T>(T item) where T : class, IResource;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -446,6 +522,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The id of the resource to delete</param>
|
/// <param name="id">The id of the resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete<T>(int id) where T : class, IResource;
|
Task Delete<T>(int id) where T : class, IResource;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -453,6 +530,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slug">The slug of the resource to delete</param>
|
/// <param name="slug">The slug of the resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete<T>(string slug) where T : class, IResource;
|
Task Delete<T>(string slug) where T : class, IResource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,25 @@ namespace Kyoo.Controllers
|
|||||||
/// <returns>The resource found</returns>
|
/// <returns>The resource found</returns>
|
||||||
Task<T> Get(Expression<Func<T, bool>> where);
|
Task<T> Get(Expression<Func<T, bool>> where);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a resource from it's ID or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The id of the resource</param>
|
||||||
|
/// <returns>The resource found</returns>
|
||||||
|
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>
|
||||||
|
Task<T> GetOrDefault(string slug);
|
||||||
|
/// <summary>
|
||||||
|
/// Get the first resource that match the predicate or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="where">A predicate to filter the resource.</param>
|
||||||
|
/// <returns>The resource found</returns>
|
||||||
|
Task<T> GetOrDefault(Expression<Func<T, bool>> where);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Search for resources.
|
/// Search for resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -203,6 +222,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="edited">The resourcce to edit, it's ID can't change.</param>
|
/// <param name="edited">The resourcce to edit, it's ID can't change.</param>
|
||||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
||||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||||
|
|
||||||
@ -210,77 +230,193 @@ namespace Kyoo.Controllers
|
|||||||
/// Delete a resource by it's ID
|
/// Delete a resource by it's ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The ID of the resource</param>
|
/// <param name="id">The ID of the resource</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete(int id);
|
Task Delete(int id);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a resource by it's slug
|
/// Delete a resource by it's slug
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slug">The slug of the resource</param>
|
/// <param name="slug">The slug of the resource</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete(string slug);
|
Task Delete(string slug);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a resource
|
/// Delete a resource
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The resource to delete</param>
|
/// <param name="obj">The resource to delete</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task Delete([NotNull] T obj);
|
Task Delete([NotNull] T obj);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="objs">One or multiple resources to delete</param>
|
/// <param name="objs">One or multiple resources to delete</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(params T[] objs) => DeleteRange(objs.AsEnumerable());
|
Task DeleteRange(params T[] objs) => DeleteRange(objs.AsEnumerable());
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="objs">An enumerable of resources to delete</param>
|
/// <param name="objs">An enumerable of resources to delete</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(IEnumerable<T> objs);
|
Task DeleteRange(IEnumerable<T> objs);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ids">One or multiple resources's id</param>
|
/// <param name="ids">One or multiple resources's id</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(params int[] ids) => DeleteRange(ids.AsEnumerable());
|
Task DeleteRange(params int[] ids) => DeleteRange(ids.AsEnumerable());
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ids">An enumearble of resources's id</param>
|
/// <param name="ids">An enumearble of resources's id</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(IEnumerable<int> ids);
|
Task DeleteRange(IEnumerable<int> ids);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slugs">One or multiple resources's slug</param>
|
/// <param name="slugs">One or multiple resources's slug</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(params string[] slugs) => DeleteRange(slugs.AsEnumerable());
|
Task DeleteRange(params string[] slugs) => DeleteRange(slugs.AsEnumerable());
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slugs">An enumerable of resources's slug</param>
|
/// <param name="slugs">An enumerable of resources's slug</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange(IEnumerable<string> slugs);
|
Task DeleteRange(IEnumerable<string> slugs);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a list of resources.
|
/// Delete a list of resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
Task DeleteRange([NotNull] Expression<Func<T, bool>> where);
|
Task DeleteRange([NotNull] Expression<Func<T, bool>> where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A repository to handle shows.
|
||||||
|
/// </summary>
|
||||||
public interface IShowRepository : IRepository<Show>
|
public interface IShowRepository : IRepository<Show>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Link a show to a collection and/or a library. The given show is now part of thoses 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>
|
||||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a show's slug from it's ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The ID of the show</param>
|
||||||
|
/// <exception cref="ItemNotFound">If a show with the given ID is not found.</exception>
|
||||||
|
/// <returns>The show's slug</returns>
|
||||||
Task<string> GetSlug(int showID);
|
Task<string> GetSlug(int showID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A repository to handle seasons.
|
||||||
|
/// </summary>
|
||||||
public interface ISeasonRepository : IRepository<Season>
|
public interface ISeasonRepository : IRepository<Season>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's showID and it's seasonNumber
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
Task<Season> Get(int showID, int seasonNumber);
|
Task<Season> Get(int showID, int seasonNumber);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's show slug and it's seasonNumber
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
Task<Season> Get(string showSlug, int seasonNumber);
|
Task<Season> Get(string showSlug, int seasonNumber);
|
||||||
Task Delete(string showSlug, int seasonNumber);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The repository to handle episodes
|
||||||
|
/// </summary>
|
||||||
public interface IEpisodeRepository : IRepository<Episode>
|
public interface IEpisodeRepository : IRepository<Episode>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's season ID and it's episode number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="seasonID">The ID of the season</param>
|
||||||
|
/// <param name="episodeNumber">The episode number</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> Get(int seasonID, int episodeNumber);
|
Task<Episode> Get(int seasonID, int episodeNumber);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's showID and it's absolute number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's showID and it's absolute number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||||
Task Delete(string showSlug, int seasonNumber, int episodeNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITrackRepository : IRepository<Track>
|
public interface ITrackRepository : IRepository<Track>
|
||||||
|
@ -15,27 +15,6 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IBaseRepository[] _repositories;
|
private readonly IBaseRepository[] _repositories;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="LibraryManager"/> instancce with every repository available.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="repositories">The list of repositories that this library manager should manage. If a repository for every base type is not available, this instance won't be stable.</param>
|
|
||||||
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
|
||||||
{
|
|
||||||
_repositories = repositories.ToArray();
|
|
||||||
LibraryRepository = GetRepository<Library>() as ILibraryRepository;
|
|
||||||
LibraryItemRepository = GetRepository<LibraryItem>() as ILibraryItemRepository;
|
|
||||||
CollectionRepository = GetRepository<Collection>() as ICollectionRepository;
|
|
||||||
ShowRepository = GetRepository<Show>() as IShowRepository;
|
|
||||||
SeasonRepository = GetRepository<Season>() as ISeasonRepository;
|
|
||||||
EpisodeRepository = GetRepository<Episode>() as IEpisodeRepository;
|
|
||||||
TrackRepository = GetRepository<Track>() as ITrackRepository;
|
|
||||||
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
|
||||||
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
|
||||||
GenreRepository = GetRepository<Genre>() as IGenreRepository;
|
|
||||||
ProviderRepository = GetRepository<Provider>() as IProviderRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The repository that handle libraries.
|
/// The repository that handle libraries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,7 +69,60 @@ namespace Kyoo.Controllers
|
|||||||
/// The repository that handle providers.
|
/// The repository that handle providers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IProviderRepository ProviderRepository { get; }
|
public IProviderRepository ProviderRepository { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="LibraryManager"/> instancce with every repository available.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repositories">The list of repositories that this library manager should manage. If a repository for every base type is not available, this instance won't be stable.</param>
|
||||||
|
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
||||||
|
{
|
||||||
|
_repositories = repositories.ToArray();
|
||||||
|
LibraryRepository = GetRepository<Library>() as ILibraryRepository;
|
||||||
|
LibraryItemRepository = GetRepository<LibraryItem>() as ILibraryItemRepository;
|
||||||
|
CollectionRepository = GetRepository<Collection>() as ICollectionRepository;
|
||||||
|
ShowRepository = GetRepository<Show>() as IShowRepository;
|
||||||
|
SeasonRepository = GetRepository<Season>() as ISeasonRepository;
|
||||||
|
EpisodeRepository = GetRepository<Episode>() as IEpisodeRepository;
|
||||||
|
TrackRepository = GetRepository<Track>() as ITrackRepository;
|
||||||
|
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
||||||
|
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
||||||
|
GenreRepository = GetRepository<Genre>() as IGenreRepository;
|
||||||
|
ProviderRepository = GetRepository<Provider>() as IProviderRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (IBaseRepository repo in _repositories)
|
||||||
|
repo.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A task that represents the asynchronous dispose operation.</returns>
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await Task.WhenAll(_repositories.Select(x => x.DisposeAsync().AsTask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the repository corresponding to the T item.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type you want</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The repository corresponding</returns>
|
||||||
|
public IRepository<T> GetRepository<T>()
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository<T> ret)
|
||||||
|
return ret;
|
||||||
|
throw new ItemNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the resource by it's ID
|
/// Get the resource by it's ID
|
||||||
@ -188,44 +220,104 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
/// <returns>The tracl found</returns>
|
/// <returns>The tracl found</returns>
|
||||||
public Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknown)
|
public Task<Track> Get(string slug, StreamType type = StreamType.Unknown)
|
||||||
{
|
{
|
||||||
return TrackRepository.Get(slug, type);
|
return TrackRepository.Get(slug, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
/// Get the resource by it's ID or null if it is not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
/// <param name="id">The id of the resource</param>
|
||||||
{
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
foreach (IBaseRepository repo in _repositories)
|
/// <returns>The resource found</returns>
|
||||||
repo.Dispose();
|
public async Task<T> GetOrDefault<T>(int id)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A task that represents the asynchronous dispose operation.</returns>
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
await Task.WhenAll(_repositories.Select(x => x.DisposeAsync().AsTask()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the repository corresponding to the T item.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type you want</typeparam>
|
|
||||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
|
||||||
/// <returns>The repository corresponding</returns>
|
|
||||||
public IRepository<T> GetRepository<T>()
|
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository<T> ret)
|
return await GetRepository<T>().GetOrDefault(id);
|
||||||
return ret;
|
}
|
||||||
throw new ItemNotFound();
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the resource by it's slug or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slug">The slug of the resource</param>
|
||||||
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
|
/// <returns>The resource found</returns>
|
||||||
|
public async Task<T> GetOrDefault<T>(string slug)
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
return await GetRepository<T>().GetOrDefault(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the resource by a filter function or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="where">The filter function.</param>
|
||||||
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
|
/// <returns>The first resource found that match the where function</returns>
|
||||||
|
public async Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where)
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
return await GetRepository<T>().GetOrDefault(where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
public async Task<Season> GetOrDefault(int showID, int seasonNumber)
|
||||||
|
{
|
||||||
|
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <returns>The season found</returns>
|
||||||
|
public async Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
||||||
|
{
|
||||||
|
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showID">The id of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
public async Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
|
/// <returns>The episode found</returns>
|
||||||
|
public async Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a track from it's slug and it's type or null if it is not found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slug">The slug of the track</param>
|
||||||
|
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||||
|
/// <returns>The tracl found</returns>
|
||||||
|
public async Task<Track> GetOrDefault(string slug, StreamType type = StreamType.Unknown)
|
||||||
|
{
|
||||||
|
return await TrackRepository.GetOrDefault(slug, type);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a related resource
|
/// Load a related resource
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -360,7 +452,7 @@ namespace Kyoo.Controllers
|
|||||||
.Then(x => s.Collections = x),
|
.Then(x => s.Collections = x),
|
||||||
|
|
||||||
(Show s, nameof(Show.Studio)) => StudioRepository
|
(Show s, nameof(Show.Studio)) => StudioRepository
|
||||||
.Get(x => x.Shows.Any(y => y.ID == obj.ID))
|
.GetOrDefault(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
s.Studio = x;
|
s.Studio = x;
|
||||||
@ -379,7 +471,7 @@ namespace Kyoo.Controllers
|
|||||||
(x, y) => { x.Season = y; x.SeasonID = y.ID; }),
|
(x, y) => { x.Season = y; x.SeasonID = y.ID; }),
|
||||||
|
|
||||||
(Season s, nameof(Season.Show)) => ShowRepository
|
(Season s, nameof(Season.Show)) => ShowRepository
|
||||||
.Get(x => x.Seasons.Any(y => y.ID == obj.ID))
|
.GetOrDefault(x => x.Seasons.Any(y => y.ID == obj.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
s.Show = x;
|
s.Show = x;
|
||||||
@ -398,7 +490,7 @@ namespace Kyoo.Controllers
|
|||||||
(x, y) => { x.Episode = y; x.EpisodeID = y.ID; }),
|
(x, y) => { x.Episode = y; x.EpisodeID = y.ID; }),
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Show)) => ShowRepository
|
(Episode e, nameof(Episode.Show)) => ShowRepository
|
||||||
.Get(x => x.Episodes.Any(y => y.ID == obj.ID))
|
.GetOrDefault(x => x.Episodes.Any(y => y.ID == obj.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
e.Show = x;
|
e.Show = x;
|
||||||
@ -406,7 +498,7 @@ namespace Kyoo.Controllers
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Season)) => SeasonRepository
|
(Episode e, nameof(Episode.Season)) => SeasonRepository
|
||||||
.Get(x => x.Episodes.Any(y => y.ID == e.ID))
|
.GetOrDefault(x => x.Episodes.Any(y => y.ID == e.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
e.Season = x;
|
e.Season = x;
|
||||||
@ -415,7 +507,7 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Track t, nameof(Track.Episode)) => EpisodeRepository
|
(Track t, nameof(Track.Episode)) => EpisodeRepository
|
||||||
.Get(x => x.Tracks.Any(y => y.ID == obj.ID))
|
.GetOrDefault(x => x.Tracks.Any(y => y.ID == obj.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
t.Episode = x;
|
t.Episode = x;
|
||||||
@ -623,6 +715,18 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
return GetRepository<T>().Create(item);
|
return GetRepository<T>().Create(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The object to create</param>
|
||||||
|
/// <typeparam name="T">The type of resource</typeparam>
|
||||||
|
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||||
|
public Task<T> CreateIfNotExists<T>(T item)
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
return GetRepository<T>().CreateIfNotExists(item);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Edit a resource
|
/// Edit a resource
|
||||||
@ -630,6 +734,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
|
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
|
||||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||||
/// <typeparam name="T">The type of resources</typeparam>
|
/// <typeparam name="T">The type of resources</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
||||||
public Task<T> Edit<T>(T item, bool resetOld)
|
public Task<T> Edit<T>(T item, bool resetOld)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
@ -642,6 +747,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The resource to delete</param>
|
/// <param name="item">The resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
public Task Delete<T>(T item)
|
public Task Delete<T>(T item)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
@ -653,6 +759,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The id of the resource to delete</param>
|
/// <param name="id">The id of the resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
public Task Delete<T>(int id)
|
public Task Delete<T>(int id)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
@ -664,6 +771,7 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slug">The slug of the resource to delete</param>
|
/// <param name="slug">The slug of the resource to delete</param>
|
||||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
public Task Delete<T>(string slug)
|
public Task Delete<T>(string slug)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
|
@ -29,22 +29,28 @@ namespace Kyoo.CommonApi
|
|||||||
[Authorize(Policy = "Read")]
|
[Authorize(Policy = "Read")]
|
||||||
public virtual async Task<ActionResult<T>> Get(int id)
|
public virtual async Task<ActionResult<T>> Get(int id)
|
||||||
{
|
{
|
||||||
T resource = await _repository.Get(id);
|
try
|
||||||
if (resource == null)
|
{
|
||||||
|
return await _repository.Get(id);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
}
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}")]
|
[HttpGet("{slug}")]
|
||||||
[Authorize(Policy = "Read")]
|
[Authorize(Policy = "Read")]
|
||||||
public virtual async Task<ActionResult<T>> Get(string slug)
|
public virtual async Task<ActionResult<T>> Get(string slug)
|
||||||
{
|
{
|
||||||
T resource = await _repository.Get(slug);
|
try
|
||||||
if (resource == null)
|
{
|
||||||
|
return await _repository.Get(slug);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
}
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("count")]
|
[HttpGet("count")]
|
||||||
@ -114,15 +120,19 @@ namespace Kyoo.CommonApi
|
|||||||
[Authorize(Policy = "Write")]
|
[Authorize(Policy = "Write")]
|
||||||
public virtual async Task<ActionResult<T>> Edit([FromQuery] bool resetOld, [FromBody] T resource)
|
public virtual async Task<ActionResult<T>> Edit([FromQuery] bool resetOld, [FromBody] T resource)
|
||||||
{
|
{
|
||||||
if (resource.ID > 0)
|
try
|
||||||
|
{
|
||||||
|
if (resource.ID > 0)
|
||||||
|
return await _repository.Edit(resource, resetOld);
|
||||||
|
|
||||||
|
T old = await _repository.Get(resource.Slug);
|
||||||
|
resource.ID = old.ID;
|
||||||
return await _repository.Edit(resource, resetOld);
|
return await _repository.Edit(resource, resetOld);
|
||||||
|
}
|
||||||
T old = await _repository.Get(resource.Slug);
|
catch (ItemNotFound)
|
||||||
if (old == null)
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
}
|
||||||
resource.ID = old.ID;
|
|
||||||
return await _repository.Edit(resource, resetOld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id:int}")]
|
[HttpPut("{id:int}")]
|
||||||
@ -144,11 +154,16 @@ namespace Kyoo.CommonApi
|
|||||||
[Authorize(Policy = "Write")]
|
[Authorize(Policy = "Write")]
|
||||||
public virtual async Task<ActionResult<T>> Edit(string slug, [FromQuery] bool resetOld, [FromBody] T resource)
|
public virtual async Task<ActionResult<T>> Edit(string slug, [FromQuery] bool resetOld, [FromBody] T resource)
|
||||||
{
|
{
|
||||||
T old = await _repository.Get(slug);
|
try
|
||||||
if (old == null)
|
{
|
||||||
|
T old = await _repository.Get(slug);
|
||||||
|
resource.ID = old.ID;
|
||||||
|
return await _repository.Edit(resource, resetOld);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
resource.ID = old.ID;
|
}
|
||||||
return await _repository.Edit(resource, resetOld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("{id:int}")]
|
[HttpDelete("{id:int}")]
|
||||||
|
@ -12,54 +12,112 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A base class to create repositories using Entity Framework.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of this repository</typeparam>
|
||||||
public abstract class LocalRepository<T> : IRepository<T>
|
public abstract class LocalRepository<T> : IRepository<T>
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Entity Framework's Database handle.
|
||||||
|
/// </summary>
|
||||||
protected readonly DbContext Database;
|
protected readonly DbContext Database;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default sort order that will be used for this resource's type.
|
||||||
|
/// </summary>
|
||||||
protected abstract Expression<Func<T, object>> DefaultSort { get; }
|
protected abstract Expression<Func<T, object>> DefaultSort { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new base <see cref="LocalRepository{T}"/> with the given database handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="database">A database connection to load resources of type <see cref="T"/></param>
|
||||||
protected LocalRepository(DbContext database)
|
protected LocalRepository(DbContext database)
|
||||||
{
|
{
|
||||||
Database = database;
|
Database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public Type RepositoryType => typeof(T);
|
public Type RepositoryType => typeof(T);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
Database.Dispose();
|
Database.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual ValueTask DisposeAsync()
|
public virtual ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return Database.DisposeAsync();
|
return Database.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task<T> Get(int id)
|
/// <summary>
|
||||||
|
/// Get a resource from it's ID and make the <see cref="Database"/> instance track it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the resource</param>
|
||||||
|
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||||
|
/// <returns>The tracked resource with the given ID</returns>
|
||||||
|
protected virtual async Task<T> GetWithTracking(int id)
|
||||||
|
{
|
||||||
|
T ret = await Database.Set<T>().AsTracking().FirstOrDefaultAsync(x => x.ID == id);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFound($"No {typeof(T).Name} found with the id {id}");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(int id)
|
||||||
|
{
|
||||||
|
T ret = await GetOrDefault(id);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFound($"No {typeof(T).Name} found with the id {id}");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(string slug)
|
||||||
|
{
|
||||||
|
T ret = await GetOrDefault(slug);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFound($"No {typeof(T).Name} found with the slug {slug}");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(Expression<Func<T, bool>> where)
|
||||||
|
{
|
||||||
|
T ret = await GetOrDefault(where);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFound($"No {typeof(T).Name} found with the given predicate.");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<T> GetOrDefault(int id)
|
||||||
{
|
{
|
||||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
|
return Database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task<T> GetWithTracking(int id)
|
/// <inheritdoc />
|
||||||
{
|
public Task<T> GetOrDefault(string slug)
|
||||||
return Database.Set<T>().AsTracking().FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<T> Get(string slug)
|
|
||||||
{
|
{
|
||||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
|
return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task<T> Get(Expression<Func<T, bool>> predicate)
|
|
||||||
{
|
|
||||||
return Database.Set<T>().FirstOrDefaultAsync(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<T> GetOrDefault(Expression<Func<T, bool>> where)
|
||||||
|
{
|
||||||
|
return Database.Set<T>().FirstOrDefaultAsync(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public abstract Task<ICollection<T>> Search(string query);
|
public abstract Task<ICollection<T>> Search(string query);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||||
Sort<T> sort = default,
|
Sort<T> sort = default,
|
||||||
Pagination limit = default)
|
Pagination limit = default)
|
||||||
@ -67,6 +125,14 @@ namespace Kyoo.Controllers
|
|||||||
return ApplyFilters(Database.Set<T>(), where, sort, limit);
|
return ApplyFilters(Database.Set<T>(), where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply filters to a query to ease sort, pagination & where queries for resources of this repository
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The base query to filter.</param>
|
||||||
|
/// <param name="where">An expression to filter based on arbitrary conditions</param>
|
||||||
|
/// <param name="sort">The sort settings (sort order & sort by)</param>
|
||||||
|
/// <param name="limit">Paginations information (where to start and how many to get)</param>
|
||||||
|
/// <returns>The filtered query</returns>
|
||||||
protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||||
Expression<Func<T, bool>> where = null,
|
Expression<Func<T, bool>> where = null,
|
||||||
Sort<T> sort = default,
|
Sort<T> sort = default,
|
||||||
@ -75,6 +141,17 @@ namespace Kyoo.Controllers
|
|||||||
return ApplyFilters(query, Get, DefaultSort, where, sort, limit);
|
return ApplyFilters(query, Get, DefaultSort, where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply filters to a query to ease sort, pagination & where queries for any resources types.
|
||||||
|
/// For resources of type <see cref="T"/>, see <see cref="ApplyFilters"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="get">A function to asynchronously get a resource from the database using it's ID.</param>
|
||||||
|
/// <param name="defaultSort">The default sort order of this resource's type.</param>
|
||||||
|
/// <param name="query">The base query to filter.</param>
|
||||||
|
/// <param name="where">An expression to filter based on arbitrary conditions</param>
|
||||||
|
/// <param name="sort">The sort settings (sort order & sort by)</param>
|
||||||
|
/// <param name="limit">Paginations information (where to start and how many to get)</param>
|
||||||
|
/// <returns>The filtered query</returns>
|
||||||
protected async Task<ICollection<TValue>> ApplyFilters<TValue>(IQueryable<TValue> query,
|
protected async Task<ICollection<TValue>> ApplyFilters<TValue>(IQueryable<TValue> query,
|
||||||
Func<int, Task<TValue>> get,
|
Func<int, Task<TValue>> get,
|
||||||
Expression<Func<TValue, object>> defaultSort,
|
Expression<Func<TValue, object>> defaultSort,
|
||||||
@ -110,6 +187,7 @@ namespace Kyoo.Controllers
|
|||||||
return await query.ToListAsync();
|
return await query.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
|
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
|
||||||
{
|
{
|
||||||
IQueryable<T> query = Database.Set<T>();
|
IQueryable<T> query = Database.Set<T>();
|
||||||
@ -118,6 +196,7 @@ namespace Kyoo.Controllers
|
|||||||
return query.CountAsync();
|
return query.CountAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Create(T obj)
|
public virtual async Task<T> Create(T obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
@ -126,6 +205,7 @@ namespace Kyoo.Controllers
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> CreateIfNotExists(T obj, bool silentFail = false)
|
public virtual async Task<T> CreateIfNotExists(T obj, bool silentFail = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -141,10 +221,7 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
catch (DuplicatedItemException)
|
catch (DuplicatedItemException)
|
||||||
{
|
{
|
||||||
T old = await Get(obj!.Slug);
|
return await Get(obj.Slug);
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old;
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -154,6 +231,7 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Edit(T edited, bool resetOld)
|
public virtual async Task<T> Edit(T edited, bool resetOld)
|
||||||
{
|
{
|
||||||
if (edited == null)
|
if (edited == null)
|
||||||
@ -164,9 +242,7 @@ namespace Kyoo.Controllers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
T old = await GetWithTracking(edited.ID);
|
T old = await GetWithTracking(edited.ID);
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No resource found with the ID {edited.ID}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
if (resetOld)
|
||||||
Utility.Nullify(old);
|
Utility.Nullify(old);
|
||||||
Utility.Complete(old, edited, x => x.GetCustomAttribute<LoadableRelationAttribute>() == null);
|
Utility.Complete(old, edited, x => x.GetCustomAttribute<LoadableRelationAttribute>() == null);
|
||||||
@ -180,11 +256,24 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An overridable method to edit relatiosn of a resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resource">The non edited resource</param>
|
||||||
|
/// <param name="changed">The new version of <see cref="resource"/>. This item will be saved on the databse and replace <see cref="resource"/></param>
|
||||||
|
/// <param name="resetOld">A boolean to indicate if all values of resource should be discarded or not.</param>
|
||||||
|
/// <returns></returns>
|
||||||
protected virtual Task EditRelations(T resource, T changed, bool resetOld)
|
protected virtual Task EditRelations(T resource, T changed, bool resetOld)
|
||||||
{
|
{
|
||||||
return Validate(resource);
|
return Validate(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A method called just before saving a new resource to the database.
|
||||||
|
/// It is also called on the default implementation of <see cref="EditRelations"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resource">The resource that will be saved</param>
|
||||||
|
/// <exception cref="ArgumentException">You can throw this if the resource is illegal and should not be saved.</exception>
|
||||||
protected virtual Task Validate(T resource)
|
protected virtual Task Validate(T resource)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(resource.Slug))
|
if (string.IsNullOrEmpty(resource.Slug))
|
||||||
@ -207,38 +296,45 @@ namespace Kyoo.Controllers
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task Delete(int id)
|
public virtual async Task Delete(int id)
|
||||||
{
|
{
|
||||||
T resource = await Get(id);
|
T resource = await Get(id);
|
||||||
await Delete(resource);
|
await Delete(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task Delete(string slug)
|
public virtual async Task Delete(string slug)
|
||||||
{
|
{
|
||||||
T resource = await Get(slug);
|
T resource = await Get(slug);
|
||||||
await Delete(resource);
|
await Delete(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public abstract Task Delete(T obj);
|
public abstract Task Delete(T obj);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task DeleteRange(IEnumerable<T> objs)
|
public virtual async Task DeleteRange(IEnumerable<T> objs)
|
||||||
{
|
{
|
||||||
foreach (T obj in objs)
|
foreach (T obj in objs)
|
||||||
await Delete(obj);
|
await Delete(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task DeleteRange(IEnumerable<int> ids)
|
public virtual async Task DeleteRange(IEnumerable<int> ids)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
foreach (int id in ids)
|
||||||
await Delete(id);
|
await Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public virtual async Task DeleteRange(IEnumerable<string> slugs)
|
public virtual async Task DeleteRange(IEnumerable<string> slugs)
|
||||||
{
|
{
|
||||||
foreach (string slug in slugs)
|
foreach (string slug in slugs)
|
||||||
await Delete(slug);
|
await Delete(slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public async Task DeleteRange(Expression<Func<T, bool>> where)
|
public async Task DeleteRange(Expression<Func<T, bool>> where)
|
||||||
{
|
{
|
||||||
ICollection<T> resources = await GetAll(where);
|
ICollection<T> resources = await GetAll(where);
|
||||||
|
17
Kyoo.Tests/Library/RepositoryTests.cs
Normal file
17
Kyoo.Tests/Library/RepositoryTests.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Kyoo.Tests
|
||||||
|
{
|
||||||
|
public class RepositoryTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Get_Test()
|
||||||
|
{
|
||||||
|
TestContext context = new();
|
||||||
|
using DatabaseContext database = context.New();
|
||||||
|
|
||||||
|
Assert.Equal(1, database.Shows.Count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
Kyoo.Tests/Library/TestContext.cs
Normal file
79
Kyoo.Tests/Library/TestContext.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Kyoo.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class responsible to fill and create in memory databases for unit tests.
|
||||||
|
/// </summary>
|
||||||
|
public class TestContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The context's options that specify to use an in memory Sqlite database.
|
||||||
|
/// </summary>
|
||||||
|
private readonly DbContextOptions<DatabaseContext> _context;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new database and fill it with informations.
|
||||||
|
/// </summary>
|
||||||
|
public TestContext()
|
||||||
|
{
|
||||||
|
SqliteConnection connection = new("DataSource=:memory:");
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_context = new DbContextOptionsBuilder<DatabaseContext>()
|
||||||
|
.UseSqlite(connection)
|
||||||
|
.Options;
|
||||||
|
FillDatabase();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fill the database with pre defined values using a clean context.
|
||||||
|
/// </summary>
|
||||||
|
private void FillDatabase()
|
||||||
|
{
|
||||||
|
using DatabaseContext context = new(_context);
|
||||||
|
context.Shows.Add(new Show
|
||||||
|
{
|
||||||
|
ID = 67,
|
||||||
|
Slug = "anohana",
|
||||||
|
Title = "Anohana: The Flower We Saw That Day",
|
||||||
|
Aliases = new[]
|
||||||
|
{
|
||||||
|
"Ano Hi Mita Hana no Namae o Bokutachi wa Mada Shiranai.",
|
||||||
|
"AnoHana",
|
||||||
|
"We Still Don't Know the Name of the Flower We Saw That Day."
|
||||||
|
},
|
||||||
|
Overview = "When Yadomi Jinta was a child, he was a central piece in a group of close friends. " +
|
||||||
|
"In time, however, these childhood friends drifted apart, and when they became high " +
|
||||||
|
"school students, they had long ceased to think of each other as friends.",
|
||||||
|
Status = Status.Finished,
|
||||||
|
TrailerUrl = null,
|
||||||
|
StartYear = 2011,
|
||||||
|
EndYear = 2011,
|
||||||
|
Poster = "poster",
|
||||||
|
Logo = "logo",
|
||||||
|
Backdrop = "backdrop",
|
||||||
|
IsMovie = false,
|
||||||
|
Studio = null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a new databse context connected to a in memory Sqlite databse.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A valid DatabaseContext</returns>
|
||||||
|
public DatabaseContext New()
|
||||||
|
{
|
||||||
|
return new(_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -210,13 +210,7 @@ namespace Kyoo.Controllers
|
|||||||
return x;
|
return x;
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(string showSlug, int seasonNumber, int episodeNumber)
|
|
||||||
{
|
|
||||||
Episode obj = await Get(showSlug, seasonNumber, episodeNumber);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task Delete(Episode obj)
|
public override async Task Delete(Episode obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
|
@ -5,22 +5,39 @@ using System.Linq.Expressions;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A local repository to handle seasons.
|
||||||
|
/// </summary>
|
||||||
public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
|
public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Has this instance been disposed and should not handle requests?
|
||||||
|
/// </summary>
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
private readonly IShowRepository _shows;
|
private readonly IShowRepository _shows;
|
||||||
private readonly Lazy<IEpisodeRepository> _episodes;
|
private readonly Lazy<IEpisodeRepository> _episodes;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
protected override Expression<Func<Season, object>> DefaultSort => x => x.SeasonNumber;
|
protected override Expression<Func<Season, object>> DefaultSort => x => x.SeasonNumber;
|
||||||
|
|
||||||
|
|
||||||
public SeasonRepository(DatabaseContext database,
|
/// <summary>
|
||||||
|
/// Create a new <see cref="SeasonRepository"/> using the provided handle, a provider & a show repository and
|
||||||
|
/// a service provider to lazilly request an episode repository.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="database">The database handle that will be used</param>
|
||||||
|
/// <param name="providers">A provider repository</param>
|
||||||
|
/// <param name="shows">A show repository</param>
|
||||||
|
/// <param name="services">A service provider to lazilly request an episode repository.</param>
|
||||||
|
public SeasonRepository(DatabaseContext database,
|
||||||
IProviderRepository providers,
|
IProviderRepository providers,
|
||||||
IShowRepository shows,
|
IShowRepository shows,
|
||||||
IServiceProvider services)
|
IServiceProvider services)
|
||||||
@ -33,6 +50,7 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@ -46,6 +64,7 @@ namespace Kyoo.Controllers
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@ -58,22 +77,23 @@ namespace Kyoo.Controllers
|
|||||||
await _episodes.Value.DisposeAsync();
|
await _episodes.Value.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async Task<Season> Get(int id)
|
public override async Task<Season> Get(int id)
|
||||||
{
|
{
|
||||||
Season ret = await base.Get(id);
|
Season ret = await base.Get(id);
|
||||||
if (ret != null)
|
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
|
||||||
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async Task<Season> Get(Expression<Func<Season, bool>> predicate)
|
public override async Task<Season> Get(Expression<Func<Season, bool>> predicate)
|
||||||
{
|
{
|
||||||
Season ret = await base.Get(predicate);
|
Season ret = await base.Get(predicate);
|
||||||
if (ret != null)
|
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
|
||||||
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override Task<Season> Get(string slug)
|
public override Task<Season> Get(string slug)
|
||||||
{
|
{
|
||||||
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)");
|
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)");
|
||||||
@ -83,24 +103,41 @@ namespace Kyoo.Controllers
|
|||||||
return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value));
|
return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public async Task<Season> Get(int showID, int seasonNumber)
|
public async Task<Season> Get(int showID, int seasonNumber)
|
||||||
{
|
{
|
||||||
Season ret = await _database.Seasons.FirstOrDefaultAsync(x => x.ShowID == showID
|
Season ret = await GetOrDefault(showID, seasonNumber);
|
||||||
&& x.SeasonNumber == seasonNumber);
|
if (ret == null)
|
||||||
if (ret != null)
|
throw new ItemNotFound($"No season {seasonNumber} found for the show {showID}");
|
||||||
ret.ShowSlug = await _shows.GetSlug(showID);
|
ret.ShowSlug = await _shows.GetSlug(showID);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public async Task<Season> Get(string showSlug, int seasonNumber)
|
public async Task<Season> Get(string showSlug, int seasonNumber)
|
||||||
{
|
{
|
||||||
Season ret = await _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
Season ret = await GetOrDefault(showSlug, seasonNumber);
|
||||||
&& x.SeasonNumber == seasonNumber);
|
if (ret == null)
|
||||||
if (ret != null)
|
throw new ItemNotFound($"No season {seasonNumber} found for the show {showSlug}");
|
||||||
ret.ShowSlug = showSlug;
|
ret.ShowSlug = showSlug;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Task<Season> GetOrDefault(int showID, int seasonNumber)
|
||||||
|
{
|
||||||
|
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||||
|
&& x.SeasonNumber == seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
||||||
|
{
|
||||||
|
return _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||||
|
&& x.SeasonNumber == seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async Task<ICollection<Season>> Search(string query)
|
public override async Task<ICollection<Season>> Search(string query)
|
||||||
{
|
{
|
||||||
List<Season> seasons = await _database.Seasons
|
List<Season> seasons = await _database.Seasons
|
||||||
@ -113,6 +150,7 @@ namespace Kyoo.Controllers
|
|||||||
return seasons;
|
return seasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async Task<ICollection<Season>> GetAll(Expression<Func<Season, bool>> where = null,
|
public override async Task<ICollection<Season>> GetAll(Expression<Func<Season, bool>> where = null,
|
||||||
Sort<Season> sort = default,
|
Sort<Season> sort = default,
|
||||||
Pagination limit = default)
|
Pagination limit = default)
|
||||||
@ -123,6 +161,7 @@ namespace Kyoo.Controllers
|
|||||||
return seasons;
|
return seasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override async Task<Season> Create(Season obj)
|
public override async Task<Season> Create(Season obj)
|
||||||
{
|
{
|
||||||
await base.Create(obj);
|
await base.Create(obj);
|
||||||
@ -132,6 +171,7 @@ namespace Kyoo.Controllers
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
protected override async Task Validate(Season resource)
|
protected override async Task Validate(Season resource)
|
||||||
{
|
{
|
||||||
if (resource.ShowID <= 0)
|
if (resource.ShowID <= 0)
|
||||||
@ -146,6 +186,7 @@ namespace Kyoo.Controllers
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
protected override async Task EditRelations(Season resource, Season changed, bool resetOld)
|
protected override async Task EditRelations(Season resource, Season changed, bool resetOld)
|
||||||
{
|
{
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
if (changed.ExternalIDs != null || resetOld)
|
||||||
@ -155,13 +196,8 @@ namespace Kyoo.Controllers
|
|||||||
}
|
}
|
||||||
await base.EditRelations(resource, changed, resetOld);
|
await base.EditRelations(resource, changed, resetOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(string showSlug, int seasonNumber)
|
/// <inheritdoc/>
|
||||||
{
|
|
||||||
Season obj = await Get(showSlug, seasonNumber);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task Delete(Season obj)
|
public override async Task Delete(Season obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
|
@ -58,13 +58,13 @@ namespace Kyoo
|
|||||||
modelBuilder.HasPostgresEnum<ItemType>();
|
modelBuilder.HasPostgresEnum<ItemType>();
|
||||||
modelBuilder.HasPostgresEnum<StreamType>();
|
modelBuilder.HasPostgresEnum<StreamType>();
|
||||||
|
|
||||||
modelBuilder.Entity<Library>()
|
// modelBuilder.Entity<Library>()
|
||||||
.Property(x => x.Paths)
|
// .Property(x => x.Paths)
|
||||||
.HasColumnType("text[]");
|
// .HasColumnType("text[]");
|
||||||
|
//
|
||||||
modelBuilder.Entity<Show>()
|
// modelBuilder.Entity<Show>()
|
||||||
.Property(x => x.Aliases)
|
// .Property(x => x.Aliases)
|
||||||
.HasColumnType("text[]");
|
// .HasColumnType("text[]");
|
||||||
|
|
||||||
modelBuilder.Entity<Track>()
|
modelBuilder.Entity<Track>()
|
||||||
.Property(t => t.IsDefault)
|
.Property(t => t.IsDefault)
|
||||||
|
@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace Kyoo.Models.DatabaseMigrations.Internal
|
namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||||
{
|
{
|
||||||
[DbContext(typeof(DatabaseContext))]
|
[DbContext(typeof(DatabaseContext))]
|
||||||
[Migration("20210417232515_Initial")]
|
[Migration("20210420221509_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
@ -144,44 +144,48 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
private async Task RegisterExternalSubtitle(string path, CancellationToken token)
|
private async Task RegisterExternalSubtitle(string path, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (token.IsCancellationRequested || path.Split(Path.DirectorySeparatorChar).Contains("Subtitles"))
|
try
|
||||||
return;
|
|
||||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
|
||||||
await using ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
|
||||||
|
|
||||||
string patern = _config.GetValue<string>("subtitleRegex");
|
|
||||||
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
|
||||||
Match match = regex.Match(path);
|
|
||||||
|
|
||||||
if (!match.Success)
|
|
||||||
{
|
{
|
||||||
await Console.Error.WriteLineAsync($"The subtitle at {path} does not match the subtitle's regex.");
|
if (token.IsCancellationRequested || path.Split(Path.DirectorySeparatorChar).Contains("Subtitles"))
|
||||||
return;
|
return;
|
||||||
|
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||||
|
await using ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||||
|
|
||||||
|
string patern = _config.GetValue<string>("subtitleRegex");
|
||||||
|
Regex regex = new(patern, RegexOptions.IgnoreCase);
|
||||||
|
Match match = regex.Match(path);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
await Console.Error.WriteLineAsync($"The subtitle at {path} does not match the subtitle's regex.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string episodePath = match.Groups["Episode"].Value;
|
||||||
|
Episode episode = await libraryManager!.Get<Episode>(x => x.Path.StartsWith(episodePath));
|
||||||
|
Track track = new()
|
||||||
|
{
|
||||||
|
Type = StreamType.Subtitle,
|
||||||
|
Language = match.Groups["Language"].Value,
|
||||||
|
IsDefault = match.Groups["Default"].Value.Length > 0,
|
||||||
|
IsForced = match.Groups["Forced"].Value.Length > 0,
|
||||||
|
Codec = SubtitleExtensions[Path.GetExtension(path)],
|
||||||
|
IsExternal = true,
|
||||||
|
Path = path,
|
||||||
|
Episode = episode
|
||||||
|
};
|
||||||
|
|
||||||
|
await libraryManager.Create(track);
|
||||||
|
Console.WriteLine($"Registering subtitle at: {path}.");
|
||||||
}
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
string episodePath = match.Groups["Episode"].Value;
|
|
||||||
Episode episode = await libraryManager!.Get<Episode>(x => x.Path.StartsWith(episodePath));
|
|
||||||
|
|
||||||
if (episode == null)
|
|
||||||
{
|
{
|
||||||
await Console.Error.WriteLineAsync($"No episode found for subtitle at: ${path}.");
|
await Console.Error.WriteLineAsync($"No episode found for subtitle at: ${path}.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
Track track = new(StreamType.Subtitle,
|
|
||||||
null,
|
|
||||||
match.Groups["Language"].Value,
|
|
||||||
match.Groups["Default"].Value.Length > 0,
|
|
||||||
match.Groups["Forced"].Value.Length > 0,
|
|
||||||
SubtitleExtensions[Path.GetExtension(path)],
|
|
||||||
true,
|
|
||||||
path)
|
|
||||||
{
|
{
|
||||||
Episode = episode
|
await Console.Error.WriteLineAsync($"Unknown error while registering subtitle: {ex.Message}");
|
||||||
};
|
}
|
||||||
|
|
||||||
await libraryManager.Create(track);
|
|
||||||
Console.WriteLine($"Registering subtitle at: {path}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RegisterFile(string path, string relativePath, Library library, CancellationToken token)
|
private async Task RegisterFile(string path, string relativePath, Library library, CancellationToken token)
|
||||||
@ -308,22 +312,20 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
if (seasonNumber == -1)
|
if (seasonNumber == -1)
|
||||||
return default;
|
return default;
|
||||||
Season season = await libraryManager.Get(show.Slug, seasonNumber);
|
try
|
||||||
if (season == null)
|
|
||||||
{
|
{
|
||||||
season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
Season season = await libraryManager.Get(show.Slug, seasonNumber);
|
||||||
try
|
season.Show = show;
|
||||||
{
|
return season;
|
||||||
await libraryManager.Create(season);
|
}
|
||||||
await _thumbnailsManager.Validate(season);
|
catch (ItemNotFound)
|
||||||
}
|
{
|
||||||
catch (DuplicatedItemException)
|
Season season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
||||||
{
|
await libraryManager.CreateIfNotExists(season);
|
||||||
season = await libraryManager.Get(show.Slug, season.SeasonNumber);
|
await _thumbnailsManager.Validate(season);
|
||||||
}
|
season.Show = show;
|
||||||
|
return season;
|
||||||
}
|
}
|
||||||
season.Show = show;
|
|
||||||
return season;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Episode> GetEpisode(ILibraryManager libraryManager,
|
private async Task<Episode> GetEpisode(ILibraryManager libraryManager,
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.CommonApi;
|
using Kyoo.CommonApi;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
@ -163,20 +164,30 @@ namespace Kyoo.Api
|
|||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<IActionResult> GetThumb(int id)
|
public async Task<IActionResult> GetThumb(int id)
|
||||||
{
|
{
|
||||||
Episode episode = await _libraryManager.Get<Episode>(id);
|
try
|
||||||
if (episode == null)
|
{
|
||||||
|
Episode episode = await _libraryManager.Get<Episode>(id);
|
||||||
|
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}/thumb")]
|
[HttpGet("{slug}/thumb")]
|
||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<IActionResult> GetThumb(string slug)
|
public async Task<IActionResult> GetThumb(string slug)
|
||||||
{
|
{
|
||||||
Episode episode = await _libraryManager.Get<Episode>(slug);
|
try
|
||||||
if (episode == null)
|
{
|
||||||
|
Episode episode = await _libraryManager.Get<Episode>(slug);
|
||||||
|
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -376,13 +376,18 @@ namespace Kyoo.Api
|
|||||||
[Authorize(Policy = "Read")]
|
[Authorize(Policy = "Read")]
|
||||||
public async Task<ActionResult<Dictionary<string, string>>> GetFonts(string slug)
|
public async Task<ActionResult<Dictionary<string, string>>> GetFonts(string slug)
|
||||||
{
|
{
|
||||||
Show show = await _libraryManager.Get<Show>(slug);
|
try
|
||||||
if (show == null)
|
{
|
||||||
|
Show show = await _libraryManager.Get<Show>(slug);
|
||||||
|
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments");
|
||||||
|
return (await _files.ListFiles(path))
|
||||||
|
.ToDictionary(Path.GetFileNameWithoutExtension,
|
||||||
|
x => $"{BaseURL}/api/shows/{slug}/fonts/{Path.GetFileName(x)}");
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments");
|
}
|
||||||
return (await _files.ListFiles(path))
|
|
||||||
.ToDictionary(Path.GetFileNameWithoutExtension,
|
|
||||||
x => $"{BaseURL}/api/shows/{slug}/fonts/{Path.GetFileName(x)}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{showSlug}/font/{slug}")]
|
[HttpGet("{showSlug}/font/{slug}")]
|
||||||
@ -390,41 +395,61 @@ namespace Kyoo.Api
|
|||||||
[Authorize(Policy = "Read")]
|
[Authorize(Policy = "Read")]
|
||||||
public async Task<IActionResult> GetFont(string showSlug, string slug)
|
public async Task<IActionResult> GetFont(string showSlug, string slug)
|
||||||
{
|
{
|
||||||
Show show = await _libraryManager.Get<Show>(showSlug);
|
try
|
||||||
if (show == null)
|
{
|
||||||
|
Show show = await _libraryManager.Get<Show>(showSlug);
|
||||||
|
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments", slug);
|
||||||
|
return _files.FileResult(path);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments", slug);
|
}
|
||||||
return _files.FileResult(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}/poster")]
|
[HttpGet("{slug}/poster")]
|
||||||
[Authorize(Policy = "Read")]
|
[Authorize(Policy = "Read")]
|
||||||
public async Task<IActionResult> GetPoster(string slug)
|
public async Task<IActionResult> GetPoster(string slug)
|
||||||
{
|
{
|
||||||
Show show = await _libraryManager.Get<Show>(slug);
|
try
|
||||||
if (show == null)
|
{
|
||||||
|
Show show = await _libraryManager.Get<Show>(slug);
|
||||||
|
return _files.FileResult(await _thumbs.GetShowPoster(show));
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return _files.FileResult(await _thumbs.GetShowPoster(show));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}/logo")]
|
[HttpGet("{slug}/logo")]
|
||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<IActionResult> GetLogo(string slug)
|
public async Task<IActionResult> GetLogo(string slug)
|
||||||
{
|
{
|
||||||
Show show = await _libraryManager.Get<Show>(slug);
|
try
|
||||||
if (show == null)
|
{
|
||||||
|
Show show = await _libraryManager.Get<Show>(slug);
|
||||||
|
return _files.FileResult(await _thumbs.GetShowLogo(show));
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return _files.FileResult(await _thumbs.GetShowLogo(show));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}/backdrop")]
|
[HttpGet("{slug}/backdrop")]
|
||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<IActionResult> GetBackdrop(string slug)
|
public async Task<IActionResult> GetBackdrop(string slug)
|
||||||
{
|
{
|
||||||
Show show = await _libraryManager.Get<Show>(slug);
|
try
|
||||||
if (show == null)
|
{
|
||||||
|
Show show = await _libraryManager.Get<Show>(slug);
|
||||||
|
return _files.FileResult(await _thumbs.GetShowBackdrop(show));
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return _files.FileResult(await _thumbs.GetShowBackdrop(show));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Api
|
|||||||
Track subtitle;
|
Track subtitle;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
subtitle = await _libraryManager.GetTrack(slug, StreamType.Subtitle);
|
subtitle = await _libraryManager.Get(slug, StreamType.Subtitle);
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -21,10 +22,15 @@ namespace Kyoo.Api
|
|||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<ActionResult<WatchItem>> GetWatchItem(string slug)
|
public async Task<ActionResult<WatchItem>> GetWatchItem(string slug)
|
||||||
{
|
{
|
||||||
Episode item = await _libraryManager.Get<Episode>(slug);
|
try
|
||||||
if (item == null)
|
{
|
||||||
|
Episode item = await _libraryManager.Get<Episode>(slug);
|
||||||
|
return await WatchItem.FromEpisode(item, _libraryManager);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return await WatchItem.FromEpisode(item, _libraryManager);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user