mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Merging the rest branch
This commit is contained in:
commit
0609006cab
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
@ -8,6 +10,31 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
public interface ILibraryManager : IDisposable, IAsyncDisposable
|
public interface ILibraryManager : IDisposable, IAsyncDisposable
|
||||||
{
|
{
|
||||||
|
// Repositories
|
||||||
|
ILibraryRepository LibraryRepository { get; }
|
||||||
|
ILibraryItemRepository LibraryItemRepository { get; }
|
||||||
|
ICollectionRepository CollectionRepository { get; }
|
||||||
|
IShowRepository ShowRepository { get; }
|
||||||
|
ISeasonRepository SeasonRepository { get; }
|
||||||
|
IEpisodeRepository EpisodeRepository { get; }
|
||||||
|
ITrackRepository TrackRepository { get; }
|
||||||
|
IPeopleRepository PeopleRepository { get; }
|
||||||
|
IStudioRepository StudioRepository { get; }
|
||||||
|
IGenreRepository GenreRepository { get; }
|
||||||
|
IProviderRepository ProviderRepository { get; }
|
||||||
|
|
||||||
|
// Get by id
|
||||||
|
Task<Library> GetLibrary(int id);
|
||||||
|
Task<Collection> GetCollection(int id);
|
||||||
|
Task<Show> GetShow(int id);
|
||||||
|
Task<Season> GetSeason(int id);
|
||||||
|
Task<Season> GetSeason(int showID, int seasonNumber);
|
||||||
|
Task<Episode> GetEpisode(int id);
|
||||||
|
Task<Episode> GetEpisode(int showID, int seasonNumber, int episodeNumber);
|
||||||
|
Task<Genre> GetGenre(int id);
|
||||||
|
Task<Studio> GetStudio(int id);
|
||||||
|
Task<People> GetPeople(int id);
|
||||||
|
|
||||||
// Get by slug
|
// Get by slug
|
||||||
Task<Library> GetLibrary(string slug);
|
Task<Library> GetLibrary(string slug);
|
||||||
Task<Collection> GetCollection(string slug);
|
Task<Collection> GetCollection(string slug);
|
||||||
@ -16,38 +43,408 @@ namespace Kyoo.Controllers
|
|||||||
Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
|
Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
Task<Episode> GetMovieEpisode(string movieSlug);
|
Task<Episode> GetMovieEpisode(string movieSlug);
|
||||||
Task<Track> GetTrack(int id);
|
Task<Track> GetTrack(int id);
|
||||||
Task<Track> GetTrack(int episodeID, string language, bool isForced);
|
|
||||||
Task<Genre> GetGenre(string slug);
|
Task<Genre> GetGenre(string slug);
|
||||||
Task<Studio> GetStudio(string slug);
|
Task<Studio> GetStudio(string slug);
|
||||||
Task<People> GetPeople(string slug);
|
Task<People> GetPeople(string slug);
|
||||||
|
|
||||||
// Get by relations
|
// Get by relations
|
||||||
Task<ICollection<Season>> GetSeasons(int showID);
|
Task<ICollection<Season>> GetSeasonsFromShow(int showID,
|
||||||
Task<ICollection<Season>> GetSeasons(string showSlug);
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Season>> GetSeasonsFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Season, bool>> where,
|
||||||
|
Expression<Func<Season, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetSeasonsFromShow(showID, where, new Sort<Season>(sort), limit);
|
||||||
|
Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Season, bool>> where,
|
||||||
|
Expression<Func<Season, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetSeasonsFromShow(showSlug, where, new Sort<Season>(sort), limit);
|
||||||
|
|
||||||
Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber);
|
Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
|
||||||
Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber);
|
Expression<Func<Episode, bool>> where = null,
|
||||||
Task<ICollection<Episode>> GetEpisodes(int seasonID);
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromShow(showID, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromShow(showSlug, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromSeason(seasonID, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromSeason(showID, seasonNumber, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<PeopleLink, bool>> where,
|
||||||
|
Expression<Func<PeopleLink, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetPeopleFromShow(showID, where, new Sort<PeopleLink>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<PeopleLink, bool>> where,
|
||||||
|
Expression<Func<PeopleLink, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Genre>> GetGenresFromShow(int showID,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Genre>> GetGenresFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Genre, bool>> where,
|
||||||
|
Expression<Func<Genre, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetGenresFromShow(showID, where, new Sort<Genre>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Genre>> GetGenresFromShow(string showSlug,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Genre>> GetGenresFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Genre, bool>> where,
|
||||||
|
Expression<Func<Genre, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetGenresFromShow(showSlug, where, new Sort<Genre>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(int episodeID,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(int episodeID,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetTracksFromEpisode(episodeID, where, new Sort<Track>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetTracksFromEpisode(showID, seasonNumber, episodeNumber, where, new Sort<Track>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetTracksFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetTracksFromEpisode(showSlug, seasonNumber, episodeNumber, where, new Sort<Track>(sort), limit);
|
||||||
|
|
||||||
|
Task<Studio> GetStudioFromShow(int showID);
|
||||||
|
Task<Studio> GetStudioFromShow(string showSlug);
|
||||||
|
Task<Show> GetShowFromSeason(int seasonID);
|
||||||
|
Task<Show> GetShowFromEpisode(int episodeID);
|
||||||
|
Task<Season> GetSeasonFromEpisode(int episodeID);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromShow(int showID,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetLibrariesFromShow(showID, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromShow(string showSlug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetLibrariesFromShow(showSlug, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromShow(int showID,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetCollectionsFromShow(showID, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromShow(string showSlug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetCollectionsFromShow(showSlug, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetShowsFromLibrary(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetShowsFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetShowsFromLibrary(id, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetShowsFromLibrary(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetShowsFromLibrary(string slug,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetShowsFromLibrary(slug, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromLibrary(int id,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetCollectionsFromLibrary(id, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromLibrary(string showSlug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetCollectionsFromLibrary(string showSlug,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetCollectionsFromLibrary(showSlug, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||||
|
Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||||
|
Expression<Func<LibraryItem, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
|
||||||
|
Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
|
||||||
|
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||||
|
Expression<Func<LibraryItem, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetItemsFromLibrary(librarySlug, where, new Sort<LibraryItem>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetShowsFromCollection(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetShowsFromCollection(int id,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetShowsFromCollection(id, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetShowsFromCollection(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetShowsFromCollection(string slug,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetShowsFromCollection(slug, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromCollection(int id,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromCollection(int id,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetLibrariesFromCollection(id, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromCollection(string slug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetLibrariesFromCollection(string slug,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetLibrariesFromCollection(slug, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<ShowRole>> GetRolesFromPeople(int showID,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<ShowRole>> GetRolesFromPeople(int showID,
|
||||||
|
[Optional] Expression<Func<ShowRole, bool>> where,
|
||||||
|
Expression<Func<ShowRole, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetRolesFromPeople(showID, where, new Sort<ShowRole>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<ShowRole>> GetRolesFromPeople(string showSlug,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<ShowRole>> GetRolesFromPeople(string showSlug,
|
||||||
|
[Optional] Expression<Func<ShowRole, bool>> where,
|
||||||
|
Expression<Func<ShowRole, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetRolesFromPeople(showSlug, where, new Sort<ShowRole>(sort), limit);
|
||||||
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
Task<Show> GetShowByPath(string path);
|
|
||||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||||
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
|
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
|
||||||
|
|
||||||
// Get all
|
// Get all
|
||||||
Task<ICollection<Library>> GetLibraries();
|
Task<ICollection<Library>> GetLibraries(Expression<Func<Library, bool>> where = null,
|
||||||
Task<ICollection<Collection>> GetCollections();
|
Sort<Library> sort = default,
|
||||||
Task<ICollection<Show>> GetShows();
|
Pagination limit = default);
|
||||||
Task<ICollection<Season>> GetSeasons();
|
Task<ICollection<Collection>> GetCollections(Expression<Func<Collection, bool>> where = null,
|
||||||
Task<ICollection<Episode>> GetEpisodes();
|
Sort<Collection> sort = default,
|
||||||
Task<ICollection<Track>> GetTracks();
|
Pagination limit = default);
|
||||||
Task<ICollection<Studio>> GetStudios();
|
Task<ICollection<Show>> GetShows(Expression<Func<Show, bool>> where = null,
|
||||||
Task<ICollection<People>> GetPeoples();
|
Sort<Show> sort = default,
|
||||||
Task<ICollection<Genre>> GetGenres();
|
Pagination limit = default);
|
||||||
Task<ICollection<ProviderID>> GetProviders();
|
Task<ICollection<Season>> GetSeasonsFromShow(Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromShow(Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetTracks(Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Studio>> GetStudios(Expression<Func<Studio, bool>> where = null,
|
||||||
|
Sort<Studio> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<People>> GetPeople(Expression<Func<People, bool>> where = null,
|
||||||
|
Sort<People> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Genre>> GetGenres(Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<ProviderID>> GetProviders(Expression<Func<ProviderID, bool>> where = null,
|
||||||
|
Sort<ProviderID> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetLibraries([Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetLibraries(where, new Sort<Library>(sort), limit);
|
||||||
|
Task<ICollection<Collection>> GetCollections([Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetCollections(where, new Sort<Collection>(sort), limit);
|
||||||
|
Task<ICollection<Show>> GetShows([Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetShows(where, new Sort<Show>(sort), limit);
|
||||||
|
Task<ICollection<Season>> GetSeasonsFromShow([Optional] Expression<Func<Season, bool>> where,
|
||||||
|
Expression<Func<Season, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetSeasonsFromShow(where, new Sort<Season>(sort), limit);
|
||||||
|
Task<ICollection<Episode>> GetEpisodesFromShow([Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetEpisodesFromShow(where, new Sort<Episode>(sort), limit);
|
||||||
|
Task<ICollection<Track>> GetTracks([Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetTracks(where, new Sort<Track>(sort), limit);
|
||||||
|
Task<ICollection<Studio>> GetStudios([Optional] Expression<Func<Studio, bool>> where,
|
||||||
|
Expression<Func<Studio, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetStudios(where, new Sort<Studio>(sort), limit);
|
||||||
|
Task<ICollection<People>> GetPeople([Optional] Expression<Func<People, bool>> where,
|
||||||
|
Expression<Func<People, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetPeople(where, new Sort<People>(sort), limit);
|
||||||
|
Task<ICollection<Genre>> GetGenres([Optional] Expression<Func<Genre, bool>> where,
|
||||||
|
Expression<Func<Genre, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetGenres(where, new Sort<Genre>(sort), limit);
|
||||||
|
Task<ICollection<ProviderID>> GetProviders([Optional] Expression<Func<ProviderID, bool>> where,
|
||||||
|
Expression<Func<ProviderID, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetProviders(where, new Sort<ProviderID>(sort), limit);
|
||||||
|
|
||||||
// Search
|
|
||||||
|
// Search
|
||||||
Task<ICollection<Library>> SearchLibraries(string searchQuery);
|
Task<ICollection<Library>> SearchLibraries(string searchQuery);
|
||||||
Task<ICollection<Collection>> SearchCollections(string searchQuery);
|
Task<ICollection<Collection>> SearchCollections(string searchQuery);
|
||||||
Task<ICollection<Show>> SearchShows(string searchQuery);
|
Task<ICollection<Show>> SearchShows(string searchQuery);
|
||||||
@ -58,26 +455,26 @@ namespace Kyoo.Controllers
|
|||||||
Task<ICollection<People>> SearchPeople(string searchQuery);
|
Task<ICollection<People>> SearchPeople(string searchQuery);
|
||||||
|
|
||||||
//Register values
|
//Register values
|
||||||
Task RegisterLibrary(Library library);
|
Task<Library> RegisterLibrary(Library library);
|
||||||
Task RegisterCollection(Collection collection);
|
Task<Collection> RegisterCollection(Collection collection);
|
||||||
Task RegisterShow(Show show);
|
Task<Show> RegisterShow(Show show);
|
||||||
Task RegisterSeason(Season season);
|
Task<Season> RegisterSeason(Season season);
|
||||||
Task RegisterEpisode(Episode episode);
|
Task<Episode> RegisterEpisode(Episode episode);
|
||||||
Task RegisterTrack(Track track);
|
Task<Track> RegisterTrack(Track track);
|
||||||
Task RegisterGenre(Genre genre);
|
Task<Genre> RegisterGenre(Genre genre);
|
||||||
Task RegisterStudio(Studio studio);
|
Task<Studio> RegisterStudio(Studio studio);
|
||||||
Task RegisterPeople(People people);
|
Task<People> RegisterPeople(People people);
|
||||||
|
|
||||||
// Edit values
|
// Edit values
|
||||||
Task EditLibrary(Library library, bool resetOld);
|
Task<Library> EditLibrary(Library library, bool resetOld);
|
||||||
Task EditCollection(Collection collection, bool resetOld);
|
Task<Collection> EditCollection(Collection collection, bool resetOld);
|
||||||
Task EditShow(Show show, bool resetOld);
|
Task<Show> EditShow(Show show, bool resetOld);
|
||||||
Task EditSeason(Season season, bool resetOld);
|
Task<Season> EditSeason(Season season, bool resetOld);
|
||||||
Task EditEpisode(Episode episode, bool resetOld);
|
Task<Episode> EditEpisode(Episode episode, bool resetOld);
|
||||||
Task EditTrack(Track track, bool resetOld);
|
Task<Track> EditTrack(Track track, bool resetOld);
|
||||||
Task EditGenre(Genre genre, bool resetOld);
|
Task<Genre> EditGenre(Genre genre, bool resetOld);
|
||||||
Task EditStudio(Studio studio, bool resetOld);
|
Task<Studio> EditStudio(Studio studio, bool resetOld);
|
||||||
Task EditPeople(People people, bool resetOld);
|
Task<People> EditPeople(People people, bool resetOld);
|
||||||
|
|
||||||
|
|
||||||
// Delete values
|
// Delete values
|
||||||
@ -90,5 +487,27 @@ namespace Kyoo.Controllers
|
|||||||
Task DeleteGenre(Genre genre);
|
Task DeleteGenre(Genre genre);
|
||||||
Task DeleteStudio(Studio studio);
|
Task DeleteStudio(Studio studio);
|
||||||
Task DeletePeople(People people);
|
Task DeletePeople(People people);
|
||||||
|
|
||||||
|
//Delete by slug
|
||||||
|
Task DelteLibrary(string slug);
|
||||||
|
Task DeleteCollection(string slug);
|
||||||
|
Task DeleteShow(string slug);
|
||||||
|
Task DeleteSeason(string slug);
|
||||||
|
Task DeleteEpisode(string slug);
|
||||||
|
Task DeleteTrack(string slug);
|
||||||
|
Task DeleteGenre(string slug);
|
||||||
|
Task DeleteStudio(string slug);
|
||||||
|
Task DeletePeople(string slug);
|
||||||
|
|
||||||
|
//Delete by id
|
||||||
|
Task DelteLibrary(int id);
|
||||||
|
Task DeleteCollection(int id);
|
||||||
|
Task DeleteShow(int id);
|
||||||
|
Task DeleteSeason(int id);
|
||||||
|
Task DeleteEpisode(int id);
|
||||||
|
Task DeleteTrack(int id);
|
||||||
|
Task DeleteGenre(int id);
|
||||||
|
Task DeleteStudio(int id);
|
||||||
|
Task DeletePeople(int id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,91 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public interface IRepository<T> : IDisposable, IAsyncDisposable
|
public readonly struct Pagination
|
||||||
|
{
|
||||||
|
public int Count { get; }
|
||||||
|
public int AfterID { get; }
|
||||||
|
|
||||||
|
public Pagination(int count, int afterID = 0)
|
||||||
|
{
|
||||||
|
Count = count;
|
||||||
|
AfterID = afterID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Pagination(int limit) => new Pagination(limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Sort<T>
|
||||||
|
{
|
||||||
|
public Expression<Func<T, object>> Key;
|
||||||
|
public bool Descendant;
|
||||||
|
|
||||||
|
public Sort(Expression<Func<T, object>> key, bool descendant = false)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Descendant = descendant;
|
||||||
|
|
||||||
|
if (Key.Body is MemberExpression ||
|
||||||
|
Key.Body.NodeType == ExpressionType.Convert && ((UnaryExpression)Key.Body).Operand is MemberExpression)
|
||||||
|
return;
|
||||||
|
|
||||||
|
throw new ArgumentException("The given sort key is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sort(string sortBy)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(sortBy))
|
||||||
|
{
|
||||||
|
Key = null;
|
||||||
|
Descendant = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string key = sortBy.Contains(':') ? sortBy.Substring(0, sortBy.IndexOf(':')) : sortBy;
|
||||||
|
string order = sortBy.Contains(':') ? sortBy.Substring(sortBy.IndexOf(':') + 1) : null;
|
||||||
|
|
||||||
|
ParameterExpression param = Expression.Parameter(typeof(T), "x");
|
||||||
|
MemberExpression property = Expression.Property(param, key);
|
||||||
|
Key = property.Type.IsValueType
|
||||||
|
? Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param)
|
||||||
|
: Expression.Lambda<Func<T, object>>(property, param);
|
||||||
|
|
||||||
|
Descendant = order switch
|
||||||
|
{
|
||||||
|
"desc" => true,
|
||||||
|
"asc" => false,
|
||||||
|
null => false,
|
||||||
|
_ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IRepository<T> : IDisposable, IAsyncDisposable where T : IResource
|
||||||
{
|
{
|
||||||
Task<T> Get(int id);
|
Task<T> Get(int id);
|
||||||
Task<T> Get(string slug);
|
Task<T> Get(string slug);
|
||||||
Task<ICollection<T>> Search(string query);
|
Task<ICollection<T>> Search(string query);
|
||||||
Task<ICollection<T>> GetAll();
|
|
||||||
Task<int> Create([NotNull] T obj);
|
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||||
Task<int> CreateIfNotExists([NotNull] T obj);
|
Sort<T> sort = default,
|
||||||
Task Edit([NotNull] T edited, bool resetOld);
|
Pagination limit = default);
|
||||||
|
|
||||||
|
Task<ICollection<T>> GetAll([Optional] Expression<Func<T, bool>> where,
|
||||||
|
Expression<Func<T, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetAll(where, new Sort<T>(sort), limit);
|
||||||
|
|
||||||
|
Task<T> Create([NotNull] T obj);
|
||||||
|
Task<T> CreateIfNotExists([NotNull] T obj);
|
||||||
|
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||||
|
|
||||||
Task Delete(int id);
|
Task Delete(int id);
|
||||||
Task Delete(string slug);
|
Task Delete(string slug);
|
||||||
@ -31,37 +101,365 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
public interface IShowRepository : IRepository<Show>
|
public interface IShowRepository : IRepository<Show>
|
||||||
{
|
{
|
||||||
Task<Show> GetByPath(string path);
|
|
||||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetFromLibrary(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(id, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetFromLibrary(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetFromLibrary(string slug,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(slug, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetFromCollection(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetFromCollection(int id,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromCollection(id, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Show>> GetFromCollection(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Show>> GetFromCollection(string slug,
|
||||||
|
[Optional] Expression<Func<Show, bool>> where,
|
||||||
|
Expression<Func<Show, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromCollection(slug, where, new Sort<Show>(sort), limit);
|
||||||
|
|
||||||
|
Task<Show> GetFromSeason(int seasonID);
|
||||||
|
Task<Show> GetFromEpisode(int episodeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISeasonRepository : IRepository<Season>
|
public interface ISeasonRepository : IRepository<Season>
|
||||||
{
|
{
|
||||||
|
Task<Season> Get(int showID, int seasonNumber);
|
||||||
Task<Season> Get(string showSlug, int seasonNumber);
|
Task<Season> Get(string showSlug, int seasonNumber);
|
||||||
Task Delete(string showSlug, int seasonNumber);
|
Task Delete(string showSlug, int seasonNumber);
|
||||||
|
|
||||||
Task<ICollection<Season>> GetSeasons(int showID);
|
Task<ICollection<Season>> GetFromShow(int showID,
|
||||||
Task<ICollection<Season>> GetSeasons(string showSlug);
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Season>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Season, bool>> where,
|
||||||
|
Expression<Func<Season, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<Season>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Season>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Season>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Season, bool>> where,
|
||||||
|
Expression<Func<Season, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<Season>(sort), limit);
|
||||||
|
|
||||||
|
Task<Season> GetFromEpisode(int episodeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IEpisodeRepository : IRepository<Episode>
|
public interface IEpisodeRepository : IRepository<Episode>
|
||||||
{
|
{
|
||||||
|
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
Task<Episode> Get(int seasonID, int episodeNumber);
|
||||||
|
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
||||||
|
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||||
Task Delete(string showSlug, int seasonNumber, int episodeNumber);
|
Task Delete(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber);
|
Task<ICollection<Episode>> GetFromShow(int showID,
|
||||||
Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber);
|
Expression<Func<Episode, bool>> where = null,
|
||||||
Task<ICollection<Episode>> GetEpisodes(int seasonID);
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<Episode>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(int seasonID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(int seasonID,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromSeason(seasonID, where, new Sort<Episode>(sort), limit);
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromSeason(showID, seasonNumber, where, new Sort<Episode>(sort), limit);
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Episode>> GetFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
[Optional] Expression<Func<Episode, bool>> where,
|
||||||
|
Expression<Func<Episode, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITrackRepository : IRepository<Track>
|
public interface ITrackRepository : IRepository<Track>
|
||||||
{
|
{
|
||||||
Task<Track> Get(int episodeID, string languageTag, bool isForced);
|
Task<ICollection<Track>> GetFromEpisode(int episodeID,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetFromEpisode(int episodeID,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromEpisode(episodeID, where, new Sort<Track>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Track>> GetFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromEpisode(showID, seasonNumber, episodeNumber, where, new Sort<Track>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Track>> GetFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Track>> GetFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[Optional] Expression<Func<Track, bool>> where,
|
||||||
|
Expression<Func<Track, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromEpisode(showSlug, seasonNumber, episodeNumber, where, new Sort<Track>(sort), limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ILibraryRepository : IRepository<Library>
|
||||||
|
{
|
||||||
|
Task<ICollection<Library>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetFromCollection(int id,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetFromCollection(int id,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromCollection(id, where, new Sort<Library>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Library>> GetFromCollection(string slug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Library>> GetFromCollection(string slug,
|
||||||
|
[Optional] Expression<Func<Library, bool>> where,
|
||||||
|
Expression<Func<Library, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromCollection(slug, where, new Sort<Library>(sort), limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ILibraryItemRepository : IRepository<LibraryItem>
|
||||||
|
{
|
||||||
|
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||||
|
Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
|
||||||
|
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||||
|
Expression<Func<LibraryItem, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||||
|
|
||||||
|
public Task<ICollection<LibraryItem>> GetFromLibrary(string librarySlug,
|
||||||
|
Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
|
||||||
|
public Task<ICollection<LibraryItem>> GetFromLibrary(string librarySlug,
|
||||||
|
[Optional] Expression<Func<LibraryItem, bool>> where,
|
||||||
|
Expression<Func<LibraryItem, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(librarySlug, where, new Sort<LibraryItem>(sort), limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICollectionRepository : IRepository<Collection>
|
||||||
|
{
|
||||||
|
Task<ICollection<Collection>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetFromLibrary(int id,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetFromLibrary(int id,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(id, where, new Sort<Collection>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Collection>> GetFromLibrary(string slug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Collection>> GetFromLibrary(string slug,
|
||||||
|
[Optional] Expression<Func<Collection, bool>> where,
|
||||||
|
Expression<Func<Collection, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromLibrary(slug, where, new Sort<Collection>(sort), limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IGenreRepository : IRepository<Genre>
|
||||||
|
{
|
||||||
|
Task<ICollection<Genre>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Genre>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<Genre, bool>> where,
|
||||||
|
Expression<Func<Genre, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<Genre>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<Genre>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<Genre>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<Genre, bool>> where,
|
||||||
|
Expression<Func<Genre, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<Genre>(sort), limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IStudioRepository : IRepository<Studio>
|
||||||
|
{
|
||||||
|
Task<Studio> GetFromShow(int showID);
|
||||||
|
Task<Studio> GetFromShow(string showSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IPeopleRepository : IRepository<People>
|
||||||
|
{
|
||||||
|
Task<ICollection<PeopleLink>> GetFromShow(int showID,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<PeopleLink>> GetFromShow(int showID,
|
||||||
|
[Optional] Expression<Func<PeopleLink, bool>> where,
|
||||||
|
Expression<Func<PeopleLink, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showID, where, new Sort<PeopleLink>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
|
||||||
|
[Optional] Expression<Func<PeopleLink, bool>> where,
|
||||||
|
Expression<Func<PeopleLink, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<ShowRole>> GetFromPeople(int showID,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<ShowRole>> GetFromPeople(int showID,
|
||||||
|
[Optional] Expression<Func<ShowRole, bool>> where,
|
||||||
|
Expression<Func<ShowRole, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromPeople(showID, where, new Sort<ShowRole>(sort), limit);
|
||||||
|
|
||||||
|
Task<ICollection<ShowRole>> GetFromPeople(string showSlug,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default);
|
||||||
|
Task<ICollection<ShowRole>> GetFromPeople(string showSlug,
|
||||||
|
[Optional] Expression<Func<ShowRole, bool>> where,
|
||||||
|
Expression<Func<ShowRole, object>> sort,
|
||||||
|
Pagination limit = default
|
||||||
|
) => GetFromPeople(showSlug, where, new Sort<ShowRole>(sort), limit);
|
||||||
}
|
}
|
||||||
public interface ILibraryRepository : IRepository<Library> {}
|
|
||||||
public interface ICollectionRepository : IRepository<Collection> {}
|
|
||||||
public interface IGenreRepository : IRepository<Genre> {}
|
|
||||||
public interface IStudioRepository : IRepository<Studio> {}
|
|
||||||
public interface IPeopleRepository : IRepository<People> {}
|
|
||||||
public interface IProviderRepository : IRepository<ProviderID> {}
|
public interface IProviderRepository : IRepository<ProviderID> {}
|
||||||
}
|
}
|
796
Kyoo.Common/Controllers/Implementations/LibraryManager.cs
Normal file
796
Kyoo.Common/Controllers/Implementations/LibraryManager.cs
Normal file
@ -0,0 +1,796 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Models;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
public class LibraryManager : ILibraryManager
|
||||||
|
{
|
||||||
|
public ILibraryRepository LibraryRepository { get; }
|
||||||
|
public ILibraryItemRepository LibraryItemRepository { get; }
|
||||||
|
public ICollectionRepository CollectionRepository { get; }
|
||||||
|
public IShowRepository ShowRepository { get; }
|
||||||
|
public ISeasonRepository SeasonRepository { get; }
|
||||||
|
public IEpisodeRepository EpisodeRepository { get; }
|
||||||
|
public ITrackRepository TrackRepository { get; }
|
||||||
|
public IGenreRepository GenreRepository { get; }
|
||||||
|
public IStudioRepository StudioRepository { get; }
|
||||||
|
public IPeopleRepository PeopleRepository { get; }
|
||||||
|
public IProviderRepository ProviderRepository { get; }
|
||||||
|
|
||||||
|
public LibraryManager(ILibraryRepository libraryRepository,
|
||||||
|
ILibraryItemRepository libraryItemRepository,
|
||||||
|
ICollectionRepository collectionRepository,
|
||||||
|
IShowRepository showRepository,
|
||||||
|
ISeasonRepository seasonRepository,
|
||||||
|
IEpisodeRepository episodeRepository,
|
||||||
|
ITrackRepository trackRepository,
|
||||||
|
IGenreRepository genreRepository,
|
||||||
|
IStudioRepository studioRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IPeopleRepository peopleRepository)
|
||||||
|
{
|
||||||
|
LibraryRepository = libraryRepository;
|
||||||
|
LibraryItemRepository = libraryItemRepository;
|
||||||
|
CollectionRepository = collectionRepository;
|
||||||
|
ShowRepository = showRepository;
|
||||||
|
SeasonRepository = seasonRepository;
|
||||||
|
EpisodeRepository = episodeRepository;
|
||||||
|
TrackRepository = trackRepository;
|
||||||
|
GenreRepository = genreRepository;
|
||||||
|
StudioRepository = studioRepository;
|
||||||
|
ProviderRepository = providerRepository;
|
||||||
|
PeopleRepository = peopleRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
LibraryRepository.Dispose();
|
||||||
|
CollectionRepository.Dispose();
|
||||||
|
ShowRepository.Dispose();
|
||||||
|
SeasonRepository.Dispose();
|
||||||
|
EpisodeRepository.Dispose();
|
||||||
|
TrackRepository.Dispose();
|
||||||
|
GenreRepository.Dispose();
|
||||||
|
StudioRepository.Dispose();
|
||||||
|
PeopleRepository.Dispose();
|
||||||
|
ProviderRepository.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await Task.WhenAll(
|
||||||
|
LibraryRepository.DisposeAsync().AsTask(),
|
||||||
|
CollectionRepository.DisposeAsync().AsTask(),
|
||||||
|
ShowRepository.DisposeAsync().AsTask(),
|
||||||
|
SeasonRepository.DisposeAsync().AsTask(),
|
||||||
|
EpisodeRepository.DisposeAsync().AsTask(),
|
||||||
|
TrackRepository.DisposeAsync().AsTask(),
|
||||||
|
GenreRepository.DisposeAsync().AsTask(),
|
||||||
|
StudioRepository.DisposeAsync().AsTask(),
|
||||||
|
PeopleRepository.DisposeAsync().AsTask(),
|
||||||
|
ProviderRepository.DisposeAsync().AsTask()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Library> GetLibrary(int id)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Collection> GetCollection(int id)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> GetShow(int id)
|
||||||
|
{
|
||||||
|
return ShowRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> GetSeason(int id)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> GetSeason(int showID, int seasonNumber)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Get(showID, seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetEpisode(int id)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetEpisode(int showID, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Get(showID, seasonNumber, episodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Genre> GetGenre(int id)
|
||||||
|
{
|
||||||
|
return GenreRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> GetStudio(int id)
|
||||||
|
{
|
||||||
|
return StudioRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<People> GetPeople(int id)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Library> GetLibrary(string slug)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Collection> GetCollection(string slug)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> GetShow(string slug)
|
||||||
|
{
|
||||||
|
return ShowRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> GetSeason(string showSlug, int seasonNumber)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Get(showSlug, seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Get(showSlug, seasonNumber, episodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetMovieEpisode(string movieSlug)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Get(movieSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Track> GetTrack(int id)
|
||||||
|
{
|
||||||
|
return TrackRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Genre> GetGenre(string slug)
|
||||||
|
{
|
||||||
|
return GenreRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> GetStudio(string slug)
|
||||||
|
{
|
||||||
|
return StudioRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<People> GetPeople(string slug)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Get(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> GetLibraries(Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return LibraryRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> GetCollections(Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return CollectionRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> GetShows(Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetAll(where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Season>> GetSeasonsFromShow(Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return SeasonRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromShow(Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Track>> GetTracks(Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return TrackRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Studio>> GetStudios(Expression<Func<Studio, bool>> where = null,
|
||||||
|
Sort<Studio> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return StudioRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<People>> GetPeople(Expression<Func<People, bool>> where = null,
|
||||||
|
Sort<People> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return PeopleRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Genre>> GetGenres(Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return GenreRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<ProviderID>> GetProviders(Expression<Func<ProviderID, bool>> where = null,
|
||||||
|
Sort<ProviderID> sort = default,
|
||||||
|
Pagination page = default)
|
||||||
|
{
|
||||||
|
return ProviderRepository.GetAll(where, sort, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Season>> GetSeasonsFromShow(int showID,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return SeasonRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return SeasonRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetFromSeason(seasonID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetFromSeason(showID, seasonNumber, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.GetFromSeason(showSlug, seasonNumber, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return PeopleRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Genre>> GetGenresFromShow(int showID,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return GenreRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Genre>> GetGenresFromShow(string showSlug,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return GenreRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Track>> GetTracksFromEpisode(int episodeID,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return TrackRepository.GetFromEpisode(episodeID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Track>> GetTracksFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return TrackRepository.GetFromEpisode(showID, seasonNumber, episodeNumber, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Track>> GetTracksFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return TrackRepository.GetFromEpisode(showSlug, seasonNumber, episodeNumber, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> GetStudioFromShow(int showID)
|
||||||
|
{
|
||||||
|
return StudioRepository.GetFromShow(showID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> GetStudioFromShow(string showSlug)
|
||||||
|
{
|
||||||
|
return StudioRepository.GetFromShow(showSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> GetShowFromSeason(int seasonID)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromSeason(seasonID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> GetShowFromEpisode(int episodeID)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromEpisode(episodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> GetSeasonFromEpisode(int episodeID)
|
||||||
|
{
|
||||||
|
return SeasonRepository.GetFromEpisode(episodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> GetLibrariesFromShow(int showID,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return LibraryRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> GetLibrariesFromShow(string showSlug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return LibraryRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> GetCollectionsFromShow(int showID,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return CollectionRepository.GetFromShow(showID, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> GetCollectionsFromShow(string showSlug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return CollectionRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> GetShowsFromLibrary(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromLibrary(id, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> GetShowsFromLibrary(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromLibrary(slug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> GetCollectionsFromLibrary(int id,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return CollectionRepository.GetFromLibrary(id, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> GetCollectionsFromLibrary(string slug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return CollectionRepository.GetFromLibrary(slug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
|
||||||
|
Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return LibraryItemRepository.GetFromLibrary(librarySlug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> GetShowsFromCollection(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromCollection(id, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> GetShowsFromCollection(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ShowRepository.GetFromCollection(slug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> GetLibrariesFromCollection(int id,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return LibraryRepository.GetFromCollection(id, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> GetLibrariesFromCollection(string slug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return LibraryRepository.GetFromCollection(slug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<ShowRole>> GetRolesFromPeople(int id,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return PeopleRepository.GetFromPeople(id, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<ShowRole>> GetRolesFromPeople(string slug,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
||||||
|
{
|
||||||
|
return ShowRepository.AddShowLink(showID, libraryID, collectionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddShowLink(Show show, Library library, Collection collection)
|
||||||
|
{
|
||||||
|
if (show == null)
|
||||||
|
throw new ArgumentNullException(nameof(show));
|
||||||
|
return AddShowLink(show.ID, library?.ID, collection?.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Library>> SearchLibraries(string searchQuery)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Collection>> SearchCollections(string searchQuery)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Show>> SearchShows(string searchQuery)
|
||||||
|
{
|
||||||
|
return ShowRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Season>> SearchSeasons(string searchQuery)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Episode>> SearchEpisodes(string searchQuery)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Genre>> SearchGenres(string searchQuery)
|
||||||
|
{
|
||||||
|
return GenreRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<Studio>> SearchStudios(string searchQuery)
|
||||||
|
{
|
||||||
|
return StudioRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<People>> SearchPeople(string searchQuery)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Search(searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Library> RegisterLibrary(Library library)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Create(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Collection> RegisterCollection(Collection collection)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Create(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> RegisterShow(Show show)
|
||||||
|
{
|
||||||
|
return ShowRepository.Create(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> RegisterSeason(Season season)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Create(season);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> RegisterEpisode(Episode episode)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Create(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Track> RegisterTrack(Track track)
|
||||||
|
{
|
||||||
|
return TrackRepository.Create(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Genre> RegisterGenre(Genre genre)
|
||||||
|
{
|
||||||
|
return GenreRepository.Create(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> RegisterStudio(Studio studio)
|
||||||
|
{
|
||||||
|
return StudioRepository.Create(studio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<People> RegisterPeople(People people)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Create(people);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Library> EditLibrary(Library library, bool resetOld)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Edit(library, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Collection> EditCollection(Collection collection, bool resetOld)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Edit(collection, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> EditShow(Show show, bool resetOld)
|
||||||
|
{
|
||||||
|
return ShowRepository.Edit(show, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Season> EditSeason(Season season, bool resetOld)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Edit(season, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> EditEpisode(Episode episode, bool resetOld)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Edit(episode, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Track> EditTrack(Track track, bool resetOld)
|
||||||
|
{
|
||||||
|
return TrackRepository.Edit(track, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Genre> EditGenre(Genre genre, bool resetOld)
|
||||||
|
{
|
||||||
|
return GenreRepository.Edit(genre, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Studio> EditStudio(Studio studio, bool resetOld)
|
||||||
|
{
|
||||||
|
return StudioRepository.Edit(studio, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<People> EditPeople(People people, bool resetOld)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Edit(people, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DelteLibrary(Library library)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Delete(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteCollection(Collection collection)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Delete(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteShow(Show show)
|
||||||
|
{
|
||||||
|
return ShowRepository.Delete(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteSeason(Season season)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Delete(season);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteEpisode(Episode episode)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Delete(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteTrack(Track track)
|
||||||
|
{
|
||||||
|
return TrackRepository.Delete(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteGenre(Genre genre)
|
||||||
|
{
|
||||||
|
return GenreRepository.Delete(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteStudio(Studio studio)
|
||||||
|
{
|
||||||
|
return StudioRepository.Delete(studio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeletePeople(People people)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Delete(people);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DelteLibrary(string library)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Delete(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteCollection(string collection)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Delete(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteShow(string show)
|
||||||
|
{
|
||||||
|
return ShowRepository.Delete(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteSeason(string season)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Delete(season);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteEpisode(string episode)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Delete(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteTrack(string track)
|
||||||
|
{
|
||||||
|
return TrackRepository.Delete(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteGenre(string genre)
|
||||||
|
{
|
||||||
|
return GenreRepository.Delete(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteStudio(string studio)
|
||||||
|
{
|
||||||
|
return StudioRepository.Delete(studio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeletePeople(string people)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Delete(people);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DelteLibrary(int library)
|
||||||
|
{
|
||||||
|
return LibraryRepository.Delete(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteCollection(int collection)
|
||||||
|
{
|
||||||
|
return CollectionRepository.Delete(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteShow(int show)
|
||||||
|
{
|
||||||
|
return ShowRepository.Delete(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteSeason(int season)
|
||||||
|
{
|
||||||
|
return SeasonRepository.Delete(season);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteEpisode(int episode)
|
||||||
|
{
|
||||||
|
return EpisodeRepository.Delete(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteTrack(int track)
|
||||||
|
{
|
||||||
|
return TrackRepository.Delete(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteGenre(int genre)
|
||||||
|
{
|
||||||
|
return GenreRepository.Delete(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteStudio(int studio)
|
||||||
|
{
|
||||||
|
return StudioRepository.Delete(studio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeletePeople(int people)
|
||||||
|
{
|
||||||
|
return PeopleRepository.Delete(people);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,8 @@ namespace Kyoo.Models.Exceptions
|
|||||||
{
|
{
|
||||||
public override string Message { get; }
|
public override string Message { get; }
|
||||||
|
|
||||||
|
public DuplicatedItemException() {}
|
||||||
|
|
||||||
public DuplicatedItemException(string message)
|
public DuplicatedItemException(string message)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
|
@ -6,6 +6,8 @@ namespace Kyoo.Models.Exceptions
|
|||||||
{
|
{
|
||||||
public override string Message { get; }
|
public override string Message { get; }
|
||||||
|
|
||||||
|
public ItemNotFound() {}
|
||||||
|
|
||||||
public ItemNotFound(string message)
|
public ItemNotFound(string message)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
|
84
Kyoo.Common/Models/LibraryItem.cs
Normal file
84
Kyoo.Common/Models/LibraryItem.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace Kyoo.Models
|
||||||
|
{
|
||||||
|
public enum ItemType
|
||||||
|
{
|
||||||
|
Show,
|
||||||
|
Movie,
|
||||||
|
Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LibraryItem : IResource
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Slug { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public Status? Status { get; set; }
|
||||||
|
public string TrailerUrl { get; set; }
|
||||||
|
public int? StartYear { get; set; }
|
||||||
|
public int? EndYear { get; set; }
|
||||||
|
public string Poster { get; set; }
|
||||||
|
public ItemType Type { get; set; }
|
||||||
|
|
||||||
|
public LibraryItem() {}
|
||||||
|
|
||||||
|
public LibraryItem(Show show)
|
||||||
|
{
|
||||||
|
ID = show.ID;
|
||||||
|
Slug = show.Slug;
|
||||||
|
Title = show.Title;
|
||||||
|
Overview = show.Overview;
|
||||||
|
Status = show.Status;
|
||||||
|
TrailerUrl = show.TrailerUrl;
|
||||||
|
StartYear = show.StartYear;
|
||||||
|
EndYear = show.EndYear;
|
||||||
|
Poster = show.Poster;
|
||||||
|
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LibraryItem(Collection collection)
|
||||||
|
{
|
||||||
|
ID = -collection.ID;
|
||||||
|
Slug = collection.Slug;
|
||||||
|
Title = collection.Name;
|
||||||
|
Overview = collection.Overview;
|
||||||
|
Status = Models.Status.Unknown;
|
||||||
|
TrailerUrl = null;
|
||||||
|
StartYear = null;
|
||||||
|
EndYear = null;
|
||||||
|
Poster = collection.Poster;
|
||||||
|
Type = ItemType.Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
TrailerUrl = x.TrailerUrl,
|
||||||
|
StartYear = x.StartYear,
|
||||||
|
EndYear = x.EndYear,
|
||||||
|
Poster= x.Poster,
|
||||||
|
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Expression<Func<Collection, LibraryItem>> FromCollection => x => new LibraryItem
|
||||||
|
{
|
||||||
|
ID = -x.ID,
|
||||||
|
Slug = x.Slug,
|
||||||
|
Title = x.Name,
|
||||||
|
Overview = x.Overview,
|
||||||
|
Status = Models.Status.Unknown,
|
||||||
|
TrailerUrl = null,
|
||||||
|
StartYear = null,
|
||||||
|
EndYear = null,
|
||||||
|
Poster= x.Poster,
|
||||||
|
Type = ItemType.Collection
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
48
Kyoo.Common/Models/Page.cs
Normal file
48
Kyoo.Common/Models/Page.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Kyoo.Models
|
||||||
|
{
|
||||||
|
public class Page<T> where T : IResource
|
||||||
|
{
|
||||||
|
public string This { get; set; }
|
||||||
|
public string First { get; set; }
|
||||||
|
public string Next { get; set; }
|
||||||
|
|
||||||
|
public int Count => Items.Count;
|
||||||
|
public ICollection<T> Items { get; set; }
|
||||||
|
|
||||||
|
public Page() { }
|
||||||
|
|
||||||
|
public Page(ICollection<T> items)
|
||||||
|
{
|
||||||
|
Items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page(ICollection<T> items, string @this, string next, string first)
|
||||||
|
{
|
||||||
|
Items = items;
|
||||||
|
This = @this;
|
||||||
|
Next = next;
|
||||||
|
First = first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page(ICollection<T> items,
|
||||||
|
string url,
|
||||||
|
Dictionary<string, string> query,
|
||||||
|
int limit)
|
||||||
|
{
|
||||||
|
Items = items;
|
||||||
|
This = url + query.ToQueryString();
|
||||||
|
|
||||||
|
if (items.Count == limit)
|
||||||
|
{
|
||||||
|
query["afterID"] = items.Last().ID.ToString();
|
||||||
|
Next = url + query.ToQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Remove("afterID");
|
||||||
|
First = url + query.ToQueryString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class PeopleLink
|
public class PeopleLink : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
[JsonIgnore] public int PeopleID { get; set; }
|
[JsonIgnore] public int PeopleID { get; set; }
|
||||||
@ -21,6 +23,12 @@ namespace Kyoo.Models
|
|||||||
set => People.Name = value;
|
set => People.Name = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Poster
|
||||||
|
{
|
||||||
|
get => People.Poster;
|
||||||
|
set => People.Poster = value;
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<MetadataID> ExternalIDs
|
public IEnumerable<MetadataID> ExternalIDs
|
||||||
{
|
{
|
||||||
get => People.ExternalIDs;
|
get => People.ExternalIDs;
|
||||||
@ -42,11 +50,79 @@ namespace Kyoo.Models
|
|||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeopleLink(string slug, string name, string role, string type, string imgPrimary, IEnumerable<MetadataID> externalIDs)
|
public PeopleLink(string slug,
|
||||||
|
string name,
|
||||||
|
string role,
|
||||||
|
string type,
|
||||||
|
string poster,
|
||||||
|
IEnumerable<MetadataID> externalIDs)
|
||||||
{
|
{
|
||||||
People = new People(slug, name, imgPrimary, externalIDs);
|
People = new People(slug, name, poster, externalIDs);
|
||||||
Role = role;
|
Role = role;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ShowRole : IResource
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Role { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
public string Slug { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public IEnumerable<string> Aliases { get; set; }
|
||||||
|
[JsonIgnore] public string Path { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public Status? Status { get; set; }
|
||||||
|
public string TrailerUrl { get; set; }
|
||||||
|
public int? StartYear { get; set; }
|
||||||
|
public int? EndYear { get; set; }
|
||||||
|
public string Poster { get; set; }
|
||||||
|
public string Logo { get; set; }
|
||||||
|
public string Backdrop { get; set; }
|
||||||
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
|
public ShowRole() {}
|
||||||
|
|
||||||
|
public ShowRole(PeopleLink x)
|
||||||
|
{
|
||||||
|
ID = x.ID;
|
||||||
|
Role = x.Role;
|
||||||
|
Type = x.Type;
|
||||||
|
Slug = x.Show.Slug;
|
||||||
|
Title = x.Show.Title;
|
||||||
|
Aliases = x.Show.Aliases;
|
||||||
|
Path = x.Show.Path;
|
||||||
|
Overview = x.Show.Overview;
|
||||||
|
Status = x.Show.Status;
|
||||||
|
TrailerUrl = x.Show.TrailerUrl;
|
||||||
|
StartYear = x.Show.StartYear;
|
||||||
|
EndYear = x.Show.EndYear;
|
||||||
|
Poster = x.Show.Poster;
|
||||||
|
Logo = x.Show.Logo;
|
||||||
|
Backdrop = x.Show.Backdrop;
|
||||||
|
IsMovie = x.Show.IsMovie;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<PeopleLink, ShowRole>> FromPeopleRole => x => new ShowRole
|
||||||
|
{
|
||||||
|
ID = x.ID,
|
||||||
|
Role = x.Role,
|
||||||
|
Type = x.Type,
|
||||||
|
Slug = x.Show.Slug,
|
||||||
|
Title = x.Show.Title,
|
||||||
|
Aliases = x.Show.Aliases,
|
||||||
|
Path = x.Show.Path,
|
||||||
|
Overview = x.Show.Overview,
|
||||||
|
Status = x.Show.Status,
|
||||||
|
TrailerUrl = x.Show.TrailerUrl,
|
||||||
|
StartYear = x.Show.StartYear,
|
||||||
|
EndYear = x.Show.EndYear,
|
||||||
|
Poster = x.Show.Poster,
|
||||||
|
Logo = x.Show.Logo,
|
||||||
|
Backdrop = x.Show.Backdrop,
|
||||||
|
IsMovie = x.Show.IsMovie
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,16 +5,15 @@ using Kyoo.Models.Attributes;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Collection
|
public class Collection : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Poster { get; set; }
|
public string Poster { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
|
||||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> Links { get; set; }
|
[NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> Links { get; set; }
|
||||||
public virtual IEnumerable<Show> Shows
|
[JsonIgnore] public virtual IEnumerable<Show> Shows
|
||||||
{
|
{
|
||||||
get => Links.Select(x => x.Show);
|
get => Links.Select(x => x.Show);
|
||||||
set => Links = value.Select(x => new CollectionLink(this, x));
|
set => Links = value.Select(x => new CollectionLink(this, x));
|
||||||
@ -30,20 +29,12 @@ namespace Kyoo.Models
|
|||||||
|
|
||||||
public Collection() { }
|
public Collection() { }
|
||||||
|
|
||||||
public Collection(string slug, string name, string overview, string imgPrimary)
|
public Collection(string slug, string name, string overview, string poster)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
Overview = overview;
|
Overview = overview;
|
||||||
ImgPrimary = imgPrimary;
|
Poster = poster;
|
||||||
}
|
|
||||||
|
|
||||||
public Show AsShow()
|
|
||||||
{
|
|
||||||
return new Show(Slug, Name, null, null, Overview, null, null, null, null, null, null)
|
|
||||||
{
|
|
||||||
IsCollection = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ using Kyoo.Models.Attributes;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Episode : IOnMerge
|
public class Episode : IResource, IOnMerge
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
[JsonIgnore] public int ShowID { get; set; }
|
[JsonIgnore] public int ShowID { get; set; }
|
@ -5,7 +5,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Genre
|
public class Genre : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
8
Kyoo.Common/Models/Resources/IResource.cs
Normal file
8
Kyoo.Common/Models/Resources/IResource.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Kyoo.Models
|
||||||
|
{
|
||||||
|
public interface IResource
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Slug { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Library
|
public class Library : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
@ -4,23 +4,23 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class People
|
public class People : IResource
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
public string Poster { get; set; }
|
||||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||||
|
|
||||||
[JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; }
|
[JsonIgnore] public virtual IEnumerable<PeopleLink> Roles { get; set; }
|
||||||
|
|
||||||
public People() {}
|
public People() {}
|
||||||
|
|
||||||
public People(string slug, string name, string imgPrimary, IEnumerable<MetadataID> externalIDs)
|
public People(string slug, string name, string poster, IEnumerable<MetadataID> externalIDs)
|
||||||
{
|
{
|
||||||
Slug = slug;
|
Slug = slug;
|
||||||
Name = name;
|
Name = name;
|
||||||
ImgPrimary = imgPrimary;
|
Poster = poster;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,17 +2,26 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class ProviderID
|
public class ProviderID : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
|
public string Slug { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Logo { get; set; }
|
public string Logo { get; set; }
|
||||||
|
|
||||||
public ProviderID() { }
|
public ProviderID() { }
|
||||||
|
|
||||||
|
public ProviderID(string name, string logo)
|
||||||
|
{
|
||||||
|
Slug = Utility.ToSlug(name);
|
||||||
|
Name = name;
|
||||||
|
Logo = logo;
|
||||||
|
}
|
||||||
|
|
||||||
public ProviderID(int id, string name, string logo)
|
public ProviderID(int id, string name, string logo)
|
||||||
{
|
{
|
||||||
ID = id;
|
ID = id;
|
||||||
|
Slug = Utility.ToSlug(name);
|
||||||
Name = name;
|
Name = name;
|
||||||
Logo = logo;
|
Logo = logo;
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Season
|
public class Season : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
[JsonIgnore] public int ShowID { get; set; }
|
[JsonIgnore] public int ShowID { get; set; }
|
@ -5,7 +5,7 @@ using Kyoo.Models.Attributes;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Show : IOnMerge
|
public class Show : IResource, IOnMerge
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ namespace Kyoo.Models
|
|||||||
|
|
||||||
public bool IsMovie { get; set; }
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
public bool IsCollection;
|
|
||||||
|
|
||||||
public virtual IEnumerable<Genre> Genres
|
public virtual IEnumerable<Genre> Genres
|
||||||
{
|
{
|
||||||
@ -82,7 +81,6 @@ namespace Kyoo.Models
|
|||||||
StartYear = startYear;
|
StartYear = startYear;
|
||||||
EndYear = endYear;
|
EndYear = endYear;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
IsCollection = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Show(string slug,
|
public Show(string slug,
|
||||||
@ -112,7 +110,6 @@ namespace Kyoo.Models
|
|||||||
Logo = logo;
|
Logo = logo;
|
||||||
Backdrop = backdrop;
|
Backdrop = backdrop;
|
||||||
ExternalIDs = externalIDs;
|
ExternalIDs = externalIDs;
|
||||||
IsCollection = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetID(string provider)
|
public string GetID(string provider)
|
||||||
@ -140,5 +137,5 @@ namespace Kyoo.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Status { Finished, Airing, Planned }
|
public enum Status { Finished, Airing, Planned, Unknown }
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
public class Studio
|
public class Studio : IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
@ -53,7 +53,7 @@ namespace Kyoo.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Track : Stream
|
public class Track : Stream, IResource
|
||||||
{
|
{
|
||||||
[JsonIgnore] public int ID { get; set; }
|
[JsonIgnore] public int ID { get; set; }
|
||||||
[JsonIgnore] public int EpisodeID { get; set; }
|
[JsonIgnore] public int EpisodeID { get; set; }
|
||||||
@ -93,9 +93,10 @@ namespace Kyoo.Models
|
|||||||
{
|
{
|
||||||
if (Type != StreamType.Subtitle)
|
if (Type != StreamType.Subtitle)
|
||||||
return null;
|
return null;
|
||||||
string slug = $"/subtitle/{Episode.Slug}.{Language ?? ID.ToString()}";
|
|
||||||
if (IsForced)
|
string slug = string.IsNullOrEmpty(Language)
|
||||||
slug += "-forced";
|
? ID.ToString()
|
||||||
|
: $"{Episode.Slug}.{Language}{(IsForced ? "-forced" : "")}";
|
||||||
switch (Codec)
|
switch (Codec)
|
||||||
{
|
{
|
||||||
case "ass":
|
case "ass":
|
@ -9,7 +9,6 @@ using System.Text.RegularExpressions;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Attributes;
|
using Kyoo.Models.Attributes;
|
||||||
using Microsoft.VisualBasic;
|
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
@ -224,5 +223,12 @@ namespace Kyoo
|
|||||||
yield return ret;
|
yield return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ToQueryString(this Dictionary<string, string> query)
|
||||||
|
{
|
||||||
|
if (!query.Any())
|
||||||
|
return string.Empty;
|
||||||
|
return "?" + string.Join('&', query.Select(x => $"{x.Key}={x.Value}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
110
Kyoo.CommonAPI/ApiHelper.cs
Normal file
110
Kyoo.CommonAPI/ApiHelper.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Kyoo.CommonApi
|
||||||
|
{
|
||||||
|
public static class ApiHelper
|
||||||
|
{
|
||||||
|
public static Expression StringCompatibleExpression(Func<Expression, Expression, BinaryExpression> operand,
|
||||||
|
Expression left,
|
||||||
|
Expression right)
|
||||||
|
{
|
||||||
|
if (left is MemberExpression member && ((PropertyInfo)member.Member).PropertyType == typeof(string))
|
||||||
|
{
|
||||||
|
MethodCallExpression call = Expression.Call(typeof(string), "Compare", null, left, right);
|
||||||
|
return operand(call, Expression.Constant(0));
|
||||||
|
}
|
||||||
|
return operand(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<T, bool>> ParseWhere<T>(Dictionary<string, string> where,
|
||||||
|
Expression<Func<T, bool>> defaultWhere = null)
|
||||||
|
{
|
||||||
|
if (where == null || where.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ParameterExpression param = Expression.Parameter(typeof(T));
|
||||||
|
Expression expression = defaultWhere?.Body;
|
||||||
|
|
||||||
|
foreach ((string key, string desired) in where)
|
||||||
|
{
|
||||||
|
string value = desired;
|
||||||
|
string operand = "eq";
|
||||||
|
if (desired.Contains(':'))
|
||||||
|
{
|
||||||
|
operand = desired.Substring(0, desired.IndexOf(':'));
|
||||||
|
value = desired.Substring(desired.IndexOf(':') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo property = typeof(T).GetProperty(key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
|
||||||
|
if (property == null)
|
||||||
|
throw new ArgumentException($"No filterable parameter with the name {key}.");
|
||||||
|
MemberExpression propertyExpr = Expression.Property(param, property);
|
||||||
|
|
||||||
|
ConstantExpression valueExpr = null;
|
||||||
|
if (operand != "ctn")
|
||||||
|
{
|
||||||
|
Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
|
||||||
|
object val = string.IsNullOrEmpty(value) || value.Equals("null", StringComparison.OrdinalIgnoreCase)
|
||||||
|
? null
|
||||||
|
: Convert.ChangeType(value, propertyType);
|
||||||
|
valueExpr = Expression.Constant(val, property.PropertyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression condition = operand switch
|
||||||
|
{
|
||||||
|
"eq" => Expression.Equal(propertyExpr, valueExpr!),
|
||||||
|
"not" => Expression.NotEqual(propertyExpr, valueExpr!),
|
||||||
|
"lt" => StringCompatibleExpression(Expression.LessThan, propertyExpr, valueExpr),
|
||||||
|
"lte" => StringCompatibleExpression(Expression.LessThanOrEqual, propertyExpr, valueExpr),
|
||||||
|
"gt" => StringCompatibleExpression(Expression.GreaterThan, propertyExpr, valueExpr),
|
||||||
|
"gte" => StringCompatibleExpression(Expression.GreaterThanOrEqual, propertyExpr, valueExpr),
|
||||||
|
"ctn" => ContainsResourceExpression(propertyExpr, value),
|
||||||
|
_ => throw new ArgumentException($"Invalid operand: {operand}")
|
||||||
|
};
|
||||||
|
|
||||||
|
if (expression != null)
|
||||||
|
expression = Expression.AndAlso(expression, condition);
|
||||||
|
else
|
||||||
|
expression = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Expression.Lambda<Func<T, bool>>(expression!, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Expression ContainsResourceExpression(MemberExpression xProperty, string value)
|
||||||
|
{
|
||||||
|
// x => x.PROPERTY.Any(y => y.Slug == value)
|
||||||
|
Expression ret = null;
|
||||||
|
ParameterExpression y = Expression.Parameter(xProperty.Type.GenericTypeArguments.First(), "y");
|
||||||
|
foreach (string val in value.Split(','))
|
||||||
|
{
|
||||||
|
MemberExpression yProperty;
|
||||||
|
ConstantExpression yValue;
|
||||||
|
if (int.TryParse(val, out int id))
|
||||||
|
{
|
||||||
|
yProperty = Expression.Property(y, "ID");
|
||||||
|
yValue = Expression.Constant(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yProperty = Expression.Property(y, "Slug");
|
||||||
|
yValue = Expression.Constant(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaExpression lambda = Expression.Lambda(Expression.Equal(yProperty, yValue), y);
|
||||||
|
Expression iteration = Expression.Call(typeof(Enumerable), "Any", xProperty.Type.GenericTypeArguments,
|
||||||
|
xProperty, lambda);
|
||||||
|
|
||||||
|
if (ret == null)
|
||||||
|
ret = iteration;
|
||||||
|
else
|
||||||
|
ret = Expression.AndAlso(ret, iteration);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
Kyoo.CommonAPI/CrudApi.cs
Normal file
176
Kyoo.CommonAPI/CrudApi.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.CommonApi
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
public class CrudApi<T> : ControllerBase where T : IResource
|
||||||
|
{
|
||||||
|
private readonly IRepository<T> _repository;
|
||||||
|
private readonly string _baseURL;
|
||||||
|
|
||||||
|
public CrudApi(IRepository<T> repository, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_baseURL = configuration.GetValue<string>("public_url").TrimEnd('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
[JsonDetailed]
|
||||||
|
public virtual async Task<ActionResult<T>> Get(int id)
|
||||||
|
{
|
||||||
|
T ressource = await _repository.Get(id);
|
||||||
|
if (ressource == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return ressource;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
[JsonDetailed]
|
||||||
|
public virtual async Task<ActionResult<T>> Get(string slug)
|
||||||
|
{
|
||||||
|
T ressource = await _repository.Get(slug);
|
||||||
|
if (ressource == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return ressource;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public virtual async Task<ActionResult<Page<T>>> GetAll([FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<T> ressources = await _repository.GetAll(ApiHelper.ParseWhere<T>(where),
|
||||||
|
new Sort<T>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Page<TResult> Page<TResult>(ICollection<TResult> ressources, int limit)
|
||||||
|
where TResult : IResource
|
||||||
|
{
|
||||||
|
return new Page<TResult>(ressources,
|
||||||
|
_baseURL + Request.Path,
|
||||||
|
Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString(), StringComparer.InvariantCultureIgnoreCase),
|
||||||
|
limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<ActionResult<T>> Create([FromBody] T ressource)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.Create(ressource);
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
catch (DuplicatedItemException)
|
||||||
|
{
|
||||||
|
T existing = await _repository.Get(ressource.Slug);
|
||||||
|
return Conflict(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<ActionResult<T>> Edit([FromQuery] bool resetOld, [FromBody] T ressource)
|
||||||
|
{
|
||||||
|
if (ressource.ID > 0)
|
||||||
|
return await _repository.Edit(ressource, resetOld);
|
||||||
|
|
||||||
|
T old = await _repository.Get(ressource.Slug);
|
||||||
|
if (old == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
ressource.ID = old.ID;
|
||||||
|
return await _repository.Edit(ressource, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id:int}")]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<ActionResult<T>> Edit(int id, [FromQuery] bool resetOld, [FromBody] T ressource)
|
||||||
|
{
|
||||||
|
ressource.ID = id;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.Edit(ressource, resetOld);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{slug}")]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<ActionResult<T>> Edit(string slug, [FromQuery] bool resetOld, [FromBody] T ressource)
|
||||||
|
{
|
||||||
|
T old = await _repository.Get(slug);
|
||||||
|
if (old == null)
|
||||||
|
return NotFound();
|
||||||
|
ressource.ID = old.ID;
|
||||||
|
return await _repository.Edit(ressource, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id:int}")]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<IActionResult> Delete(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _repository.Delete(id);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{slug}")]
|
||||||
|
[Authorize(Policy = "Write")]
|
||||||
|
public virtual async Task<IActionResult> Delete(string slug)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _repository.Delete(slug);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -77,8 +77,9 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
ContractResolver = new JsonPropertySelector(null, new Dictionary<Type, HashSet<string>>()
|
ContractResolver = new JsonPropertySelector(null, new Dictionary<Type, HashSet<string>>()
|
||||||
{
|
{
|
||||||
{typeof(Show), new HashSet<string> {"genres", "studio", "people", "seasons"}},
|
{typeof(Show), new HashSet<string> {"genres", "studio"}},
|
||||||
{typeof(Episode), new HashSet<string> {"tracks"}}
|
{typeof(Episode), new HashSet<string> {"tracks"}},
|
||||||
|
{typeof(PeopleLink), new HashSet<string> {"show"}}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
context.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(),
|
context.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(),
|
23
Kyoo.CommonAPI/Kyoo.CommonAPI.csproj
Normal file
23
Kyoo.CommonAPI/Kyoo.CommonAPI.csproj
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<AssemblyName>Kyoo.CommonApi</AssemblyName>
|
||||||
|
<RootNamespace>Kyoo.CommonApi</RootNamespace>
|
||||||
|
<PackageId>Kyoo.CommonApi</PackageId>
|
||||||
|
<Authors>AnonymusRaccoon</Authors>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Npgsql" Version="4.1.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Kyoo.Common\Kyoo.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
173
Kyoo.CommonAPI/LocalRepository.cs
Normal file
173
Kyoo.CommonAPI/LocalRepository.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
public abstract class LocalRepository<T> : IRepository<T> where T : class, IResource
|
||||||
|
{
|
||||||
|
private readonly DbContext _database;
|
||||||
|
|
||||||
|
protected abstract Expression<Func<T, object>> DefaultSort { get; }
|
||||||
|
|
||||||
|
|
||||||
|
protected LocalRepository(DbContext database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
_database.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
return _database.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task<T> Get(int id)
|
||||||
|
{
|
||||||
|
return _database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task<T> Get(string slug)
|
||||||
|
{
|
||||||
|
return _database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<ICollection<T>> Search(string query);
|
||||||
|
|
||||||
|
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||||
|
Sort<T> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ApplyFilters(_database.Set<T>(), where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||||
|
Expression<Func<T, bool>> where = null,
|
||||||
|
Sort<T> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ApplyFilters(query, Get, DefaultSort, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<ICollection<TValue>> ApplyFilters<TValue>(IQueryable<TValue> query,
|
||||||
|
Func<int, Task<TValue>> get,
|
||||||
|
Expression<Func<TValue, object>> defaultSort,
|
||||||
|
Expression<Func<TValue, bool>> where = null,
|
||||||
|
Sort<TValue> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
if (where != null)
|
||||||
|
query = query.Where(where);
|
||||||
|
|
||||||
|
Expression<Func<TValue, object>> sortKey = sort.Key ?? defaultSort;
|
||||||
|
Expression sortExpression = sortKey.Body.NodeType == ExpressionType.Convert
|
||||||
|
? ((UnaryExpression)sortKey.Body).Operand
|
||||||
|
: sortKey.Body;
|
||||||
|
|
||||||
|
if (typeof(Enum).IsAssignableFrom(sortExpression.Type))
|
||||||
|
throw new ArgumentException("Invalid sort key.");
|
||||||
|
|
||||||
|
query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey);
|
||||||
|
|
||||||
|
if (limit.AfterID != 0)
|
||||||
|
{
|
||||||
|
TValue after = await get(limit.AfterID);
|
||||||
|
Expression key = Expression.Constant(sortKey.Compile()(after), sortExpression.Type);
|
||||||
|
query = query.Where(Expression.Lambda<Func<TValue, bool>>(
|
||||||
|
ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortExpression, key),
|
||||||
|
sortKey.Parameters.First()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (limit.Count > 0)
|
||||||
|
query = query.Take(limit.Count);
|
||||||
|
|
||||||
|
return await query.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<T> Create(T obj);
|
||||||
|
|
||||||
|
public virtual async Task<T> CreateIfNotExists(T obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
|
T old = await Get(obj.Slug);
|
||||||
|
if (old != null)
|
||||||
|
return old;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await Create(obj);
|
||||||
|
}
|
||||||
|
catch (DuplicatedItemException)
|
||||||
|
{
|
||||||
|
old = await Get(obj.Slug);
|
||||||
|
if (old == null)
|
||||||
|
throw new SystemException("Unknown database state.");
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<T> Edit(T edited, bool resetOld)
|
||||||
|
{
|
||||||
|
if (edited == null)
|
||||||
|
throw new ArgumentNullException(nameof(edited));
|
||||||
|
|
||||||
|
T old = await Get(edited.Slug);
|
||||||
|
|
||||||
|
if (old == null)
|
||||||
|
throw new ItemNotFound($"No ressource found with the slug {edited.Slug}.");
|
||||||
|
|
||||||
|
if (resetOld)
|
||||||
|
Utility.Nullify(old);
|
||||||
|
Utility.Merge(old, edited);
|
||||||
|
await Validate(old);
|
||||||
|
await _database.SaveChangesAsync();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task Validate(T ressource);
|
||||||
|
|
||||||
|
public virtual async Task Delete(int id)
|
||||||
|
{
|
||||||
|
T ressource = await Get(id);
|
||||||
|
await Delete(ressource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task Delete(string slug)
|
||||||
|
{
|
||||||
|
T ressource = await Get(slug);
|
||||||
|
await Delete(ressource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task Delete(T obj);
|
||||||
|
|
||||||
|
public virtual async Task DeleteRange(IEnumerable<T> objs)
|
||||||
|
{
|
||||||
|
foreach (T obj in objs)
|
||||||
|
await Delete(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task DeleteRange(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
foreach (int id in ids)
|
||||||
|
await Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task DeleteRange(IEnumerable<string> slugs)
|
||||||
|
{
|
||||||
|
foreach (string slug in slugs)
|
||||||
|
await Delete(slug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
Kyoo.sln
6
Kyoo.sln
@ -3,6 +3,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo", "Kyoo\Kyoo.csproj",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Common", "Kyoo.Common\Kyoo.Common.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Common", "Kyoo.Common\Kyoo.Common.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.CommonAPI", "Kyoo.CommonAPI\Kyoo.CommonAPI.csproj", "{6F91B645-F785-46BB-9C4F-1EFC83E489B6}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -17,5 +19,9 @@ Global
|
|||||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.Build.0 = Release|Any CPU
|
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -1,396 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Models;
|
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
|
||||||
{
|
|
||||||
public class LibraryManager : ILibraryManager
|
|
||||||
{
|
|
||||||
private readonly ILibraryRepository _libraries;
|
|
||||||
private readonly ICollectionRepository _collections;
|
|
||||||
private readonly IShowRepository _shows;
|
|
||||||
private readonly ISeasonRepository _seasons;
|
|
||||||
private readonly IEpisodeRepository _episodes;
|
|
||||||
private readonly ITrackRepository _tracks;
|
|
||||||
private readonly IGenreRepository _genres;
|
|
||||||
private readonly IStudioRepository _studios;
|
|
||||||
private readonly IPeopleRepository _people;
|
|
||||||
private readonly IProviderRepository _providers;
|
|
||||||
|
|
||||||
public LibraryManager(ILibraryRepository libraries,
|
|
||||||
ICollectionRepository collections,
|
|
||||||
IShowRepository shows,
|
|
||||||
ISeasonRepository seasons,
|
|
||||||
IEpisodeRepository episodes,
|
|
||||||
ITrackRepository tracks,
|
|
||||||
IGenreRepository genres,
|
|
||||||
IStudioRepository studios,
|
|
||||||
IProviderRepository providers,
|
|
||||||
IPeopleRepository people)
|
|
||||||
{
|
|
||||||
_libraries = libraries;
|
|
||||||
_collections = collections;
|
|
||||||
_shows = shows;
|
|
||||||
_seasons = seasons;
|
|
||||||
_episodes = episodes;
|
|
||||||
_tracks = tracks;
|
|
||||||
_genres = genres;
|
|
||||||
_studios = studios;
|
|
||||||
_providers = providers;
|
|
||||||
_people = people;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_libraries.Dispose();
|
|
||||||
_collections.Dispose();
|
|
||||||
_shows.Dispose();
|
|
||||||
_seasons.Dispose();
|
|
||||||
_episodes.Dispose();
|
|
||||||
_tracks.Dispose();
|
|
||||||
_genres.Dispose();
|
|
||||||
_studios.Dispose();
|
|
||||||
_people.Dispose();
|
|
||||||
_providers.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
await Task.WhenAll(
|
|
||||||
_libraries.DisposeAsync().AsTask(),
|
|
||||||
_collections.DisposeAsync().AsTask(),
|
|
||||||
_shows.DisposeAsync().AsTask(),
|
|
||||||
_seasons.DisposeAsync().AsTask(),
|
|
||||||
_episodes.DisposeAsync().AsTask(),
|
|
||||||
_tracks.DisposeAsync().AsTask(),
|
|
||||||
_genres.DisposeAsync().AsTask(),
|
|
||||||
_studios.DisposeAsync().AsTask(),
|
|
||||||
_people.DisposeAsync().AsTask(),
|
|
||||||
_providers.DisposeAsync().AsTask()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Library> GetLibrary(string slug)
|
|
||||||
{
|
|
||||||
return _libraries.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Collection> GetCollection(string slug)
|
|
||||||
{
|
|
||||||
return _collections.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Show> GetShow(string slug)
|
|
||||||
{
|
|
||||||
return _shows.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Season> GetSeason(string showSlug, int seasonNumber)
|
|
||||||
{
|
|
||||||
return _seasons.Get(showSlug, seasonNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber)
|
|
||||||
{
|
|
||||||
return _episodes.Get(showSlug, seasonNumber, episodeNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Episode> GetMovieEpisode(string movieSlug)
|
|
||||||
{
|
|
||||||
return _episodes.Get(movieSlug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Track> GetTrack(int id)
|
|
||||||
{
|
|
||||||
return _tracks.Get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Track> GetTrack(int episodeID, string language, bool isForced)
|
|
||||||
{
|
|
||||||
return _tracks.Get(episodeID, language, isForced);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Genre> GetGenre(string slug)
|
|
||||||
{
|
|
||||||
return _genres.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Studio> GetStudio(string slug)
|
|
||||||
{
|
|
||||||
return _studios.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<People> GetPeople(string slug)
|
|
||||||
{
|
|
||||||
return _people.Get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Library>> GetLibraries()
|
|
||||||
{
|
|
||||||
return _libraries.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Collection>> GetCollections()
|
|
||||||
{
|
|
||||||
return _collections.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Show>> GetShows()
|
|
||||||
{
|
|
||||||
return _shows.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Season>> GetSeasons()
|
|
||||||
{
|
|
||||||
return _seasons.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Episode>> GetEpisodes()
|
|
||||||
{
|
|
||||||
return _episodes.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Track>> GetTracks()
|
|
||||||
{
|
|
||||||
return _tracks.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Studio>> GetStudios()
|
|
||||||
{
|
|
||||||
return _studios.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<People>> GetPeoples()
|
|
||||||
{
|
|
||||||
return _people.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Genre>> GetGenres()
|
|
||||||
{
|
|
||||||
return _genres.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<ProviderID>> GetProviders()
|
|
||||||
{
|
|
||||||
return _providers.GetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Season>> GetSeasons(int showID)
|
|
||||||
{
|
|
||||||
return _seasons.GetSeasons(showID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Season>> GetSeasons(string showSlug)
|
|
||||||
{
|
|
||||||
return _seasons.GetSeasons(showSlug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber)
|
|
||||||
{
|
|
||||||
return _episodes.GetEpisodes(showID, seasonNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber)
|
|
||||||
{
|
|
||||||
return _episodes.GetEpisodes(showSlug, seasonNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Episode>> GetEpisodes(int seasonID)
|
|
||||||
{
|
|
||||||
return _episodes.GetEpisodes(seasonID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Show> GetShowByPath(string path)
|
|
||||||
{
|
|
||||||
return _shows.GetByPath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
|
||||||
{
|
|
||||||
return _shows.AddShowLink(showID, libraryID, collectionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task AddShowLink(Show show, Library library, Collection collection)
|
|
||||||
{
|
|
||||||
if (show == null)
|
|
||||||
throw new ArgumentNullException(nameof(show));
|
|
||||||
return AddShowLink(show.ID, library?.ID, collection?.ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Library>> SearchLibraries(string searchQuery)
|
|
||||||
{
|
|
||||||
return _libraries.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Collection>> SearchCollections(string searchQuery)
|
|
||||||
{
|
|
||||||
return _collections.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Show>> SearchShows(string searchQuery)
|
|
||||||
{
|
|
||||||
return _shows.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Season>> SearchSeasons(string searchQuery)
|
|
||||||
{
|
|
||||||
return _seasons.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Episode>> SearchEpisodes(string searchQuery)
|
|
||||||
{
|
|
||||||
return _episodes.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Genre>> SearchGenres(string searchQuery)
|
|
||||||
{
|
|
||||||
return _genres.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Studio>> SearchStudios(string searchQuery)
|
|
||||||
{
|
|
||||||
return _studios.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<People>> SearchPeople(string searchQuery)
|
|
||||||
{
|
|
||||||
return _people.Search(searchQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterLibrary(Library library)
|
|
||||||
{
|
|
||||||
return _libraries.Create(library);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterCollection(Collection collection)
|
|
||||||
{
|
|
||||||
return _collections.Create(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterShow(Show show)
|
|
||||||
{
|
|
||||||
return _shows.Create(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterSeason(Season season)
|
|
||||||
{
|
|
||||||
return _seasons.Create(season);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterEpisode(Episode episode)
|
|
||||||
{
|
|
||||||
return _episodes.Create(episode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterTrack(Track track)
|
|
||||||
{
|
|
||||||
return _tracks.Create(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterGenre(Genre genre)
|
|
||||||
{
|
|
||||||
return _genres.Create(genre);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterStudio(Studio studio)
|
|
||||||
{
|
|
||||||
return _studios.Create(studio);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task RegisterPeople(People people)
|
|
||||||
{
|
|
||||||
return _people.Create(people);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditLibrary(Library library, bool resetOld)
|
|
||||||
{
|
|
||||||
return _libraries.Edit(library, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditCollection(Collection collection, bool resetOld)
|
|
||||||
{
|
|
||||||
return _collections.Edit(collection, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditShow(Show show, bool resetOld)
|
|
||||||
{
|
|
||||||
return _shows.Edit(show, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditSeason(Season season, bool resetOld)
|
|
||||||
{
|
|
||||||
return _seasons.Edit(season, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditEpisode(Episode episode, bool resetOld)
|
|
||||||
{
|
|
||||||
return _episodes.Edit(episode, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditTrack(Track track, bool resetOld)
|
|
||||||
{
|
|
||||||
return _tracks.Edit(track, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditGenre(Genre genre, bool resetOld)
|
|
||||||
{
|
|
||||||
return _genres.Edit(genre, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditStudio(Studio studio, bool resetOld)
|
|
||||||
{
|
|
||||||
return _studios.Edit(studio, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task EditPeople(People people, bool resetOld)
|
|
||||||
{
|
|
||||||
return _people.Edit(people, resetOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DelteLibrary(Library library)
|
|
||||||
{
|
|
||||||
return _libraries.Delete(library);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteCollection(Collection collection)
|
|
||||||
{
|
|
||||||
return _collections.Delete(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteShow(Show show)
|
|
||||||
{
|
|
||||||
return _shows.Delete(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteSeason(Season season)
|
|
||||||
{
|
|
||||||
return _seasons.Delete(season);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteEpisode(Episode episode)
|
|
||||||
{
|
|
||||||
return _episodes.Delete(episode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteTrack(Track track)
|
|
||||||
{
|
|
||||||
return _tracks.Delete(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteGenre(Genre genre)
|
|
||||||
{
|
|
||||||
return _genres.Delete(genre);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteStudio(Studio studio)
|
|
||||||
{
|
|
||||||
return _studios.Delete(studio);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeletePeople(People people)
|
|
||||||
{
|
|
||||||
return _people.Delete(people);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ namespace Kyoo.Controllers
|
|||||||
T ret = new T();
|
T ret = new T();
|
||||||
|
|
||||||
IEnumerable<IMetadataProvider> providers = library?.Providers
|
IEnumerable<IMetadataProvider> providers = library?.Providers
|
||||||
.Select(x => _providers.FirstOrDefault(y => y.Provider.Name == x.Name))
|
.Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
||||||
.Where(x => x != null)
|
.Where(x => x != null)
|
||||||
?? _providers;
|
?? _providers;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ namespace Kyoo.Controllers
|
|||||||
List<T> ret = new List<T>();
|
List<T> ret = new List<T>();
|
||||||
|
|
||||||
IEnumerable<IMetadataProvider> providers = library?.Providers
|
IEnumerable<IMetadataProvider> providers = library?.Providers
|
||||||
.Select(x => _providers.FirstOrDefault(y => y.Provider.Name == x.Name))
|
.Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
||||||
.Where(x => x != null)
|
.Where(x => x != null)
|
||||||
?? _providers;
|
?? _providers;
|
||||||
|
|
||||||
|
@ -1,129 +1,71 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class CollectionRepository : ICollectionRepository
|
public class CollectionRepository : LocalRepository<Collection>, ICollectionRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
private readonly Lazy<IShowRepository> _shows;
|
||||||
|
private readonly Lazy<ILibraryRepository> _libraries;
|
||||||
|
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
|
||||||
|
|
||||||
|
public CollectionRepository(DatabaseContext database, IServiceProvider services) : base(database)
|
||||||
public CollectionRepository(DatabaseContext database)
|
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
|
||||||
|
_libraries = new Lazy<ILibraryRepository>(services.GetRequiredService<ILibraryRepository>);
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_database.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
base.Dispose();
|
||||||
}
|
if (_shows.IsValueCreated)
|
||||||
|
_shows.Value.Dispose();
|
||||||
public Task<Collection> Get(int id)
|
if (_libraries.IsValueCreated)
|
||||||
{
|
_libraries.Value.Dispose();
|
||||||
return _database.Collections.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Collection> Get(string slug)
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return _database.Collections.FirstOrDefaultAsync(x => x.Slug == slug);
|
await _database.DisposeAsync();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
await _shows.Value.DisposeAsync();
|
||||||
|
if (_libraries.IsValueCreated)
|
||||||
|
await _libraries.Value.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Collection>> Search(string query)
|
public override async Task<ICollection<Collection>> Search(string query)
|
||||||
{
|
{
|
||||||
return await _database.Collections
|
return await _database.Collections
|
||||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Collection>> GetAll()
|
public override async Task<Collection> Create(Collection obj)
|
||||||
{
|
|
||||||
return await _database.Collections.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Collection obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
await _database.SaveChangesAsync($"Trying to insert a duplicated collection (slug {obj.Slug} already exists).");
|
||||||
try
|
return obj;
|
||||||
{
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated collection (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Collection obj)
|
protected override Task Validate(Collection ressource)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
return Task.CompletedTask;
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Collection old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(Collection edited, bool resetOld)
|
public override async Task Delete(Collection obj)
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Collection old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No collection found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Collection obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Collection obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(Collection obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -138,22 +80,70 @@ namespace Kyoo.Controllers
|
|||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Collection> objs)
|
public async Task<ICollection<Collection>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (Collection obj in objs)
|
ICollection<Collection> collections = await ApplyFilters(_database.CollectionLinks
|
||||||
await Delete(obj);
|
.Where(x => x.ShowID == showID)
|
||||||
|
.Select(x => x.Collection),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!collections.Any() & await _shows.Value.Get(showID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return collections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<ICollection<Collection>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
ICollection<Collection> collections = await ApplyFilters(_database.CollectionLinks
|
||||||
await Delete(id);
|
.Where(x => x.Show.Slug == showSlug)
|
||||||
|
.Select(x => x.Collection),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!collections.Any() & await _shows.Value.Get(showSlug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return collections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
public async Task<ICollection<Collection>> GetFromLibrary(int id,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (string slug in slugs)
|
ICollection<Collection> collections = await ApplyFilters(_database.LibraryLinks
|
||||||
await Delete(slug);
|
.Where(x => x.LibraryID == id && x.CollectionID != null)
|
||||||
|
.Select(x => x.Collection),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!collections.Any() && await _libraries.Value.Get(id) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return collections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Collection>> GetFromLibrary(string slug,
|
||||||
|
Expression<Func<Collection, bool>> where = null,
|
||||||
|
Sort<Collection> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Collection> collections = await ApplyFilters(_database.LibraryLinks
|
||||||
|
.Where(x => x.Library.Slug == slug && x.CollectionID != null)
|
||||||
|
.Select(x => x.Collection),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!collections.Any() && await _libraries.Value.Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return collections;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
@ -8,50 +10,49 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class EpisodeRepository : IEpisodeRepository
|
public class EpisodeRepository : LocalRepository<Episode>, IEpisodeRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
// private readonly ITrackRepository _tracks;
|
private readonly IShowRepository _shows;
|
||||||
|
private readonly ISeasonRepository _seasons;
|
||||||
|
protected override Expression<Func<Episode, object>> DefaultSort => x => x.EpisodeNumber;
|
||||||
|
|
||||||
|
|
||||||
public EpisodeRepository(DatabaseContext database, IProviderRepository providers)
|
public EpisodeRepository(DatabaseContext database,
|
||||||
|
IProviderRepository providers,
|
||||||
|
IShowRepository shows,
|
||||||
|
ISeasonRepository seasons)
|
||||||
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
_providers = providers;
|
||||||
|
_shows = shows;
|
||||||
|
_seasons = seasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_database.Dispose();
|
_database.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
await _database.DisposeAsync();
|
||||||
}
|
await _providers.DisposeAsync();
|
||||||
|
|
||||||
public Task<Episode> Get(int id)
|
|
||||||
{
|
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Episode> Get(string slug)
|
public override Task<Episode> Get(string slug)
|
||||||
{
|
{
|
||||||
int sIndex = slug.IndexOf("-s", StringComparison.Ordinal);
|
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)-e(?<episode>\d*)");
|
||||||
int eIndex = slug.IndexOf("-e", StringComparison.Ordinal);
|
|
||||||
|
|
||||||
if (sIndex == -1 && eIndex == -1)
|
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == slug);
|
|
||||||
|
|
||||||
if (sIndex == -1 || eIndex == -1 || eIndex < sIndex)
|
if (!match.Success)
|
||||||
throw new InvalidOperationException("Invalid episode slug. Format: {showSlug}-s{seasonNumber}-e{episodeNumber}");
|
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == slug);
|
||||||
string showSlug = slug.Substring(0, sIndex);
|
return Get(match.Groups["show"].Value,
|
||||||
if (!int.TryParse(slug.Substring(sIndex + 2), out int seasonNumber))
|
int.Parse(match.Groups["season"].Value),
|
||||||
throw new InvalidOperationException("Invalid episode slug. Format: {showSlug}-s{seasonNumber}-e{episodeNumber}");
|
int.Parse(match.Groups["episode"].Value));
|
||||||
if (!int.TryParse(slug.Substring(eIndex + 2), out int episodeNumber))
|
|
||||||
throw new InvalidOperationException("Invalid episode slug. Format: {showSlug}-s{seasonNumber}-e{episodeNumber}");
|
|
||||||
return Get(showSlug, seasonNumber, episodeNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
public Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
@ -60,21 +61,41 @@ namespace Kyoo.Controllers
|
|||||||
&& x.SeasonNumber == seasonNumber
|
&& x.SeasonNumber == seasonNumber
|
||||||
&& x.EpisodeNumber == episodeNumber);
|
&& x.EpisodeNumber == episodeNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Episode>> Search(string query)
|
public Task<Episode> Get(int showID, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||||
|
&& x.SeasonNumber == seasonNumber
|
||||||
|
&& x.EpisodeNumber == episodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> Get(int seasonID, int episodeNumber)
|
||||||
|
{
|
||||||
|
return _database.Episodes.FirstOrDefaultAsync(x => x.SeasonID == seasonID
|
||||||
|
&& x.EpisodeNumber == episodeNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetAbsolute(int showID, int absoluteNumber)
|
||||||
|
{
|
||||||
|
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||||
|
&& x.AbsoluteNumber == absoluteNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Episode> GetAbsolute(string showSlug, int absoluteNumber)
|
||||||
|
{
|
||||||
|
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||||
|
&& x.AbsoluteNumber == absoluteNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ICollection<Episode>> Search(string query)
|
||||||
{
|
{
|
||||||
return await _database.Episodes
|
return await _database.Episodes
|
||||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Episode>> GetAll()
|
public override async Task<Episode> Create(Episode obj)
|
||||||
{
|
|
||||||
return await _database.Episodes.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Episode obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -85,76 +106,15 @@ namespace Kyoo.Controllers
|
|||||||
foreach (MetadataID entry in obj.ExternalIDs)
|
foreach (MetadataID entry in obj.ExternalIDs)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
// Since Episodes & Tracks are on the same DB, using a single commit is quicker.
|
|
||||||
if (obj.Tracks != null)
|
if (obj.Tracks != null)
|
||||||
foreach (Track entry in obj.Tracks)
|
foreach (Track entry in obj.Tracks)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated episode (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since Episodes & Tracks are on the same DB, using a single commit is quicker.
|
await _database.SaveChangesAsync($"Trying to insert a duplicated episode (slug {obj.Slug} already exists).");
|
||||||
/*if (obj.Tracks != null)
|
return obj;
|
||||||
* foreach (Track track in obj.Tracks)
|
|
||||||
* {
|
|
||||||
* track.EpisodeID = obj.ID;
|
|
||||||
* await _tracks.Create(track);
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Episode obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Episode old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(Episode edited, bool resetOld)
|
protected override async Task Validate(Episode obj)
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Episode old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No episode found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
|
|
||||||
await Validate(old);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Validate(Episode obj)
|
|
||||||
{
|
{
|
||||||
if (obj.ShowID <= 0)
|
if (obj.ShowID <= 0)
|
||||||
throw new InvalidOperationException($"Can't store an episode not related to any show (showID: {obj.ShowID}).");
|
throw new InvalidOperationException($"Can't store an episode not related to any show (showID: {obj.ShowID}).");
|
||||||
@ -162,37 +122,82 @@ namespace Kyoo.Controllers
|
|||||||
if (obj.ExternalIDs != null)
|
if (obj.ExternalIDs != null)
|
||||||
{
|
{
|
||||||
foreach (MetadataID link in obj.ExternalIDs)
|
foreach (MetadataID link in obj.ExternalIDs)
|
||||||
link.ProviderID = await _providers.CreateIfNotExists(link.Provider);
|
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber)
|
public async Task<ICollection<Episode>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
return await _database.Episodes.Where(x => x.ShowID == showID
|
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.ShowID == showID),
|
||||||
&& x.SeasonNumber == seasonNumber).ToListAsync();
|
where,
|
||||||
}
|
sort,
|
||||||
|
limit);
|
||||||
public async Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber)
|
if (!episodes.Any() && await _shows.Get(showID) == null)
|
||||||
{
|
throw new ItemNotFound();
|
||||||
return await _database.Episodes.Where(x => x.Show.Slug == showSlug
|
return episodes;
|
||||||
&& x.SeasonNumber == seasonNumber).ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<Episode>> GetEpisodes(int seasonID)
|
|
||||||
{
|
|
||||||
return await _database.Episodes.Where(x => x.SeasonID == seasonID).ToListAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(int id)
|
public async Task<ICollection<Episode>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
Episode obj = await Get(id);
|
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.Show.Slug == showSlug),
|
||||||
await Delete(obj);
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!episodes.Any() && await _shows.Get(showSlug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
public async Task<ICollection<Episode>> GetFromSeason(int seasonID,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
Episode obj = await Get(slug);
|
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.SeasonID == seasonID),
|
||||||
await Delete(obj);
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!episodes.Any() && await _seasons.Get(seasonID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Episode>> GetFromSeason(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.ShowID == showID
|
||||||
|
&& x.SeasonNumber == seasonNumber),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!episodes.Any() && await _seasons.Get(showID, seasonNumber) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Episode>> GetFromSeason(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
Expression<Func<Episode, bool>> where = null,
|
||||||
|
Sort<Episode> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.Show.Slug == showSlug
|
||||||
|
&& x.SeasonNumber == seasonNumber),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!episodes.Any() && await _seasons.Get(showSlug, seasonNumber) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(string showSlug, int seasonNumber, int episodeNumber)
|
public async Task Delete(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
@ -201,7 +206,7 @@ namespace Kyoo.Controllers
|
|||||||
await Delete(obj);
|
await Delete(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(Episode obj)
|
public override async Task Delete(Episode obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -213,23 +218,5 @@ namespace Kyoo.Controllers
|
|||||||
// Since Tracks & Episodes are on the same database and handled by dotnet-ef, we can't use the repository to delete them.
|
// Since Tracks & Episodes are on the same database and handled by dotnet-ef, we can't use the repository to delete them.
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Episode> objs)
|
|
||||||
{
|
|
||||||
foreach (Episode obj in objs)
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
|
||||||
{
|
|
||||||
foreach (int id in ids)
|
|
||||||
await Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
|
||||||
{
|
|
||||||
foreach (string slug in slugs)
|
|
||||||
await Delete(slug);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,129 +1,66 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class GenreRepository : IGenreRepository
|
public class GenreRepository : LocalRepository<Genre>, IGenreRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
private readonly Lazy<IShowRepository> _shows;
|
||||||
|
protected override Expression<Func<Genre, object>> DefaultSort => x => x.Slug;
|
||||||
|
|
||||||
|
|
||||||
public GenreRepository(DatabaseContext database)
|
public GenreRepository(DatabaseContext database, IServiceProvider services) : base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_database.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
base.Dispose();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
_shows.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Genre> Get(int id)
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return await _database.Genres.FirstOrDefaultAsync(x => x.ID == id);
|
await _database.DisposeAsync();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
await _shows.Value.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Genre> Get(string slug)
|
public override async Task<ICollection<Genre>> Search(string query)
|
||||||
{
|
|
||||||
return await _database.Genres.FirstOrDefaultAsync(x => x.Slug == slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<Genre>> Search(string query)
|
|
||||||
{
|
{
|
||||||
return await _database.Genres
|
return await _database.Genres
|
||||||
.Where(genre => EF.Functions.Like(genre.Name, $"%{query}%"))
|
.Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Genre>> GetAll()
|
public override async Task<Genre> Create(Genre obj)
|
||||||
{
|
|
||||||
return await _database.Genres.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Genre obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
await _database.SaveChangesAsync($"Trying to insert a duplicated genre (slug {obj.Slug} already exists).");
|
||||||
try
|
return obj;
|
||||||
{
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated genre (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Genre obj)
|
protected override Task Validate(Genre ressource)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
return Task.CompletedTask;
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Genre old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(Genre edited, bool resetOld)
|
public override async Task Delete(Genre obj)
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Genre old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No genre found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Genre obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Genre obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(Genre obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -134,23 +71,36 @@ namespace Kyoo.Controllers
|
|||||||
_database.Entry(link).State = EntityState.Deleted;
|
_database.Entry(link).State = EntityState.Deleted;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Genre> objs)
|
public async Task<ICollection<Genre>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (Genre obj in objs)
|
ICollection<Genre> genres = await ApplyFilters(_database.GenreLinks.Where(x => x.ShowID == showID)
|
||||||
await Delete(obj);
|
.Select(x => x.Genre),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!genres.Any() && await _shows.Value.Get(showID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return genres;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<ICollection<Genre>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Genre, bool>> where = null,
|
||||||
|
Sort<Genre> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
ICollection<Genre> genres = await ApplyFilters(_database.GenreLinks
|
||||||
await Delete(id);
|
.Where(x => x.Show.Slug == showSlug)
|
||||||
}
|
.Select(x => x.Genre),
|
||||||
|
where,
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
sort,
|
||||||
{
|
limit);
|
||||||
foreach (string slug in slugs)
|
if (!genres.Any() && await _shows.Value.Get(showSlug) == null)
|
||||||
await Delete(slug);
|
throw new ItemNotFound();
|
||||||
|
return genres;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Npgsql;
|
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
|
||||||
{
|
|
||||||
public static class Helper
|
|
||||||
{
|
|
||||||
public static bool IsDuplicateException(DbUpdateException ex)
|
|
||||||
{
|
|
||||||
return ex.InnerException is PostgresException inner
|
|
||||||
&& inner.SqlState == PostgresErrorCodes.UniqueViolation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
136
Kyoo/Controllers/Repositories/LibraryItemRepository.cs
Normal file
136
Kyoo/Controllers/Repositories/LibraryItemRepository.cs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
public class LibraryItemRepository : LocalRepository<LibraryItem>, ILibraryItemRepository
|
||||||
|
{
|
||||||
|
private readonly DatabaseContext _database;
|
||||||
|
private readonly IProviderRepository _providers;
|
||||||
|
private readonly Lazy<ILibraryRepository> _libraries;
|
||||||
|
private readonly Lazy<IShowRepository> _shows;
|
||||||
|
private readonly Lazy<ICollectionRepository> _collections;
|
||||||
|
protected override Expression<Func<LibraryItem, object>> DefaultSort => x => x.Title;
|
||||||
|
|
||||||
|
|
||||||
|
public LibraryItemRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
|
||||||
|
: base(database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
_providers = providers;
|
||||||
|
_libraries = new Lazy<ILibraryRepository>(services.GetRequiredService<ILibraryRepository>);
|
||||||
|
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
|
||||||
|
_collections = new Lazy<ICollectionRepository>(services.GetRequiredService<ICollectionRepository>);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
_database.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
_shows.Value.Dispose();
|
||||||
|
if (_collections.IsValueCreated)
|
||||||
|
_collections.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await _database.DisposeAsync();
|
||||||
|
await _providers.DisposeAsync();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
await _shows.Value.DisposeAsync();
|
||||||
|
if (_collections.IsValueCreated)
|
||||||
|
await _collections.Value.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<LibraryItem> Get(int id)
|
||||||
|
{
|
||||||
|
return id > 0
|
||||||
|
? new LibraryItem(await _shows.Value.Get(id))
|
||||||
|
: new LibraryItem(await _collections.Value.Get(-id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<LibraryItem> Get(string slug)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<LibraryItem> ItemsQuery
|
||||||
|
=> _database.Shows
|
||||||
|
.Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID))
|
||||||
|
.Select(LibraryItem.FromShow)
|
||||||
|
.Concat(_database.Collections
|
||||||
|
.Select(LibraryItem.FromCollection));
|
||||||
|
|
||||||
|
public override Task<ICollection<LibraryItem>> GetAll(Expression<Func<LibraryItem, bool>> where = null,
|
||||||
|
Sort<LibraryItem> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
return ApplyFilters(ItemsQuery, where, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ICollection<LibraryItem>> Search(string query)
|
||||||
|
{
|
||||||
|
return await ItemsQuery
|
||||||
|
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
|
||||||
|
.Take(20)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<LibraryItem> Create(LibraryItem obj) => throw new InvalidOperationException();
|
||||||
|
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj) => throw new InvalidOperationException();
|
||||||
|
public override Task<LibraryItem> Edit(LibraryItem obj, bool reset) => throw new InvalidOperationException();
|
||||||
|
protected override Task Validate(LibraryItem obj) => throw new InvalidOperationException();
|
||||||
|
public override Task Delete(int id) => throw new InvalidOperationException();
|
||||||
|
public override Task Delete(string slug) => throw new InvalidOperationException();
|
||||||
|
public override Task Delete(LibraryItem obj) => throw new InvalidOperationException();
|
||||||
|
|
||||||
|
private IQueryable<LibraryItem> LibraryRelatedQuery(Expression<Func<LibraryLink, bool>> selector)
|
||||||
|
=> _database.LibraryLinks
|
||||||
|
.Where(selector)
|
||||||
|
.Select(x => x.Show)
|
||||||
|
.Where(x => x != null)
|
||||||
|
.Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID))
|
||||||
|
.Select(LibraryItem.FromShow)
|
||||||
|
.Concat(_database.LibraryLinks
|
||||||
|
.Where(selector)
|
||||||
|
.Select(x => x.Collection)
|
||||||
|
.Where(x => x != null)
|
||||||
|
.Select(LibraryItem.FromCollection));
|
||||||
|
|
||||||
|
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.LibraryID == id),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!items.Any() && await _libraries.Value.Get(id) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Library.Slug == slug),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!items.Any() && await _libraries.Value.Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,59 +1,56 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class LibraryRepository : ILibraryRepository
|
public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
|
private readonly Lazy<IShowRepository> _shows;
|
||||||
|
protected override Expression<Func<Library, object>> DefaultSort => x => x.ID;
|
||||||
|
|
||||||
|
|
||||||
public LibraryRepository(DatabaseContext database, IProviderRepository providers)
|
public LibraryRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
|
||||||
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
_providers = providers;
|
||||||
}
|
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_database.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
return _database.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Library> Get(int id)
|
|
||||||
{
|
|
||||||
return _database.Libraries.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Library> Get(string slug)
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
return _database.Libraries.FirstOrDefaultAsync(x => x.Slug == slug);
|
_database.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
_shows.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Library>> Search(string query)
|
public override async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await _database.DisposeAsync();
|
||||||
|
await _providers.DisposeAsync();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
await _shows.Value.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ICollection<Library>> Search(string query)
|
||||||
{
|
{
|
||||||
return await _database.Libraries
|
return await _database.Libraries
|
||||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Library>> GetAll()
|
public override async Task<Library> Create(Library obj)
|
||||||
{
|
|
||||||
return await _database.Libraries.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Library obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -64,79 +61,25 @@ namespace Kyoo.Controllers
|
|||||||
foreach (ProviderLink entry in obj.ProviderLinks)
|
foreach (ProviderLink entry in obj.ProviderLinks)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated library (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Library obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Library old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(Library edited, bool resetOld)
|
protected override async Task Validate(Library obj)
|
||||||
{
|
{
|
||||||
if (edited == null)
|
if (string.IsNullOrEmpty(obj.Slug))
|
||||||
throw new ArgumentNullException(nameof(edited));
|
throw new ArgumentException("The library's slug must be set and not empty");
|
||||||
|
if (string.IsNullOrEmpty(obj.Name))
|
||||||
|
throw new ArgumentException("The library's name must be set and not empty");
|
||||||
|
if (obj.Paths == null || !obj.Paths.Any())
|
||||||
|
throw new ArgumentException("The library should have a least one path.");
|
||||||
|
|
||||||
Library old = await Get(edited.Name);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No library found with the name {edited.Name}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await Validate(old);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Validate(Library obj)
|
|
||||||
{
|
|
||||||
if (obj.ProviderLinks != null)
|
if (obj.ProviderLinks != null)
|
||||||
foreach (ProviderLink link in obj.ProviderLinks)
|
foreach (ProviderLink link in obj.ProviderLinks)
|
||||||
link.ProviderID = await _providers.CreateIfNotExists(link.Provider);
|
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(int id)
|
public override async Task Delete(Library obj)
|
||||||
{
|
|
||||||
Library obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Library obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(Library obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -150,23 +93,69 @@ namespace Kyoo.Controllers
|
|||||||
_database.Entry(entry).State = EntityState.Deleted;
|
_database.Entry(entry).State = EntityState.Deleted;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Library> objs)
|
public async Task<ICollection<Library>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (Library obj in objs)
|
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||||
await Delete(obj);
|
.Where(x => x.ShowID == showID)
|
||||||
|
.Select(x => x.Library),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!libraries.Any() && await _shows.Value.Get(showID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return libraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Library>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||||
|
.Where(x => x.Show.Slug == showSlug)
|
||||||
|
.Select(x => x.Library),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!libraries.Any() && await _shows.Value.Get(showSlug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return libraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<ICollection<Library>> GetFromCollection(int id,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||||
await Delete(id);
|
.Where(x => x.CollectionID == id)
|
||||||
|
.Select(x => x.Library),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!libraries.Any() && await _shows.Value.Get(id) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return libraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
public async Task<ICollection<Library>> GetFromCollection(string slug,
|
||||||
|
Expression<Func<Library, bool>> where = null,
|
||||||
|
Sort<Library> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (string slug in slugs)
|
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||||
await Delete(slug);
|
.Where(x => x.Collection.Slug == slug)
|
||||||
|
.Select(x => x.Library),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!libraries.Any() && await _shows.Value.Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return libraries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,58 +1,56 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class PeopleRepository : IPeopleRepository
|
public class PeopleRepository : LocalRepository<People>, IPeopleRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
|
private readonly Lazy<IShowRepository> _shows;
|
||||||
|
protected override Expression<Func<People, object>> DefaultSort => x => x.Name;
|
||||||
|
|
||||||
public PeopleRepository(DatabaseContext database, IProviderRepository providers)
|
public PeopleRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
|
||||||
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
_providers = providers;
|
||||||
|
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_database.Dispose();
|
_database.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
_shows.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
await _database.DisposeAsync();
|
||||||
|
await _providers.DisposeAsync();
|
||||||
|
if (_shows.IsValueCreated)
|
||||||
|
await _shows.Value.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<People> Get(int id)
|
public override async Task<ICollection<People>> Search(string query)
|
||||||
{
|
{
|
||||||
return _database.Peoples.FirstOrDefaultAsync(x => x.ID == id);
|
return await _database.People
|
||||||
}
|
.Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))
|
||||||
|
|
||||||
public Task<People> Get(string slug)
|
|
||||||
{
|
|
||||||
return _database.Peoples.FirstOrDefaultAsync(x => x.Slug == slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<People>> Search(string query)
|
|
||||||
{
|
|
||||||
return await _database.Peoples
|
|
||||||
.Where(people => EF.Functions.Like(people.Name, $"%{query}%"))
|
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<People>> GetAll()
|
public override async Task<People> Create(People obj)
|
||||||
{
|
|
||||||
return await _database.Peoples.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(People obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -63,79 +61,18 @@ namespace Kyoo.Controllers
|
|||||||
foreach (MetadataID entry in obj.ExternalIDs)
|
foreach (MetadataID entry in obj.ExternalIDs)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated people (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated people (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(People obj)
|
protected override async Task Validate(People obj)
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
People old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Edit(People edited, bool resetOld)
|
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
People old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No people found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await Validate(old);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Validate(People obj)
|
|
||||||
{
|
{
|
||||||
if (obj.ExternalIDs != null)
|
if (obj.ExternalIDs != null)
|
||||||
foreach (MetadataID link in obj.ExternalIDs)
|
foreach (MetadataID link in obj.ExternalIDs)
|
||||||
link.ProviderID = await _providers.CreateIfNotExists(link.Provider);
|
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(int id)
|
public override async Task Delete(People obj)
|
||||||
{
|
|
||||||
People obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
People obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(People obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -149,23 +86,91 @@ namespace Kyoo.Controllers
|
|||||||
_database.Entry(link).State = EntityState.Deleted;
|
_database.Entry(link).State = EntityState.Deleted;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<People> objs)
|
public async Task<ICollection<PeopleLink>> GetFromShow(int showID,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (People obj in objs)
|
if (sort.Key?.Body is MemberExpression member)
|
||||||
await Delete(obj);
|
{
|
||||||
|
sort.Key = member.Member.Name switch
|
||||||
|
{
|
||||||
|
"Name" => x => x.People.Name,
|
||||||
|
"Slug" => x => x.People.Slug,
|
||||||
|
_ => sort.Key
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.ShowID == showID),
|
||||||
|
id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
|
||||||
|
x => x.People.Name,
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!people.Any() && await _shows.Value.Get(showID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return people;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<PeopleLink, bool>> where = null,
|
||||||
|
Sort<PeopleLink> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
if (sort.Key?.Body is MemberExpression member)
|
||||||
|
{
|
||||||
|
sort.Key = member.Member.Name switch
|
||||||
|
{
|
||||||
|
"Name" => x => x.People.Name,
|
||||||
|
"Slug" => x => x.People.Slug,
|
||||||
|
_ => sort.Key
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.Show.Slug == showSlug),
|
||||||
|
id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
|
||||||
|
x => x.People.Name,
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!people.Any() && await _shows.Value.Get(showSlug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return people;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<ICollection<ShowRole>> GetFromPeople(int peopleID,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
ICollection<ShowRole> roles = await ApplyFilters(_database.PeopleRoles.Where(x => x.PeopleID == peopleID)
|
||||||
await Delete(id);
|
.Select(ShowRole.FromPeopleRole),
|
||||||
|
async id => new ShowRole(await _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id)),
|
||||||
|
x => x.Title,
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!roles.Any() && await Get(peopleID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
public async Task<ICollection<ShowRole>> GetFromPeople(string slug,
|
||||||
|
Expression<Func<ShowRole, bool>> where = null,
|
||||||
|
Sort<ShowRole> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (string slug in slugs)
|
ICollection<ShowRole> roles = await ApplyFilters(_database.PeopleRoles.Where(x => x.People.Slug == slug)
|
||||||
await Delete(slug);
|
.Select(ShowRole.FromPeopleRole),
|
||||||
|
async id => new ShowRole(await _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id)),
|
||||||
|
x => x.Title,
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!roles.Any() && await Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return roles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
@ -8,121 +9,42 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class ProviderRepository : IProviderRepository
|
public class ProviderRepository : LocalRepository<ProviderID>, IProviderRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
protected override Expression<Func<ProviderID, object>> DefaultSort => x => x.Slug;
|
||||||
|
|
||||||
|
|
||||||
public ProviderRepository(DatabaseContext database)
|
public ProviderRepository(DatabaseContext database) : base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_database.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override async Task<ICollection<ProviderID>> Search(string query)
|
||||||
{
|
|
||||||
return _database.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ProviderID> Get(int id)
|
|
||||||
{
|
|
||||||
return await _database.Providers.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ProviderID> Get(string slug)
|
|
||||||
{
|
|
||||||
return await _database.Providers.FirstOrDefaultAsync(x => x.Name == slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<ProviderID>> Search(string query)
|
|
||||||
{
|
{
|
||||||
return await _database.Providers
|
return await _database.Providers
|
||||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<ProviderID>> GetAll()
|
public override async Task<ProviderID> Create(ProviderID obj)
|
||||||
{
|
|
||||||
return await _database.Providers.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(ProviderID obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated provider (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(ProviderID obj)
|
protected override Task Validate(ProviderID ressource)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
return Task.CompletedTask;
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
ProviderID old = await Get(obj.Name);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Name);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(ProviderID edited, bool resetOld)
|
public override async Task Delete(ProviderID obj)
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
ProviderID old = await Get(edited.Name);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No provider found with the name {edited.Name}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
ProviderID obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
ProviderID obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(ProviderID obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -131,23 +53,5 @@ namespace Kyoo.Controllers
|
|||||||
// TODO handle ExternalID deletion when they refer to this providerID.
|
// TODO handle ExternalID deletion when they refer to this providerID.
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<ProviderID> objs)
|
|
||||||
{
|
|
||||||
foreach (ProviderID obj in objs)
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
|
||||||
{
|
|
||||||
foreach (int id in ids)
|
|
||||||
await Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
|
||||||
{
|
|
||||||
foreach (string slug in slugs)
|
|
||||||
await Delete(slug);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,51 +1,67 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class SeasonRepository : ISeasonRepository
|
public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
private readonly IEpisodeRepository _episodes;
|
private readonly Lazy<IEpisodeRepository> _episodes;
|
||||||
|
private readonly IShowRepository _shows;
|
||||||
|
protected override Expression<Func<Season, object>> DefaultSort => x => x.SeasonNumber;
|
||||||
|
|
||||||
|
|
||||||
public SeasonRepository(DatabaseContext database, IProviderRepository providers, IEpisodeRepository episodes)
|
public SeasonRepository(DatabaseContext database,
|
||||||
|
IProviderRepository providers,
|
||||||
|
IShowRepository shows,
|
||||||
|
IServiceProvider services)
|
||||||
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
_providers = providers;
|
||||||
_episodes = episodes;
|
_episodes = new Lazy<IEpisodeRepository>(services.GetRequiredService<IEpisodeRepository>);
|
||||||
|
_shows = shows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_database.Dispose();
|
_database.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
|
if (_episodes.IsValueCreated)
|
||||||
|
_episodes.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
await _database.DisposeAsync();
|
||||||
|
await _providers.DisposeAsync();
|
||||||
|
if (_episodes.IsValueCreated)
|
||||||
|
await _episodes.Value.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<Season> Get(string slug)
|
||||||
|
{
|
||||||
|
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)");
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
||||||
|
return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Season> Get(int id)
|
public Task<Season> Get(int showID, int seasonNumber)
|
||||||
{
|
{
|
||||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ID == id);
|
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||||
}
|
&& x.SeasonNumber == seasonNumber);
|
||||||
|
|
||||||
public Task<Season> Get(string slug)
|
|
||||||
{
|
|
||||||
int index = slug.IndexOf("-s", StringComparison.Ordinal);
|
|
||||||
if (index == -1)
|
|
||||||
throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
|
||||||
string showSlug = slug.Substring(0, index);
|
|
||||||
if (!int.TryParse(slug.Substring(index + 2), out int seasonNumber))
|
|
||||||
throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
|
||||||
return Get(showSlug, seasonNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Season> Get(string showSlug, int seasonNumber)
|
public Task<Season> Get(string showSlug, int seasonNumber)
|
||||||
@ -54,20 +70,15 @@ namespace Kyoo.Controllers
|
|||||||
&& x.SeasonNumber == seasonNumber);
|
&& x.SeasonNumber == seasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Season>> Search(string query)
|
public override async Task<ICollection<Season>> Search(string query)
|
||||||
{
|
{
|
||||||
return await _database.Seasons
|
return await _database.Seasons
|
||||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Season>> GetAll()
|
public override async Task<Season> Create(Season obj)
|
||||||
{
|
|
||||||
return await _database.Seasons.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Season obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -78,61 +89,11 @@ namespace Kyoo.Controllers
|
|||||||
foreach (MetadataID entry in obj.ExternalIDs)
|
foreach (MetadataID entry in obj.ExternalIDs)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated season (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated season (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Season obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Season old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Edit(Season edited, bool resetOld)
|
protected override async Task Validate(Season obj)
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Season old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No season found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
|
|
||||||
await Validate(old);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Validate(Season obj)
|
|
||||||
{
|
{
|
||||||
if (obj.ShowID <= 0)
|
if (obj.ShowID <= 0)
|
||||||
throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID}).");
|
throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID}).");
|
||||||
@ -140,39 +101,45 @@ namespace Kyoo.Controllers
|
|||||||
if (obj.ExternalIDs != null)
|
if (obj.ExternalIDs != null)
|
||||||
{
|
{
|
||||||
foreach (MetadataID link in obj.ExternalIDs)
|
foreach (MetadataID link in obj.ExternalIDs)
|
||||||
link.ProviderID = await _providers.CreateIfNotExists(link.Provider);
|
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Season>> GetSeasons(int showID)
|
public async Task<ICollection<Season>> GetFromShow(int showID,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
return await _database.Seasons.Where(x => x.ShowID == showID).ToListAsync();
|
ICollection<Season> seasons = await ApplyFilters(_database.Seasons.Where(x => x.ShowID == showID),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!seasons.Any() && await _shows.Get(showID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return seasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Season>> GetSeasons(string showSlug)
|
public async Task<ICollection<Season>> GetFromShow(string showSlug,
|
||||||
|
Expression<Func<Season, bool>> where = null,
|
||||||
|
Sort<Season> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
return await _database.Seasons.Where(x => x.Show.Slug == showSlug).ToListAsync();
|
ICollection<Season> seasons = await ApplyFilters(_database.Seasons.Where(x => x.Show.Slug == showSlug),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!seasons.Any() && await _shows.Get(showSlug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return seasons;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Season obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Season obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string showSlug, int seasonNumber)
|
public async Task Delete(string showSlug, int seasonNumber)
|
||||||
{
|
{
|
||||||
Season obj = await Get(showSlug, seasonNumber);
|
Season obj = await Get(showSlug, seasonNumber);
|
||||||
await Delete(obj);
|
await Delete(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(Season obj)
|
public override async Task Delete(Season obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -186,25 +153,12 @@ namespace Kyoo.Controllers
|
|||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
|
|
||||||
if (obj.Episodes != null)
|
if (obj.Episodes != null)
|
||||||
await _episodes.DeleteRange(obj.Episodes);
|
await _episodes.Value.DeleteRange(obj.Episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Season> objs)
|
public Task<Season> GetFromEpisode(int episodeID)
|
||||||
{
|
{
|
||||||
foreach (Season obj in objs)
|
return _database.Seasons.FirstOrDefaultAsync(x => x.Episodes.Any(y => y.ID == episodeID));
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
|
||||||
{
|
|
||||||
foreach (int id in ids)
|
|
||||||
await Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
|
||||||
{
|
|
||||||
foreach (string slug in slugs)
|
|
||||||
await Delete(slug);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,81 +1,92 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class ShowRepository : IShowRepository
|
public class ShowRepository : LocalRepository<Show>, IShowRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
private readonly IStudioRepository _studios;
|
private readonly IStudioRepository _studios;
|
||||||
private readonly IPeopleRepository _people;
|
private readonly IPeopleRepository _people;
|
||||||
private readonly IGenreRepository _genres;
|
private readonly IGenreRepository _genres;
|
||||||
private readonly IProviderRepository _providers;
|
private readonly IProviderRepository _providers;
|
||||||
private readonly ISeasonRepository _seasons;
|
private readonly Lazy<ISeasonRepository> _seasons;
|
||||||
private readonly IEpisodeRepository _episodes;
|
private readonly Lazy<IEpisodeRepository> _episodes;
|
||||||
|
private readonly Lazy<ILibraryRepository> _libraries;
|
||||||
|
private readonly Lazy<ICollectionRepository> _collections;
|
||||||
|
protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
|
||||||
|
|
||||||
public ShowRepository(DatabaseContext database,
|
public ShowRepository(DatabaseContext database,
|
||||||
IStudioRepository studios,
|
IStudioRepository studios,
|
||||||
IPeopleRepository people,
|
IPeopleRepository people,
|
||||||
IGenreRepository genres,
|
IGenreRepository genres,
|
||||||
IProviderRepository providers,
|
IProviderRepository providers,
|
||||||
ISeasonRepository seasons,
|
IServiceProvider services)
|
||||||
IEpisodeRepository episodes)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_studios = studios;
|
_studios = studios;
|
||||||
_people = people;
|
_people = people;
|
||||||
_genres = genres;
|
_genres = genres;
|
||||||
_providers = providers;
|
_providers = providers;
|
||||||
_seasons = seasons;
|
_seasons = new Lazy<ISeasonRepository>(services.GetRequiredService<ISeasonRepository>);
|
||||||
_episodes = episodes;
|
_episodes = new Lazy<IEpisodeRepository>(services.GetRequiredService<IEpisodeRepository>);
|
||||||
|
_libraries = new Lazy<ILibraryRepository>(services.GetRequiredService<ILibraryRepository>);
|
||||||
|
_collections = new Lazy<ICollectionRepository>(services.GetRequiredService<ICollectionRepository>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_database.Dispose();
|
_database.Dispose();
|
||||||
_studios.Dispose();
|
_studios.Dispose();
|
||||||
|
_people.Dispose();
|
||||||
|
_genres.Dispose();
|
||||||
|
_providers.Dispose();
|
||||||
|
if (_seasons.IsValueCreated)
|
||||||
|
_seasons.Value.Dispose();
|
||||||
|
if (_episodes.IsValueCreated)
|
||||||
|
_episodes.Value.Dispose();
|
||||||
|
if (_libraries.IsValueCreated)
|
||||||
|
_libraries.Value.Dispose();
|
||||||
|
if (_collections.IsValueCreated)
|
||||||
|
_collections.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
await Task.WhenAll(_database.DisposeAsync().AsTask(), _studios.DisposeAsync().AsTask());
|
await _database.DisposeAsync();
|
||||||
}
|
await _studios.DisposeAsync();
|
||||||
|
await _people.DisposeAsync();
|
||||||
public Task<Show> Get(int id)
|
await _genres.DisposeAsync();
|
||||||
{
|
await _providers.DisposeAsync();
|
||||||
return _database.Shows.FirstOrDefaultAsync(x => x.ID == id);
|
if (_seasons.IsValueCreated)
|
||||||
}
|
await _seasons.Value.DisposeAsync();
|
||||||
|
if (_episodes.IsValueCreated)
|
||||||
public Task<Show> Get(string slug)
|
await _episodes.Value.DisposeAsync();
|
||||||
{
|
if (_libraries.IsValueCreated)
|
||||||
return _database.Shows.FirstOrDefaultAsync(x => x.Slug == slug);
|
await _libraries.Value.DisposeAsync();
|
||||||
|
if (_collections.IsValueCreated)
|
||||||
|
await _collections.Value.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Show> GetByPath(string path)
|
public override async Task<ICollection<Show>> Search(string query)
|
||||||
{
|
|
||||||
return _database.Shows.FirstOrDefaultAsync(x => x.Path == path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<Show>> Search(string query)
|
|
||||||
{
|
{
|
||||||
|
query = $"%{query}%";
|
||||||
return await _database.Shows
|
return await _database.Shows
|
||||||
.FromSqlInterpolated($@"SELECT * FROM Shows WHERE 'Shows.Title' LIKE {$"%{query}%"}
|
.Where(x => EF.Functions.ILike(x.Title, query)
|
||||||
OR 'Shows.Aliases' LIKE {$"%{query}%"}")
|
/*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Show>> GetAll()
|
public override async Task<Show> Create(Show obj)
|
||||||
{
|
|
||||||
return await _database.Shows.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Show obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -92,113 +103,49 @@ namespace Kyoo.Controllers
|
|||||||
foreach (MetadataID entry in obj.ExternalIDs)
|
foreach (MetadataID entry in obj.ExternalIDs)
|
||||||
_database.Entry(entry).State = EntityState.Added;
|
_database.Entry(entry).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Show obj)
|
protected override async Task Validate(Show obj)
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Show old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Edit(Show edited, bool resetOld)
|
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Show old = await Get(edited.Slug);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No show found with the slug {edited.Slug}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await Validate(old);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Validate(Show obj)
|
|
||||||
{
|
{
|
||||||
if (obj.Studio != null)
|
if (obj.Studio != null)
|
||||||
obj.StudioID = await _studios.CreateIfNotExists(obj.Studio);
|
obj.Studio = await _studios.CreateIfNotExists(obj.Studio);
|
||||||
|
|
||||||
if (obj.GenreLinks != null)
|
if (obj.GenreLinks != null)
|
||||||
foreach (GenreLink link in obj.GenreLinks)
|
foreach (GenreLink link in obj.GenreLinks)
|
||||||
link.GenreID = await _genres.CreateIfNotExists(link.Genre);
|
link.Genre = await _genres.CreateIfNotExists(link.Genre);
|
||||||
|
|
||||||
if (obj.People != null)
|
if (obj.People != null)
|
||||||
foreach (PeopleLink link in obj.People)
|
foreach (PeopleLink link in obj.People)
|
||||||
link.PeopleID = await _people.CreateIfNotExists(link.People);
|
link.People = await _people.CreateIfNotExists(link.People);
|
||||||
|
|
||||||
if (obj.ExternalIDs != null)
|
if (obj.ExternalIDs != null)
|
||||||
foreach (MetadataID link in obj.ExternalIDs)
|
foreach (MetadataID link in obj.ExternalIDs)
|
||||||
link.ProviderID = await _providers.CreateIfNotExists(link.Provider);
|
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
public async Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
||||||
{
|
{
|
||||||
if (collectionID != null)
|
if (collectionID != null)
|
||||||
{
|
{
|
||||||
_database.CollectionLinks.AddIfNotExist(new CollectionLink { CollectionID = collectionID, ShowID = showID},
|
await _database.CollectionLinks.AddAsync(new CollectionLink {CollectionID = collectionID, ShowID = showID});
|
||||||
x => x.CollectionID == collectionID && x.ShowID == showID);
|
await _database.SaveIfNoDuplicates();
|
||||||
}
|
}
|
||||||
if (libraryID != null)
|
if (libraryID != null)
|
||||||
{
|
{
|
||||||
_database.LibraryLinks.AddIfNotExist(new LibraryLink {LibraryID = libraryID.Value, ShowID = showID},
|
await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, ShowID = showID});
|
||||||
x => x.LibraryID == libraryID.Value && x.CollectionID == null && x.ShowID == showID);
|
await _database.SaveIfNoDuplicates();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryID != null && collectionID != null)
|
if (libraryID != null && collectionID != null)
|
||||||
{
|
{
|
||||||
_database.LibraryLinks.AddIfNotExist(
|
await _database.LibraryLinks.AddAsync(new LibraryLink {LibraryID = libraryID.Value, CollectionID = collectionID.Value});
|
||||||
new LibraryLink {LibraryID = libraryID.Value, CollectionID = collectionID.Value},
|
await _database.SaveIfNoDuplicates();
|
||||||
x => x.LibraryID == libraryID && x.CollectionID == collectionID && x.ShowID == null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Show obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Show obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(Show obj)
|
public override async Task Delete(Show obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -224,32 +171,88 @@ namespace Kyoo.Controllers
|
|||||||
if (obj.LibraryLinks != null)
|
if (obj.LibraryLinks != null)
|
||||||
foreach (LibraryLink entry in obj.LibraryLinks)
|
foreach (LibraryLink entry in obj.LibraryLinks)
|
||||||
_database.Entry(entry).State = EntityState.Deleted;
|
_database.Entry(entry).State = EntityState.Deleted;
|
||||||
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
await _database.SaveChangesAsync();
|
||||||
|
|
||||||
if (obj.Seasons != null)
|
if (obj.Seasons != null)
|
||||||
await _seasons.DeleteRange(obj.Seasons);
|
await _seasons.Value.DeleteRange(obj.Seasons);
|
||||||
|
|
||||||
if (obj.Episodes != null)
|
if (obj.Episodes != null)
|
||||||
await _episodes.DeleteRange(obj.Episodes);
|
await _episodes.Value.DeleteRange(obj.Episodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Show>> GetFromLibrary(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Show> shows = await ApplyFilters(_database.LibraryLinks
|
||||||
|
.Where(x => x.LibraryID == id && x.ShowID != null)
|
||||||
|
.Select(x => x.Show),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!shows.Any() && await _libraries.Value.Get(id) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Show>> GetFromLibrary(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Show> shows = await ApplyFilters(_database.LibraryLinks
|
||||||
|
.Where(x => x.Library.Slug == slug && x.ShowID != null)
|
||||||
|
.Select(x => x.Show),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!shows.Any() && await _libraries.Value.Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return shows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Show> objs)
|
public async Task<ICollection<Show>> GetFromCollection(int id,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (Show obj in objs)
|
ICollection<Show> shows = await ApplyFilters(_database.CollectionLinks
|
||||||
await Delete(obj);
|
.Where(x => x.CollectionID== id)
|
||||||
|
.Select(x => x.Show),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!shows.Any() && await _libraries.Value.Get(id) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<Show>> GetFromCollection(string slug,
|
||||||
|
Expression<Func<Show, bool>> where = null,
|
||||||
|
Sort<Show> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
|
{
|
||||||
|
ICollection<Show> shows = await ApplyFilters(_database.CollectionLinks
|
||||||
|
.Where(x => x.Collection.Slug == slug)
|
||||||
|
.Select(x => x.Show),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!shows.Any() && await _libraries.Value.Get(slug) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Show> GetFromSeason(int seasonID)
|
||||||
|
{
|
||||||
|
return _database.Shows.FirstOrDefaultAsync(x => x.Seasons.Any(y => y.ID == seasonID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public Task<Show> GetFromEpisode(int episodeID)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
return _database.Shows.FirstOrDefaultAsync(x => x.Episodes.Any(y => y.ID == episodeID));
|
||||||
await Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
|
||||||
{
|
|
||||||
foreach (string slug in slugs)
|
|
||||||
await Delete(slug);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
@ -8,120 +9,41 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class StudioRepository : IStudioRepository
|
public class StudioRepository : LocalRepository<Studio>, IStudioRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
protected override Expression<Func<Studio, object>> DefaultSort => x => x.Name;
|
||||||
|
|
||||||
|
|
||||||
public StudioRepository(DatabaseContext database)
|
public StudioRepository(DatabaseContext database) : base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public override async Task<ICollection<Studio>> Search(string query)
|
||||||
{
|
|
||||||
_database.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
return _database.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Studio> Get(int id)
|
|
||||||
{
|
|
||||||
return await _database.Studios.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Studio> Get(string slug)
|
|
||||||
{
|
|
||||||
return await _database.Studios.FirstOrDefaultAsync(x => x.Slug == slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<Studio>> Search(string query)
|
|
||||||
{
|
{
|
||||||
return await _database.Studios
|
return await _database.Studios
|
||||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Studio>> GetAll()
|
public override async Task<Studio> Create(Studio obj)
|
||||||
{
|
|
||||||
return await _database.Studios.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Studio obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
await _database.SaveChangesAsync($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
||||||
try
|
return obj;
|
||||||
{
|
}
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
protected override Task Validate(Studio ressource)
|
||||||
catch (DbUpdateException ex)
|
{
|
||||||
{
|
return Task.CompletedTask;
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateIfNotExists(Studio obj)
|
public override async Task Delete(Studio obj)
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
Studio old = await Get(obj.Slug);
|
|
||||||
if (old != null)
|
|
||||||
return old.ID;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await Create(obj);
|
|
||||||
}
|
|
||||||
catch (DuplicatedItemException)
|
|
||||||
{
|
|
||||||
old = await Get(obj.Slug);
|
|
||||||
if (old == null)
|
|
||||||
throw new SystemException("Unknown database state.");
|
|
||||||
return old.ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Edit(Studio edited, bool resetOld)
|
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Studio old = await Get(edited.Name);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No studio found with the name {edited.Name}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Studio obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Studio obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(Studio obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -133,23 +55,27 @@ namespace Kyoo.Controllers
|
|||||||
show.StudioID = null;
|
show.StudioID = null;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Studio> objs)
|
public async Task<Studio> GetFromShow(int showID)
|
||||||
{
|
{
|
||||||
foreach (Studio obj in objs)
|
Studio studio = await _database.Shows
|
||||||
await Delete(obj);
|
.Where(x => x.ID == showID)
|
||||||
|
.Select(x => x.Studio)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (studio == null && !_database.Shows.Any(x => x.ID == showID))
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return studio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<Studio> GetFromShow(string showSlug)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
Studio studio = await _database.Shows
|
||||||
await Delete(id);
|
.Where(x => x.Slug == showSlug)
|
||||||
}
|
.Select(x => x.Studio)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
if (studio == null && !_database.Shows.Any(x => x.Slug == showSlug))
|
||||||
{
|
throw new ItemNotFound();
|
||||||
foreach (string slug in slugs)
|
return studio;
|
||||||
await Delete(slug);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,60 +1,72 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
public class TrackRepository : ITrackRepository
|
public class TrackRepository : LocalRepository<Track>, ITrackRepository
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
private readonly Lazy<IEpisodeRepository> _episodes;
|
||||||
|
protected override Expression<Func<Track, object>> DefaultSort => x => x.ID;
|
||||||
|
|
||||||
|
|
||||||
public TrackRepository(DatabaseContext database)
|
public TrackRepository(DatabaseContext database, IServiceProvider services) : base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
|
_episodes = new Lazy<IEpisodeRepository>(services.GetRequiredService<IEpisodeRepository>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_database.Dispose();
|
_database.Dispose();
|
||||||
|
if (_episodes.IsValueCreated)
|
||||||
|
_episodes.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
return _database.DisposeAsync();
|
await _database.DisposeAsync();
|
||||||
}
|
if (_episodes.IsValueCreated)
|
||||||
|
await _episodes.Value.DisposeAsync();
|
||||||
public async Task<Track> Get(int id)
|
|
||||||
{
|
|
||||||
return await _database.Tracks.FirstOrDefaultAsync(x => x.ID == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Track> Get(string slug)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Tracks do not support the get by slug method.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Track> Get(int episodeID, string languageTag, bool isForced)
|
public override Task<Track> Get(string slug)
|
||||||
{
|
{
|
||||||
return _database.Tracks.FirstOrDefaultAsync(x => x.EpisodeID == episodeID
|
Match match = Regex.Match(slug,
|
||||||
&& x.Language == languageTag
|
@"(?<show>.*)-s(?<season>\d*)-e(?<episode>\d*).(?<language>.{0,3})(?<forced>-forced)?(\..*)?");
|
||||||
&& x.IsForced == isForced);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<Track>> Search(string query)
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
if (int.TryParse(slug, out int id))
|
||||||
|
return Get(id);
|
||||||
|
throw new ArgumentException("Invalid track slug. Format: {episodeSlug}.{language}[-forced][.{extension}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
string showSlug = match.Groups["show"].Value;
|
||||||
|
int seasonNumber = int.Parse(match.Groups["season"].Value);
|
||||||
|
int episodeNumber = int.Parse(match.Groups["episode"].Value);
|
||||||
|
string language = match.Groups["language"].Value;
|
||||||
|
bool forced = match.Groups["forced"].Success;
|
||||||
|
return _database.Tracks.FirstOrDefaultAsync(x => x.Episode.Show.Slug == showSlug
|
||||||
|
&& x.Episode.SeasonNumber == seasonNumber
|
||||||
|
&& x.Episode.EpisodeNumber == episodeNumber
|
||||||
|
&& x.Language == language
|
||||||
|
&& x.IsForced == forced);
|
||||||
|
}
|
||||||
|
public override Task<ICollection<Track>> Search(string query)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Tracks do not support the search method.");
|
throw new InvalidOperationException("Tracks do not support the search method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<Track>> GetAll()
|
public override async Task<Track> Create(Track obj)
|
||||||
{
|
|
||||||
return await _database.Tracks.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Create(Track obj)
|
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -64,54 +76,16 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
|
||||||
try
|
await _database.SaveChangesAsync($"Trying to insert a duplicated track (slug {obj.Slug} already exists).");
|
||||||
{
|
return obj;
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException ex)
|
|
||||||
{
|
|
||||||
_database.DiscardChanges();
|
|
||||||
if (Helper.IsDuplicateException(ex))
|
|
||||||
throw new DuplicatedItemException($"Trying to insert a duplicated track (slug {obj.Slug} already exists).");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return obj.ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> CreateIfNotExists(Track obj)
|
protected override Task Validate(Track ressource)
|
||||||
{
|
{
|
||||||
return Create(obj);
|
return Task.CompletedTask;
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Edit(Track edited, bool resetOld)
|
|
||||||
{
|
|
||||||
if (edited == null)
|
|
||||||
throw new ArgumentNullException(nameof(edited));
|
|
||||||
|
|
||||||
Track old = await Get(edited.ID);
|
|
||||||
|
|
||||||
if (old == null)
|
|
||||||
throw new ItemNotFound($"No track found with the ID {edited.ID}.");
|
|
||||||
|
|
||||||
if (resetOld)
|
|
||||||
Utility.Nullify(old);
|
|
||||||
Utility.Merge(old, edited);
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(int id)
|
|
||||||
{
|
|
||||||
Track obj = await Get(id);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(string slug)
|
|
||||||
{
|
|
||||||
Track obj = await Get(slug);
|
|
||||||
await Delete(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(Track obj)
|
public override async Task Delete(Track obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
@ -119,23 +93,55 @@ namespace Kyoo.Controllers
|
|||||||
_database.Entry(obj).State = EntityState.Deleted;
|
_database.Entry(obj).State = EntityState.Deleted;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<Track> objs)
|
public async Task<ICollection<Track>> GetFromEpisode(int episodeID,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (Track obj in objs)
|
ICollection<Track> tracks = await ApplyFilters(_database.Tracks.Where(x => x.EpisodeID == episodeID),
|
||||||
await Delete(obj);
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!tracks.Any() && await _episodes.Value.Get(episodeID) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<int> ids)
|
public async Task<ICollection<Track>> GetFromEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (int id in ids)
|
ICollection<Track> tracks = await ApplyFilters(_database.Tracks.Where(x => x.Episode.ShowID == showID
|
||||||
await Delete(id);
|
&& x.Episode.SeasonNumber == seasonNumber
|
||||||
|
&& x.Episode.EpisodeNumber == episodeNumber),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!tracks.Any() && await _episodes.Value.Get(showID, seasonNumber, episodeNumber) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRange(IEnumerable<string> slugs)
|
public async Task<ICollection<Track>> GetFromEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
Expression<Func<Track, bool>> where = null,
|
||||||
|
Sort<Track> sort = default,
|
||||||
|
Pagination limit = default)
|
||||||
{
|
{
|
||||||
foreach (string slug in slugs)
|
ICollection<Track> tracks = await ApplyFilters(_database.Tracks.Where(x => x.Episode.Show.Slug == showSlug
|
||||||
await Delete(slug);
|
&& x.Episode.SeasonNumber == seasonNumber
|
||||||
|
&& x.Episode.EpisodeNumber == episodeNumber),
|
||||||
|
where,
|
||||||
|
sort,
|
||||||
|
limit);
|
||||||
|
if (!tracks.Any() && await _episodes.Value.Get(showSlug, seasonNumber, episodeNumber) == null)
|
||||||
|
throw new ItemNotFound();
|
||||||
|
return tracks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -68,10 +68,10 @@ namespace Kyoo.Controllers
|
|||||||
foreach (PeopleLink peop in people)
|
foreach (PeopleLink peop in people)
|
||||||
{
|
{
|
||||||
string localPath = Path.Combine(root, peop.People.Slug + ".jpg");
|
string localPath = Path.Combine(root, peop.People.Slug + ".jpg");
|
||||||
if (peop.People.ImgPrimary == null)
|
if (peop.People.Poster == null)
|
||||||
continue;
|
continue;
|
||||||
if (alwaysDownload || !File.Exists(localPath))
|
if (alwaysDownload || !File.Exists(localPath))
|
||||||
await DownloadImage(peop.People.ImgPrimary, localPath, $"The profile picture of {peop.People.Name}");
|
await DownloadImage(peop.People.Poster, localPath, $"The profile picture of {peop.People.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return people;
|
return people;
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
<ProjectReference Include="..\Kyoo.CommonAPI\Kyoo.CommonAPI.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IdentityServer4.EntityFramework.Entities;
|
using IdentityServer4.EntityFramework.Entities;
|
||||||
using IdentityServer4.EntityFramework.Extensions;
|
using IdentityServer4.EntityFramework.Extensions;
|
||||||
using IdentityServer4.EntityFramework.Interfaces;
|
using IdentityServer4.EntityFramework.Interfaces;
|
||||||
using IdentityServer4.EntityFramework.Options;
|
using IdentityServer4.EntityFramework.Options;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Kyoo.Models.Watch;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
@ -60,42 +64,51 @@ namespace Kyoo
|
|||||||
public DbSet<Episode> Episodes { get; set; }
|
public DbSet<Episode> Episodes { get; set; }
|
||||||
public DbSet<Track> Tracks { get; set; }
|
public DbSet<Track> Tracks { get; set; }
|
||||||
public DbSet<Genre> Genres { get; set; }
|
public DbSet<Genre> Genres { get; set; }
|
||||||
public DbSet<People> Peoples { get; set; }
|
public DbSet<People> People { get; set; }
|
||||||
public DbSet<Studio> Studios { get; set; }
|
public DbSet<Studio> Studios { get; set; }
|
||||||
public DbSet<ProviderID> Providers { get; set; }
|
public DbSet<ProviderID> Providers { get; set; }
|
||||||
public DbSet<MetadataID> MetadataIds { get; set; }
|
public DbSet<MetadataID> MetadataIds { get; set; }
|
||||||
|
|
||||||
public DbSet<LibraryLink> LibraryLinks { get; set; }
|
public DbSet<PeopleLink> PeopleRoles { get; set; }
|
||||||
public DbSet<CollectionLink> CollectionLinks { get; set; }
|
|
||||||
public DbSet<PeopleLink> PeopleLinks { get; set; }
|
|
||||||
|
|
||||||
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
|
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
|
||||||
|
public DbSet<LibraryLink> LibraryLinks { get; set; }
|
||||||
|
public DbSet<CollectionLink> CollectionLinks { get; set; }
|
||||||
public DbSet<GenreLink> GenreLinks { get; set; }
|
public DbSet<GenreLink> GenreLinks { get; set; }
|
||||||
public DbSet<ProviderLink> ProviderLinks { get; set; }
|
public DbSet<ProviderLink> ProviderLinks { get; set; }
|
||||||
|
|
||||||
|
|
||||||
private readonly ValueConverter<IEnumerable<string>, string> _stringArrayConverter =
|
|
||||||
new ValueConverter<IEnumerable<string>, string>(
|
|
||||||
arr => string.Join("|", arr),
|
|
||||||
str => str.Split("|", StringSplitOptions.None));
|
|
||||||
|
|
||||||
|
public DatabaseContext()
|
||||||
|
{
|
||||||
|
NpgsqlConnection.GlobalTypeMapper.MapEnum<Status>();
|
||||||
|
NpgsqlConnection.GlobalTypeMapper.MapEnum<ItemType>();
|
||||||
|
NpgsqlConnection.GlobalTypeMapper.MapEnum<StreamType>();
|
||||||
|
}
|
||||||
|
|
||||||
private readonly ValueComparer<IEnumerable<string>> _stringArrayComparer =
|
private readonly ValueComparer<IEnumerable<string>> _stringArrayComparer =
|
||||||
new ValueComparer<IEnumerable<string>>(
|
new ValueComparer<IEnumerable<string>>(
|
||||||
(l1, l2) => l1.SequenceEqual(l2),
|
(l1, l2) => l1.SequenceEqual(l2),
|
||||||
arr => arr.Aggregate(0, (i, s) => s.GetHashCode()));
|
arr => arr.Aggregate(0, (i, s) => s.GetHashCode()));
|
||||||
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<Library>().Property(e => e.Paths)
|
modelBuilder.HasPostgresEnum<Status>();
|
||||||
.HasConversion(_stringArrayConverter).Metadata
|
modelBuilder.HasPostgresEnum<ItemType>();
|
||||||
.SetValueComparer(_stringArrayComparer);
|
modelBuilder.HasPostgresEnum<StreamType>();
|
||||||
modelBuilder.Entity<Show>().Property(e => e.Aliases)
|
|
||||||
.HasConversion(_stringArrayConverter).Metadata
|
|
||||||
.SetValueComparer(_stringArrayComparer);
|
|
||||||
|
|
||||||
|
modelBuilder.Entity<Library>()
|
||||||
|
.Property(x => x.Paths)
|
||||||
|
.HasColumnType("text[]")
|
||||||
|
.Metadata.SetValueComparer(_stringArrayComparer);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Show>()
|
||||||
|
.Property(x => x.Aliases)
|
||||||
|
.HasColumnType("text[]")
|
||||||
|
.Metadata.SetValueComparer(_stringArrayComparer);
|
||||||
|
|
||||||
|
|
||||||
modelBuilder.Entity<Track>()
|
modelBuilder.Entity<Track>()
|
||||||
.Property(t => t.IsDefault)
|
.Property(t => t.IsDefault)
|
||||||
.ValueGeneratedNever();
|
.ValueGeneratedNever();
|
||||||
@ -124,6 +137,7 @@ namespace Kyoo
|
|||||||
modelBuilder.Entity<PeopleLink>()
|
modelBuilder.Entity<PeopleLink>()
|
||||||
.Ignore(x => x.Slug)
|
.Ignore(x => x.Slug)
|
||||||
.Ignore(x => x.Name)
|
.Ignore(x => x.Name)
|
||||||
|
.Ignore(x => x.Poster)
|
||||||
.Ignore(x => x.ExternalIDs);
|
.Ignore(x => x.ExternalIDs);
|
||||||
|
|
||||||
modelBuilder.Entity<Genre>()
|
modelBuilder.Entity<Genre>()
|
||||||
@ -167,7 +181,7 @@ namespace Kyoo
|
|||||||
.HasIndex(x => x.Slug)
|
.HasIndex(x => x.Slug)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
modelBuilder.Entity<ProviderID>()
|
modelBuilder.Entity<ProviderID>()
|
||||||
.HasIndex(x => x.Name)
|
.HasIndex(x => x.Slug)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
modelBuilder.Entity<Season>()
|
modelBuilder.Entity<Season>()
|
||||||
.HasIndex(x => new {x.ShowID, x.SeasonNumber})
|
.HasIndex(x => new {x.ShowID, x.SeasonNumber})
|
||||||
@ -175,8 +189,127 @@ namespace Kyoo
|
|||||||
modelBuilder.Entity<Episode>()
|
modelBuilder.Entity<Episode>()
|
||||||
.HasIndex(x => new {x.ShowID, x.SeasonNumber, x.EpisodeNumber, x.AbsoluteNumber})
|
.HasIndex(x => new {x.ShowID, x.SeasonNumber, x.EpisodeNumber, x.AbsoluteNumber})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
modelBuilder.Entity<LibraryLink>()
|
||||||
|
.HasIndex(x => new {x.LibraryID, x.ShowID})
|
||||||
|
.IsUnique();
|
||||||
|
modelBuilder.Entity<LibraryLink>()
|
||||||
|
.HasIndex(x => new {x.LibraryID, x.CollectionID})
|
||||||
|
.IsUnique();
|
||||||
|
modelBuilder.Entity<CollectionLink>()
|
||||||
|
.HasIndex(x => new {x.CollectionID, x.ShowID})
|
||||||
|
.IsUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int SaveChanges()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return base.SaveChanges();
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SaveChanges(string duplicateMessage)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return base.SaveChanges();
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException(duplicateMessage);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess,
|
||||||
|
CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await base.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveChangesAsync(string duplicateMessage,
|
||||||
|
CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await base.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
DiscardChanges();
|
||||||
|
if (IsDuplicateException(ex))
|
||||||
|
throw new DuplicatedItemException(duplicateMessage);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveIfNoDuplicates(CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (DuplicatedItemException)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDuplicateException(DbUpdateException ex)
|
||||||
|
{
|
||||||
|
return ex.InnerException is PostgresException inner
|
||||||
|
&& inner.SqlState == PostgresErrorCodes.UniqueViolation;
|
||||||
|
}
|
||||||
|
|
||||||
public void DiscardChanges()
|
public void DiscardChanges()
|
||||||
{
|
{
|
||||||
foreach (EntityEntry entry in ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged
|
foreach (EntityEntry entry in ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged
|
||||||
@ -186,13 +319,4 @@ namespace Kyoo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static class DbSetExtension
|
|
||||||
{
|
|
||||||
public static EntityEntry<T> AddIfNotExist<T>(this DbSet<T> db, T entity, Func<T, bool> predicate) where T : class
|
|
||||||
{
|
|
||||||
bool exists = db.Any(predicate);
|
|
||||||
return exists ? null : db.Add(entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Kyoo;
|
using Kyoo;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -10,13 +11,16 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace Kyoo.Models.DatabaseMigrations.Internal
|
namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||||
{
|
{
|
||||||
[DbContext(typeof(DatabaseContext))]
|
[DbContext(typeof(DatabaseContext))]
|
||||||
[Migration("20200623233713_Initial")]
|
[Migration("20200804172021_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection")
|
||||||
|
.HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
|
||||||
|
.HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
.HasAnnotation("ProductVersion", "3.1.3")
|
.HasAnnotation("ProductVersion", "3.1.3")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
@ -28,9 +32,6 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("ImgPrimary")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
@ -66,10 +67,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasKey("ID");
|
b.HasKey("ID");
|
||||||
|
|
||||||
b.HasIndex("CollectionID");
|
|
||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
|
b.HasIndex("CollectionID", "ShowID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("CollectionLinks");
|
b.ToTable("CollectionLinks");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -169,8 +171,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Paths")
|
b.Property<IEnumerable<string>>("Paths")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text[]");
|
||||||
|
|
||||||
b.Property<string>("Slug")
|
b.Property<string>("Slug")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@ -203,10 +205,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasIndex("CollectionID");
|
b.HasIndex("CollectionID");
|
||||||
|
|
||||||
b.HasIndex("LibraryID");
|
|
||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
|
b.HasIndex("LibraryID", "CollectionID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("LibraryID", "ShowID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("LibraryLinks");
|
b.ToTable("LibraryLinks");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -260,10 +266,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("ImgPrimary")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Poster")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Slug")
|
b.Property<string>("Slug")
|
||||||
@ -274,7 +280,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.HasIndex("Slug")
|
b.HasIndex("Slug")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Peoples");
|
b.ToTable("People");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
||||||
@ -302,7 +308,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
b.ToTable("PeopleLinks");
|
b.ToTable("PeopleRoles");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
||||||
@ -318,9 +324,12 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("ID");
|
b.HasKey("ID");
|
||||||
|
|
||||||
b.HasIndex("Name")
|
b.HasIndex("Slug")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Providers");
|
b.ToTable("Providers");
|
||||||
@ -388,8 +397,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("Aliases")
|
b.Property<IEnumerable<string>>("Aliases")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text[]");
|
||||||
|
|
||||||
b.Property<string>("Backdrop")
|
b.Property<string>("Backdrop")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
@ -8,6 +8,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
{
|
{
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.AlterDatabase()
|
||||||
|
.Annotation("Npgsql:Enum:item_type", "show,movie,collection")
|
||||||
|
.Annotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
|
||||||
|
.Annotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle");
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Collections",
|
name: "Collections",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@ -17,8 +22,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
Slug = table.Column<string>(nullable: true),
|
Slug = table.Column<string>(nullable: true),
|
||||||
Name = table.Column<string>(nullable: true),
|
Name = table.Column<string>(nullable: true),
|
||||||
Poster = table.Column<string>(nullable: true),
|
Poster = table.Column<string>(nullable: true),
|
||||||
Overview = table.Column<string>(nullable: true),
|
Overview = table.Column<string>(nullable: true)
|
||||||
ImgPrimary = table.Column<string>(nullable: true)
|
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@ -47,7 +51,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Slug = table.Column<string>(nullable: true),
|
Slug = table.Column<string>(nullable: true),
|
||||||
Name = table.Column<string>(nullable: true),
|
Name = table.Column<string>(nullable: true),
|
||||||
Paths = table.Column<string>(nullable: true)
|
Paths = table.Column<string[]>(type: "text[]", nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@ -55,18 +59,18 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Peoples",
|
name: "People",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
ID = table.Column<int>(nullable: false)
|
ID = table.Column<int>(nullable: false)
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Slug = table.Column<string>(nullable: true),
|
Slug = table.Column<string>(nullable: true),
|
||||||
Name = table.Column<string>(nullable: true),
|
Name = table.Column<string>(nullable: true),
|
||||||
ImgPrimary = table.Column<string>(nullable: true)
|
Poster = table.Column<string>(nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_Peoples", x => x.ID);
|
table.PrimaryKey("PK_People", x => x.ID);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
@ -75,6 +79,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
{
|
{
|
||||||
ID = table.Column<int>(nullable: false)
|
ID = table.Column<int>(nullable: false)
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Slug = table.Column<string>(nullable: true),
|
||||||
Name = table.Column<string>(nullable: true),
|
Name = table.Column<string>(nullable: true),
|
||||||
Logo = table.Column<string>(nullable: true)
|
Logo = table.Column<string>(nullable: true)
|
||||||
},
|
},
|
||||||
@ -131,7 +136,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Slug = table.Column<string>(nullable: true),
|
Slug = table.Column<string>(nullable: true),
|
||||||
Title = table.Column<string>(nullable: true),
|
Title = table.Column<string>(nullable: true),
|
||||||
Aliases = table.Column<string>(nullable: true),
|
Aliases = table.Column<string[]>(type: "text[]", nullable: true),
|
||||||
Path = table.Column<string>(nullable: true),
|
Path = table.Column<string>(nullable: true),
|
||||||
Overview = table.Column<string>(nullable: true),
|
Overview = table.Column<string>(nullable: true),
|
||||||
Status = table.Column<int>(nullable: true),
|
Status = table.Column<int>(nullable: true),
|
||||||
@ -239,7 +244,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "PeopleLinks",
|
name: "PeopleRoles",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
ID = table.Column<int>(nullable: false)
|
ID = table.Column<int>(nullable: false)
|
||||||
@ -251,15 +256,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_PeopleLinks", x => x.ID);
|
table.PrimaryKey("PK_PeopleRoles", x => x.ID);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_PeopleLinks_Peoples_PeopleID",
|
name: "FK_PeopleRoles_People_PeopleID",
|
||||||
column: x => x.PeopleID,
|
column: x => x.PeopleID,
|
||||||
principalTable: "Peoples",
|
principalTable: "People",
|
||||||
principalColumn: "ID",
|
principalColumn: "ID",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_PeopleLinks_Shows_ShowID",
|
name: "FK_PeopleRoles_Shows_ShowID",
|
||||||
column: x => x.ShowID,
|
column: x => x.ShowID,
|
||||||
principalTable: "Shows",
|
principalTable: "Shows",
|
||||||
principalColumn: "ID",
|
principalColumn: "ID",
|
||||||
@ -349,9 +354,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
principalColumn: "ID",
|
principalColumn: "ID",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_MetadataIds_Peoples_PeopleID",
|
name: "FK_MetadataIds_People_PeopleID",
|
||||||
column: x => x.PeopleID,
|
column: x => x.PeopleID,
|
||||||
principalTable: "Peoples",
|
principalTable: "People",
|
||||||
principalColumn: "ID",
|
principalColumn: "ID",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
@ -401,16 +406,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_CollectionLinks_CollectionID",
|
|
||||||
table: "CollectionLinks",
|
|
||||||
column: "CollectionID");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_CollectionLinks_ShowID",
|
name: "IX_CollectionLinks_ShowID",
|
||||||
table: "CollectionLinks",
|
table: "CollectionLinks",
|
||||||
column: "ShowID");
|
column: "ShowID");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CollectionLinks_CollectionID_ShowID",
|
||||||
|
table: "CollectionLinks",
|
||||||
|
columns: new[] { "CollectionID", "ShowID" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_Collections_Slug",
|
name: "IX_Collections_Slug",
|
||||||
table: "Collections",
|
table: "Collections",
|
||||||
@ -450,16 +456,23 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
table: "LibraryLinks",
|
table: "LibraryLinks",
|
||||||
column: "CollectionID");
|
column: "CollectionID");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_LibraryLinks_LibraryID",
|
|
||||||
table: "LibraryLinks",
|
|
||||||
column: "LibraryID");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_LibraryLinks_ShowID",
|
name: "IX_LibraryLinks_ShowID",
|
||||||
table: "LibraryLinks",
|
table: "LibraryLinks",
|
||||||
column: "ShowID");
|
column: "ShowID");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_LibraryLinks_LibraryID_CollectionID",
|
||||||
|
table: "LibraryLinks",
|
||||||
|
columns: new[] { "LibraryID", "CollectionID" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_LibraryLinks_LibraryID_ShowID",
|
||||||
|
table: "LibraryLinks",
|
||||||
|
columns: new[] { "LibraryID", "ShowID" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_MetadataIds_EpisodeID",
|
name: "IX_MetadataIds_EpisodeID",
|
||||||
table: "MetadataIds",
|
table: "MetadataIds",
|
||||||
@ -486,21 +499,21 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
column: "ShowID");
|
column: "ShowID");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_PeopleLinks_PeopleID",
|
name: "IX_People_Slug",
|
||||||
table: "PeopleLinks",
|
table: "People",
|
||||||
|
column: "Slug",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PeopleRoles_PeopleID",
|
||||||
|
table: "PeopleRoles",
|
||||||
column: "PeopleID");
|
column: "PeopleID");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_PeopleLinks_ShowID",
|
name: "IX_PeopleRoles_ShowID",
|
||||||
table: "PeopleLinks",
|
table: "PeopleRoles",
|
||||||
column: "ShowID");
|
column: "ShowID");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Peoples_Slug",
|
|
||||||
table: "Peoples",
|
|
||||||
column: "Slug",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_ProviderLinks_LibraryID",
|
name: "IX_ProviderLinks_LibraryID",
|
||||||
table: "ProviderLinks",
|
table: "ProviderLinks",
|
||||||
@ -512,9 +525,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
column: "ProviderID");
|
column: "ProviderID");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_Providers_Name",
|
name: "IX_Providers_Slug",
|
||||||
table: "Providers",
|
table: "Providers",
|
||||||
column: "Name",
|
column: "Slug",
|
||||||
unique: true);
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
@ -561,7 +574,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
name: "MetadataIds");
|
name: "MetadataIds");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "PeopleLinks");
|
name: "PeopleRoles");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "ProviderLinks");
|
name: "ProviderLinks");
|
||||||
@ -576,7 +589,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
name: "Collections");
|
name: "Collections");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Peoples");
|
name: "People");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Libraries");
|
name: "Libraries");
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Kyoo;
|
using Kyoo;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -15,6 +16,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection")
|
||||||
|
.HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown")
|
||||||
|
.HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
.HasAnnotation("ProductVersion", "3.1.3")
|
.HasAnnotation("ProductVersion", "3.1.3")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
@ -26,9 +30,6 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("ImgPrimary")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
@ -64,10 +65,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasKey("ID");
|
b.HasKey("ID");
|
||||||
|
|
||||||
b.HasIndex("CollectionID");
|
|
||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
|
b.HasIndex("CollectionID", "ShowID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("CollectionLinks");
|
b.ToTable("CollectionLinks");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,8 +169,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Paths")
|
b.Property<IEnumerable<string>>("Paths")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text[]");
|
||||||
|
|
||||||
b.Property<string>("Slug")
|
b.Property<string>("Slug")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@ -201,10 +203,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasIndex("CollectionID");
|
b.HasIndex("CollectionID");
|
||||||
|
|
||||||
b.HasIndex("LibraryID");
|
|
||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
|
b.HasIndex("LibraryID", "CollectionID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("LibraryID", "ShowID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("LibraryLinks");
|
b.ToTable("LibraryLinks");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -258,10 +264,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("ImgPrimary")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Poster")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Slug")
|
b.Property<string>("Slug")
|
||||||
@ -272,7 +278,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.HasIndex("Slug")
|
b.HasIndex("Slug")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Peoples");
|
b.ToTable("People");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
||||||
@ -300,7 +306,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
|
|
||||||
b.HasIndex("ShowID");
|
b.HasIndex("ShowID");
|
||||||
|
|
||||||
b.ToTable("PeopleLinks");
|
b.ToTable("PeopleRoles");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
||||||
@ -316,9 +322,12 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("ID");
|
b.HasKey("ID");
|
||||||
|
|
||||||
b.HasIndex("Name")
|
b.HasIndex("Slug")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Providers");
|
b.ToTable("Providers");
|
||||||
@ -386,8 +395,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
b.Property<string>("Aliases")
|
b.Property<IEnumerable<string>>("Aliases")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text[]");
|
||||||
|
|
||||||
b.Property<string>("Backdrop")
|
b.Property<string>("Backdrop")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
@ -39,7 +39,7 @@ namespace Kyoo
|
|||||||
{
|
{
|
||||||
configuration.RootPath = "wwwroot";
|
configuration.RootPath = "wwwroot";
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddControllers().AddNewtonsoftJson();
|
services.AddControllers().AddNewtonsoftJson();
|
||||||
services.AddHttpClient();
|
services.AddHttpClient();
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ namespace Kyoo
|
|||||||
{
|
{
|
||||||
options.UseLazyLoadingProxies()
|
options.UseLazyLoadingProxies()
|
||||||
.UseNpgsql(_configuration.GetConnectionString("Database"));
|
.UseNpgsql(_configuration.GetConnectionString("Database"));
|
||||||
// .EnableSensitiveDataLogging()
|
// .EnableSensitiveDataLogging()
|
||||||
// .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
|
// .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
|
||||||
}, ServiceLifetime.Transient);
|
}, ServiceLifetime.Transient);
|
||||||
|
|
||||||
services.AddDbContext<IdentityDatabase>(options =>
|
services.AddDbContext<IdentityDatabase>(options =>
|
||||||
@ -133,16 +133,17 @@ namespace Kyoo
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
services.AddTransient<ILibraryRepository, LibraryRepository>();
|
services.AddScoped<ILibraryRepository, LibraryRepository>();
|
||||||
services.AddTransient<ICollectionRepository, CollectionRepository>();
|
services.AddScoped<ILibraryItemRepository, LibraryItemRepository>();
|
||||||
services.AddTransient<IShowRepository, ShowRepository>();
|
services.AddScoped<ICollectionRepository, CollectionRepository>();
|
||||||
services.AddTransient<ISeasonRepository, SeasonRepository>();
|
services.AddScoped<IShowRepository, ShowRepository>();
|
||||||
services.AddTransient<IEpisodeRepository, EpisodeRepository>();
|
services.AddScoped<ISeasonRepository, SeasonRepository>();
|
||||||
services.AddTransient<ITrackRepository, TrackRepository>();
|
services.AddScoped<IEpisodeRepository, EpisodeRepository>();
|
||||||
services.AddTransient<IPeopleRepository, PeopleRepository>();
|
services.AddScoped<ITrackRepository, TrackRepository>();
|
||||||
services.AddTransient<IStudioRepository, StudioRepository>();
|
services.AddScoped<IPeopleRepository, PeopleRepository>();
|
||||||
services.AddTransient<IGenreRepository, GenreRepository>();
|
services.AddScoped<IStudioRepository, StudioRepository>();
|
||||||
services.AddTransient<IProviderRepository, ProviderRepository>();
|
services.AddScoped<IGenreRepository, GenreRepository>();
|
||||||
|
services.AddScoped<IProviderRepository, ProviderRepository>();
|
||||||
|
|
||||||
services.AddScoped<ILibraryManager, LibraryManager>();
|
services.AddScoped<ILibraryManager, LibraryManager>();
|
||||||
services.AddSingleton<ITranscoder, Transcoder>();
|
services.AddSingleton<ITranscoder, Transcoder>();
|
||||||
|
@ -63,7 +63,7 @@ namespace Kyoo.Controllers
|
|||||||
if (!Directory.Exists(show.Path))
|
if (!Directory.Exists(show.Path))
|
||||||
await libraryManager.DeleteShow(show);
|
await libraryManager.DeleteShow(show);
|
||||||
|
|
||||||
ICollection<Episode> episodes = await libraryManager.GetEpisodes();
|
ICollection<Episode> episodes = await libraryManager.GetEpisodesFromShow();
|
||||||
ICollection<Library> libraries = argument == null
|
ICollection<Library> libraries = argument == null
|
||||||
? await libraryManager.GetLibraries()
|
? await libraryManager.GetLibraries()
|
||||||
: new [] { await libraryManager.GetLibrary(argument)};
|
: new [] { await libraryManager.GetLibrary(argument)};
|
||||||
@ -224,7 +224,8 @@ namespace Kyoo.Controllers
|
|||||||
bool isMovie,
|
bool isMovie,
|
||||||
Library library)
|
Library library)
|
||||||
{
|
{
|
||||||
Show show = await libraryManager.GetShowByPath(showPath);
|
Show show = (await libraryManager.GetShows(x => x.Path == showPath, limit: 1))
|
||||||
|
.FirstOrDefault();
|
||||||
if (show != null)
|
if (show != null)
|
||||||
return show;
|
return show;
|
||||||
show = await _metadataProvider.SearchShow(showTitle, isMovie, library);
|
show = await _metadataProvider.SearchShow(showTitle, isMovie, library);
|
||||||
@ -308,7 +309,9 @@ namespace Kyoo.Controllers
|
|||||||
private async Task<IEnumerable<Track>> GetTracks(Episode episode)
|
private async Task<IEnumerable<Track>> GetTracks(Episode episode)
|
||||||
{
|
{
|
||||||
IEnumerable<Track> tracks = await _transcoder.GetTrackInfo(episode.Path);
|
IEnumerable<Track> tracks = await _transcoder.GetTrackInfo(episode.Path);
|
||||||
List<Track> epTracks = tracks.Where(x => x.Type != StreamType.Subtitle).Concat(GetExtractedSubtitles(episode)).ToList();
|
List<Track> epTracks = tracks.Where(x => x.Type != StreamType.Subtitle)
|
||||||
|
.Concat(GetExtractedSubtitles(episode))
|
||||||
|
.ToList();
|
||||||
if (epTracks.Count(x => !x.IsExternal) < tracks.Count())
|
if (epTracks.Count(x => !x.IsExternal) < tracks.Count())
|
||||||
epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path));
|
epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path));
|
||||||
episode.Tracks = epTracks;
|
episode.Tracks = epTracks;
|
||||||
@ -328,26 +331,58 @@ namespace Kyoo.Controllers
|
|||||||
foreach (string sub in Directory.EnumerateFiles(path, "", SearchOption.AllDirectories))
|
foreach (string sub in Directory.EnumerateFiles(path, "", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
string episodeLink = Path.GetFileNameWithoutExtension(episode.Path);
|
string episodeLink = Path.GetFileNameWithoutExtension(episode.Path);
|
||||||
|
string subName = Path.GetFileName(sub);
|
||||||
if (!sub.Contains(episodeLink!))
|
|
||||||
|
if (episodeLink == null
|
||||||
|
|| subName?.Contains(episodeLink) == false
|
||||||
|
|| subName.Length < episodeLink.Length + 5)
|
||||||
continue;
|
continue;
|
||||||
string language = sub.Substring(Path.GetDirectoryName(sub).Length + episodeLink.Length + 2, 3);
|
string language = subName.Substring(episodeLink.Length + 2, 3);
|
||||||
bool isDefault = sub.Contains("default");
|
bool isDefault = sub.Contains("default");
|
||||||
bool isForced = sub.Contains("forced");
|
bool isForced = sub.Contains("forced");
|
||||||
Track track = new Track(StreamType.Subtitle, null, language, isDefault, isForced, null, false, sub) { EpisodeID = episode.ID };
|
Track track = new Track(StreamType.Subtitle, null, language, isDefault, isForced, null, false, sub)
|
||||||
|
{
|
||||||
|
EpisodeID = episode.ID,
|
||||||
|
Codec = Path.GetExtension(sub) switch
|
||||||
|
{
|
||||||
|
".ass" => "ass",
|
||||||
|
".srt" => "subrip",
|
||||||
|
_ => null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (Path.GetExtension(sub) == ".ass")
|
|
||||||
track.Codec = "ass";
|
|
||||||
else if (Path.GetExtension(sub) == ".srt")
|
|
||||||
track.Codec = "subrip";
|
|
||||||
else
|
|
||||||
track.Codec = null;
|
|
||||||
tracks.Add(track);
|
tracks.Add(track);
|
||||||
}
|
}
|
||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] VideoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" };
|
private static readonly string[] VideoExtensions =
|
||||||
|
{
|
||||||
|
".webm",
|
||||||
|
".mkv",
|
||||||
|
".flv",
|
||||||
|
".vob",
|
||||||
|
".ogg",
|
||||||
|
".ogv",
|
||||||
|
".avi",
|
||||||
|
".mts",
|
||||||
|
".m2ts",
|
||||||
|
".ts",
|
||||||
|
".mov",
|
||||||
|
".qt",
|
||||||
|
".asf",
|
||||||
|
".mp4",
|
||||||
|
".m4p",
|
||||||
|
".m4v",
|
||||||
|
".mpg",
|
||||||
|
".mp2",
|
||||||
|
".mpeg",
|
||||||
|
".mpe",
|
||||||
|
".mpv",
|
||||||
|
".m2v",
|
||||||
|
".3gp",
|
||||||
|
".3g2"
|
||||||
|
};
|
||||||
|
|
||||||
private static bool IsVideo(string filePath)
|
private static bool IsVideo(string filePath)
|
||||||
{
|
{
|
||||||
|
@ -17,15 +17,13 @@ namespace Kyoo.Tasks
|
|||||||
public bool RunOnStartup => true;
|
public bool RunOnStartup => true;
|
||||||
public int Priority => 1000;
|
public int Priority => 1000;
|
||||||
|
|
||||||
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
public async Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null)
|
||||||
{
|
{
|
||||||
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
using IServiceScope serviceScope = serviceProvider.CreateScope();
|
||||||
DatabaseContext database = serviceScope.ServiceProvider.GetService<DatabaseContext>();
|
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||||
IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
|
||||||
foreach (IMetadataProvider provider in pluginManager.GetPlugins<IMetadataProvider>())
|
foreach (IMetadataProvider provider in pluginManager.GetPlugins<IMetadataProvider>())
|
||||||
database.Providers.AddIfNotExist(provider.Provider, x => x.Name == provider.Provider.Name);
|
await providers.CreateIfNotExists(provider.Provider);
|
||||||
database.SaveChanges();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
public Task<IEnumerable<string>> GetPossibleParameters()
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class CollectionController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public CollectionController(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{collectionSlug}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public async Task<ActionResult<Collection>> GetShows(string collectionSlug)
|
|
||||||
{
|
|
||||||
Collection collection = await _libraryManager.GetCollection(collectionSlug);
|
|
||||||
|
|
||||||
if (collection == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
155
Kyoo/Views/API/CollectionApi.cs
Normal file
155
Kyoo/Views/API/CollectionApi.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/collection")]
|
||||||
|
[Route("api/collections")]
|
||||||
|
[ApiController]
|
||||||
|
public class CollectionApi : CrudApi<Collection>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public CollectionApi(ILibraryManager libraryManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.CollectionRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/show")]
|
||||||
|
[HttpGet("{id:int}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShowsFromCollection(id,
|
||||||
|
ApiHelper.ParseWhere<Show>(where),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/show")]
|
||||||
|
[HttpGet("{slug}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShowsFromCollection(slug,
|
||||||
|
ApiHelper.ParseWhere<Show>(where),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/library")]
|
||||||
|
[HttpGet("{id:int}/libraries")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Library>>> GetLibraries(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Library> ressources = await _libraryManager.GetLibrariesFromCollection(id,
|
||||||
|
ApiHelper.ParseWhere<Library>(where),
|
||||||
|
new Sort<Library>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/library")]
|
||||||
|
[HttpGet("{slug}/libraries")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Library>>> GetLibraries(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Library> ressources = await _libraryManager.GetLibrariesFromCollection(slug,
|
||||||
|
ApiHelper.ParseWhere<Library>(where),
|
||||||
|
new Sort<Library>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
Kyoo/Views/API/EpisodeApi.cs
Normal file
173
Kyoo/Views/API/EpisodeApi.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/episode")]
|
||||||
|
[Route("api/episodes")]
|
||||||
|
[ApiController]
|
||||||
|
public class EpisodeApi : CrudApi<Episode>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public EpisodeApi(ILibraryManager libraryManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.EpisodeRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{episodeID:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(int episodeID)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShowFromEpisode(episodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(string showSlug)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShow(showSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(int showID, int _)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShow(showID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{episodeID:int}/season")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Season>> GetSeason(int episodeID)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetSeasonFromEpisode(episodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/season")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Season>> GetSeason(string showSlug, int seasonNuber)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetSeason(showSlug, seasonNuber);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/season")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Season>> GetSeason(int showID, int seasonNumber)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetSeason(showID, seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{episodeID:int}/track")]
|
||||||
|
[HttpGet("{episodeID:int}/tracks")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Track>>> GetEpisode(int episodeID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Track> ressources = await _libraryManager.GetTracksFromEpisode(episodeID,
|
||||||
|
ApiHelper.ParseWhere<Track>(where),
|
||||||
|
new Sort<Track>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}-s{seasonNumber:int}e{episodeNumber:int}/track")]
|
||||||
|
[HttpGet("{showID:int}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Track>>> GetEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Track> ressources = await _libraryManager.GetTracksFromEpisode(showID,
|
||||||
|
seasonNumber,
|
||||||
|
episodeNumber,
|
||||||
|
ApiHelper.ParseWhere<Track>(where),
|
||||||
|
new Sort<Track>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/track")]
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Track>>> GetEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
int episodeNumber,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Track> ressources = await _libraryManager.GetTracksFromEpisode(showSlug,
|
||||||
|
seasonNumber,
|
||||||
|
episodeNumber,
|
||||||
|
ApiHelper.ParseWhere<Track>(where),
|
||||||
|
new Sort<Track>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class EpisodesController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public EpisodesController(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{showSlug}/season/{seasonNumber}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public async Task<ActionResult<IEnumerable<Episode>>> GetEpisodesForSeason(string showSlug, int seasonNumber)
|
|
||||||
{
|
|
||||||
IEnumerable<Episode> episodes = await _libraryManager.GetEpisodes(showSlug, seasonNumber);
|
|
||||||
|
|
||||||
if(episodes == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return episodes.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
[JsonDetailed]
|
|
||||||
public async Task<ActionResult<Episode>> GetEpisode(string showSlug, int seasonNumber, int episodeNumber)
|
|
||||||
{
|
|
||||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
|
||||||
|
|
||||||
if (episode == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return episode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
92
Kyoo/Views/API/GenreApi.cs
Normal file
92
Kyoo/Views/API/GenreApi.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/genre")]
|
||||||
|
[Route("api/genres")]
|
||||||
|
[ApiController]
|
||||||
|
public class GenreApi : CrudApi<Genre>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public GenreApi(ILibraryManager libraryManager, IConfiguration config)
|
||||||
|
: base(libraryManager.GenreRepository, config)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/show")]
|
||||||
|
[HttpGet("{id:int}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShows(
|
||||||
|
ApiHelper.ParseWhere<Show>(where, x => x.Genres.Any(y => y.ID == id)),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/show")]
|
||||||
|
[HttpGet("{slug}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShows(
|
||||||
|
ApiHelper.ParseWhere<Show>(where, x => x.Genres.Any(y => y.Slug == slug)),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.API
|
|
||||||
{
|
|
||||||
[Route("api/genres")]
|
|
||||||
[Route("api/genre")]
|
|
||||||
[ApiController]
|
|
||||||
public class GenresAPI : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public GenresAPI(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ActionResult<IEnumerable<Genre>>> Index()
|
|
||||||
{
|
|
||||||
return (await _libraryManager.GetGenres()).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/libraries")]
|
|
||||||
[Route("api/library")]
|
|
||||||
[ApiController]
|
|
||||||
public class LibrariesAPI : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
private readonly ITaskManager _taskManager;
|
|
||||||
|
|
||||||
public LibrariesAPI(ILibraryManager libraryManager, ITaskManager taskManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
_taskManager = taskManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<IEnumerable<Library>> GetLibraries()
|
|
||||||
{
|
|
||||||
return await _libraryManager.GetLibraries();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("/api/library/create")]
|
|
||||||
[HttpPost]
|
|
||||||
[Authorize(Policy="Admin")]
|
|
||||||
public async Task<IActionResult> CreateLibrary([FromBody] Library library)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(library);
|
|
||||||
if (string.IsNullOrEmpty(library.Slug))
|
|
||||||
return BadRequest(new {error = "The library's slug must be set and not empty"});
|
|
||||||
if (string.IsNullOrEmpty(library.Name))
|
|
||||||
return BadRequest(new {error = "The library's name must be set and not empty"});
|
|
||||||
if (library.Paths == null || !library.Paths.Any())
|
|
||||||
return BadRequest(new {error = "The library should have a least one path."});
|
|
||||||
if (await _libraryManager.GetLibrary(library.Slug) != null)
|
|
||||||
return BadRequest(new {error = "Duplicated library slug"});
|
|
||||||
await _libraryManager.RegisterLibrary(library);
|
|
||||||
_taskManager.StartTask("scan", library.Slug);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{librarySlug}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public async Task<ActionResult<IEnumerable<Show>>> GetShows(string librarySlug)
|
|
||||||
{
|
|
||||||
Library library = await _libraryManager.GetLibrary(librarySlug);
|
|
||||||
|
|
||||||
if (library == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return library.Shows.Concat(library.Collections.Select(x => x.AsShow())).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
230
Kyoo/Views/API/LibraryApi.cs
Normal file
230
Kyoo/Views/API/LibraryApi.cs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/library")]
|
||||||
|
[Route("api/libraries")]
|
||||||
|
[ApiController]
|
||||||
|
public class LibraryAPI : CrudApi<Library>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly ITaskManager _taskManager;
|
||||||
|
|
||||||
|
public LibraryAPI(ILibraryManager libraryManager, ITaskManager taskManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.LibraryRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_taskManager = taskManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public override async Task<ActionResult<Library>> Create(Library ressource)
|
||||||
|
{
|
||||||
|
ActionResult<Library> result = await base.Create(ressource);
|
||||||
|
if (result.Value != null)
|
||||||
|
_taskManager.StartTask("scan", result.Value.Slug);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/show")]
|
||||||
|
[HttpGet("{id:int}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShowsFromLibrary(id,
|
||||||
|
ApiHelper.ParseWhere<Show>(where),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/show")]
|
||||||
|
[HttpGet("{slug}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShowsFromLibrary(slug,
|
||||||
|
ApiHelper.ParseWhere<Show>(where),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/collection")]
|
||||||
|
[HttpGet("{id:int}/collections")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Collection>>> GetCollections(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Collection> ressources = await _libraryManager.GetCollectionsFromLibrary(id,
|
||||||
|
ApiHelper.ParseWhere<Collection>(where),
|
||||||
|
new Sort<Collection>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/collection")]
|
||||||
|
[HttpGet("{slug}/collections")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Collection>>> GetCollections(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Collection> ressources = await _libraryManager.GetCollectionsFromLibrary(slug,
|
||||||
|
ApiHelper.ParseWhere<Collection>(where),
|
||||||
|
new Sort<Collection>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/item")]
|
||||||
|
[HttpGet("{id:int}/items")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<LibraryItem>>> GetItems(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<LibraryItem> ressources = await _libraryManager.GetItemsFromLibrary(id,
|
||||||
|
ApiHelper.ParseWhere<LibraryItem>(where),
|
||||||
|
new Sort<LibraryItem>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/item")]
|
||||||
|
[HttpGet("{slug}/items")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<LibraryItem>>> GetItems(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<LibraryItem> ressources = await _libraryManager.GetItemsFromLibrary(slug,
|
||||||
|
ApiHelper.ParseWhere<LibraryItem>(where),
|
||||||
|
new Sort<LibraryItem>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
Kyoo/Views/API/LibraryItemApi.cs
Normal file
63
Kyoo/Views/API/LibraryItemApi.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/item")]
|
||||||
|
[Route("api/items")]
|
||||||
|
[ApiController]
|
||||||
|
public class LibraryItemApi : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILibraryItemRepository _libraryItems;
|
||||||
|
private readonly string _baseURL;
|
||||||
|
|
||||||
|
|
||||||
|
public LibraryItemApi(ILibraryItemRepository libraryItems, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_libraryItems = libraryItems;
|
||||||
|
_baseURL = configuration.GetValue<string>("public_url").TrimEnd('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<LibraryItem>>> GetAll([FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<LibraryItem> ressources = await _libraryItems.GetAll(
|
||||||
|
ApiHelper.ParseWhere<LibraryItem>(where),
|
||||||
|
new Sort<LibraryItem>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return new Page<LibraryItem>(ressources,
|
||||||
|
_baseURL + Request.Path,
|
||||||
|
Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString(), StringComparer.InvariantCultureIgnoreCase),
|
||||||
|
limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class PeopleController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public PeopleController(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{peopleSlug}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public async Task<ActionResult<Collection>> GetPeople(string peopleSlug)
|
|
||||||
{
|
|
||||||
People people = await _libraryManager.GetPeople(peopleSlug);
|
|
||||||
|
|
||||||
if (people == null)
|
|
||||||
return NotFound();
|
|
||||||
return new Collection(people.Slug, people.Name, null, null)
|
|
||||||
{
|
|
||||||
Shows = people.Roles.Select(x => x.Show),
|
|
||||||
Poster = "peopleimg/" + people.Slug
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
93
Kyoo/Views/API/PeopleApi.cs
Normal file
93
Kyoo/Views/API/PeopleApi.cs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/people")]
|
||||||
|
[ApiController]
|
||||||
|
public class PeopleApi : CrudApi<People>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public PeopleApi(ILibraryManager libraryManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.PeopleRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/role")]
|
||||||
|
[HttpGet("{id:int}/roles")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
[JsonDetailed]
|
||||||
|
public async Task<ActionResult<Page<ShowRole>>> GetRoles(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<ShowRole> resources = await _libraryManager.GetRolesFromPeople(id,
|
||||||
|
ApiHelper.ParseWhere<ShowRole>(where),
|
||||||
|
new Sort<ShowRole>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(resources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/role")]
|
||||||
|
[HttpGet("{slug}/roles")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
[JsonDetailed]
|
||||||
|
public async Task<ActionResult<Page<ShowRole>>> GetRoles(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<ShowRole> ressources = await _libraryManager.GetRolesFromPeople(slug,
|
||||||
|
ApiHelper.ParseWhere<ShowRole>(where),
|
||||||
|
new Sort<ShowRole>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.API
|
|
||||||
{
|
|
||||||
[Route("api/provider")]
|
|
||||||
[Route("api/providers")]
|
|
||||||
[ApiController]
|
|
||||||
public class ProviderAPI : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
|
|
||||||
public ProviderAPI(DatabaseContext database)
|
|
||||||
{
|
|
||||||
_database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public ActionResult<IEnumerable<ProviderID>> Index()
|
|
||||||
{
|
|
||||||
return _database.Providers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
24
Kyoo/Views/API/ProviderApi.cs
Normal file
24
Kyoo/Views/API/ProviderApi.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/provider")]
|
||||||
|
[Route("api/providers")]
|
||||||
|
[ApiController]
|
||||||
|
public class ProviderAPI : CrudApi<ProviderID>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public ProviderAPI(ILibraryManager libraryManager, IConfiguration config)
|
||||||
|
: base(libraryManager.ProviderRepository, config)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace Kyoo.Api
|
namespace Kyoo.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/search")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class SearchController : ControllerBase
|
public class SearchApi : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public SearchController(ILibraryManager libraryManager)
|
public SearchApi(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ namespace Kyoo.Api
|
|||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public async Task<ActionResult<SearchResult>> Search(string query)
|
public async Task<ActionResult<SearchResult>> Search(string query)
|
||||||
{
|
{
|
||||||
SearchResult result = new SearchResult
|
return new SearchResult
|
||||||
{
|
{
|
||||||
Query = query,
|
Query = query,
|
||||||
Collections = await _libraryManager.SearchCollections(query),
|
Collections = await _libraryManager.SearchCollections(query),
|
||||||
@ -31,7 +31,6 @@ namespace Kyoo.Api
|
|||||||
Genres = await _libraryManager.SearchGenres(query),
|
Genres = await _libraryManager.SearchGenres(query),
|
||||||
Studios = await _libraryManager.SearchStudios(query)
|
Studios = await _libraryManager.SearchStudios(query)
|
||||||
};
|
};
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
148
Kyoo/Views/API/SeasonApi.cs
Normal file
148
Kyoo/Views/API/SeasonApi.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/season")]
|
||||||
|
[Route("api/seasons")]
|
||||||
|
[ApiController]
|
||||||
|
public class SeasonApi : CrudApi<Season>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public SeasonApi(ILibraryManager libraryManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.SeasonRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{seasonID:int}/episode")]
|
||||||
|
[HttpGet("{seasonID:int}/episodes")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Episode>>> GetEpisode(int seasonID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromSeason(seasonID,
|
||||||
|
ApiHelper.ParseWhere<Episode>(where),
|
||||||
|
new Sort<Episode>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}/episode")]
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}/episodes")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Episode>>> GetEpisode(string showSlug,
|
||||||
|
int seasonNumber,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromSeason(showSlug,
|
||||||
|
seasonNumber,
|
||||||
|
ApiHelper.ParseWhere<Episode>(where),
|
||||||
|
new Sort<Episode>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}-s{seasonNumber:int}/episode")]
|
||||||
|
[HttpGet("{showID:int}-s{seasonNumber:int}/episodes")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Episode>>> GetEpisode(int showID,
|
||||||
|
int seasonNumber,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromSeason(showID,
|
||||||
|
seasonNumber,
|
||||||
|
ApiHelper.ParseWhere<Episode>(where),
|
||||||
|
new Sort<Episode>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{seasonID:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(int seasonID)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShowFromSeason(seasonID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showSlug}-s{seasonNumber:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(string showSlug, int _)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShow(showSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}-s{seasonNumber:int}/show")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Show>> GetShow(int showID, int _)
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetShow(showID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
437
Kyoo/Views/API/ShowApi.cs
Normal file
437
Kyoo/Views/API/ShowApi.cs
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
using System;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/show")]
|
||||||
|
[Route("api/shows")]
|
||||||
|
[ApiController]
|
||||||
|
public class ShowApi : CrudApi<Show>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public ShowApi(ILibraryManager libraryManager, IConfiguration configuration)
|
||||||
|
: base(libraryManager.ShowRepository, configuration)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/season")]
|
||||||
|
[HttpGet("{showID:int}/seasons")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Season>>> GetSeasons(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Season> ressources = await _libraryManager.GetSeasonsFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<Season>(where),
|
||||||
|
new Sort<Season>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/season")]
|
||||||
|
[HttpGet("{slug}/seasons")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Season>>> GetSeasons(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Season> ressources = await _libraryManager.GetSeasonsFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<Season>(where),
|
||||||
|
new Sort<Season>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/episode")]
|
||||||
|
[HttpGet("{showID:int}/episodes")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Episode>>> GetEpisodes(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<Episode>(where),
|
||||||
|
new Sort<Episode>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/episode")]
|
||||||
|
[HttpGet("{slug}/episodes")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Episode>>> GetEpisodes(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 50)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<Episode>(where),
|
||||||
|
new Sort<Episode>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/people")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<PeopleLink>>> GetPeople(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<PeopleLink> ressources = await _libraryManager.GetPeopleFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<PeopleLink>(where),
|
||||||
|
new Sort<PeopleLink>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/people")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<PeopleLink>>> GetPeople(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<PeopleLink> ressources = await _libraryManager.GetPeopleFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<PeopleLink>(where),
|
||||||
|
new Sort<PeopleLink>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/genre")]
|
||||||
|
[HttpGet("{showID:int}/genres")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Genre>>> GetGenres(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Genre> ressources = await _libraryManager.GetGenresFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<Genre>(where),
|
||||||
|
new Sort<Genre>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/genre")]
|
||||||
|
[HttpGet("{slug}/genres")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Genre>>> GetGenre(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Genre> ressources = await _libraryManager.GetGenresFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<Genre>(where),
|
||||||
|
new Sort<Genre>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/studio")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Studio>> GetStudio(int showID)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetStudioFromShow(showID);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/studio")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Studio>> GetStudio(string slug)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _libraryManager.GetStudioFromShow(slug);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/library")]
|
||||||
|
[HttpGet("{showID:int}/libraries")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Library>>> GetLibraries(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Library> ressources = await _libraryManager.GetLibrariesFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<Library>(where),
|
||||||
|
new Sort<Library>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/library")]
|
||||||
|
[HttpGet("{slug}/libraries")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Library>>> GetLibraries(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Library> ressources = await _libraryManager.GetLibrariesFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<Library>(where),
|
||||||
|
new Sort<Library>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{showID:int}/collection")]
|
||||||
|
[HttpGet("{showID:int}/collections")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Collection>>> GetCollections(int showID,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Collection> ressources = await _libraryManager.GetCollectionsFromShow(showID,
|
||||||
|
ApiHelper.ParseWhere<Collection>(where),
|
||||||
|
new Sort<Collection>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/collection")]
|
||||||
|
[HttpGet("{slug}/collections")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Collection>>> GetCollections(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 30)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Collection> ressources = await _libraryManager.GetCollectionsFromShow(slug,
|
||||||
|
ApiHelper.ParseWhere<Collection>(where),
|
||||||
|
new Sort<Collection>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,108 +0,0 @@
|
|||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Kyoo.Api
|
|
||||||
{
|
|
||||||
[Route("api/shows")]
|
|
||||||
[Route("api/show")]
|
|
||||||
[ApiController]
|
|
||||||
public class ShowsAPI : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
private readonly IProviderManager _providerManager;
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
private readonly IThumbnailsManager _thumbnailsManager;
|
|
||||||
private readonly ITaskManager _taskManager;
|
|
||||||
|
|
||||||
public ShowsAPI(ILibraryManager libraryManager,
|
|
||||||
IProviderManager providerManager,
|
|
||||||
DatabaseContext database,
|
|
||||||
IThumbnailsManager thumbnailsManager,
|
|
||||||
ITaskManager taskManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
_providerManager = providerManager;
|
|
||||||
_database = database;
|
|
||||||
_thumbnailsManager = thumbnailsManager;
|
|
||||||
_taskManager = taskManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
public IEnumerable<Show> GetShows()
|
|
||||||
{
|
|
||||||
return _database.LibraryLinks
|
|
||||||
.Include(x => x.Show)
|
|
||||||
.Include(x => x.Collection)
|
|
||||||
.AsEnumerable().Select(x => x.Show ?? x.Collection.AsShow()).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}")]
|
|
||||||
[Authorize(Policy="Read")]
|
|
||||||
[JsonDetailed]
|
|
||||||
public async Task<ActionResult<Show>> GetShow(string slug)
|
|
||||||
{
|
|
||||||
Show show = await _libraryManager.GetShow(slug);
|
|
||||||
|
|
||||||
if (show == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return show;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("edit/{slug}")]
|
|
||||||
[Authorize(Policy="Write")]
|
|
||||||
public async Task<IActionResult> EditShow(string slug, [FromBody] Show show)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(show);
|
|
||||||
|
|
||||||
Show old = _database.Shows.AsNoTracking().FirstOrDefault(x => x.Slug == slug);
|
|
||||||
if (old == null)
|
|
||||||
return NotFound();
|
|
||||||
show.ID = old.ID;
|
|
||||||
show.Slug = slug;
|
|
||||||
show.Path = old.Path;
|
|
||||||
await _libraryManager.EditShow(show, false);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("re-identify/{slug}")]
|
|
||||||
[Authorize(Policy = "Write")]
|
|
||||||
public IActionResult ReIdentityShow(string slug, [FromBody] IEnumerable<MetadataID> externalIDs)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(externalIDs);
|
|
||||||
Show show = _database.Shows.Include(x => x.ExternalIDs).FirstOrDefault(x => x.Slug == slug);
|
|
||||||
if (show == null)
|
|
||||||
return NotFound();
|
|
||||||
_database.SaveChanges();
|
|
||||||
_taskManager.StartTask("re-scan", $"show/{slug}");
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("identify/{name}")]
|
|
||||||
[Authorize(Policy = "Read")]
|
|
||||||
public async Task<IEnumerable<Show>> IdentityShow(string name, [FromQuery] bool isMovie)
|
|
||||||
{
|
|
||||||
return await _providerManager.SearchShows(name, isMovie, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("download-images/{slug}")]
|
|
||||||
[Authorize(Policy = "Write")]
|
|
||||||
public async Task<IActionResult> DownloadImages(string slug)
|
|
||||||
{
|
|
||||||
Show show = await _libraryManager.GetShow(slug);
|
|
||||||
if (show == null)
|
|
||||||
return NotFound();
|
|
||||||
await _thumbnailsManager.Validate(show, true);
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Controllers;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.API
|
|
||||||
{
|
|
||||||
[Route("api/studios")]
|
|
||||||
[Route("api/studio")]
|
|
||||||
[ApiController]
|
|
||||||
public class StudioAPI : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public StudioAPI(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ActionResult<IEnumerable<Studio>>> Index()
|
|
||||||
{
|
|
||||||
return (await _libraryManager.GetStudios()).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
91
Kyoo/Views/API/StudioApi.cs
Normal file
91
Kyoo/Views/API/StudioApi.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.CommonApi;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Kyoo.Api
|
||||||
|
{
|
||||||
|
[Route("api/studio")]
|
||||||
|
[Route("api/studios")]
|
||||||
|
[ApiController]
|
||||||
|
public class StudioAPI : CrudApi<Studio>
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public StudioAPI(ILibraryManager libraryManager, IConfiguration config)
|
||||||
|
: base(libraryManager.StudioRepository, config)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}/show")]
|
||||||
|
[HttpGet("{id:int}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(int id,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShows(
|
||||||
|
ApiHelper.ParseWhere<Show>(where, x => x.StudioID == id),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/show")]
|
||||||
|
[HttpGet("{slug}/shows")]
|
||||||
|
[Authorize(Policy = "Read")]
|
||||||
|
public async Task<ActionResult<Page<Show>>> GetShows(string slug,
|
||||||
|
[FromQuery] string sortBy,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where,
|
||||||
|
[FromQuery] int limit = 20)
|
||||||
|
{
|
||||||
|
where.Remove("sortBy");
|
||||||
|
where.Remove("limit");
|
||||||
|
where.Remove("afterID");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ICollection<Show> ressources = await _libraryManager.GetShows(
|
||||||
|
ApiHelper.ParseWhere<Show>(where, x => x.Studio.Slug == slug),
|
||||||
|
new Sort<Show>(sortBy),
|
||||||
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
|
return Page(ressources, limit);
|
||||||
|
}
|
||||||
|
catch (ItemNotFound)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(new {Error = ex.Message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ namespace Kyoo.Api
|
|||||||
string identifier,
|
string identifier,
|
||||||
string extension)
|
string extension)
|
||||||
{
|
{
|
||||||
string languageTag = identifier.Length == 3 ? identifier.Substring(0, 3) : null;
|
string languageTag = identifier.Length >= 3 ? identifier.Substring(0, 3) : null;
|
||||||
bool forced = identifier.Length > 4 && identifier.Substring(4) == "forced";
|
bool forced = identifier.Length > 4 && identifier.Substring(4) == "forced";
|
||||||
Track subtitle = null;
|
Track subtitle = null;
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit fffb6690fc5db161767753d1fc554be04eb732d4
|
Subproject commit 9e7e7a1093d85f8e980b8115e0514166701cbd6b
|
@ -33,5 +33,5 @@
|
|||||||
"plugins": "plugins/",
|
"plugins": "plugins/",
|
||||||
"defaultPermissions": "read,play,write,admin",
|
"defaultPermissions": "read,play,write,admin",
|
||||||
"newUserPermissions": "read,play,write,admin",
|
"newUserPermissions": "read,play,write,admin",
|
||||||
"regex": "(?:\\/(?<Collection>.*?))?\\/(?<Show>.*)(?: \\(\\d+\\))?\\/\\k<Show>(?: \\(\\d+\\))?(?:(?: S(?<Season>\\d+)E(?<Episode>\\d+))| (?<Absolute>\\d+))?.*$"
|
"regex": "(?:\\/(?<Collection>.*?))?\\/(?<Show>.*?)(?: \\(\\d+\\))?\\/\\k<Show>(?: \\(\\d+\\))?(?:(?: S(?<Season>\\d+)E(?<Episode>\\d+))| (?<Absolute>\\d+))?.*$"
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user