mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-08 10:44:20 -04:00
commit
6ecc031c94
@ -1,58 +1,93 @@
|
||||
using Kyoo.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Models;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public interface ILibraryManager
|
||||
{
|
||||
// Get by slug
|
||||
Library GetLibrary(string librarySlug);
|
||||
Collection GetCollection(string slug);
|
||||
Show GetShow(string slug);
|
||||
Season GetSeason(string showSlug, long seasonNumber);
|
||||
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
|
||||
Episode GetMovieEpisode(string movieSlug);
|
||||
Genre GetGenre(string slug);
|
||||
Studio GetStudio(string slug);
|
||||
People GetPeople(string slug);
|
||||
ProviderID GetProvider(string name);
|
||||
Task<Library> GetLibrary(string slug);
|
||||
Task<Collection> GetCollection(string slug);
|
||||
Task<Show> GetShow(string slug);
|
||||
Task<Season> GetSeason(string showSlug, int seasonNumber);
|
||||
Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
|
||||
Task<Episode> GetMovieEpisode(string movieSlug);
|
||||
Task<Track> GetTrack(int id);
|
||||
Task<Track> GetTrack(int episodeID, string language, bool isForced);
|
||||
Task<Genre> GetGenre(string slug);
|
||||
Task<Studio> GetStudio(string slug);
|
||||
Task<People> GetPeople(string slug);
|
||||
|
||||
// Get by relations
|
||||
Task<ICollection<Season>> GetSeasons(int showID);
|
||||
Task<ICollection<Season>> GetSeasons(string showSlug);
|
||||
|
||||
Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber);
|
||||
Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber);
|
||||
Task<ICollection<Episode>> GetEpisodes(int seasonID);
|
||||
|
||||
|
||||
// Helpers
|
||||
Task<Show> GetShowByPath(string path);
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
|
||||
|
||||
// Get all
|
||||
IEnumerable<Library> GetLibraries();
|
||||
IEnumerable<Collection> GetCollections();
|
||||
IEnumerable<Show> GetShows();
|
||||
IEnumerable<Episode> GetEpisodes();
|
||||
IEnumerable<Track> GetTracks();
|
||||
IEnumerable<Studio> GetStudios();
|
||||
IEnumerable<People> GetPeoples();
|
||||
IEnumerable<Genre> GetGenres();
|
||||
Task<ICollection<Library>> GetLibraries();
|
||||
Task<ICollection<Collection>> GetCollections();
|
||||
Task<ICollection<Show>> GetShows();
|
||||
Task<ICollection<Season>> GetSeasons();
|
||||
Task<ICollection<Episode>> GetEpisodes();
|
||||
Task<ICollection<Track>> GetTracks();
|
||||
Task<ICollection<Studio>> GetStudios();
|
||||
Task<ICollection<People>> GetPeoples();
|
||||
Task<ICollection<Genre>> GetGenres();
|
||||
Task<ICollection<ProviderID>> GetProviders();
|
||||
|
||||
// Search
|
||||
IEnumerable<Collection> SearchCollections(string searchQuery);
|
||||
IEnumerable<Show> SearchShows(string searchQuery);
|
||||
IEnumerable<Episode> SearchEpisodes(string searchQuery);
|
||||
IEnumerable<Genre> SearchGenres(string searchQuery);
|
||||
IEnumerable<Studio> SearchStudios(string searchQuery);
|
||||
IEnumerable<People> SearchPeople(string searchQuery);
|
||||
Task<ICollection<Library>> SearchLibraries(string searchQuery);
|
||||
Task<ICollection<Collection>> SearchCollections(string searchQuery);
|
||||
Task<ICollection<Show>> SearchShows(string searchQuery);
|
||||
Task<ICollection<Season>> SearchSeasons(string searchQuery);
|
||||
Task<ICollection<Episode>> SearchEpisodes(string searchQuery);
|
||||
Task<ICollection<Genre>> SearchGenres(string searchQuery);
|
||||
Task<ICollection<Studio>> SearchStudios(string searchQuery);
|
||||
Task<ICollection<People>> SearchPeople(string searchQuery);
|
||||
|
||||
// Other get helpers
|
||||
Show GetShowByPath(string path);
|
||||
IEnumerable<string> GetLibrariesPath();
|
||||
IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber);
|
||||
|
||||
//Register values
|
||||
void Register(object obj);
|
||||
Task Edit(object obj, bool resetOld);
|
||||
void RegisterShowLinks(Library library, Collection collection, Show show);
|
||||
Task SaveChanges();
|
||||
Task RegisterLibrary(Library library);
|
||||
Task RegisterCollection(Collection collection);
|
||||
Task RegisterShow(Show show);
|
||||
Task RegisterSeason(Season season);
|
||||
Task RegisterEpisode(Episode episode);
|
||||
Task RegisterTrack(Track track);
|
||||
Task RegisterGenre(Genre genre);
|
||||
Task RegisterStudio(Studio studio);
|
||||
Task RegisterPeople(People people);
|
||||
|
||||
// Validate values
|
||||
IEnumerable<MetadataID> Validate(IEnumerable<MetadataID> id);
|
||||
// Edit values
|
||||
Task EditLibrary(Library library, bool resetOld);
|
||||
Task EditCollection(Collection collection, bool resetOld);
|
||||
Task EditShow(Show show, bool resetOld);
|
||||
Task EditSeason(Season season, bool resetOld);
|
||||
Task EditEpisode(Episode episode, bool resetOld);
|
||||
Task EditTrack(Track track, bool resetOld);
|
||||
Task EditGenre(Genre genre, bool resetOld);
|
||||
Task EditStudio(Studio studio, bool resetOld);
|
||||
Task EditPeople(People people, bool resetOld);
|
||||
|
||||
|
||||
// Remove values
|
||||
void RemoveShow(Show show);
|
||||
void RemoveSeason(Season season);
|
||||
void RemoveEpisode(Episode episode);
|
||||
// Delete values
|
||||
Task DelteLibrary(Library library);
|
||||
Task DeleteCollection(Collection collection);
|
||||
Task DeleteShow(Show show);
|
||||
Task DeleteSeason(Season season);
|
||||
Task DeleteEpisode(Episode episode);
|
||||
Task DeleteTrack(Track track);
|
||||
Task DeleteGenre(Genre genre);
|
||||
Task DeleteStudio(Studio studio);
|
||||
Task DeletePeople(People people);
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ namespace Kyoo.Controllers
|
||||
Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie);
|
||||
Task<IEnumerable<PeopleLink>> GetPeople(Show show);
|
||||
|
||||
Task<Season> GetSeason(Show show, long seasonNumber);
|
||||
Task<Season> GetSeason(Show show, int seasonNumber);
|
||||
|
||||
Task<Episode> GetEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber);
|
||||
Task<Episode> GetEpisode(Show show, int seasonNumber, int episodeNumber, int absoluteNumber);
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ namespace Kyoo.Controllers
|
||||
Task<Show> CompleteShow(Show show, Library library);
|
||||
Task<Show> SearchShow(string showName, bool isMovie, Library library);
|
||||
Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie, Library library);
|
||||
Task<Season> GetSeason(Show show, long seasonNumber, Library library);
|
||||
Task<Episode> GetEpisode(Show show, string episodePath, long seasonNumber, long episodeNumber, long absoluteNumber, Library library);
|
||||
Task<Season> GetSeason(Show show, int seasonNumber, Library library);
|
||||
Task<Episode> GetEpisode(Show show, string episodePath, int seasonNumber, int episodeNumber, int absoluteNumber, Library library);
|
||||
Task<IEnumerable<PeopleLink>> GetPeople(Show show, Library library);
|
||||
}
|
||||
}
|
53
Kyoo.Common/Controllers/IRepository.cs
Normal file
53
Kyoo.Common/Controllers/IRepository.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Models;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public interface IRepository<T>
|
||||
{
|
||||
Task<T> Get(int id);
|
||||
Task<T> Get(string slug);
|
||||
Task<ICollection<T>> Search(string query);
|
||||
Task<ICollection<T>> GetAll();
|
||||
Task<int> Create([NotNull] T obj);
|
||||
Task<int> CreateIfNotExists([NotNull] T obj);
|
||||
Task Edit([NotNull] T edited, bool resetOld);
|
||||
Task Delete(T obj);
|
||||
}
|
||||
|
||||
public interface IShowRepository : IRepository<Show>
|
||||
{
|
||||
Task<Show> GetByPath(string path);
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
}
|
||||
|
||||
public interface ISeasonRepository : IRepository<Season>
|
||||
{
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
Task<ICollection<Season>> GetSeasons(int showID);
|
||||
Task<ICollection<Season>> GetSeasons(string showSlug);
|
||||
}
|
||||
|
||||
public interface IEpisodeRepository : IRepository<Episode>
|
||||
{
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber);
|
||||
Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber);
|
||||
Task<ICollection<Episode>> GetEpisodes(int seasonID);
|
||||
}
|
||||
|
||||
public interface ITrackRepository : IRepository<Track>
|
||||
{
|
||||
Task<Track> Get(int episodeID, string languageTag, bool isForced);
|
||||
}
|
||||
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> {}
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
<Company>SDG</Company>
|
||||
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageVersion>1.0.20</PackageVersion>
|
||||
<PackageVersion>1.0.21</PackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -7,7 +7,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Collection
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Poster { get; set; }
|
||||
|
@ -2,10 +2,10 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class CollectionLink
|
||||
{
|
||||
public long ID { get; set; }
|
||||
public long? CollectionID { get; set; }
|
||||
public int ID { get; set; }
|
||||
public int? CollectionID { get; set; }
|
||||
public virtual Collection Collection { get; set; }
|
||||
public long ShowID { get; set; }
|
||||
public int ShowID { get; set; }
|
||||
public virtual Show Show { get; set; }
|
||||
|
||||
public CollectionLink() { }
|
||||
|
@ -6,21 +6,21 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Episode
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long ShowID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int ShowID { get; set; }
|
||||
[JsonIgnore] public virtual Show Show { get; set; }
|
||||
[JsonIgnore] public long? SeasonID { get; set; }
|
||||
[JsonIgnore] public int? SeasonID { get; set; }
|
||||
[JsonIgnore] public virtual Season Season { get; set; }
|
||||
|
||||
public long SeasonNumber { get; set; }
|
||||
public long EpisodeNumber { get; set; }
|
||||
public long AbsoluteNumber { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public int EpisodeNumber { get; set; }
|
||||
public int AbsoluteNumber { get; set; }
|
||||
[JsonIgnore] public string Path { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
|
||||
public long Runtime { get; set; } //This runtime variable should be in minutes
|
||||
public int Runtime { get; set; } //This runtime variable should be in minutes
|
||||
|
||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
@ -42,13 +42,13 @@ namespace Kyoo.Models
|
||||
|
||||
public Episode() { }
|
||||
|
||||
public Episode(long seasonNumber,
|
||||
long episodeNumber,
|
||||
long absoluteNumber,
|
||||
public Episode(int seasonNumber,
|
||||
int episodeNumber,
|
||||
int absoluteNumber,
|
||||
string title,
|
||||
string overview,
|
||||
DateTime? releaseDate,
|
||||
long runtime,
|
||||
int runtime,
|
||||
string imgPrimary,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
@ -63,16 +63,16 @@ namespace Kyoo.Models
|
||||
ExternalIDs = externalIDs;
|
||||
}
|
||||
|
||||
public Episode(long showID,
|
||||
long seasonID,
|
||||
long seasonNumber,
|
||||
long episodeNumber,
|
||||
long absoluteNumber,
|
||||
public Episode(int showID,
|
||||
int seasonID,
|
||||
int seasonNumber,
|
||||
int episodeNumber,
|
||||
int absoluteNumber,
|
||||
string path,
|
||||
string title,
|
||||
string overview,
|
||||
DateTime? releaseDate,
|
||||
long runtime,
|
||||
int runtime,
|
||||
string imgPrimary,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
@ -90,7 +90,7 @@ namespace Kyoo.Models
|
||||
ExternalIDs = externalIDs;
|
||||
}
|
||||
|
||||
public static string GetSlug(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public static string GetSlug(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Genre
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
@ -24,7 +24,7 @@ namespace Kyoo.Models
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public Genre(long id, string slug, string name)
|
||||
public Genre(int id, string slug, string name)
|
||||
{
|
||||
ID = id;
|
||||
Slug = slug;
|
||||
|
@ -2,9 +2,9 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class GenreLink
|
||||
{
|
||||
public long ShowID { get; set; }
|
||||
public int ShowID { get; set; }
|
||||
public virtual Show Show { get; set; }
|
||||
public long GenreID { get; set; }
|
||||
public int GenreID { get; set; }
|
||||
public virtual Genre Genre { get; set; }
|
||||
|
||||
public GenreLink() {}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
@ -8,7 +7,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Library
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<string> Paths { get; set; }
|
||||
|
@ -2,12 +2,12 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class LibraryLink
|
||||
{
|
||||
public long ID { get; set; }
|
||||
public long LibraryID { get; set; }
|
||||
public int ID { get; set; }
|
||||
public int LibraryID { get; set; }
|
||||
public virtual Library Library { get; set; }
|
||||
public long? ShowID { get; set; }
|
||||
public int? ShowID { get; set; }
|
||||
public virtual Show Show { get; set; }
|
||||
public long? CollectionID { get; set; }
|
||||
public int? CollectionID { get; set; }
|
||||
public virtual Collection Collection { get; set; }
|
||||
|
||||
public LibraryLink() { }
|
||||
|
@ -4,20 +4,20 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class MetadataID
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long ProviderID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int ProviderID { get; set; }
|
||||
public virtual ProviderID Provider {get; set; }
|
||||
|
||||
[JsonIgnore] public long? ShowID { get; set; }
|
||||
[JsonIgnore] public int? ShowID { get; set; }
|
||||
[JsonIgnore] public virtual Show Show { get; set; }
|
||||
|
||||
[JsonIgnore] public long? EpisodeID { get; set; }
|
||||
[JsonIgnore] public int? EpisodeID { get; set; }
|
||||
[JsonIgnore] public virtual Episode Episode { get; set; }
|
||||
|
||||
[JsonIgnore] public long? SeasonID { get; set; }
|
||||
[JsonIgnore] public int? SeasonID { get; set; }
|
||||
[JsonIgnore] public virtual Season Season { get; set; }
|
||||
|
||||
[JsonIgnore] public long? PeopleID { get; set; }
|
||||
[JsonIgnore] public int? PeopleID { get; set; }
|
||||
[JsonIgnore] public virtual People People { get; set; }
|
||||
|
||||
public string DataID { get; set; }
|
||||
|
@ -6,7 +6,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class People
|
||||
{
|
||||
public long ID { get; set; }
|
||||
public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||
|
@ -5,8 +5,8 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class PeopleLink
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long PeopleID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int PeopleID { get; set; }
|
||||
[JsonIgnore] public virtual People People { get; set; }
|
||||
|
||||
public string Slug
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Models
|
||||
set => People.ExternalIDs = value;
|
||||
}
|
||||
|
||||
[JsonIgnore] public long ShowID { get; set; }
|
||||
[JsonIgnore] public int ShowID { get; set; }
|
||||
[JsonIgnore] public virtual Show Show { get; set; }
|
||||
public string Role { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
@ -4,13 +4,13 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class ProviderID
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Logo { get; set; }
|
||||
|
||||
public ProviderID() { }
|
||||
|
||||
public ProviderID(long id, string name, string logo)
|
||||
public ProviderID(int id, string name, string logo)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
|
@ -4,10 +4,10 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class ProviderLink
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long ProviderID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int ProviderID { get; set; }
|
||||
[JsonIgnore] public virtual ProviderID Provider { get; set; }
|
||||
[JsonIgnore] public long? LibraryID { get; set; }
|
||||
[JsonIgnore] public int? LibraryID { get; set; }
|
||||
[JsonIgnore] public virtual Library Library { get; set; }
|
||||
|
||||
public ProviderLink() { }
|
||||
|
@ -5,15 +5,15 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Season
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long ShowID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int ShowID { get; set; }
|
||||
|
||||
public long SeasonNumber { get; set; } = -1;
|
||||
public int SeasonNumber { get; set; } = -1;
|
||||
|
||||
public string Slug => $"{Show.Title}-s{SeasonNumber}";
|
||||
public string Slug => $"{Show.Slug}-s{SeasonNumber}";
|
||||
public string Title { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public long? Year { get; set; }
|
||||
public int? Year { get; set; }
|
||||
|
||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
@ -23,11 +23,11 @@ namespace Kyoo.Models
|
||||
|
||||
public Season() { }
|
||||
|
||||
public Season(long showID,
|
||||
long seasonNumber,
|
||||
public Season(int showID,
|
||||
int seasonNumber,
|
||||
string title,
|
||||
string overview,
|
||||
long? year,
|
||||
int? year,
|
||||
string imgPrimary,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Show : IOnMerge
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
|
||||
public string Slug { get; set; }
|
||||
public string Title { get; set; }
|
||||
@ -17,8 +17,8 @@ namespace Kyoo.Models
|
||||
public Status? Status { get; set; }
|
||||
public string TrailerUrl { get; set; }
|
||||
|
||||
public long? StartYear { get; set; }
|
||||
public long? EndYear { get; set; }
|
||||
public int? StartYear { get; set; }
|
||||
public int? EndYear { get; set; }
|
||||
|
||||
public string Poster { get; set; }
|
||||
public string Logo { get; set; }
|
||||
@ -36,6 +36,7 @@ namespace Kyoo.Models
|
||||
set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList();
|
||||
}
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<GenreLink> GenreLinks { get; set; }
|
||||
[JsonIgnore] public int? StudioID { get; set; }
|
||||
public virtual Studio Studio { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
|
||||
@ -50,8 +51,8 @@ namespace Kyoo.Models
|
||||
string trailerUrl,
|
||||
IEnumerable<Genre> genres,
|
||||
Status? status,
|
||||
long? startYear,
|
||||
long? endYear,
|
||||
int? startYear,
|
||||
int? endYear,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
Slug = slug;
|
||||
@ -75,8 +76,8 @@ namespace Kyoo.Models
|
||||
string overview,
|
||||
string trailerUrl,
|
||||
Status? status,
|
||||
long? startYear,
|
||||
long? endYear,
|
||||
int? startYear,
|
||||
int? endYear,
|
||||
string poster,
|
||||
string logo,
|
||||
string backdrop,
|
||||
|
@ -5,7 +5,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Studio
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Kyoo.Models
|
||||
public bool RunOnStartup { get; }
|
||||
public int Priority { get; }
|
||||
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null);
|
||||
public IEnumerable<string> GetPossibleParameters();
|
||||
public Task<IEnumerable<string>> GetPossibleParameters();
|
||||
public int? Progress();
|
||||
}
|
||||
}
|
@ -55,8 +55,8 @@ namespace Kyoo.Models
|
||||
|
||||
public class Track : Stream
|
||||
{
|
||||
[JsonIgnore] public long ID { get; set; }
|
||||
[JsonIgnore] public long EpisodeID { get; set; }
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int EpisodeID { get; set; }
|
||||
public bool IsDefault
|
||||
{
|
||||
get => isDefault;
|
||||
|
@ -7,12 +7,12 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class WatchItem
|
||||
{
|
||||
[JsonIgnore] public readonly long EpisodeID = -1;
|
||||
[JsonIgnore] public readonly int EpisodeID = -1;
|
||||
|
||||
public string ShowTitle;
|
||||
public string ShowSlug;
|
||||
public long SeasonNumber;
|
||||
public long EpisodeNumber;
|
||||
public int SeasonNumber;
|
||||
public int EpisodeNumber;
|
||||
public string Title;
|
||||
public string Link;
|
||||
public DateTime? ReleaseDate;
|
||||
@ -28,11 +28,11 @@ namespace Kyoo.Models
|
||||
|
||||
public WatchItem() { }
|
||||
|
||||
public WatchItem(long episodeID,
|
||||
public WatchItem(int episodeID,
|
||||
string showTitle,
|
||||
string showSlug,
|
||||
long seasonNumber,
|
||||
long episodeNumber,
|
||||
int seasonNumber,
|
||||
int episodeNumber,
|
||||
string title,
|
||||
DateTime? releaseDate,
|
||||
string path)
|
||||
@ -50,11 +50,11 @@ namespace Kyoo.Models
|
||||
Link = Episode.GetSlug(ShowSlug, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
public WatchItem(long episodeID,
|
||||
public WatchItem(int episodeID,
|
||||
string showTitle,
|
||||
string showSlug,
|
||||
long seasonNumber,
|
||||
long episodeNumber,
|
||||
int seasonNumber,
|
||||
int episodeNumber,
|
||||
string title,
|
||||
DateTime? releaseDate,
|
||||
string path,
|
||||
|
@ -1,394 +1,366 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class LibraryManager : ILibraryManager
|
||||
{
|
||||
private const int MaxSaveRetry = 3;
|
||||
private readonly DatabaseContext _database;
|
||||
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(DatabaseContext database)
|
||||
public LibraryManager(ILibraryRepository libraries,
|
||||
ICollectionRepository collections,
|
||||
IShowRepository shows,
|
||||
ISeasonRepository seasons,
|
||||
IEpisodeRepository episodes,
|
||||
ITrackRepository tracks,
|
||||
IGenreRepository genres,
|
||||
IStudioRepository studios,
|
||||
IProviderRepository providers,
|
||||
IPeopleRepository people)
|
||||
{
|
||||
_database = database;
|
||||
_libraries = libraries;
|
||||
_collections = collections;
|
||||
_shows = shows;
|
||||
_seasons = seasons;
|
||||
_episodes = episodes;
|
||||
_tracks = tracks;
|
||||
_genres = genres;
|
||||
_studios = studios;
|
||||
_providers = providers;
|
||||
_people = people;
|
||||
}
|
||||
|
||||
#region GetBySlug
|
||||
public Library GetLibrary(string librarySlug)
|
||||
public Task<Library> GetLibrary(string slug)
|
||||
{
|
||||
return _database.Libraries.FirstOrDefault(library => library.Slug == librarySlug);
|
||||
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 Collection GetCollection(string slug)
|
||||
public Task<Track> GetTrack(int episodeID, string language, bool isForced)
|
||||
{
|
||||
return _database.Collections.FirstOrDefault(col => col.Slug == slug);
|
||||
return _tracks.Get(episodeID, language, isForced);
|
||||
}
|
||||
|
||||
public Show GetShow(string slug)
|
||||
public Task<Genre> GetGenre(string slug)
|
||||
{
|
||||
return _database.Shows.FirstOrDefault(show => show.Slug == slug);
|
||||
return _genres.Get(slug);
|
||||
}
|
||||
|
||||
public Season GetSeason(string showSlug, long seasonNumber)
|
||||
public Task<Studio> GetStudio(string slug)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefault(x => x.Show.Slug == showSlug && x.SeasonNumber == seasonNumber);
|
||||
return _studios.Get(slug);
|
||||
}
|
||||
|
||||
public Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public Task<People> GetPeople(string slug)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefault(x => x.EpisodeNumber == episodeNumber
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.Show.Slug == showSlug);
|
||||
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 Episode GetMovieEpisode(string movieSlug)
|
||||
public Task<ICollection<Library>> SearchLibraries(string searchQuery)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefault(x => x.Show.Slug == movieSlug);
|
||||
return _libraries.Search(searchQuery);
|
||||
}
|
||||
|
||||
public Genre GetGenre(string slug)
|
||||
public Task<ICollection<Collection>> SearchCollections(string searchQuery)
|
||||
{
|
||||
return _database.Genres.FirstOrDefault(genre => genre.Slug == slug);
|
||||
return _collections.Search(searchQuery);
|
||||
}
|
||||
|
||||
public Studio GetStudio(string slug)
|
||||
public Task<ICollection<Show>> SearchShows(string searchQuery)
|
||||
{
|
||||
return _database.Studios.FirstOrDefault(studio => studio.Slug == slug);
|
||||
return _shows.Search(searchQuery);
|
||||
}
|
||||
|
||||
public People GetPeople(string slug)
|
||||
public Task<ICollection<Season>> SearchSeasons(string searchQuery)
|
||||
{
|
||||
return _database.Peoples.FirstOrDefault(people => people.Slug == slug);
|
||||
return _seasons.Search(searchQuery);
|
||||
}
|
||||
|
||||
public ProviderID GetProvider(string name)
|
||||
public Task<ICollection<Episode>> SearchEpisodes(string searchQuery)
|
||||
{
|
||||
return _database.Providers.FirstOrDefault(x => x.Name == name);
|
||||
return _episodes.Search(searchQuery);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetAll
|
||||
public IEnumerable<Library> GetLibraries()
|
||||
public Task<ICollection<Genre>> SearchGenres(string searchQuery)
|
||||
{
|
||||
return _database.Libraries;
|
||||
return _genres.Search(searchQuery);
|
||||
}
|
||||
|
||||
public IEnumerable<Collection> GetCollections()
|
||||
public Task<ICollection<Studio>> SearchStudios(string searchQuery)
|
||||
{
|
||||
return _database.Collections;
|
||||
return _studios.Search(searchQuery);
|
||||
}
|
||||
|
||||
public IEnumerable<Show> GetShows()
|
||||
public Task<ICollection<People>> SearchPeople(string searchQuery)
|
||||
{
|
||||
return _database.Shows;
|
||||
return _people.Search(searchQuery);
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> GetEpisodes()
|
||||
public Task RegisterLibrary(Library library)
|
||||
{
|
||||
return _database.Episodes;
|
||||
}
|
||||
|
||||
public IEnumerable<Genre> GetGenres()
|
||||
{
|
||||
return _database.Genres;
|
||||
}
|
||||
|
||||
public IEnumerable<Studio> GetStudios()
|
||||
{
|
||||
return _database.Studios;
|
||||
return _libraries.Create(library);
|
||||
}
|
||||
|
||||
public IEnumerable<People> GetPeoples()
|
||||
public Task RegisterCollection(Collection collection)
|
||||
{
|
||||
return _database.Peoples;
|
||||
return _collections.Create(collection);
|
||||
}
|
||||
|
||||
public IEnumerable<Track> GetTracks()
|
||||
public Task RegisterShow(Show show)
|
||||
{
|
||||
return _database.Tracks;
|
||||
return _shows.Create(show);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetHelper
|
||||
public IEnumerable<string> GetLibrariesPath()
|
||||
public Task RegisterSeason(Season season)
|
||||
{
|
||||
IEnumerable<string> paths = new List<string>();
|
||||
return Enumerable.Aggregate(_database.Libraries, paths, (current, lib) => current.Concat(lib.Paths));
|
||||
}
|
||||
|
||||
public Show GetShowByPath(string path)
|
||||
{
|
||||
return _database.Shows.FirstOrDefault(show => show.Path == path);
|
||||
return _seasons.Create(season);
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> GetEpisodes(string showSlug, long seasonNumber)
|
||||
public Task RegisterEpisode(Episode episode)
|
||||
{
|
||||
return _database.Episodes.Where(x => x.Show.Slug == showSlug && x.SeasonNumber == seasonNumber);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Search
|
||||
public IEnumerable<Collection> SearchCollections(string searchQuery)
|
||||
{
|
||||
return _database.Collections.Where(collection => EF.Functions.Like(collection.Name, $"%{searchQuery}%"))
|
||||
.Take(20);
|
||||
}
|
||||
|
||||
public IEnumerable<Show> SearchShows(string searchQuery)
|
||||
{
|
||||
return _database.Shows.FromSqlInterpolated($@"SELECT * FROM Shows WHERE Shows.Title LIKE {$"%{searchQuery}%"}
|
||||
OR Shows.Aliases LIKE {$"%{searchQuery}%"}").Take(20);
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> SearchEpisodes(string searchQuery)
|
||||
{
|
||||
return _database.Episodes.Where(x => EF.Functions.Like(x.Title, $"%{searchQuery}%")).Take(20);
|
||||
return _episodes.Create(episode);
|
||||
}
|
||||
|
||||
public IEnumerable<Genre> SearchGenres(string searchQuery)
|
||||
public Task RegisterTrack(Track track)
|
||||
{
|
||||
return _database.Genres.Where(genre => EF.Functions.Like(genre.Name, $"%{searchQuery}%"))
|
||||
.Take(20);
|
||||
}
|
||||
|
||||
public IEnumerable<Studio> SearchStudios(string searchQuery)
|
||||
{
|
||||
return _database.Studios.Where(studio => EF.Functions.Like(studio.Name, $"%{searchQuery}%"))
|
||||
.Take(20);
|
||||
}
|
||||
|
||||
public IEnumerable<People> SearchPeople(string searchQuery)
|
||||
{
|
||||
return _database.Peoples.Where(people => EF.Functions.Like(people.Name, $"%{searchQuery}%"))
|
||||
.OrderBy(x => x.ImgPrimary == null)
|
||||
.ThenBy(x => x.Name)
|
||||
.Take(20);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Register
|
||||
public void Register(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
ValidateRootEntry(_database.Entry(obj), entry =>
|
||||
{
|
||||
if (entry.State != EntityState.Detached)
|
||||
return false;
|
||||
|
||||
entry.State = EntityState.Added;
|
||||
return true;
|
||||
});
|
||||
return _tracks.Create(track);
|
||||
}
|
||||
|
||||
public void RegisterShowLinks(Library library, Collection collection, Show show)
|
||||
public Task RegisterGenre(Genre genre)
|
||||
{
|
||||
if (collection != null)
|
||||
{
|
||||
_database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Collection = collection},
|
||||
x => x.Library == library && x.Collection == collection && x.ShowID == null);
|
||||
_database.CollectionLinks.AddIfNotExist(new CollectionLink { Collection = collection, Show = show},
|
||||
x => x.Collection == collection && x.Show == show);
|
||||
}
|
||||
else
|
||||
_database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Show = show},
|
||||
x => x.Library == library && x.Collection == null && x.Show == show);
|
||||
return _genres.Create(genre);
|
||||
}
|
||||
|
||||
public Task SaveChanges()
|
||||
public Task RegisterStudio(Studio studio)
|
||||
{
|
||||
return SaveChanges(0);
|
||||
return _studios.Create(studio);
|
||||
}
|
||||
|
||||
private async Task SaveChanges(int retryCount)
|
||||
public Task RegisterPeople(People people)
|
||||
{
|
||||
ValidateChanges();
|
||||
try
|
||||
{
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
if (retryCount < MaxSaveRetry)
|
||||
await SaveChanges(retryCount + 1);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Edit(object obj, bool resetOld)
|
||||
{
|
||||
_database.ChangeTracker.LazyLoadingEnabled = false;
|
||||
_database.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
object existing = FindExisting(obj);
|
||||
|
||||
if (existing == null)
|
||||
throw new ItemNotFound($"No existing object (of type {obj.GetType().Name}) found on the databse.");
|
||||
|
||||
if (resetOld)
|
||||
Utility.Nullify(existing);
|
||||
Utility.Merge(existing, obj);
|
||||
|
||||
ValidateRootEntry(_database.Entry(existing), entry => entry.State != EntityState.Added);
|
||||
|
||||
_database.ChangeTracker.DetectChanges();
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_database.ChangeTracker.LazyLoadingEnabled = true;
|
||||
_database.ChangeTracker.AutoDetectChangesEnabled = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ValidateValue
|
||||
private void ValidateChanges()
|
||||
{
|
||||
_database.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||
try
|
||||
{
|
||||
foreach (EntityEntry sourceEntry in _database.ChangeTracker.Entries())
|
||||
{
|
||||
if (sourceEntry.State != EntityState.Added && sourceEntry.State != EntityState.Modified)
|
||||
continue;
|
||||
|
||||
foreach (NavigationEntry navigation in sourceEntry.Navigations)
|
||||
ValidateNavigation(navigation);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_database.ChangeTracker.AutoDetectChangesEnabled = true;
|
||||
_database.ChangeTracker.DetectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateRootEntry(EntityEntry entry, Func<EntityEntry, bool> shouldRun)
|
||||
{
|
||||
if (!shouldRun.Invoke(entry))
|
||||
return;
|
||||
foreach (NavigationEntry navigation in entry.Navigations)
|
||||
{
|
||||
ValidateNavigation(navigation);
|
||||
if (navigation.CurrentValue == null)
|
||||
continue;
|
||||
if (navigation.Metadata.IsCollection())
|
||||
{
|
||||
IEnumerable entities = (IEnumerable)navigation.CurrentValue;
|
||||
foreach (object childEntry in entities)
|
||||
ValidateRootEntry(_database.Entry(childEntry), shouldRun);
|
||||
}
|
||||
else
|
||||
ValidateRootEntry(_database.Entry(navigation.CurrentValue), shouldRun);
|
||||
}
|
||||
return _people.Create(people);
|
||||
}
|
||||
|
||||
private void ValidateNavigation(NavigationEntry navigation)
|
||||
public Task EditLibrary(Library library, bool resetOld)
|
||||
{
|
||||
object oldValue = navigation.CurrentValue;
|
||||
if (oldValue == null)
|
||||
return;
|
||||
object newValue = Validate(oldValue);
|
||||
if (ReferenceEquals(oldValue, newValue))
|
||||
return;
|
||||
navigation.CurrentValue = newValue;
|
||||
if (!navigation.Metadata.IsCollection())
|
||||
_database.Entry(oldValue).State = EntityState.Detached;
|
||||
}
|
||||
|
||||
private T Validate<T>(T obj) where T : class
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case null:
|
||||
return null;
|
||||
case IEnumerable<object> enumerable:
|
||||
return (T)Utility.RunGenericMethod(
|
||||
this,
|
||||
"ValidateList",
|
||||
Utility.GetEnumerableType(enumerable), new [] {obj});
|
||||
}
|
||||
|
||||
EntityState state = _database.Entry(obj).State;
|
||||
if (state != EntityState.Added && state != EntityState.Detached)
|
||||
return obj;
|
||||
|
||||
return (T)(FindExisting(obj) ?? obj);
|
||||
return _libraries.Edit(library, resetOld);
|
||||
}
|
||||
|
||||
public IEnumerable<T> ValidateList<T>(IEnumerable<T> list) where T : class
|
||||
public Task EditCollection(Collection collection, bool resetOld)
|
||||
{
|
||||
return list.Select(x =>
|
||||
{
|
||||
T tmp = Validate(x);
|
||||
if (tmp != x)
|
||||
_database.Entry(x).State = EntityState.Detached;
|
||||
return tmp ?? x;
|
||||
})/*.GroupBy(GetSlug).Select(x => x.First()).Where(x => x != null)*/.ToList();
|
||||
return _collections.Edit(collection, resetOld);
|
||||
}
|
||||
|
||||
private object FindExisting(object obj)
|
||||
public Task EditShow(Show show, bool resetOld)
|
||||
{
|
||||
return obj switch
|
||||
{
|
||||
Library library => GetLibrary(library.Slug),
|
||||
Collection collection => GetCollection(collection.Slug),
|
||||
Show show => GetShow(show.Slug),
|
||||
Season season => GetSeason(season.Show.Slug, season.SeasonNumber),
|
||||
Episode episode => GetEpisode(episode.Show.Slug, episode.SeasonNumber, episode.EpisodeNumber),
|
||||
Studio studio => GetStudio(studio.Slug),
|
||||
People people => GetPeople(people.Slug),
|
||||
Genre genre => GetGenre(genre.Slug),
|
||||
ProviderID provider => GetProvider(provider.Name),
|
||||
_ => null
|
||||
};
|
||||
return _shows.Edit(show, resetOld);
|
||||
}
|
||||
|
||||
public IEnumerable<MetadataID> Validate(IEnumerable<MetadataID> ids)
|
||||
public Task EditSeason(Season season, bool resetOld)
|
||||
{
|
||||
return ids?.Select(x =>
|
||||
{
|
||||
x.Provider = _database.Providers.FirstOrDefault(y => y.Name == x.Provider.Name) ?? x.Provider;
|
||||
return x;
|
||||
}).GroupBy(x => x.Provider.Name).Select(x => x.First()).ToList();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
public void RemoveShow(Show show)
|
||||
{
|
||||
if (_database.Entry(show).State == EntityState.Detached)
|
||||
_database.Shows.Attach(show);
|
||||
_database.Shows.Remove(show);
|
||||
return _seasons.Edit(season, resetOld);
|
||||
}
|
||||
|
||||
public void RemoveSeason(Season season)
|
||||
public Task EditEpisode(Episode episode, bool resetOld)
|
||||
{
|
||||
if (_database.Entry(season).State == EntityState.Detached)
|
||||
_database.Seasons.Attach(season);
|
||||
_database.Seasons.Remove(season);
|
||||
return _episodes.Edit(episode, resetOld);
|
||||
}
|
||||
|
||||
public void RemoveEpisode(Episode episode)
|
||||
public Task EditTrack(Track track, bool resetOld)
|
||||
{
|
||||
if (_database.Entry(episode).State == EntityState.Detached)
|
||||
_database.Episodes.Attach(episode);
|
||||
_database.Episodes.Remove(episode);
|
||||
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);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -113,13 +113,14 @@ namespace Kyoo.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
|
||||
public async Task<Season> GetSeason(Show show, int seasonNumber, Library library)
|
||||
{
|
||||
Season season = await GetMetadata(
|
||||
provider => provider.GetSeason(show, seasonNumber),
|
||||
library,
|
||||
$"the season {seasonNumber} of {show.Title}");
|
||||
season.Show = show;
|
||||
season.ShowID = show.ID;
|
||||
season.SeasonNumber = season.SeasonNumber == -1 ? seasonNumber : season.SeasonNumber;
|
||||
season.Title ??= $"Season {season.SeasonNumber}";
|
||||
return season;
|
||||
@ -127,9 +128,9 @@ namespace Kyoo.Controllers
|
||||
|
||||
public async Task<Episode> GetEpisode(Show show,
|
||||
string episodePath,
|
||||
long seasonNumber,
|
||||
long episodeNumber,
|
||||
long absoluteNumber,
|
||||
int seasonNumber,
|
||||
int episodeNumber,
|
||||
int absoluteNumber,
|
||||
Library library)
|
||||
{
|
||||
Episode episode = await GetMetadata(
|
||||
@ -137,6 +138,7 @@ namespace Kyoo.Controllers
|
||||
library,
|
||||
"an episode");
|
||||
episode.Show = show;
|
||||
episode.ShowID = show.ID;
|
||||
episode.Path = episodePath;
|
||||
episode.SeasonNumber = episode.SeasonNumber != -1 ? episode.SeasonNumber : seasonNumber;
|
||||
episode.EpisodeNumber = episode.EpisodeNumber != -1 ? episode.EpisodeNumber : episodeNumber;
|
||||
@ -155,6 +157,7 @@ namespace Kyoo.Controllers
|
||||
.Select(x =>
|
||||
{
|
||||
x.Show = show;
|
||||
x.ShowID = show.ID;
|
||||
return x;
|
||||
}).ToList();
|
||||
}
|
||||
|
88
Kyoo/Controllers/Repositories/CollectionRepository.cs
Normal file
88
Kyoo/Controllers/Repositories/CollectionRepository.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class CollectionRepository : ICollectionRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
public CollectionRepository(DatabaseContext database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public Task<Collection> Get(int id)
|
||||
{
|
||||
return _database.Collections.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public Task<Collection> Get(string slug)
|
||||
{
|
||||
return _database.Collections.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Collection>> Search(string query)
|
||||
{
|
||||
return await _database.Collections
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Collection>> GetAll()
|
||||
{
|
||||
return await _database.Collections.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Collection obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await _database.Collections.AddAsync(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(Collection obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
Collection old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(Collection edited, bool resetOld)
|
||||
{
|
||||
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(Collection obj)
|
||||
{
|
||||
_database.Collections.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
147
Kyoo/Controllers/Repositories/EpisodeRepository.cs
Normal file
147
Kyoo/Controllers/Repositories/EpisodeRepository.cs
Normal file
@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class EpisodeRepository : IEpisodeRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
|
||||
public EpisodeRepository(DatabaseContext database, IServiceProvider serviceProvider)
|
||||
{
|
||||
_database = database;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task<Episode> Get(int id)
|
||||
{
|
||||
return await _database.Episodes.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public Task<Episode> Get(string slug)
|
||||
{
|
||||
int sIndex = slug.IndexOf("-s", StringComparison.Ordinal);
|
||||
int eIndex = slug.IndexOf("-e", StringComparison.Ordinal);
|
||||
if (sIndex == -1 || eIndex == -1 || eIndex < sIndex)
|
||||
throw new InvalidOperationException("Invalid episode slug. Format: {showSlug}-s{seasonNumber}-e{episodeNumber}");
|
||||
string showSlug = slug.Substring(0, sIndex);
|
||||
if (!int.TryParse(slug.Substring(sIndex + 2), out int seasonNumber))
|
||||
throw new InvalidOperationException("Invalid episode slug. Format: {showSlug}-s{seasonNumber}-e{episodeNumber}");
|
||||
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 async Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return await _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.EpisodeNumber == episodeNumber);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Episode>> Search(string query)
|
||||
{
|
||||
return await _database.Episodes
|
||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Episode>> GetAll()
|
||||
{
|
||||
return await _database.Episodes.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Episode obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
if (obj.ExternalIDs != null)
|
||||
foreach (MetadataID entry in obj.ExternalIDs)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync();
|
||||
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;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(Episode edited, bool resetOld)
|
||||
{
|
||||
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)
|
||||
throw new InvalidOperationException($"Can't store an episode not related to any show (showID: {obj.ShowID}).");
|
||||
|
||||
if (obj.ExternalIDs != null)
|
||||
{
|
||||
obj.ExternalIDs = (await Task.WhenAll(obj.ExternalIDs.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||
|
||||
x.ProviderID = await providers.CreateIfNotExists(x.Provider);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(Episode obj)
|
||||
{
|
||||
_database.Episodes.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Episode>> GetEpisodes(int showID, int seasonNumber)
|
||||
{
|
||||
return await _database.Episodes.Where(x => x.ShowID == showID
|
||||
&& x.SeasonNumber == seasonNumber).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Episode>> GetEpisodes(string showSlug, int seasonNumber)
|
||||
{
|
||||
return await _database.Episodes.Where(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Episode>> GetEpisodes(int seasonID)
|
||||
{
|
||||
return await _database.Episodes.Where(x => x.SeasonID == seasonID).ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
87
Kyoo/Controllers/Repositories/GenreRepository.cs
Normal file
87
Kyoo/Controllers/Repositories/GenreRepository.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class GenreRepository : IGenreRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
public GenreRepository(DatabaseContext database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async Task<Genre> Get(int id)
|
||||
{
|
||||
return await _database.Genres.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public async Task<Genre> Get(string slug)
|
||||
{
|
||||
return await _database.Genres.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Genre>> Search(string query)
|
||||
{
|
||||
return await _database.Genres
|
||||
.Where(genre => EF.Functions.Like(genre.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Genre>> GetAll()
|
||||
{
|
||||
return await _database.Genres.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Genre obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await _database.Genres.AddAsync(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(Genre obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
Genre old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(Genre edited, bool resetOld)
|
||||
{
|
||||
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(Genre obj)
|
||||
{
|
||||
_database.Genres.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
107
Kyoo/Controllers/Repositories/LibraryRepository.cs
Normal file
107
Kyoo/Controllers/Repositories/LibraryRepository.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class LibraryRepository : ILibraryRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
|
||||
public LibraryRepository(DatabaseContext database, IServiceProvider serviceProvider)
|
||||
{
|
||||
_database = database;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task<Library> Get(int id)
|
||||
{
|
||||
return _database.Libraries.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public Task<Library> Get(string slug)
|
||||
{
|
||||
return _database.Libraries.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Library>> Search(string query)
|
||||
{
|
||||
return await _database.Libraries
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Library>> GetAll()
|
||||
{
|
||||
return await _database.Libraries.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Library obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
if (obj.ProviderLinks != null)
|
||||
foreach (ProviderLink entry in obj.ProviderLinks)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(Library obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
Library old = await Get(obj.Name);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(Library edited, bool resetOld)
|
||||
{
|
||||
if (edited == null)
|
||||
throw new ArgumentNullException(nameof(edited));
|
||||
|
||||
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)
|
||||
{
|
||||
obj.ProviderLinks = (await Task.WhenAll(obj.ProviderLinks.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||
|
||||
x.ProviderID = await providers.CreateIfNotExists(x.Provider);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
|
||||
public async Task Delete(Library obj)
|
||||
{
|
||||
_database.Libraries.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
106
Kyoo/Controllers/Repositories/PeopleRepository.cs
Normal file
106
Kyoo/Controllers/Repositories/PeopleRepository.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class PeopleRepository : IPeopleRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public PeopleRepository(DatabaseContext database, IServiceProvider serviceProvider)
|
||||
{
|
||||
_database = database;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task<People> Get(int id)
|
||||
{
|
||||
return _database.Peoples.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
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)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<People>> GetAll()
|
||||
{
|
||||
return await _database.Peoples.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(People obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
if (obj.ExternalIDs != null)
|
||||
foreach (MetadataID entry in obj.ExternalIDs)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(People obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
People old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
obj.ExternalIDs = (await Task.WhenAll(obj.ExternalIDs.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||
|
||||
x.ProviderID = await providers.CreateIfNotExists(x.Provider);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
|
||||
public async Task Delete(People obj)
|
||||
{
|
||||
_database.Peoples.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
87
Kyoo/Controllers/Repositories/ProviderRepository.cs
Normal file
87
Kyoo/Controllers/Repositories/ProviderRepository.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class ProviderRepository : IProviderRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
public ProviderRepository(DatabaseContext database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
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
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<ProviderID>> GetAll()
|
||||
{
|
||||
return await _database.Providers.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(ProviderID obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await _database.Providers.AddAsync(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(ProviderID obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
ProviderID old = await Get(obj.Name);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(ProviderID edited, bool resetOld)
|
||||
{
|
||||
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(ProviderID obj)
|
||||
{
|
||||
_database.Providers.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
136
Kyoo/Controllers/Repositories/SeasonRepository.cs
Normal file
136
Kyoo/Controllers/Repositories/SeasonRepository.cs
Normal file
@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class SeasonRepository : ISeasonRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
|
||||
public SeasonRepository(DatabaseContext database, IServiceProvider serviceProvider)
|
||||
{
|
||||
_database = database;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task<Season> Get(int id)
|
||||
{
|
||||
return await _database.Seasons.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
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 async Task<Season> Get(string showSlug, int seasonNumber)
|
||||
{
|
||||
return await _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> Search(string query)
|
||||
{
|
||||
return await _database.Seasons
|
||||
.Where(x => EF.Functions.Like(x.Title, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> GetAll()
|
||||
{
|
||||
return await _database.Seasons.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Season obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
if (obj.ExternalIDs != null)
|
||||
foreach (MetadataID entry in obj.ExternalIDs)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync();
|
||||
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;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
public async Task Edit(Season edited, bool resetOld)
|
||||
{
|
||||
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)
|
||||
throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID}).");
|
||||
|
||||
if (obj.ExternalIDs != null)
|
||||
{
|
||||
obj.ExternalIDs = (await Task.WhenAll(obj.ExternalIDs.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||
|
||||
x.ProviderID = await providers.CreateIfNotExists(x.Provider);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(Season obj)
|
||||
{
|
||||
_database.Seasons.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> GetSeasons(int showID)
|
||||
{
|
||||
return await _database.Seasons.Where(x => x.ShowID == showID).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Season>> GetSeasons(string showSlug)
|
||||
{
|
||||
return await _database.Seasons.Where(x => x.Show.Slug == showSlug).ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
175
Kyoo/Controllers/Repositories/ShowRepository.cs
Normal file
175
Kyoo/Controllers/Repositories/ShowRepository.cs
Normal file
@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class ShowRepository : IShowRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IStudioRepository _studios;
|
||||
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IServiceProvider serviceProvider,
|
||||
IStudioRepository studios)
|
||||
{
|
||||
_database = database;
|
||||
_serviceProvider = serviceProvider;
|
||||
_studios = studios;
|
||||
}
|
||||
|
||||
public async Task<Show> Get(int id)
|
||||
{
|
||||
return await _database.Shows.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public async Task<Show> Get(string slug)
|
||||
{
|
||||
return await _database.Shows.FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
public async Task<Show> GetByPath(string path)
|
||||
{
|
||||
return await _database.Shows.FirstOrDefaultAsync(x => x.Path == path);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Show>> Search(string query)
|
||||
{
|
||||
return await _database.Shows
|
||||
.FromSqlInterpolated($@"SELECT * FROM Shows WHERE Shows.Title LIKE {$"%{query}%"}
|
||||
OR Shows.Aliases LIKE {$"%{query}%"}")
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Show>> GetAll()
|
||||
{
|
||||
return await _database.Shows.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Show obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
if (obj.GenreLinks != null)
|
||||
foreach (GenreLink entry in obj.GenreLinks)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
if (obj.People != null)
|
||||
foreach (PeopleLink entry in obj.People)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
if (obj.ExternalIDs != null)
|
||||
foreach (MetadataID entry in obj.ExternalIDs)
|
||||
_database.Entry(entry).State = EntityState.Added;
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(Show obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
Show old = await Get(obj.Slug);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
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)
|
||||
obj.StudioID = await _studios.CreateIfNotExists(obj.Studio);
|
||||
|
||||
if (obj.GenreLinks != null)
|
||||
{
|
||||
obj.GenreLinks = (await Task.WhenAll(obj.GenreLinks.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IGenreRepository genres = serviceScope.ServiceProvider.GetService<IGenreRepository>();
|
||||
|
||||
x.GenreID = await genres.CreateIfNotExists(x.Genre);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
|
||||
if (obj.People != null)
|
||||
{
|
||||
obj.People = (await Task.WhenAll(obj.People.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IPeopleRepository people = serviceScope.ServiceProvider.GetService<IPeopleRepository>();
|
||||
|
||||
x.PeopleID = await people.CreateIfNotExists(x.People);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
|
||||
if (obj.ExternalIDs != null)
|
||||
{
|
||||
obj.ExternalIDs = (await Task.WhenAll(obj.ExternalIDs.Select(async x =>
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
IProviderRepository providers = serviceScope.ServiceProvider.GetService<IProviderRepository>();
|
||||
|
||||
x.ProviderID = await providers.CreateIfNotExists(x.Provider);
|
||||
return x;
|
||||
}))).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(Show show)
|
||||
{
|
||||
_database.Shows.Remove(show);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task AddShowLink(int showID, int? libraryID, int? collectionID)
|
||||
{
|
||||
if (collectionID != null)
|
||||
{
|
||||
_database.CollectionLinks.AddIfNotExist(new CollectionLink { CollectionID = collectionID, ShowID = showID},
|
||||
x => x.CollectionID == collectionID && x.ShowID == showID);
|
||||
}
|
||||
if (libraryID != null)
|
||||
{
|
||||
_database.LibraryLinks.AddIfNotExist(new LibraryLink {LibraryID = libraryID.Value, ShowID = showID},
|
||||
x => x.LibraryID == libraryID.Value && x.CollectionID == null && x.ShowID == showID);
|
||||
}
|
||||
|
||||
if (libraryID != null && collectionID != null)
|
||||
{
|
||||
_database.LibraryLinks.AddIfNotExist(
|
||||
new LibraryLink {LibraryID = libraryID.Value, CollectionID = collectionID.Value},
|
||||
x => x.LibraryID == libraryID && x.CollectionID == collectionID && x.ShowID == null);
|
||||
}
|
||||
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
87
Kyoo/Controllers/Repositories/StudioRepository.cs
Normal file
87
Kyoo/Controllers/Repositories/StudioRepository.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class StudioRepository : IStudioRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
public StudioRepository(DatabaseContext database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
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.Name == slug);
|
||||
}
|
||||
|
||||
public async Task<ICollection<Studio>> Search(string query)
|
||||
{
|
||||
return await _database.Studios
|
||||
.Where(x => EF.Functions.Like(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ICollection<Studio>> GetAll()
|
||||
{
|
||||
return await _database.Studios.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Studio obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
await _database.Studios.AddAsync(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public async Task<int> CreateIfNotExists(Studio obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
Studio old = await Get(obj.Name);
|
||||
if (old != null)
|
||||
return old.ID;
|
||||
return await Create(obj);
|
||||
}
|
||||
|
||||
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(Studio obj)
|
||||
{
|
||||
_database.Studios.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
88
Kyoo/Controllers/Repositories/TrackRepository.cs
Normal file
88
Kyoo/Controllers/Repositories/TrackRepository.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class TrackRepository : ITrackRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
public TrackRepository(DatabaseContext database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return _database.Tracks.FirstOrDefaultAsync(x => x.EpisodeID == episodeID
|
||||
&& x.Language == languageTag
|
||||
&& x.IsForced == isForced);
|
||||
}
|
||||
|
||||
public Task<ICollection<Track>> Search(string query)
|
||||
{
|
||||
throw new InvalidOperationException("Tracks do not support the search method.");
|
||||
}
|
||||
|
||||
public async Task<ICollection<Track>> GetAll()
|
||||
{
|
||||
return await _database.Tracks.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Create(Track obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
if (obj.EpisodeID <= 0)
|
||||
throw new InvalidOperationException($"Can't store a track not related to any episode (episodeID: {obj.EpisodeID}).");
|
||||
|
||||
obj.Episode = null;
|
||||
await _database.Tracks.AddAsync(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
return obj.ID;
|
||||
}
|
||||
|
||||
public Task<int> CreateIfNotExists(Track obj)
|
||||
{
|
||||
return Create(obj);
|
||||
}
|
||||
|
||||
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(Track obj)
|
||||
{
|
||||
_database.Tracks.Remove(obj);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20200526235513_Initial")]
|
||||
[Migration("20200607010830_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@ -23,9 +23,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Collection", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -53,16 +53,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.CollectionLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("CollectionID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("CollectionID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -75,16 +75,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Episode", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long>("AbsoluteNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("AbsoluteNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("EpisodeNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("EpisodeNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
.HasColumnType("text");
|
||||
@ -98,17 +98,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<DateTime?>("ReleaseDate")
|
||||
.HasColumnType("timestamp without time zone");
|
||||
|
||||
b.Property<long>("Runtime")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("Runtime")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("SeasonID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("SeasonID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("SeasonNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("SeasonNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
@ -124,9 +124,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Genre", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -145,11 +145,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.GenreLink", b =>
|
||||
{
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("GenreID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("GenreID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ShowID", "GenreID");
|
||||
|
||||
@ -160,9 +160,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Library", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -184,19 +184,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.LibraryLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("CollectionID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("CollectionID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("LibraryID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("LibraryID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -211,31 +211,31 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("DataID")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("EpisodeID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("EpisodeID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Link")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("PeopleID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("PeopleID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ProviderID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ProviderID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("SeasonID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("SeasonID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -254,9 +254,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.People", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -278,19 +278,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long>("PeopleID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("PeopleID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("text");
|
||||
@ -306,9 +306,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Logo")
|
||||
@ -327,16 +327,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.ProviderLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("LibraryID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("LibraryID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ProviderID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ProviderID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -349,9 +349,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Season", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -360,17 +360,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("SeasonNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("SeasonNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("Year")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("Year")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -381,9 +381,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Show", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Aliases")
|
||||
@ -392,8 +392,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Backdrop")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("EndYear")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("EndYear")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("IsMovie")
|
||||
.HasColumnType("boolean");
|
||||
@ -413,14 +413,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Slug")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("StartYear")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("StartYear")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int?>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("StudioID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("StudioID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
@ -440,9 +440,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Studio", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -461,16 +461,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Track", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Codec")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("EpisodeID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("EpisodeID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("boolean");
|
@ -12,7 +12,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Collections",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(nullable: true),
|
||||
@ -29,7 +29,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Genres",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(nullable: true)
|
||||
@ -43,7 +43,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Libraries",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(nullable: true),
|
||||
@ -58,7 +58,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Peoples",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(nullable: true),
|
||||
@ -73,7 +73,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Providers",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Name = table.Column<string>(nullable: true),
|
||||
Logo = table.Column<string>(nullable: true)
|
||||
@ -87,7 +87,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Studios",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Name = table.Column<string>(nullable: true)
|
||||
@ -101,10 +101,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "ProviderLinks",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ProviderID = table.Column<long>(nullable: false),
|
||||
LibraryID = table.Column<long>(nullable: true)
|
||||
ProviderID = table.Column<int>(nullable: false),
|
||||
LibraryID = table.Column<int>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -127,7 +127,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Shows",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Slug = table.Column<string>(nullable: true),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
@ -136,13 +136,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
Overview = table.Column<string>(nullable: true),
|
||||
Status = table.Column<int>(nullable: true),
|
||||
TrailerUrl = table.Column<string>(nullable: true),
|
||||
StartYear = table.Column<long>(nullable: true),
|
||||
EndYear = table.Column<long>(nullable: true),
|
||||
StartYear = table.Column<int>(nullable: true),
|
||||
EndYear = table.Column<int>(nullable: true),
|
||||
Poster = table.Column<string>(nullable: true),
|
||||
Logo = table.Column<string>(nullable: true),
|
||||
Backdrop = table.Column<string>(nullable: true),
|
||||
IsMovie = table.Column<bool>(nullable: false),
|
||||
StudioID = table.Column<long>(nullable: true)
|
||||
StudioID = table.Column<int>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -159,10 +159,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "CollectionLinks",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
CollectionID = table.Column<long>(nullable: true),
|
||||
ShowID = table.Column<long>(nullable: false)
|
||||
CollectionID = table.Column<int>(nullable: true),
|
||||
ShowID = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -185,8 +185,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "GenreLinks",
|
||||
columns: table => new
|
||||
{
|
||||
ShowID = table.Column<long>(nullable: false),
|
||||
GenreID = table.Column<long>(nullable: false)
|
||||
ShowID = table.Column<int>(nullable: false),
|
||||
GenreID = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -209,11 +209,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "LibraryLinks",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
LibraryID = table.Column<long>(nullable: false),
|
||||
ShowID = table.Column<long>(nullable: true),
|
||||
CollectionID = table.Column<long>(nullable: true)
|
||||
LibraryID = table.Column<int>(nullable: false),
|
||||
ShowID = table.Column<int>(nullable: true),
|
||||
CollectionID = table.Column<int>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -242,10 +242,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "PeopleLinks",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
PeopleID = table.Column<long>(nullable: false),
|
||||
ShowID = table.Column<long>(nullable: false),
|
||||
PeopleID = table.Column<int>(nullable: false),
|
||||
ShowID = table.Column<int>(nullable: false),
|
||||
Role = table.Column<string>(nullable: true),
|
||||
Type = table.Column<string>(nullable: true)
|
||||
},
|
||||
@ -270,13 +270,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Seasons",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ShowID = table.Column<long>(nullable: false),
|
||||
SeasonNumber = table.Column<long>(nullable: false),
|
||||
ShowID = table.Column<int>(nullable: false),
|
||||
SeasonNumber = table.Column<int>(nullable: false),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
Overview = table.Column<string>(nullable: true),
|
||||
Year = table.Column<long>(nullable: true),
|
||||
Year = table.Column<int>(nullable: true),
|
||||
ImgPrimary = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
@ -294,18 +294,18 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Episodes",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ShowID = table.Column<long>(nullable: false),
|
||||
SeasonID = table.Column<long>(nullable: true),
|
||||
SeasonNumber = table.Column<long>(nullable: false),
|
||||
EpisodeNumber = table.Column<long>(nullable: false),
|
||||
AbsoluteNumber = table.Column<long>(nullable: false),
|
||||
ShowID = table.Column<int>(nullable: false),
|
||||
SeasonID = table.Column<int>(nullable: true),
|
||||
SeasonNumber = table.Column<int>(nullable: false),
|
||||
EpisodeNumber = table.Column<int>(nullable: false),
|
||||
AbsoluteNumber = table.Column<int>(nullable: false),
|
||||
Path = table.Column<string>(nullable: true),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
Overview = table.Column<string>(nullable: true),
|
||||
ReleaseDate = table.Column<DateTime>(nullable: true),
|
||||
Runtime = table.Column<long>(nullable: false),
|
||||
Runtime = table.Column<int>(nullable: false),
|
||||
ImgPrimary = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
@ -329,13 +329,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "MetadataIds",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ProviderID = table.Column<long>(nullable: false),
|
||||
ShowID = table.Column<long>(nullable: true),
|
||||
EpisodeID = table.Column<long>(nullable: true),
|
||||
SeasonID = table.Column<long>(nullable: true),
|
||||
PeopleID = table.Column<long>(nullable: true),
|
||||
ProviderID = table.Column<int>(nullable: false),
|
||||
ShowID = table.Column<int>(nullable: true),
|
||||
EpisodeID = table.Column<int>(nullable: true),
|
||||
SeasonID = table.Column<int>(nullable: true),
|
||||
PeopleID = table.Column<int>(nullable: true),
|
||||
DataID = table.Column<string>(nullable: true),
|
||||
Link = table.Column<string>(nullable: true)
|
||||
},
|
||||
@ -378,14 +378,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
name: "Tracks",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<long>(nullable: false)
|
||||
ID = table.Column<int>(nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
Language = table.Column<string>(nullable: true),
|
||||
Codec = table.Column<string>(nullable: true),
|
||||
Path = table.Column<string>(nullable: true),
|
||||
Type = table.Column<int>(nullable: false),
|
||||
EpisodeID = table.Column<long>(nullable: false),
|
||||
EpisodeID = table.Column<int>(nullable: false),
|
||||
IsDefault = table.Column<bool>(nullable: false),
|
||||
IsForced = table.Column<bool>(nullable: false),
|
||||
IsExternal = table.Column<bool>(nullable: false)
|
@ -21,9 +21,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Collection", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -51,16 +51,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.CollectionLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("CollectionID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("CollectionID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -73,16 +73,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Episode", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long>("AbsoluteNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("AbsoluteNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("EpisodeNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("EpisodeNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
.HasColumnType("text");
|
||||
@ -96,17 +96,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<DateTime?>("ReleaseDate")
|
||||
.HasColumnType("timestamp without time zone");
|
||||
|
||||
b.Property<long>("Runtime")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("Runtime")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("SeasonID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("SeasonID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("SeasonNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("SeasonNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
@ -122,9 +122,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Genre", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -143,11 +143,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.GenreLink", b =>
|
||||
{
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("GenreID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("GenreID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ShowID", "GenreID");
|
||||
|
||||
@ -158,9 +158,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Library", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -182,19 +182,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.LibraryLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("CollectionID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("CollectionID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("LibraryID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("LibraryID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -209,31 +209,31 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("DataID")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("EpisodeID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("EpisodeID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Link")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("PeopleID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("PeopleID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ProviderID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ProviderID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("SeasonID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("SeasonID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -252,9 +252,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.People", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -276,19 +276,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long>("PeopleID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("PeopleID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("text");
|
||||
@ -304,9 +304,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Logo")
|
||||
@ -325,16 +325,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.ProviderLink", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<long?>("LibraryID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("LibraryID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ProviderID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ProviderID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -347,9 +347,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Season", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ImgPrimary")
|
||||
@ -358,17 +358,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("SeasonNumber")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("SeasonNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long>("ShowID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("ShowID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("Year")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("Year")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
@ -379,9 +379,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Show", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Aliases")
|
||||
@ -390,8 +390,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Backdrop")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("EndYear")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("EndYear")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("IsMovie")
|
||||
.HasColumnType("boolean");
|
||||
@ -411,14 +411,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
b.Property<string>("Slug")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long?>("StartYear")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("StartYear")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int?>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<long?>("StudioID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int?>("StudioID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
@ -438,9 +438,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Studio", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -459,16 +459,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
|
||||
|
||||
modelBuilder.Entity("Kyoo.Models.Track", b =>
|
||||
{
|
||||
b.Property<long>("ID")
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("Codec")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("EpisodeID")
|
||||
.HasColumnType("bigint");
|
||||
b.Property<int>("EpisodeID")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("boolean");
|
||||
|
@ -137,6 +137,18 @@ namespace Kyoo
|
||||
AllowedOrigins = { new Uri(publicUrl).GetLeftPart(UriPartial.Authority) }
|
||||
});
|
||||
|
||||
|
||||
services.AddTransient<ILibraryRepository, LibraryRepository>();
|
||||
services.AddTransient<ICollectionRepository, CollectionRepository>();
|
||||
services.AddTransient<IShowRepository, ShowRepository>();
|
||||
services.AddTransient<ISeasonRepository, SeasonRepository>();
|
||||
services.AddTransient<IEpisodeRepository, EpisodeRepository>();
|
||||
services.AddTransient<ITrackRepository, TrackRepository>();
|
||||
services.AddTransient<IPeopleRepository, PeopleRepository>();
|
||||
services.AddTransient<IStudioRepository, StudioRepository>();
|
||||
services.AddTransient<IGenreRepository, GenreRepository>();
|
||||
services.AddTransient<IProviderRepository, ProviderRepository>();
|
||||
|
||||
services.AddScoped<ILibraryManager, LibraryManager>();
|
||||
services.AddSingleton<ITranscoder, Transcoder>();
|
||||
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
||||
|
@ -8,7 +8,6 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models.Watch;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
@ -28,11 +27,11 @@ namespace Kyoo.Controllers
|
||||
private ITranscoder _transcoder;
|
||||
private IConfiguration _config;
|
||||
|
||||
public IEnumerable<string> GetPossibleParameters()
|
||||
public async Task<IEnumerable<string>> GetPossibleParameters()
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||
return libraryManager.GetLibraries().Select(x => x.Slug);
|
||||
return (await libraryManager.GetLibraries()).Select(x => x.Slug);
|
||||
}
|
||||
|
||||
public int? Progress()
|
||||
@ -53,28 +52,27 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||
IEnumerable<Episode> episodes = libraryManager.GetEpisodes();
|
||||
IEnumerable<Library> libraries = argument == null
|
||||
? libraryManager.GetLibraries()
|
||||
: new [] {libraryManager.GetLibrary(argument)};
|
||||
ICollection<Episode> episodes = await libraryManager.GetEpisodes();
|
||||
ICollection<Library> libraries = argument == null
|
||||
? await libraryManager.GetLibraries()
|
||||
: new [] { await libraryManager.GetLibrary(argument)};
|
||||
|
||||
foreach (Episode episode in episodes)
|
||||
{
|
||||
if (!File.Exists(episode.Path))
|
||||
libraryManager.RemoveEpisode(episode);
|
||||
await libraryManager.DeleteEpisode(episode);
|
||||
}
|
||||
await libraryManager.SaveChanges();
|
||||
|
||||
await Task.WhenAll(libraries.ToList().Select(x => Scan(x, libraryManager, cancellationToken)));
|
||||
await Task.WhenAll(libraries.Select(x => Scan(x, episodes, cancellationToken)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"Unknown exception thrown durring libraries scan.\nException: {ex.Message}");
|
||||
await Console.Error.WriteLineAsync($"Unknown exception thrown durring libraries scan.\nException: {ex.Message}");
|
||||
}
|
||||
Console.WriteLine("Scan finished!");
|
||||
}
|
||||
|
||||
private Task Scan(Library library, ILibraryManager libraryManager, CancellationToken cancellationToken)
|
||||
private Task Scan(Library library, ICollection<Episode> episodes, CancellationToken cancellationToken)
|
||||
{
|
||||
Console.WriteLine($"Scanning library {library.Name} at {string.Join(", ", library.Paths)}.");
|
||||
return Task.WhenAll(library.Paths.Select(async path =>
|
||||
@ -89,29 +87,29 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
Console.Error.WriteLine($"The library's directory {path} could not be found (library slug: {library.Slug})");
|
||||
await Console.Error.WriteLineAsync($"The library's directory {path} could not be found (library slug: {library.Slug})");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
Console.Error.WriteLine($"The library's directory {path} is too long for this system. (library slug: {library.Slug})");
|
||||
await Console.Error.WriteLineAsync($"The library's directory {path} is too long for this system. (library slug: {library.Slug})");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
Console.Error.WriteLine($"The library's directory {path} is invalid. (library slug: {library.Slug})");
|
||||
await Console.Error.WriteLineAsync($"The library's directory {path} is invalid. (library slug: {library.Slug})");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Console.Error.WriteLine($"Permission denied: can't access library's directory at {path}. (library slug: {library.Slug})");
|
||||
await Console.Error.WriteLineAsync($"Permission denied: can't access library's directory at {path}. (library slug: {library.Slug})");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// return Task.WhenAll(files.Select(file =>
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!IsVideo(file) || libraryManager.GetEpisodes().Any(x => x.Path == file))
|
||||
if (!IsVideo(file) || episodes.Any(x => x.Path == file))
|
||||
continue; //return Task.CompletedTask;
|
||||
string relativePath = file.Substring(path.Length);
|
||||
/*return*/ await RegisterFile(file, relativePath, library, cancellationToken);
|
||||
@ -128,7 +126,6 @@ namespace Kyoo.Controllers
|
||||
|
||||
using IServiceScope serviceScope = _serviceProvider.CreateScope();
|
||||
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
|
||||
((DbSet<Library>)libraryManager.GetLibraries()).Attach(library);
|
||||
|
||||
string patern = _config.GetValue<string>("regex");
|
||||
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
|
||||
@ -137,74 +134,97 @@ namespace Kyoo.Controllers
|
||||
string showPath = Path.GetDirectoryName(path);
|
||||
string collectionName = match.Groups["Collection"]?.Value;
|
||||
string showName = match.Groups["ShowTitle"].Value;
|
||||
long seasonNumber = long.TryParse(match.Groups["Season"].Value, out long tmp) ? tmp : -1;
|
||||
long episodeNumber = long.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1;
|
||||
long absoluteNumber = long.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1;
|
||||
int seasonNumber = int.TryParse(match.Groups["Season"].Value, out int tmp) ? tmp : -1;
|
||||
int episodeNumber = int.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1;
|
||||
int absoluteNumber = int.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1;
|
||||
|
||||
Collection collection = await GetCollection(libraryManager, collectionName, library);
|
||||
bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1;
|
||||
Show show = await GetShow(libraryManager, showName, showPath, isMovie, library);
|
||||
if (isMovie)
|
||||
libraryManager.Register(await GetMovie(show, path));
|
||||
await libraryManager.RegisterEpisode(await GetMovie(show, path));
|
||||
else
|
||||
{
|
||||
Season season = await GetSeason(libraryManager, show, seasonNumber, library);
|
||||
Episode episode = await GetEpisode(libraryManager, show, season, episodeNumber, absoluteNumber, path, library);
|
||||
libraryManager.Register(episode);
|
||||
await libraryManager.RegisterEpisode(episode);
|
||||
}
|
||||
if (collection != null)
|
||||
libraryManager.Register(collection);
|
||||
libraryManager.RegisterShowLinks(library, collection, show);
|
||||
Console.WriteLine($"Registering episode at: {path}");
|
||||
await libraryManager.SaveChanges();
|
||||
|
||||
await libraryManager.AddShowLink(show, library, collection);
|
||||
Console.WriteLine($"Episode at {path} registered.");
|
||||
}
|
||||
|
||||
private async Task<Collection> GetCollection(ILibraryManager libraryManager, string collectionName, Library library)
|
||||
private async Task<Collection> GetCollection(ILibraryManager libraryManager,
|
||||
string collectionName,
|
||||
Library library)
|
||||
{
|
||||
if (string.IsNullOrEmpty(collectionName))
|
||||
return await Task.FromResult<Collection>(null);
|
||||
Collection name = libraryManager.GetCollection(Utility.ToSlug(collectionName));
|
||||
if (name != null)
|
||||
return name;
|
||||
return await _metadataProvider.GetCollectionFromName(collectionName, library);
|
||||
return null;
|
||||
Collection collection = await libraryManager.GetCollection(Utility.ToSlug(collectionName));
|
||||
if (collection != null)
|
||||
return collection;
|
||||
collection = await _metadataProvider.GetCollectionFromName(collectionName, library);
|
||||
await libraryManager.RegisterCollection(collection);
|
||||
return collection;
|
||||
}
|
||||
|
||||
private async Task<Show> GetShow(ILibraryManager libraryManager, string showTitle, string showPath, bool isMovie, Library library)
|
||||
private async Task<Show> GetShow(ILibraryManager libraryManager,
|
||||
string showTitle,
|
||||
string showPath,
|
||||
bool isMovie,
|
||||
Library library)
|
||||
{
|
||||
Show show = libraryManager.GetShowByPath(showPath);
|
||||
Show show = await libraryManager.GetShowByPath(showPath);
|
||||
if (show != null)
|
||||
return show;
|
||||
show = await _metadataProvider.SearchShow(showTitle, isMovie, library);
|
||||
show.Path = showPath;
|
||||
show.People = await _metadataProvider.GetPeople(show, library);
|
||||
await libraryManager.RegisterShow(show);
|
||||
await _thumbnailsManager.Validate(show.People);
|
||||
await _thumbnailsManager.Validate(show);
|
||||
return show;
|
||||
}
|
||||
|
||||
private async Task<Season> GetSeason(ILibraryManager libraryManager, Show show, long seasonNumber, Library library)
|
||||
private async Task<Season> GetSeason(ILibraryManager libraryManager,
|
||||
Show show,
|
||||
int seasonNumber,
|
||||
Library library)
|
||||
{
|
||||
if (seasonNumber == -1)
|
||||
return default;
|
||||
Season season = libraryManager.GetSeason(show.Slug, seasonNumber);
|
||||
Season season = await libraryManager.GetSeason(show.Slug, seasonNumber);
|
||||
if (season == null)
|
||||
{
|
||||
season = await _metadataProvider.GetSeason(show, seasonNumber, library);
|
||||
await libraryManager.RegisterSeason(season);
|
||||
await _thumbnailsManager.Validate(season);
|
||||
}
|
||||
season.Show = show;
|
||||
return season;
|
||||
}
|
||||
|
||||
private async Task<Episode> GetEpisode(ILibraryManager libraryManager, Show show, Season season, long episodeNumber, long absoluteNumber, string episodePath, Library library)
|
||||
private async Task<Episode> GetEpisode(ILibraryManager libraryManager,
|
||||
Show show,
|
||||
Season season,
|
||||
int episodeNumber,
|
||||
int absoluteNumber,
|
||||
string episodePath,
|
||||
Library library)
|
||||
{
|
||||
Episode episode = await _metadataProvider.GetEpisode(show, episodePath, season?.SeasonNumber ?? -1, episodeNumber, absoluteNumber, library);
|
||||
if (season == null)
|
||||
season = await GetSeason(libraryManager, show, episode.SeasonNumber, library);
|
||||
Episode episode = await _metadataProvider.GetEpisode(show,
|
||||
episodePath,
|
||||
season?.SeasonNumber ?? -1,
|
||||
episodeNumber,
|
||||
absoluteNumber,
|
||||
library);
|
||||
|
||||
season ??= await GetSeason(libraryManager, show, episode.SeasonNumber, library);
|
||||
episode.Season = season;
|
||||
episode.SeasonID = season?.ID;
|
||||
if (season == null)
|
||||
{
|
||||
await Console.Error.WriteLineAsync("\tError: You don't have any provider that support absolute epiode numbering. Install one and try again.");
|
||||
await Console.Error.WriteLineAsync("Error: You don't have any provider that support absolute epiode numbering. Install one and try again.");
|
||||
return default;
|
||||
}
|
||||
|
||||
@ -215,7 +235,13 @@ namespace Kyoo.Controllers
|
||||
|
||||
private async Task<Episode> GetMovie(Show show, string episodePath)
|
||||
{
|
||||
Episode episode = new Episode {Title = show.Title, Path = episodePath, Show = show};
|
||||
Episode episode = new Episode
|
||||
{
|
||||
Title = show.Title,
|
||||
Path = episodePath,
|
||||
Show = show,
|
||||
ShowID = show.ID
|
||||
};
|
||||
episode.Tracks = await GetTracks(episode);
|
||||
return episode;
|
||||
}
|
||||
|
@ -58,9 +58,9 @@ namespace Kyoo.Tasks
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetPossibleParameters()
|
||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
||||
{
|
||||
return null;
|
||||
return Task.FromResult<IEnumerable<string>>(null);
|
||||
}
|
||||
|
||||
public int? Progress()
|
||||
|
@ -28,9 +28,9 @@ namespace Kyoo.Tasks
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetPossibleParameters()
|
||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
||||
{
|
||||
return null;
|
||||
return Task.FromResult<IEnumerable<string>>(null);
|
||||
}
|
||||
|
||||
public int? Progress()
|
||||
|
@ -24,9 +24,9 @@ namespace Kyoo.Tasks
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetPossibleParameters()
|
||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
||||
{
|
||||
return null;
|
||||
return Task.FromResult<IEnumerable<string>>(null);
|
||||
}
|
||||
|
||||
public int? Progress()
|
||||
|
@ -62,7 +62,7 @@ namespace Kyoo.Tasks
|
||||
edited.ID = old.ID;
|
||||
edited.Slug = old.Slug;
|
||||
edited.Path = old.Path;
|
||||
await libraryManager.Edit(edited, true);
|
||||
await libraryManager.EditShow(edited, true);
|
||||
await _thumbnailsManager.Validate(edited, true);
|
||||
}
|
||||
if (old.Seasons != null)
|
||||
@ -95,7 +95,7 @@ namespace Kyoo.Tasks
|
||||
Library library = _database.LibraryLinks.First(x => x.Show == show && x.Library != null).Library;
|
||||
Season edited = await _providerManager.GetSeason(show, old.SeasonNumber, library);
|
||||
edited.ID = old.ID;
|
||||
await libraryManager.Edit(edited, true);
|
||||
await libraryManager.EditSeason(edited, true);
|
||||
await _thumbnailsManager.Validate(edited, true);
|
||||
}
|
||||
if (old.Episodes != null)
|
||||
@ -110,13 +110,13 @@ namespace Kyoo.Tasks
|
||||
Library library = _database.LibraryLinks.First(x => x.Show == show && x.Library != null).Library;
|
||||
Episode edited = await _providerManager.GetEpisode(show, old.Path, old.SeasonNumber, old.EpisodeNumber, old.AbsoluteNumber, library);
|
||||
edited.ID = old.ID;
|
||||
await libraryManager.Edit(edited, true);
|
||||
await libraryManager.EditEpisode(edited, true);
|
||||
await _thumbnailsManager.Validate(edited, true);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetPossibleParameters()
|
||||
public Task<IEnumerable<string>> GetPossibleParameters()
|
||||
{
|
||||
return default;
|
||||
return Task.FromResult<IEnumerable<string>>(null);
|
||||
}
|
||||
|
||||
public int? Progress()
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Kyoo.Api
|
||||
@ -19,9 +20,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{collectionSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<Collection> GetShows(string collectionSlug)
|
||||
public async Task<ActionResult<Collection>> GetShows(string collectionSlug)
|
||||
{
|
||||
Collection collection = _libraryManager.GetCollection(collectionSlug);
|
||||
Collection collection = await _libraryManager.GetCollection(collectionSlug);
|
||||
|
||||
if (collection == null)
|
||||
return NotFound();
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@ -20,9 +21,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{showSlug}/season/{seasonNumber}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<IEnumerable<Episode>> GetEpisodesForSeason(string showSlug, long seasonNumber)
|
||||
public async Task<ActionResult<IEnumerable<Episode>>> GetEpisodesForSeason(string showSlug, int seasonNumber)
|
||||
{
|
||||
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug, seasonNumber);
|
||||
IEnumerable<Episode> episodes = await _libraryManager.GetEpisodes(showSlug, seasonNumber);
|
||||
|
||||
if(episodes == null)
|
||||
return NotFound();
|
||||
@ -33,9 +34,9 @@ namespace Kyoo.Api
|
||||
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
|
||||
[Authorize(Policy="Read")]
|
||||
[JsonDetailed]
|
||||
public ActionResult<Episode> GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<ActionResult<Episode>> GetEpisode(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -18,9 +19,9 @@ namespace Kyoo.API
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public ActionResult<IEnumerable<Genre>> Index()
|
||||
public async Task<ActionResult<IEnumerable<Genre>>> Index()
|
||||
{
|
||||
return _libraryManager.GetGenres().ToList();
|
||||
return (await _libraryManager.GetGenres()).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ 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
|
||||
@ -22,15 +23,15 @@ namespace Kyoo.Api
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<Library> GetLibraries()
|
||||
public async Task<IEnumerable<Library>> GetLibraries()
|
||||
{
|
||||
return _libraryManager.GetLibraries();
|
||||
return await _libraryManager.GetLibraries();
|
||||
}
|
||||
|
||||
[Route("/api/library/create")]
|
||||
[HttpPost]
|
||||
[Authorize(Policy="Admin")]
|
||||
public IActionResult CreateLibrary([FromBody] Library library)
|
||||
public async Task<IActionResult> CreateLibrary([FromBody] Library library)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(library);
|
||||
@ -40,19 +41,18 @@ namespace Kyoo.Api
|
||||
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 (_libraryManager.GetLibrary(library.Slug) != null)
|
||||
if (await _libraryManager.GetLibrary(library.Slug) != null)
|
||||
return BadRequest(new {error = "Duplicated library slug"});
|
||||
_libraryManager.Register(library);
|
||||
_libraryManager.SaveChanges();
|
||||
await _libraryManager.RegisterLibrary(library);
|
||||
_taskManager.StartTask("scan", library.Slug);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("{librarySlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<IEnumerable<Show>> GetShows(string librarySlug)
|
||||
public async Task<ActionResult<IEnumerable<Show>>> GetShows(string librarySlug)
|
||||
{
|
||||
Library library = _libraryManager.GetLibrary(librarySlug);
|
||||
Library library = await _libraryManager.GetLibrary(librarySlug);
|
||||
|
||||
if (library == null)
|
||||
return NotFound();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -19,9 +20,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{peopleSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<Collection> GetPeople(string peopleSlug)
|
||||
public async Task<ActionResult<Collection>> GetPeople(string peopleSlug)
|
||||
{
|
||||
People people = _libraryManager.GetPeople(peopleSlug);
|
||||
People people = await _libraryManager.GetPeople(peopleSlug);
|
||||
|
||||
if (people == null)
|
||||
return NotFound();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Kyoo.Controllers;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -18,17 +19,17 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{query}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<SearchResult> Search(string query)
|
||||
public async Task<ActionResult<SearchResult>> Search(string query)
|
||||
{
|
||||
SearchResult result = new SearchResult
|
||||
{
|
||||
Query = query,
|
||||
Collections = _libraryManager.SearchCollections(query),
|
||||
Shows = _libraryManager.SearchShows(query),
|
||||
Episodes = _libraryManager.SearchEpisodes(query),
|
||||
People = _libraryManager.SearchPeople(query),
|
||||
Genres = _libraryManager.SearchGenres(query),
|
||||
Studios = _libraryManager.SearchStudios(query)
|
||||
Collections = await _libraryManager.SearchCollections(query),
|
||||
Shows = await _libraryManager.SearchShows(query),
|
||||
Episodes = await _libraryManager.SearchEpisodes(query),
|
||||
People = await _libraryManager.SearchPeople(query),
|
||||
Genres = await _libraryManager.SearchGenres(query),
|
||||
Studios = await _libraryManager.SearchStudios(query)
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
@ -37,15 +37,18 @@ namespace Kyoo.Api
|
||||
[Authorize(Policy="Read")]
|
||||
public IEnumerable<Show> GetShows()
|
||||
{
|
||||
return _database.LibraryLinks.AsEnumerable().Select(x => x.Show ?? x.Collection.AsShow());
|
||||
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 ActionResult<Show> GetShow(string slug)
|
||||
public async Task<ActionResult<Show>> GetShow(string slug)
|
||||
{
|
||||
Show show = _libraryManager.GetShow(slug);
|
||||
Show show = await _libraryManager.GetShow(slug);
|
||||
|
||||
if (show == null)
|
||||
return NotFound();
|
||||
@ -55,7 +58,7 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpPost("edit/{slug}")]
|
||||
[Authorize(Policy="Write")]
|
||||
public IActionResult EditShow(string slug, [FromBody] Show show)
|
||||
public async Task<IActionResult> EditShow(string slug, [FromBody] Show show)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(show);
|
||||
@ -66,7 +69,7 @@ namespace Kyoo.Api
|
||||
show.ID = old.ID;
|
||||
show.Slug = slug;
|
||||
show.Path = old.Path;
|
||||
_libraryManager.Edit(show, false);
|
||||
await _libraryManager.EditShow(show, false);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -79,7 +82,6 @@ namespace Kyoo.Api
|
||||
Show show = _database.Shows.Include(x => x.ExternalIDs).FirstOrDefault(x => x.Slug == slug);
|
||||
if (show == null)
|
||||
return NotFound();
|
||||
show.ExternalIDs = _libraryManager.Validate(externalIDs);
|
||||
_database.SaveChanges();
|
||||
_taskManager.StartTask("re-scan", $"show/{slug}");
|
||||
return Ok();
|
||||
@ -96,7 +98,7 @@ namespace Kyoo.Api
|
||||
[Authorize(Policy = "Write")]
|
||||
public async Task<IActionResult> DownloadImages(string slug)
|
||||
{
|
||||
Show show = _libraryManager.GetShow(slug);
|
||||
Show show = await _libraryManager.GetShow(slug);
|
||||
if (show == null)
|
||||
return NotFound();
|
||||
await _thumbnailsManager.Validate(show, true);
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -18,9 +19,9 @@ namespace Kyoo.API
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public ActionResult<IEnumerable<Studio>> Index()
|
||||
public async Task<ActionResult<IEnumerable<Studio>>> Index()
|
||||
{
|
||||
return _libraryManager.GetStudios().ToList();
|
||||
return (await _libraryManager.GetStudios()).ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -14,31 +14,37 @@ namespace Kyoo.Api
|
||||
public class SubtitleController : ControllerBase
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ITranscoder _transcoder;
|
||||
//private readonly ITranscoder _transcoder;
|
||||
|
||||
public SubtitleController(ILibraryManager libraryManager, ITranscoder transcoder)
|
||||
public SubtitleController(ILibraryManager libraryManager/*, ITranscoder transcoder*/)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_transcoder = transcoder;
|
||||
// _transcoder = transcoder;
|
||||
}
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
|
||||
[Authorize(Policy="Play")]
|
||||
public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension)
|
||||
public async Task<IActionResult> GetSubtitle(string showSlug,
|
||||
int seasonNumber,
|
||||
int episodeNumber,
|
||||
string identifier,
|
||||
string extension)
|
||||
{
|
||||
string languageTag = identifier.Length == 3 ? identifier.Substring(0, 3) : null;
|
||||
bool forced = identifier.Length > 4 && identifier.Substring(4) == "forced";
|
||||
Track subtitle = null;
|
||||
|
||||
if (languageTag != null)
|
||||
subtitle = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Tracks
|
||||
subtitle = (await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber))?.Tracks
|
||||
.FirstOrDefault(x => x.Language == languageTag && x.IsForced == forced);
|
||||
|
||||
if (subtitle == null)
|
||||
{
|
||||
string idString = identifier.IndexOf('-') != -1 ? identifier.Substring(0, identifier.IndexOf('-')) : identifier;
|
||||
long.TryParse(idString, out long id);
|
||||
subtitle = _libraryManager.GetTracks().FirstOrDefault(x => x.ID == id);
|
||||
string idString = identifier.IndexOf('-') != -1
|
||||
? identifier.Substring(0, identifier.IndexOf('-'))
|
||||
: identifier;
|
||||
int.TryParse(idString, out int id);
|
||||
subtitle = await _libraryManager.GetTrack(id);
|
||||
}
|
||||
|
||||
if (subtitle == null)
|
||||
@ -57,43 +63,43 @@ namespace Kyoo.Api
|
||||
return PhysicalFile(subtitle.Path, mime);
|
||||
}
|
||||
|
||||
[HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Admin")]
|
||||
public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
|
||||
{
|
||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
episode.Tracks = null;
|
||||
|
||||
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||
foreach (Track track in tracks)
|
||||
{
|
||||
track.EpisodeID = episode.ID;
|
||||
_libraryManager.Register(track);
|
||||
}
|
||||
await _libraryManager.SaveChanges();
|
||||
return "Done. " + tracks.Length + " track(s) extracted.";
|
||||
}
|
||||
|
||||
[HttpGet("extract/{showSlug}")]
|
||||
[Authorize(Policy="Admin")]
|
||||
public async Task<string> ExtractSubtitle(string showSlug)
|
||||
{
|
||||
IEnumerable<Episode> episodes = _libraryManager.GetShow(showSlug).Episodes;
|
||||
foreach (Episode episode in episodes)
|
||||
{
|
||||
episode.Tracks = null;
|
||||
|
||||
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||
foreach (Track track in tracks)
|
||||
{
|
||||
track.EpisodeID = episode.ID;
|
||||
_libraryManager.Register(track);
|
||||
}
|
||||
await _libraryManager.SaveChanges();
|
||||
}
|
||||
|
||||
return "Done.";
|
||||
}
|
||||
// [HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
// [Authorize(Policy="Admin")]
|
||||
// public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
|
||||
// {
|
||||
// Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
// episode.Tracks = null;
|
||||
//
|
||||
// Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||
// foreach (Track track in tracks)
|
||||
// {
|
||||
// track.EpisodeID = episode.ID;
|
||||
// _libraryManager.Register(track);
|
||||
// }
|
||||
// await _libraryManager.SaveChanges();
|
||||
// return "Done. " + tracks.Length + " track(s) extracted.";
|
||||
// }
|
||||
//
|
||||
// [HttpGet("extract/{showSlug}")]
|
||||
// [Authorize(Policy="Admin")]
|
||||
// public async Task<string> ExtractSubtitle(string showSlug)
|
||||
// {
|
||||
// IEnumerable<Episode> episodes = _libraryManager.GetShow(showSlug).Episodes;
|
||||
// foreach (Episode episode in episodes)
|
||||
// {
|
||||
// episode.Tracks = null;
|
||||
//
|
||||
// Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
|
||||
// foreach (Track track in tracks)
|
||||
// {
|
||||
// track.EpisodeID = episode.ID;
|
||||
// _libraryManager.Register(track);
|
||||
// }
|
||||
// await _libraryManager.SaveChanges();
|
||||
// }
|
||||
//
|
||||
// return "Done.";
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@ -20,9 +21,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("poster/{showSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public IActionResult GetShowThumb(string showSlug)
|
||||
public async Task<IActionResult> GetShowThumb(string showSlug)
|
||||
{
|
||||
string path = _libraryManager.GetShow(showSlug)?.Path;
|
||||
string path = (await _libraryManager.GetShow(showSlug))?.Path;
|
||||
if (path == null)
|
||||
return NotFound();
|
||||
|
||||
@ -35,9 +36,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("logo/{showSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public IActionResult GetShowLogo(string showSlug)
|
||||
public async Task<IActionResult> GetShowLogo(string showSlug)
|
||||
{
|
||||
string path = _libraryManager.GetShow(showSlug)?.Path;
|
||||
string path = (await _libraryManager.GetShow(showSlug))?.Path;
|
||||
if (path == null)
|
||||
return NotFound();
|
||||
|
||||
@ -50,9 +51,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("backdrop/{showSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public IActionResult GetShowBackdrop(string showSlug)
|
||||
public async Task<IActionResult> GetShowBackdrop(string showSlug)
|
||||
{
|
||||
string path = _libraryManager.GetShow(showSlug)?.Path;
|
||||
string path = (await _libraryManager.GetShow(showSlug))?.Path;
|
||||
if (path == null)
|
||||
return NotFound();
|
||||
|
||||
@ -76,9 +77,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public IActionResult GetEpisodeThumb(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<IActionResult> GetEpisodeThumb(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
string path = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Path;
|
||||
string path = (await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber))?.Path;
|
||||
if (path == null)
|
||||
return NotFound();
|
||||
|
||||
|
@ -27,9 +27,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Play")]
|
||||
public IActionResult Index(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<IActionResult> Index(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
return PhysicalFile(episode.Path, "video/x-matroska", true);
|
||||
@ -38,9 +38,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Play")]
|
||||
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<IActionResult> Transmux(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
return NotFound();
|
||||
@ -61,9 +61,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Play")]
|
||||
public async Task<IActionResult> Transcode(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<IActionResult> Transcode(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
return NotFound();
|
||||
@ -85,9 +85,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{movieSlug}")]
|
||||
[Authorize(Policy="Play")]
|
||||
public IActionResult Index(string movieSlug)
|
||||
public async Task<IActionResult> Index(string movieSlug)
|
||||
{
|
||||
Episode episode = _libraryManager.GetMovieEpisode(movieSlug);
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
return PhysicalFile(episode.Path, "video/webm", true);
|
||||
@ -98,7 +98,7 @@ namespace Kyoo.Api
|
||||
[Authorize(Policy="Play")]
|
||||
public async Task<IActionResult> Transmux(string movieSlug)
|
||||
{
|
||||
Episode episode = _libraryManager.GetMovieEpisode(movieSlug);
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
return NotFound();
|
||||
@ -112,7 +112,7 @@ namespace Kyoo.Api
|
||||
[Authorize(Policy="Play")]
|
||||
public async Task<IActionResult> Transcode(string movieSlug)
|
||||
{
|
||||
Episode episode = _libraryManager.GetMovieEpisode(movieSlug);
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
return NotFound();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Kyoo.Controllers;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -18,9 +19,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<WatchItem> Index(string showSlug, long seasonNumber, long episodeNumber)
|
||||
public async Task<ActionResult<WatchItem>> Index(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
Episode item = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
Episode item = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if(item == null)
|
||||
return NotFound();
|
||||
@ -30,9 +31,9 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet("{movieSlug}")]
|
||||
[Authorize(Policy="Read")]
|
||||
public ActionResult<WatchItem> Index(string movieSlug)
|
||||
public async Task<ActionResult<WatchItem>> Index(string movieSlug)
|
||||
{
|
||||
Episode item = _libraryManager.GetMovieEpisode(movieSlug);
|
||||
Episode item = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if(item == null)
|
||||
return NotFound();
|
||||
|
Loading…
x
Reference in New Issue
Block a user